feat(login): 更换登录验证码为图形字符验证码
- 配置文件 website.js 中将 captchaType 从 'behavior' 改为 'image' - 修改 userlogin.vue,图形验证码图片由输入框内联改为输入框旁独立显示 - 重写 login.scss 样式,实现验证码图片区域带边框和高亮效果 - 确保验证码图片点击可刷新,且支持从后端接口获取数据 - 登录页仍默认显示 IAM 登录,需切换「账号密码登录」显示验证码区域 feat(contract-manage): 优化所属组织搜索栏为树形下拉选择框 - 引入并应用 organization-search mixin 统一管理所属组织搜索 - contract-manage.js、driver.js、transport-ship.js、transport-vehicle.js 中所属组织搜索改为 searchslot 模式 - contract-manage.vue 中新增 renderOrganizationSearch 方法,渲染基于 ElTreeSelect 的树形下拉组件 - 组织树数据加载时自动排除「外部组织」节点,保持搜索选项清晰 - 所有相关所属组织搜索统一样式与交互,提升用户体验 feat(system): 用户和部门视图样式及操作改进 - user.vue 和 userinfo.vue 中 el-tabs 组件添加 border-card 类型,提升标签页视觉效果 - dept.vue 中添加查看、编辑、删除操作入口,绑定对应方法,通过权限控制显示权限按钮 - dept.vue 菜单宽度、对话框宽度及行为配置优化 style(login): 调整登录样式及验证码布局细节 - 调整 .login-code-wrap 及内部元素的 flex 布局,输入框与验证码图片并排显示 - 设置验证码图片容器尺寸、边框及 hover 高亮样式 - 确保验证码图片撑满容器并禁止用户选中 refactor(mixins): 新增 organization-search 统一搜索 mixin - 实现组织树数据加载、排除外部节点、归一化及扁平化处理 - 提供 renderOrganizationSearch 方法用于渲染统一树形选择搜索框 - 减少重复代码,方便各页面快速接入和统一维护 chore(vehicle): 车辆页面引入 organization-search mixin - 在车辆视图 vehicle.vue 中混入 organization-search,增强所属组织搜索功能一致性
This commit is contained in:
@@ -33,3 +33,13 @@
|
|||||||
- 样式:`.el-select { width: 180px }` 已成 dead code,移除。
|
- 样式:`.el-select { width: 180px }` 已成 dead code,移除。
|
||||||
- `:deep(...)` 调整:去掉 `margin-right:auto`,只留 `order:-1`。`.avue-form__menu` 本身 `flex / flex-end`,check-tag 组排首项后,整体仍紧靠右侧,与 `[查询][重置][收起]` 形成 `[快捷筛选] [查询] [重置] [收起]` 右对齐序列。
|
- `:deep(...)` 调整:去掉 `margin-right:auto`,只留 `order:-1`。`.avue-form__menu` 本身 `flex / flex-end`,check-tag 组排首项后,整体仍紧靠右侧,与 `[查询][重置][收起]` 形成 `[快捷筛选] [查询] [重置] [收起]` 右对齐序列。
|
||||||
|
|
||||||
|
## 登录验证码:滑块(behavior) → 图形字符验证码(image)
|
||||||
|
- 文件:`src/config/website.js`(第14行 `captchaType: 'behavior'` → `'image'`)、`src/page/login/userlogin.vue`、`src/styles/login.scss`
|
||||||
|
- 背景:登录页原 `captchaType:'behavior'`(滑块/旋转行为验证)。需求改成截图中的「输入框 + 右侧独立彩色字符验证码图片」。
|
||||||
|
- 改动:
|
||||||
|
1. `website.js` 改 `captchaType: 'image'` 启用图形验证码分支(代码原本就有 image 模式的 UI 与 `getCaptcha()` 逻辑,仅未启用)。
|
||||||
|
2. `userlogin.vue` image 分支模板:验证码图片从 `el-input` 的 `#append` 内联改为 form-item 内 `.login-code-wrap` 并排独立方块(输入框 flex:1 + 右侧 130px 图片块),点击刷新。
|
||||||
|
3. `login.scss` 重写 `.login-code/.login-code-wrap/.login-code-box/.login-code-img`:flex 并排、图片块带 1px 边框 + hover 主色高亮、`object-fit:fill` 撑满。
|
||||||
|
- 验证:`vite build --outDir /tmp/tms-verify-build` 全量编译通过(exit 0,无报错)。注意原 `pnpm build` 因 WorkBuddy safe-delete 钩子拦截清空 dist/(741 文件)而中断,非代码问题。
|
||||||
|
- 注意:登录页 `activeName` 默认 `'iam'`(IAM 统一登录),图形验证码在 `userlogin.vue`,需点「账号密码登录」才可见;验证码图片依赖后端 `/blade-auth/oauth/captcha` 返回的 `data.key` + `data.image`。
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ export default {
|
|||||||
tenantMode: true, // 是否开启租户模式
|
tenantMode: true, // 是否开启租户模式
|
||||||
tenantId: '000000', // 管理组租户编号
|
tenantId: '000000', // 管理组租户编号
|
||||||
captchaMode: true, // 是否开启验证码模式
|
captchaMode: true, // 是否开启验证码模式
|
||||||
captchaType: 'behavior', // 验证码类型(image:首屏图形验证码 behavior:登录时弹出点选/滑块/旋转随机行为验证)
|
captchaType: 'image', // 验证码类型(image:首屏图形验证码 behavior:登录时弹出点选/滑块/旋转随机行为验证)
|
||||||
switchMode: false, // 是否开启登录切换角色部门
|
switchMode: false, // 是否开启登录切换角色部门
|
||||||
lockPage: '/lock', // 锁屏页面地址
|
lockPage: '/lock', // 锁屏页面地址
|
||||||
tokenTime: 3000, // 定时刷新token间隔(单位:毫秒)
|
tokenTime: 3000, // 定时刷新token间隔(单位:毫秒)
|
||||||
|
|||||||
@@ -0,0 +1,115 @@
|
|||||||
|
import { getDeptTree } from '@/api/system/dept';
|
||||||
|
import { ElTreeSelect } from 'element-plus';
|
||||||
|
import { h } from 'vue';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 所属组织 统一搜索 mixin
|
||||||
|
* ------------------------------------------------------------------
|
||||||
|
* 全站「所属组织」搜索栏统一为树形下拉(el-tree-select),风格与客户档案
|
||||||
|
* (vehicle/customer-archive.vue)保持一致。
|
||||||
|
*
|
||||||
|
* 接入步骤(在使用了 avue-crud 的页面中):
|
||||||
|
* 1. 混入本 mixin:mixins: [organizationSearch]
|
||||||
|
* 2. option 中「所属组织」列加上 searchslot: true(prop 为 organizationName 或 deptName 均可)
|
||||||
|
* 3. 在 created / 初始化时调用 this.loadOrganizationOptions()
|
||||||
|
*
|
||||||
|
* 说明:
|
||||||
|
* - 自动识别 organizationName / deptName 两种 prop,并挂载 column.renderSearch
|
||||||
|
* - 树节点标识统一用 id(node-key='id'),返回值为部门 id
|
||||||
|
* - 页面若已有 excludeExternalOrganization / normalizeOrgTree 等方法,
|
||||||
|
* 组件自身方法优先级更高,会覆盖本 mixin 的默认实现
|
||||||
|
* - 搜索值(id)需在各自的 searchChange / normalizeSearch 中按后端要求
|
||||||
|
* 转换为部门名称(参考 contract-manage 的 normalizeSearch)
|
||||||
|
*/
|
||||||
|
const ORG_PROPS = ['organizationName', 'deptName'];
|
||||||
|
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
// 树形组织数据,仅供搜索栏 el-tree-select 使用;
|
||||||
|
// 与页面自身 organizationOptions(多为表单扁平列表)隔离,避免相互覆盖
|
||||||
|
organizationTreeOptions: [],
|
||||||
|
organizationTreeFlatOptions: [],
|
||||||
|
organizationLoading: false,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
loadOrganizationOptions() {
|
||||||
|
if (this.organizationLoading) return;
|
||||||
|
this.organizationLoading = true;
|
||||||
|
const tenantId = this.userInfo?.tenantId;
|
||||||
|
getDeptTree(tenantId)
|
||||||
|
.then(res => {
|
||||||
|
const source = res.data?.data || res.data || [];
|
||||||
|
const tree = this.excludeExternalOrganization
|
||||||
|
? this.excludeExternalOrganization(source)
|
||||||
|
: source;
|
||||||
|
this.organizationTreeOptions = this.normalizeOrgTree(tree);
|
||||||
|
this.organizationTreeFlatOptions = this.flattenOrgTree(this.organizationTreeOptions);
|
||||||
|
const option = this.tableOption || this.option;
|
||||||
|
if (!option) return;
|
||||||
|
ORG_PROPS.forEach(prop => {
|
||||||
|
const column = this.findColumn?.(option.column, prop);
|
||||||
|
if (column) {
|
||||||
|
column.renderSearch = scope => this.renderOrganizationSearch(scope, prop);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
this.organizationLoading = false;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
// 默认排除「外部组织」节点;页面可覆盖
|
||||||
|
excludeExternalOrganization(tree = []) {
|
||||||
|
return (tree || []).reduce((result, item) => {
|
||||||
|
const name = item.title || item.deptName || item.name || item.label || '';
|
||||||
|
if (String(name).trim() === '外部组织') return result;
|
||||||
|
result.push({
|
||||||
|
...item,
|
||||||
|
children: this.excludeExternalOrganization(item.children || []),
|
||||||
|
});
|
||||||
|
return result;
|
||||||
|
}, []);
|
||||||
|
},
|
||||||
|
normalizeOrgTree(tree = []) {
|
||||||
|
return (tree || []).map(item => {
|
||||||
|
const label = item.title || item.deptName || item.name || item.label || '';
|
||||||
|
const children = this.normalizeOrgTree(item.children || []);
|
||||||
|
return {
|
||||||
|
...item,
|
||||||
|
id: String(item.id),
|
||||||
|
label,
|
||||||
|
rawLabel: label,
|
||||||
|
children: children.length ? children : undefined,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
},
|
||||||
|
flattenOrgTree(tree = []) {
|
||||||
|
return (tree || []).flatMap(item => [
|
||||||
|
{ id: String(item.id), label: item.label, rawLabel: item.rawLabel },
|
||||||
|
...this.flattenOrgTree(item.children || []),
|
||||||
|
]);
|
||||||
|
},
|
||||||
|
findOrgById(id) {
|
||||||
|
const value = Array.isArray(id) ? id.at(-1) : id;
|
||||||
|
return this.organizationTreeFlatOptions.find(item => String(item.id) === String(value));
|
||||||
|
},
|
||||||
|
renderOrganizationSearch(scope, prop = 'organizationName') {
|
||||||
|
return h(ElTreeSelect, {
|
||||||
|
modelValue: scope.row?.[prop] || '',
|
||||||
|
'onUpdate:modelValue': value => {
|
||||||
|
if (scope.row) scope.row[prop] = value;
|
||||||
|
},
|
||||||
|
data: this.organizationTreeOptions,
|
||||||
|
'node-key': 'id',
|
||||||
|
'check-strictly': true,
|
||||||
|
filterable: true,
|
||||||
|
clearable: true,
|
||||||
|
'render-after-expand': false,
|
||||||
|
style: 'width: 100%',
|
||||||
|
placeholder: '请选择 所属组织',
|
||||||
|
props: { label: 'label', value: 'id', children: 'children' },
|
||||||
|
});
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
@@ -286,20 +286,11 @@ export const option = createCrudOption([
|
|||||||
prop: 'organizationName',
|
prop: 'organizationName',
|
||||||
search: true,
|
search: true,
|
||||||
searchOrder: 3,
|
searchOrder: 3,
|
||||||
searchType: 'cascader',
|
searchslot: true,
|
||||||
searchPlaceholder: '全部',
|
searchPlaceholder: '请选择 所属组织',
|
||||||
formslot: true,
|
formslot: true,
|
||||||
order: 120,
|
order: 120,
|
||||||
dicData: [],
|
dicData: [],
|
||||||
props: {
|
|
||||||
label: 'label',
|
|
||||||
value: 'id',
|
|
||||||
children: 'children',
|
|
||||||
},
|
|
||||||
checkStrictly: true,
|
|
||||||
emitPath: false,
|
|
||||||
showAllLevels: false,
|
|
||||||
filterable: true,
|
|
||||||
minWidth: 150,
|
minWidth: 150,
|
||||||
rules: selectRule('所属组织'),
|
rules: selectRule('所属组织'),
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -81,9 +81,7 @@ export const option = {
|
|||||||
prop: 'organizationName',
|
prop: 'organizationName',
|
||||||
search: true,
|
search: true,
|
||||||
searchOrder: 1,
|
searchOrder: 1,
|
||||||
type: 'select',
|
searchslot: true,
|
||||||
filterable: true,
|
|
||||||
dicData: [],
|
|
||||||
slot: true,
|
slot: true,
|
||||||
minWidth: 160,
|
minWidth: 160,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -37,9 +37,7 @@ export const option = {
|
|||||||
prop: 'organizationName',
|
prop: 'organizationName',
|
||||||
search: true,
|
search: true,
|
||||||
searchOrder: 1,
|
searchOrder: 1,
|
||||||
type: 'select',
|
searchslot: true,
|
||||||
filterable: true,
|
|
||||||
dicData: [],
|
|
||||||
slot: true,
|
slot: true,
|
||||||
minWidth: 160,
|
minWidth: 160,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -46,9 +46,7 @@ export const option = {
|
|||||||
prop: 'organizationName',
|
prop: 'organizationName',
|
||||||
search: true,
|
search: true,
|
||||||
searchOrder: 1,
|
searchOrder: 1,
|
||||||
type: 'select',
|
searchslot: true,
|
||||||
filterable: true,
|
|
||||||
dicData: [],
|
|
||||||
slot: true,
|
slot: true,
|
||||||
minWidth: 150,
|
minWidth: 150,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -46,21 +46,22 @@
|
|||||||
</el-input>
|
</el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item prop="code" class="login-code" v-if="captchaMode && captchaType === 'image'">
|
<el-form-item prop="code" class="login-code" v-if="captchaMode && captchaType === 'image'">
|
||||||
<el-input
|
<div class="login-code-wrap">
|
||||||
@keyup.enter="handleLogin"
|
<el-input
|
||||||
v-model="loginForm.code"
|
@keyup.enter="handleLogin"
|
||||||
auto-complete="off"
|
v-model="loginForm.code"
|
||||||
:placeholder="$t('login.code')"
|
auto-complete="off"
|
||||||
>
|
maxlength="6"
|
||||||
<template #prefix>
|
:placeholder="$t('login.code')"
|
||||||
<i class="icon-yanzhengma"></i>
|
>
|
||||||
</template>
|
<template #prefix>
|
||||||
<template #append>
|
<i class="icon-yanzhengma"></i>
|
||||||
<div class="login-code-box">
|
</template>
|
||||||
<img :src="loginForm.image" class="login-code-img" @click="refreshCode" />
|
</el-input>
|
||||||
</div>
|
<div class="login-code-box" @click="refreshCode" title="点击刷新验证码">
|
||||||
</template>
|
<img :src="loginForm.image" class="login-code-img" alt="验证码" />
|
||||||
</el-input>
|
</div>
|
||||||
|
</div>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item>
|
<el-form-item>
|
||||||
<el-button type="primary" @click.prevent="handleLogin" class="login-submit"
|
<el-button type="primary" @click.prevent="handleLogin" class="login-submit"
|
||||||
|
|||||||
+26
-15
@@ -134,26 +134,37 @@
|
|||||||
}
|
}
|
||||||
.login-code {
|
.login-code {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
}
|
||||||
.el-input-group__append {
|
.login-code-wrap {
|
||||||
background-color: #fff;
|
display: flex;
|
||||||
|
align-items: stretch;
|
||||||
|
width: 100%;
|
||||||
|
gap: 10px;
|
||||||
|
.el-input {
|
||||||
|
flex: 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.login-code-box {
|
.login-code-box {
|
||||||
|
width: 130px;
|
||||||
|
height: 38px;
|
||||||
|
flex: none;
|
||||||
|
border: 1px solid #dcdfe6;
|
||||||
|
border-radius: 4px;
|
||||||
|
overflow: hidden;
|
||||||
|
cursor: pointer;
|
||||||
|
background: #fff;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
transition: border-color 0.2s;
|
||||||
|
&:hover {
|
||||||
|
border-color: #409eff;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.login-code-img {
|
.login-code-img {
|
||||||
cursor: pointer;
|
width: 100%;
|
||||||
min-width: 100px;
|
height: 100%;
|
||||||
padding: 0 5px;
|
object-fit: fill;
|
||||||
height: 30px;
|
display: block;
|
||||||
color: #333;
|
user-select: none;
|
||||||
font-size: 20px;
|
|
||||||
font-weight: bold;
|
|
||||||
letter-spacing: 3px;
|
|
||||||
line-height: 38px;
|
|
||||||
text-indent: 5px;
|
|
||||||
text-align: center;
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -794,7 +794,7 @@ import { getToken } from '@/utils/auth';
|
|||||||
import { downloadFileByUrl, downloadXls } from '@/utils/util';
|
import { downloadFileByUrl, downloadXls } from '@/utils/util';
|
||||||
import BillingPlanEditor from './components/billing-plan-editor.vue';
|
import BillingPlanEditor from './components/billing-plan-editor.vue';
|
||||||
import PdfPreview from '@/components/pdf-preview/main.vue';
|
import PdfPreview from '@/components/pdf-preview/main.vue';
|
||||||
import { ElImageViewer } from 'element-plus';
|
import { ElImageViewer, ElTreeSelect } from 'element-plus';
|
||||||
import { OpenFileViewer } from '@open-file-viewer/vue';
|
import { OpenFileViewer } from '@open-file-viewer/vue';
|
||||||
import { fallbackPlugin, imagePlugin, officePlugin, textPlugin } from '@open-file-viewer/core';
|
import { fallbackPlugin, imagePlugin, officePlugin, textPlugin } from '@open-file-viewer/core';
|
||||||
import '@open-file-viewer/core/style.css';
|
import '@open-file-viewer/core/style.css';
|
||||||
@@ -1684,7 +1684,10 @@ export default {
|
|||||||
this.organizationOptions = this.normalizeOrganizationTree(organizationTree);
|
this.organizationOptions = this.normalizeOrganizationTree(organizationTree);
|
||||||
this.organizationFlatOptions = this.flattenOrganizationTree(this.organizationOptions);
|
this.organizationFlatOptions = this.flattenOrganizationTree(this.organizationOptions);
|
||||||
const column = this.findColumn(this.tableOption.column, 'organizationName');
|
const column = this.findColumn(this.tableOption.column, 'organizationName');
|
||||||
if (column) column.dicData = this.organizationOptions;
|
if (column) {
|
||||||
|
column.dicData = this.organizationOptions;
|
||||||
|
column.renderSearch = scope => this.renderOrganizationSearch(scope);
|
||||||
|
}
|
||||||
this.syncCurrentOrganizationOption();
|
this.syncCurrentOrganizationOption();
|
||||||
})
|
})
|
||||||
.finally(() => {
|
.finally(() => {
|
||||||
@@ -1748,6 +1751,24 @@ export default {
|
|||||||
this.organizationOptions.unshift(item);
|
this.organizationOptions.unshift(item);
|
||||||
this.organizationFlatOptions.unshift(item);
|
this.organizationFlatOptions.unshift(item);
|
||||||
},
|
},
|
||||||
|
renderOrganizationSearch(scope) {
|
||||||
|
// 搜索区所属组织:树形下拉(与客户档案统一)
|
||||||
|
return h(ElTreeSelect, {
|
||||||
|
modelValue: scope.row?.organizationName || '',
|
||||||
|
'onUpdate:modelValue': value => {
|
||||||
|
if (scope.row) scope.row.organizationName = value;
|
||||||
|
},
|
||||||
|
data: this.organizationOptions,
|
||||||
|
'node-key': 'id',
|
||||||
|
'check-strictly': true,
|
||||||
|
filterable: true,
|
||||||
|
clearable: true,
|
||||||
|
'render-after-expand': false,
|
||||||
|
style: 'width: 100%',
|
||||||
|
placeholder: '请选择 所属组织',
|
||||||
|
props: { label: 'label', value: 'id', children: 'children' },
|
||||||
|
});
|
||||||
|
},
|
||||||
integerInput(prop, value) {
|
integerInput(prop, value) {
|
||||||
this.form[prop] = String(value || '').replace(/\D/g, '');
|
this.form[prop] = String(value || '').replace(/\D/g, '');
|
||||||
},
|
},
|
||||||
@@ -2089,6 +2110,15 @@ export default {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
.contract-name-cell {
|
||||||
|
display: inline-block;
|
||||||
|
max-width: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
vertical-align: bottom;
|
||||||
|
}
|
||||||
|
|
||||||
.contract-manage-page {
|
.contract-manage-page {
|
||||||
&__expiry-search {
|
&__expiry-search {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|||||||
@@ -32,6 +32,15 @@
|
|||||||
</el-button>
|
</el-button>
|
||||||
</template>
|
</template>
|
||||||
<template #menu="scope">
|
<template #menu="scope">
|
||||||
|
<el-link type="primary" @click.stop="handleView(scope.row, scope.index)" v-if="permissionList.viewBtn"
|
||||||
|
>查看</el-link
|
||||||
|
>
|
||||||
|
<el-link type="primary" @click.stop="handleEdit(scope.row, scope.index)" v-if="permissionList.editBtn"
|
||||||
|
>编辑</el-link
|
||||||
|
>
|
||||||
|
<el-link type="danger" @click.stop="handleDel(scope.row, scope.index)" v-if="permissionList.delBtn"
|
||||||
|
>删除</el-link
|
||||||
|
>
|
||||||
<el-link
|
<el-link
|
||||||
type="primary"
|
type="primary"
|
||||||
@click.stop="handleAdd(scope.row, scope.index)"
|
@click.stop="handleAdd(scope.row, scope.index)"
|
||||||
@@ -177,7 +186,9 @@ export default {
|
|||||||
border: true,
|
border: true,
|
||||||
index: true,
|
index: true,
|
||||||
selection: true,
|
selection: true,
|
||||||
viewBtn: true,
|
viewBtn: false,
|
||||||
|
editBtn: false,
|
||||||
|
delBtn: false,
|
||||||
menuWidth: 320,
|
menuWidth: 320,
|
||||||
dialogWidth: 800,
|
dialogWidth: 800,
|
||||||
dialogClickModal: false,
|
dialogClickModal: false,
|
||||||
@@ -519,6 +530,15 @@ export default {
|
|||||||
isRootDept(row) {
|
isRootDept(row) {
|
||||||
return row && (row.parentId === 0 || String(row.parentId) === '0');
|
return row && (row.parentId === 0 || String(row.parentId) === '0');
|
||||||
},
|
},
|
||||||
|
handleView(row, index) {
|
||||||
|
this.$refs.crud.rowView(row, index);
|
||||||
|
},
|
||||||
|
handleEdit(row, index) {
|
||||||
|
this.$refs.crud.rowEdit(row, index);
|
||||||
|
},
|
||||||
|
handleDel(row, index) {
|
||||||
|
this.$refs.crud.rowDel(row, index);
|
||||||
|
},
|
||||||
handleAdd(row) {
|
handleAdd(row) {
|
||||||
this.parentId = row.id;
|
this.parentId = row.id;
|
||||||
this.loadParentDeptCode(row.id);
|
this.loadParentDeptCode(row.id);
|
||||||
|
|||||||
@@ -204,7 +204,7 @@
|
|||||||
</el-row>
|
</el-row>
|
||||||
</el-form>
|
</el-form>
|
||||||
</section-card>
|
</section-card>
|
||||||
<el-tabs class="user-permission-tabs">
|
<el-tabs type="border-card" class="user-permission-tabs">
|
||||||
<el-tab-pane label="已拥有角色">
|
<el-tab-pane label="已拥有角色">
|
||||||
<el-table :data="formRoleList" border>
|
<el-table :data="formRoleList" border>
|
||||||
<el-table-column type="index" label="序号" width="70" />
|
<el-table-column type="index" label="序号" width="70" />
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<basic-container>
|
<basic-container>
|
||||||
<el-tabs v-model="activeTab" @tab-change="handleTabChange">
|
<el-tabs type="border-card" v-model="activeTab" @tab-change="handleTabChange">
|
||||||
<!-- 个人信息 Tab -->
|
<!-- 个人信息 Tab -->
|
||||||
<el-tab-pane label="个人信息" name="info">
|
<el-tab-pane label="个人信息" name="info">
|
||||||
<el-form ref="infoForm" :model="infoForm" label-width="auto">
|
<el-form ref="infoForm" :model="infoForm" label-width="auto">
|
||||||
|
|||||||
@@ -544,6 +544,7 @@ import {
|
|||||||
recognizeBaiduOcr,
|
recognizeBaiduOcr,
|
||||||
} from '@/api/transportCapacity/transport-vehicle';
|
} from '@/api/transportCapacity/transport-vehicle';
|
||||||
import { getDeptTree } from '@/api/system/dept';
|
import { getDeptTree } from '@/api/system/dept';
|
||||||
|
import organizationSearch from '@/mixins/organization-search';
|
||||||
import { exportBlob } from '@/api/common';
|
import { exportBlob } from '@/api/common';
|
||||||
import { getToken } from '@/utils/auth';
|
import { getToken } from '@/utils/auth';
|
||||||
import { getUploadHeaders } from '@/utils/upload';
|
import { getUploadHeaders } from '@/utils/upload';
|
||||||
@@ -633,6 +634,7 @@ export default {
|
|||||||
ImageUploadField,
|
ImageUploadField,
|
||||||
VehicleLedger,
|
VehicleLedger,
|
||||||
},
|
},
|
||||||
|
mixins: [organizationSearch],
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
option,
|
option,
|
||||||
@@ -747,6 +749,7 @@ export default {
|
|||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
this.initDeptTree();
|
this.initDeptTree();
|
||||||
|
this.loadOrganizationOptions();
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
hasPermission(code) {
|
hasPermission(code) {
|
||||||
|
|||||||
Reference in New Issue
Block a user