xy 11 months ago
parent 443d667d72
commit 767b6c5e0a

@ -9,10 +9,10 @@
<script>
window._AMapSecurityConfig = {
securityJsCode: '0d59d0a3fa5483849b52b0edc4bc97ec',
securityJsCode: 'f8a702571a8addbf0054149057bc3d4b',
}
</script>
<script type="text/javascript" src='https://webapi.amap.com/maps?v=1.4.11&key=795a757114c371f42cee1f8efa527684&plugin=AMap.PlaceSearch,AMap.MarkerClusterer'></script>
<script type="text/javascript" src='https://webapi.amap.com/maps?v=1.4.11&key=a37c084cac0c3459b892276ec0a1c880&plugin=AMap.PlaceSearch,AMap.MarkerClusterer'></script>
<script src="https://webapi.amap.com/ui/1.0/main.js?v=1.0.11"></script>
</head>
<body>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 213 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 121 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

@ -98,7 +98,7 @@ Vue.use(AMap);
// 初始化vue-amap
AMap.initAMapApiLoader({
// 高德的key
key: '795a757114c371f42cee1f8efa527684',
key: 'a37c084cac0c3459b892276ec0a1c880',
// 插件集合 (插件按需引入)
plugin: ['AMap.AutoComplete','AMap.Geocoder','AMap.PlaceSearch', 'AMap.Scale', 'AMap.OverView', 'AMap.ToolBar', 'AMap.MapType',
'AMap.PolyEditor', 'AMap.CircleEditor', 'AMap.DistrictSearch','AMap.CircleMarker','AMap.Polyline','AMap.MarkerClusterer'
@ -107,7 +107,7 @@ AMap.initAMapApiLoader({
});
//高德的安全密钥
window._AMapSecurityConfig = {
securityJsCode: '0d59d0a3fa5483849b52b0edc4bc97ec',
securityJsCode: 'f8a702571a8addbf0054149057bc3d4b',
}
// 解决地图刷新显示不出来
const amapKeys = Object.keys(localStorage).filter(key => key.match(/^_AMap_/))
@ -121,6 +121,26 @@ defineDirective();
import dataV from "@jiaminghi/data-view";
Vue.use(dataV);
// loading
let loadingInstance
function loading (text) {
loadingInstance = ElementUI.Loading.service({
fullscreen: true,
lock: true,
text: text || '加载中...',
spinner: 'el-icon-loading',
background: 'rgba(0, 0, 0, 0.7)'
})
}
Vue.prototype.$myLoading = loading
function loadingClose () {
Vue.prototype.$nextTick(() => {
loadingInstance.close()
})
}
Vue.prototype.$myLoadingClose = loadingClose
new Vue({
el: '#app',
router,

@ -60,6 +60,9 @@ export class CreateDialog {
} else {
props.fileList = that.file[info.field]
}
props.onChange = () => that.$myLoadingClose()
props.onProgress = () => that.$myLoading("文件上传中...")
props.beforeUpload = (file) => {
if (file.size / 1000 > (50 * 1024)) {
that.$message({

@ -13,6 +13,8 @@
:headers="{
Authorization: `Bearer ${getToken()}`,
}"
:on-progress="onProgress"
:on-change="onChange"
:on-success="successHandle"
:before-upload="uploadBefore"
:before-remove="beforeRemove"
@ -75,6 +77,12 @@ export default {
};
},
methods: {
onChange() {
this.$myLoadingClose()
},
onProgress(event, file, fileList) {
this.$myLoading("文件上传中...")
},
getToken,
show() {
this.isShow = true;
@ -132,7 +140,6 @@ export default {
this.fileList = fileList;
},
uploadBefore(file) {
console.log(file);
if (file.size / 1000 > 50 * 1024) {
this.$message({
type: "warning",

@ -40,6 +40,8 @@
style="width: 400px"
ref="upload"
multiple
:on-progress="onProgress"
:on-change="onChange"
:on-success="successHandle"
:before-upload="uploadBefore"
:before-remove="beforeRemove"
@ -202,6 +204,12 @@ export default {
},
//
onChange() {
this.$myLoadingClose()
},
onProgress(event, file, fileList) {
this.$myLoading("文件上传中...")
},
successHandle(response, file, fileList) {
this.fileList = fileList
},

@ -350,38 +350,19 @@ export default {
Object.assign(this.select, { page: 1, page_size: 9999 })
);
if (res.data) {
let headers = this.form.filter(i => filterTableColumns.find(j => j.prop === i.field)).map((i) => {
let headers = filterTableColumns.filter(i => !!i.prop).map((i) => {
return {
key: i.field,
title: i.name,
key: i.prop,
title: i.label,
};
});
if(filterTableColumns.find(j => j.prop === 'assets')) {
headers.unshift({
key: 'assets',
title: '资产'
})
}
const data = res.data.map((row) =>
headers.map((header) => {
if(header.key === 'assets') {
return row.asset_handles_to_assets?.map(i => (i.land_id ? '【土地】' : '【房产】')+(i.lands?.name || i.house?.name)).toString()
}
let data = []
let merges = []
let rowIndex = 0
res.data.forEach((row, rindex) => {
let myRow = headers.map((header) => {
const i = this.form.find(i => i.field === header.key)
//if (i.edit_input === 'file' || i.edit_input === 'files') return ''
// if (
// i.select_item &&
// typeof i.select_item === "object" &&
// !(i.select_item instanceof Array)
// ) {
// let keys = Object.keys(i.select_item);
// let paramMap = new Map();
// keys.forEach((key) => {
// paramMap.set(i.select_item[key], key);
// });
// return paramMap.get(row[i.field]?.toString());
// }
if (i._relations) {
if (i && i._relations) {
let { link_relation, foreign_key, link_with_name } = i._relations;
if (link_relation === "newHasOne" || link_relation === "hasOne") {
return row[link_with_name]?.original_name || row[link_with_name]?.name ||
@ -401,14 +382,54 @@ export default {
}
if (this.table.find(i => i.prop === header.key)?.formatter) {
return this.table.find(i => i.prop === header.key).formatter(row, {}, row[header.key])
return this.table.find(i => i.prop === header.key).formatter(row, {}, row[header.key], rindex)
}
return row[header.key]
})
);
if (row['asset_handles_to_assets'].length > 0) {
for (let j = 0;j<row['asset_handles_to_assets'].length;j++) {
let myAssetLink = row['asset_handles_to_assets'][j]
let myAsset = {}
if (myAssetLink.land_id) {
myAsset = myAssetLink['lands']
} else if (myAssetLink.house_id) {
myAsset = myAssetLink['house']
}
data.push([...myRow,myAsset.name,myAssetLink.bencizhengshoumianji,myAssetLink.zichanshengyumianji])
}
if (headers.length > 0) {
for (let q = 0;q < headers.length;q ++) {
merges.push({
s: {
r: rowIndex + 1,
c: q
},
e: {
r: rowIndex + 1 + row['asset_handles_to_assets'].length - 1,
c: q
}
})
}
}
rowIndex += row['asset_handles_to_assets'].length
} else {
rowIndex++
data.push(myRow)
}
});
headers.push({
title: '资产名称'
})
headers.push({
title: '本次征收面积'
})
headers.push({
title: '资产剩余面积'
})
data.unshift(headers.map((header) => header.title));
const wb = XLSX.utils.book_new();
const ws = XLSX.utils.aoa_to_sheet(data);
ws['!merges'] = merges
XLSX.utils.book_append_sheet(wb, ws, sheetName);
const wbout = XLSX.write(wb, {
bookType: "xlsx",
@ -649,7 +670,7 @@ export default {
}
})
this.table.unshift({
prop: "id",
prop: "",
width: 60,
label: "序号",
formatter: (row, column, cellValue, index) => (this.$refs['xyTable'].selectOpt.page - 1) * this.$refs['xyTable'].selectOpt.page_size + index + 1

@ -381,6 +381,10 @@ export default {
}
};
props.onChange = () => this.$myLoadingClose()
props.onProgress = () => this.$myLoading("文件上传中...")
props.onSuccess = (response, file, fileList) => {
this.file[info.field] = fileList;
};

@ -392,6 +392,14 @@ export default {
key: "weidaoweiyuanyin",
title: "未到位原因",
minWidth: 140
},
{
key: "dept",
title: "分公司",
width: 160,
render: (h, { row }) => {
return h('div',`${row.department ? ('【' + row.department.name + '】') : ''}${row.admin ? row.admin.name : ''}`)
}
}
],
@ -585,6 +593,14 @@ export default {
key: "weidaoweiyuanyin",
minWidth: 140,
},
{
key: "dept",
title: "分公司",
width: 160,
render: (h, { row }) => {
return h('div',`${row.department ? ('【' + row.department.name + '】') : ''}${row.admin ? row.admin.name : ''}`)
}
}
],
systemSelect: {
is_auth: 1,

@ -243,7 +243,7 @@
</div>
<xy-table
:btn-width="300"
:btn-width="350"
:row-style="rowStyle"
:auths="auths_auth_mixin"
:delay-req="true"
@ -270,7 +270,7 @@
@loaded="adjustAlignment"
>
<template #rentCollection="{ row }">
<template v-if="$moment().isBetween($moment(row.zulinkaishiqixian),$moment(row.zulinjieshuqixian))">
<template>
<Button size="small" type="warning" @click="$refs['payList'].setLeaseId(row.id),$refs['payList'].show()"></Button>
</template>
</template>
@ -371,29 +371,19 @@ export default {
Object.assign(this.select, { page: 1, page_size: 9999 })
);
if (res.data) {
let headers = this.form.filter(i => filterTableColumns.find(j => j.prop === i.field)).map((i) => {
let headers = filterTableColumns.filter(i => !!i.prop).map((i) => {
return {
key: i.field,
title: i.name,
key: i.prop,
title: i.label,
};
});
const data = res.data.map((row) =>
headers.map((header) => {
let data = []
let merges = []
let rowIndex = 0
res.data.forEach((row, rindex) => {
let myRow = headers.map((header) => {
const i = this.form.find(i => i.field === header.key)
//if (i.edit_input === 'file' || i.edit_input === 'files') return ''
// if (
// i.select_item &&
// typeof i.select_item === "object" &&
// !(i.select_item instanceof Array)
// ) {
// let keys = Object.keys(i.select_item);
// let paramMap = new Map();
// keys.forEach((key) => {
// paramMap.set(i.select_item[key], key);
// });
// return paramMap.get(row[i.field]?.toString());
// }
if (i._relations) {
if (i && i._relations) {
let { link_relation, foreign_key, link_with_name } = i._relations;
if (link_relation === "newHasOne" || link_relation === "hasOne") {
return row[link_with_name]?.original_name || row[link_with_name]?.name ||
@ -413,14 +403,51 @@ export default {
}
if (this.table.find(i => i.prop === header.key)?.formatter) {
return this.table.find(i => i.prop === header.key).formatter(row, {}, row[header.key])
return this.table.find(i => i.prop === header.key).formatter(row, {}, row[header.key], rindex)
}
return row[header.key]
})
);
if (row['id_leases_to_assets_lease_id_relation'].length > 0) {
for (let j = 0;j<row['id_leases_to_assets_lease_id_relation'].length;j++) {
let myAssetLink = row['id_leases_to_assets_lease_id_relation'][j]
let myAsset = {}
if (myAssetLink.land_id) {
myAsset = row['land'].find(k => k.id === myAssetLink.land_id)
} else if (myAssetLink.house_id) {
myAsset = row['houses'].find(k => k.id === myAssetLink.house_id)
}
data.push([...myRow,myAsset.name,myAssetLink.chuzumianji])
}
if (headers.length > 0) {
for (let q = 0;q < headers.length;q ++) {
merges.push({
s: {
r: rowIndex + 1,
c: q
},
e: {
r: rowIndex + 1 + row['id_leases_to_assets_lease_id_relation'].length - 1,
c: q
}
})
}
}
rowIndex += row['id_leases_to_assets_lease_id_relation'].length
} else {
rowIndex++
data.push(myRow)
}
});
headers.push({
title: '资产名称'
})
headers.push({
title: '出租面积'
})
data.unshift(headers.map((header) => header.title));
const wb = XLSX.utils.book_new();
const ws = XLSX.utils.aoa_to_sheet(data);
ws['!merges'] = merges
XLSX.utils.book_append_sheet(wb, ws, sheetName);
const wbout = XLSX.write(wb, {
bookType: "xlsx",
@ -626,20 +653,22 @@ export default {
);
});
this.table.unshift({
prop: "id",
prop: "",
width: 60,
label: "序号",
formatter: (row, column, cellValue, index) => (this.$refs['xyTable'].selectOpt.page - 1) * this.$refs['xyTable'].selectOpt.page_size + index + 1
})
this.table.push({
prop: 'admin.name',
prop: 'admin_id',
width: 120,
label: '提交人'
label: '提交人',
formatter: (row, column, cellValue, index) => row['admin']?.name
})
this.table.push({
prop: 'department.name',
prop: 'department_id',
width: 120,
label: '提交部门'
label: '提交部门',
formatter: (row, column, cellValue, index) => row['department']?.name
})
this.table.push({
prop: 'created_at',

@ -344,14 +344,15 @@ export default {
},
async exportExcel(sheetName) {
let filterTableColumns = this.$refs['xyTable']?.tableFormat || []
const res = await index(
Object.assign(this.select, { page: 1, page_size: 9999 })
);
if (res.data) {
let headers = this.form.map((i) => {
let headers = filterTableColumns.filter(i => !!i.prop).map((i) => {
return {
key: i.field,
title: i.name,
key: i.prop,
title: i.label,
};
});
const data = res.data.map((row) =>
@ -567,7 +568,7 @@ export default {
);
});
this.table.unshift({
prop: "id",
prop: "",
width: 60,
label: "序号",
formatter: (row, column, cellValue, index) => (this.$refs['xyTable'].selectOpt.page - 1) * this.$refs['xyTable'].selectOpt.page_size + index + 1

@ -3,6 +3,7 @@ import { save, show, index, destroy, imports } from "@/api/system/baseForm";
import { CreateDialog } from "@/utils/createDialog";
import { deepCopy } from "@/utils";
import { resolveFormInfo } from "@/utils/createTable";
import { listCommondepartment } from "@/api/common"
export default {
components: {},
props: {
@ -13,6 +14,34 @@ export default {
let dialog = new CreateDialog(
this,
[
{
show: true,
key: "chengzufang",
label: "承租方",
render: h("el-autocomplete",{
style: { width: '100%' },
props: {
value: _this.form.chengzufang,
clearable: true,
label: 'name',
'value-key': 'name',
'fetch-suggestions': (queryString, cb) => {
const depts = _this.departments;
let results = queryString ? depts.filter(dept => {
return (dept.name.toLowerCase().indexOf(queryString.toLowerCase()) === 0)
}) : depts;
// callback
cb(results);
}
},
on: {
'input':e => {
_this.form.chengzufang = e
_this.form = Object.assign({}, _this.form);
}
}
})
},
{
show: true,
key: "qiandingnianyue",
@ -1140,6 +1169,7 @@ export default {
},
data() {
return {
departments: [],
wxAreas: [
"宜兴市",
"惠山区",
@ -1211,6 +1241,18 @@ export default {
}
},
async getDepts () {
try {
const res = await listCommondepartment({
page: 1,
page_size: 9999
})
this.departments = res.data
} catch(err) {
}
},
async getDetail() {
const res = await show({ id: this.id, table_name: "leases" });
this.$integrateData(this.form, res);
@ -1457,6 +1499,7 @@ export default {
},
},
created() {
this.getDepts()
this.id = this.$route.query.leaseId;
this.type = this.$route.query.type;
resolveFormInfo(15).then((res) => {

@ -1,14 +1,23 @@
<template>
<div class="login-container">
<img class="build-img" src="~@/assets/login/build.png" alt="">
<!-- <vue-particles color="#ffffff" :particleOpacity="0.7" :particlesNumber="80" shapeType="circle" :particleSize="4"-->
<!-- linesColor="#ffffff" :linesWidth="1" :lineLinked="true" :lineOpacity="0.4" :linesDistance="150" :moveSpeed="3"-->
<!-- :hoverEffect="true" hoverMode="grab" :clickEffect="true" clickMode="push"> </vue-particles>-->
<img class="title-img" src="~@/assets/login/title.png" alt="">
<el-form size="small" ref="loginForm" :model="loginForm" :rules="loginRules" class="login-form" auto-complete="on"
label-position="left">
<div class="bkg-image-container">
<img class="bkg-image" v-for="(img, index) in bkgImgs" :class="{ active: isActive(index) }" :key="img" :src="img" alt="" />
</div>
<!-- <img class="build-img" src="~@/assets/login/build.png" alt="">-->
<!-- <vue-particles color="#ffffff" :particleOpacity="0.7" :particlesNumber="80" shapeType="circle" :particleSize="4"-->
<!-- linesColor="#ffffff" :linesWidth="1" :lineLinked="true" :lineOpacity="0.4" :linesDistance="150" :moveSpeed="3"-->
<!-- :hoverEffect="true" hoverMode="grab" :clickEffect="true" clickMode="push"> </vue-particles>-->
<img class="title-img" src="~@/assets/login/title.png" alt="" />
<el-form
size="small"
ref="loginForm"
:model="loginForm"
:rules="loginRules"
class="login-form"
auto-complete="on"
label-position="left"
>
<div class="title-container">
<h3 class="title">欢迎登录</h3>
</div>
@ -16,22 +25,40 @@
<el-form-item prop="username">
<div class="form-item">
<span class="svg-container">
<svg-icon icon-class="user" />
</span>
<el-input ref="username" v-model="loginForm.username" placeholder="请输入登录名" name="username" type="text"
tabindex="1" auto-complete="on" />
<svg-icon icon-class="user" />
</span>
<el-input
ref="username"
v-model="loginForm.username"
placeholder="请输入登录名"
name="username"
type="text"
tabindex="1"
auto-complete="on"
/>
</div>
</el-form-item>
<el-form-item prop="password">
<div class="form-item">
<span class="svg-container">
<svg-icon icon-class="password" />
</span>
<el-input :key="passwordType" ref="password" v-model="loginForm.password" :type="passwordType"
placeholder="请输入密码" name="password" tabindex="2" auto-complete="on" @keyup.enter.native="handleLogin" />
<svg-icon icon-class="password" />
</span>
<el-input
:key="passwordType"
ref="password"
v-model="loginForm.password"
:type="passwordType"
placeholder="请输入密码"
name="password"
tabindex="2"
auto-complete="on"
@keyup.enter.native="handleLogin"
/>
<span class="show-pwd" @click="showPwd">
<svg-icon :icon-class="passwordType === 'password' ? 'eye' : 'eye-open'" />
<svg-icon
:icon-class="passwordType === 'password' ? 'eye' : 'eye-open'"
/>
</span>
</div>
</el-form-item>
@ -41,380 +68,486 @@
<span class="svg-container">
<svg-icon icon-class="message" />
</span>
<el-input ref="username" v-model="loginForm.code" placeholder="请输入验证码" name="username" type="text"
tabindex="1" auto-complete="on" />
<el-button class="msg-btn" :loading="msgLoading" type="primary" size="small" :disabled="isVer" @click="sendSms">{{ isVer ? (''+verTime+'') : '' }}</el-button>
<el-input
ref="username"
v-model="loginForm.code"
placeholder="请输入验证码"
name="username"
type="text"
tabindex="1"
auto-complete="on"
/>
<el-button
class="msg-btn"
:loading="msgLoading"
type="primary"
size="small"
:disabled="isVer"
@click="sendSms"
>发送验证{{ isVer ? "" + verTime + "" : "" }}</el-button
>
</div>
</el-form-item>
<el-button :loading="loading" type="primary" class="login-btn"
@click.native.prevent="handleLogin">登录</el-button>
<el-button
:loading="loading"
type="primary"
class="login-btn"
@click.native.prevent="handleLogin"
>登录</el-button
>
</el-form>
<footer class="copyright">
版权所有无锡市交通产业集团有限公司
</footer>
<footer class="copyright">版权所有无锡市交通产业集团有限公司</footer>
</div>
</template>
<script>
import {
validUsername
} from '@/utils/validate'
import { login, getInfo } from "@/api/user";
import { sendSms, checkSms } from "@/api/common"
const defaultSettings = require('../../../src/settings.js')
export default {
name: 'Login',
data() {
const validateUsername = (rule, value, callback) => {
if (!validUsername(value)) {
callback(new Error('请正确输入登录名'))
} else {
callback()
}
const files = require.context("@/assets/login/bkg", false, /\.png$/)
const imgs = files.keys().map(key => {
return files(key).default || files(key);
})
import { validUsername } from "@/utils/validate";
import { login, getInfo } from "@/api/user";
import { sendSms, checkSms } from "@/api/common";
const defaultSettings = require("../../../src/settings.js");
export default {
name: "Login",
data() {
const validateUsername = (rule, value, callback) => {
if (!validUsername(value)) {
callback(new Error("请正确输入登录名"));
} else {
callback();
}
const validatePassword = (rule, value, callback) => {
if (value.length < 6) {
callback(new Error('密码输入错误'))
} else {
callback()
}
};
const validatePassword = (rule, value, callback) => {
if (value.length < 6) {
callback(new Error("密码输入错误"));
} else {
callback();
}
return {
title: "",
loginForm: {
username: '',
password: '',
code: ''
},
loginRules: {
username: [{
};
return {
bkgImgs: imgs,
current: 0,
speed: 5000,
timer: null,
title: "",
loginForm: {
username: "",
password: "",
code: "",
},
loginRules: {
username: [
{
required: true,
trigger: 'blur',
validator: validateUsername
}],
password: [{
trigger: "blur",
validator: validateUsername,
},
],
password: [
{
required: true,
trigger: 'blur',
validator: validatePassword
}],
code: [
{
trigger: "blur",
validator: validatePassword,
},
],
code: [
{
required: true,
trigger: 'blur',
message: '请输入验证码',
trigger: "blur",
message: "请输入验证码",
validator: (rule, value, callback) => {
if (value.length !== 4) {
callback(new Error('验证码输入错误'))
callback(new Error("验证码输入错误"));
} else {
callback()
callback();
}
},
},
],
},
msgLoading: false,
loading: false,
passwordType: "password",
redirect: undefined,
verTime: 60,
isVer: false,
temp: {
mobile: "",
token: "",
},
};
},
watch: {
$route: {
handler: function (route) {
this.redirect = route.query && route.query.redirect;
},
immediate: true,
},
},
created() {
this.title = defaultSettings.title;
},
mounted() {
this.startRotation()
},
methods: {
// img slide start
startRotation: function () {
this.timer = setInterval(this.next, this.speed);
},
stopRotation: function () {
clearTimeout(this.timer);
this.timer = null;
},
next: function () {
let current = this.current;
var next = Math.floor(Math.random() * this.bkgImgs.length);
while (next === current) {
next = Math.floor(Math.random() * this.bkgImgs.length);
}
this.current = next;
this.setActive(this.current);
},
isActive: function (slide) {
return this.current === slide;
},
setActive: function (slide) {
this.current = slide;
},
// img silde end
async sendSms() {
if (this.isVer) return;
if (this.loginForm.username) {
this.msgLoading = true;
try {
await sendSms({
username: this.loginForm.username,
});
this.isVer = true;
this.verTime = 60;
this.$message({
message: "验证码已发送",
type: "success",
});
let timer = setInterval(() => {
this.verTime--;
if (this.verTime <= 0) {
this.isVer = false;
clearInterval(timer);
}
}
]
},
msgLoading: false,
loading: false,
passwordType: 'password',
redirect: undefined,
verTime: 60,
isVer: false,
temp: {
mobile: "",
token: ""
}, 1000);
this.msgLoading = false;
} catch (e) {
this.msgLoading = false;
}
} else {
this.$message({
message: "请输入登录名",
type: "warning",
});
}
},
watch: {
$route: {
handler: function(route) {
this.redirect = route.query && route.query.redirect
},
immediate: true
showPwd() {
if (this.passwordType === "password") {
this.passwordType = "";
} else {
this.passwordType = "password";
}
this.$nextTick(() => {
this.$refs.password.focus();
});
},
created() {
this.title = defaultSettings.title;
},
methods: {
async sendSms () {
if (this.isVer) return;
if (this.loginForm.username) {
this.msgLoading = true;
try {
await sendSms({
username: this.loginForm.username
})
this.isVer = true;
this.verTime = 60;
this.$message({
message: '验证码已发送',
type:'success'
//
async handleLogin() {
this.$refs.loginForm.validate(async (valid) => {
if (valid) {
this.loading = true;
this.$store
.dispatch("user/login", this.loginForm)
.then(() => {
this.$router.push({
path: this.redirect || "/",
});
this.loading = false;
})
let timer = setInterval(() => {
this.verTime--;
if (this.verTime <= 0) {
this.isVer = false;
clearInterval(timer);
}
}, 1000);
this.msgLoading = false;
} catch (e) {
this.msgLoading = false;
}
.catch(() => {
this.loading = false;
});
} else {
this.$message({
message: '请输入登录名',
type: 'warning'
})
console.log("error submit!!");
return false;
}
},
});
},
},
};
</script>
showPwd() {
if (this.passwordType === 'password') {
this.passwordType = ''
} else {
this.passwordType = 'password'
}
this.$nextTick(() => {
this.$refs.password.focus()
})
},
//
async handleLogin() {
this.$refs.loginForm.validate(async(valid) => {
if (valid) {
<style lang="scss">
#particles-js {
width: 100%;
height: 99%;
position: absolute;
}
/* 修复input 背景不协调 和光标变色 */
/* Detail see https://github.com/PanJiaChen/vue-element-admin/pull/927 */
$bg: #122583;
$light_gray: #122583;
$cursor: #122583;
@supports (-webkit-mask: none) and (not (cater-color: $cursor)) {
.login-container .el-input input {
color: $cursor;
}
}
/* reset element-ui css */
.login-container {
.el-input {
flex: 1;
display: inline-block;
input {
background: transparent;
border: 0px;
-webkit-appearance: none;
border-radius: 0px;
padding: 4px 5px 4px 15px;
color: $light_gray;
caret-color: $cursor;
&:-webkit-autofill {
//box-shadow: 0 0 0px 1000px $bg inset !important;
//-webkit-text-fill-color: $cursor !important;
}
}
}
}
</style>
this.loading = true
this.$store.dispatch('user/login', this.loginForm).then(() => {
<style lang="scss" scoped>
$bg: #122583;
$dark_gray: #122583;
$light_gray: #122583;
.build-img {
position: absolute;
width: 46.5vw;
object-fit: contain;
top: 26.8%;
left: 4%;
}
.title-img {
position: relative;
display: block;
width: 44.64vw;
object-fit: contain;
filter: drop-shadow(1px 1px 4px #0005);
margin: 16.11vh auto 0;
}
//how many images we have
$slides: 8;
// how much we want each slide to show
$time_per_slide: 6;
// total time needed for full animation
$total_animation_time: $time_per_slide * $slides;
.bkg-image-container {
overflow: hidden;
background: #1A5CD7;
z-index: 0;
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
& > img {
width: 100%;
height: 100%;
object-fit: cover;
position:absolute;
top: 0;
left: 0;
opacity:0;
display: block;
filter: blur(12px);
transition: all 1s cubic-bezier(0.550, 0.085, 0.680, 0.530);
}
.active {
filter: blur(0);
opacity: 1;
}
}
.form-item {
height: 3vw;
width: 86.4%;
margin: auto;
border-radius: 8px;
background-color: #f4f4f4;
filter: drop-shadow(0 0 1px #cdcdcd);
display: flex;
align-items: center;
}
.login-container {
height: 100%;
width: 100%;
// background: url("~@/assets/login/bkg.png") no-repeat;
background-size: cover;
overflow: hidden;
.login-form {
position: relative;
width: 28.7vw;
margin: 9.81vh 10.2vw 0 auto;
overflow: hidden;
border-radius: 10px;
box-shadow: inset 0 0 4px rgb(255, 255, 255, 0.8);
filter: drop-shadow(0 0 7px rgba(0, 0, 0, 0.2));
background-color: rgba(255, 255, 255, 0.2);
}
this.$router.push({
path: this.redirect || '/'
})
this.loading = false
}).catch(() => {
this.loading = false
})
} else {
console.log('error submit!!')
return false
}
})
.tips {
font-size: 14px;
color: #fff;
margin-bottom: 10px;
span {
&:first-of-type {
margin-right: 16px;
}
}
}
</script>
<style lang="scss">
#particles-js {
width: 100%;
height: 99%;
position: absolute;
.svg-container {
padding: 6px 5px 6px 15px;
color: $dark_gray;
vertical-align: middle;
width: 30px;
display: inline-block;
}
/* 修复input 背景不协调 和光标变色 */
/* Detail see https://github.com/PanJiaChen/vue-element-admin/pull/927 */
.title-container {
position: relative;
margin-bottom: 2vw;
$bg:#122583;
$light_gray:#122583;
$cursor: #122583;
.title {
text-align: center;
font-size: 1.7vw;
letter-spacing: 4px;
color: #ffffff;
padding: 1.41vw 0 1.2vw;
text-shadow: 1px 0 #000, 0 1px #000, 1px 1px #000;
filter: drop-shadow(1px 1px 4px #0002);
position: relative;
@supports (-webkit-mask: none) and (not (cater-color: $cursor)) {
.login-container .el-input input {
color: $cursor;
}
}
&::after {
content: "";
width: 100%;
height: 1px;
background: linear-gradient(to right, #fff0 20%, #fff, #fff0 80%);
/* reset element-ui css */
.login-container {
.el-input {
flex: 1;
display: inline-block;
input {
background: transparent;
border: 0px;
-webkit-appearance: none;
border-radius: 0px;
padding: 4px 5px 4px 15px;
color: $light_gray;
caret-color: $cursor;
&:-webkit-autofill {
//box-shadow: 0 0 0px 1000px $bg inset !important;
//-webkit-text-fill-color: $cursor !important;
}
position: absolute;
bottom: 0;
left: 0;
right: 0;
}
}
}
</style>
<style lang="scss" scoped>
$bg:#122583;
$dark_gray:#122583;
$light_gray:#122583;
.build-img {
.show-pwd {
position: absolute;
width: 46.5vw;
object-fit: contain;
top: 26.8%;
left: 4%;
right: 8%;
top: 50%;
transform: translate(0, -50%);
font-size: 16px;
color: $dark_gray;
cursor: pointer;
user-select: none;
}
.title-img {
display: block;
width: 44.64vw;
object-fit: contain;
margin: 16.11vh auto 0;
.msg-btn {
border-radius: 0 8px 8px 0;
height: 100%;
background-image: linear-gradient(
90deg,
#1d57da 0%,
#1d57da 0%,
#4185c5 100%
);
}
.form-item {
height: 3vw;
.login-btn {
width: 86.4%;
margin: auto;
height: 3vw;
border-radius: 8px;
background-color: #f4f4f4;
filter: drop-shadow(0 0 1px #cdcdcd);
display: flex;
align-items: center;
padding: 0;
background-image: linear-gradient(
90deg,
#1d57da 0%,
#1d57da 0%,
#05a658 100%
);
display: block;
margin: auto auto 3.2vw;
font-size: 1.21vw;
letter-spacing: 3px;
color: #ffffff;
}
.login-container {
height: 100%;
width: 100%;
background: url("~@/assets/login/bkg.png") no-repeat;
background-size: cover;
overflow: hidden;
.login-form {
position: relative;
width: 28.7vw;
margin: 9.81vh 10.2vw 0 auto;
overflow: hidden;
border-radius: 10px;
box-shadow: inset 0 0 4px rgb(255,255,255,0.8);
filter: drop-shadow(0 0 7px rgba(0,0,0,0.2));
background-color: rgba(255,255,255,0.2);
}
.tips {
font-size: 14px;
color: #fff;
margin-bottom: 10px;
span {
&:first-of-type {
margin-right: 16px;
}
}
}
.svg-container {
padding: 6px 5px 6px 15px;
color: $dark_gray;
vertical-align: middle;
width: 30px;
display: inline-block;
}
.title-container {
position: relative;
margin-bottom: 2vw;
.title {
text-align: center;
font-size: 1.7vw;
letter-spacing: 4px;
color: #ffffff;
padding: 1.41vw 0 1.2vw;
position: relative;
&::after {
content: "";
width: 100%;
height: 1px;
background: linear-gradient(to right, #fff0 20%, #fff, #fff0 80%);
position: absolute;
bottom: 0;
left: 0;
right: 0;
}
}
}
.show-pwd {
position: absolute;
right: 8%;
top: 50%;
transform: translate(0, -50%);
font-size: 16px;
color: $dark_gray;
cursor: pointer;
user-select: none;
}
.msg-btn {
border-radius: 0 8px 8px 0;
height: 100%;
background-image: linear-gradient(90deg, #1d57da 0%, #1d57da 0%, #4185c5 100%);
}
.login-btn {
width: 86.4%;
height: 3vw;
border-radius: 8px;
padding: 0;
background-image: linear-gradient(90deg, #1d57da 0%, #1d57da 0%, #05a658 100%);
display: block;
margin: auto auto 3.2vw;
font-size: 1.21vw;
letter-spacing: 3px;
color: #ffffff;
}
}
::v-deep .el-form-item--small.el-form-item {
margin-bottom: 1.3vw;
}
.copyright {
width: 100%;
text-align: center;
color: #fff;
line-height: 16px;
font-size: 16px;
text-shadow: 1px 0 #000, 0 1px #000, 1px 1px #000;
filter: drop-shadow(1px 1px 4px #000);
position: absolute;
left: 0;
bottom: 6vh;
}
@media (max-width: 960px) {
.title-img {
display: none;
}
::v-deep .el-form-item--small.el-form-item {
margin-bottom: 1.3vw;
.login-container .login-form {
width: 90%;
margin: auto;
position: relative;
top: 50%;
transform: translateY(-50%);
}
.copyright {
width: 100%;
text-align: center;
color: #fff;
line-height: 16px;
font-size: 16px;
position: absolute;
left: 0;
bottom: 6vh;
.login-container .title-container .title {
font-size: 15px;
}
@media (max-width: 960px) {
.title-img {
display: none;
}
.login-container .login-form {
width: 90%;
margin: auto;
position: relative;
top: 50%;
transform: translateY(-50%);
}
.login-container .title-container .title {
font-size: 15px;
}
.form-item {
height: 40px;
margin-bottom: 10px;
}
.login-container .login-btn {
height: 40px;
font-size: 14px;
}
::v-deep .el-form-item__error {
transform: translate(-20px,-76%);
}
.form-item {
height: 40px;
margin-bottom: 10px;
}
.login-container .login-btn {
height: 40px;
font-size: 14px;
}
::v-deep .el-form-item__error {
transform: translate(-20px, -76%);
}
}
</style>

@ -1,231 +1,231 @@
<template>
<div class="container">
<!-- 查询配置 -->
<div >
<div ref="lxHeader">
<LxHeader icon="md-apps" text="部门管理" style="margin-bottom: 10px; border: 0px; margin-top: 15px">
<div slot="content"></div>
<slot>
<div>
<Button type="primary" @click="load" style="margin-left: 10px">查询</Button>
<Button type="primary" @click="edit()" style="margin-left: 10px">新增部门</Button>
</div>
</slot>
</LxHeader>
</div>
<div class="table-tree">
<el-table :data="tableData" :height="tableHeight" class="v-table" style="width: 100%;margin-bottom: 20px;"
row-key="id" border default-expand-all :tree-props="{children: 'children', hasChildren: 'hasChildren'}">
<el-table-column type="index" align="center">
</el-table-column>
<el-table-column prop="name" label="部门名称" sortable>
</el-table-column>
<el-table-column prop="manger" label="部门负责人" sortable width="180">
<template slot-scope="scope">
<el-tag type="primary" disable-transitions>{{scope.row.manager?scope.row.manager.name:"无"}}
</el-tag>
</template>
</el-table-column>
<el-table-column prop="leader" label="部门分管人" sortable width="180">
<template slot-scope="scope">
<el-tag type="success" disable-transitions>{{scope.row.leader?scope.row.leader.name:"无"}}
</el-tag>
</template>
</el-table-column>
<el-table-column prop="sortnumber" align="center" label="排序" sortable width="80">
</el-table-column>
<el-table-column fixed="right" label="操作" width="300">
<template slot-scope="scope">
<Button type="primary" @click="addchildren(scope.row)" size="small" style="margin-left: 10px;"
ghost>下级部门</Button>
<Button type="error" @click="del(scope.row)" size="small" style="margin-left: 10px;" ghost>删除</Button>
<Button type="primary" @click="edit(scope.row)" size="small" style="margin-left: 10px;" ghost>编辑</Button>
</template>
</el-table-column>
</el-table>
</div>
</div>
<el-dialog title="部门编辑" :visible.sync="dialogFormVisible" width="30%">
<el-form :model="form" :rules="rules" ref="form" label-position="right" :label-width="formLabelWidth">
<el-form-item label="上级部门">
<el-input v-model="form.pname" disabled autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="部门名称" prop="name">
<el-input v-model="form.name" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="部门负责人" prop="manager">
<el-autocomplete class="inline-input" v-model="form.manager" :fetch-suggestions="querySearch"
placeholder="请输入部门负责人" :trigger-on-focus="false" @select="handleSelectManager"></el-autocomplete>
</el-form-item>
<el-form-item label="部门分管人" prop="leader">
<el-autocomplete class="inline-input" v-model="form.leader" :fetch-suggestions="querySearch"
placeholder="请输入部门分管人" :trigger-on-focus="false" @select="handleSelectLeader"></el-autocomplete>
</el-form-item>
<el-form-item label="排序">
<el-input v-model="form.sortnumber" autocomplete="off"></el-input>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="resetForm('form')"> </el-button>
<el-button type="primary" @click="submitForm('form')"> </el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import LxHeader from "@/components/LxHeader/index.vue";
import {
listdept,
save,
del
} from "../../api/system/department.js";
import {
listuser
} from "../../api/system/user.js";
export default {
components: {
LxHeader
},
created() {
this.initLoad();
this.load();
},
mounted() {},
data() {
return {
dialogFormVisible: false,
formLabelWidth: "120px",
form: {
name: "",
id: "",
pid: "0",
manager_id: "",
leader_id: "",
manager: "",
leader: "",
sortnumber: 0,
icon: "",
pname: "上级部门"
},
rules: {
name: [{
required: true,
message: '请输入部门名称',
trigger: 'blur'
}]
},
tableHeight: 0,
//
searchFields: {
KeyWord: ""
},
tableData: []
}
},
methods: {
querySearch(queryString, cb) {
listuser().then(response => {
var data = response.data;
for (var m of data) {
m.value = m.name;
}
cb(data)
}).catch(error => {
//reject(error)
})
},
handleSelectManager(item) {
this.form.manager_id = item.id;
},
handleSelectLeader(item) {
this.form.leader_id = item.id;
},
initLoad() {
var that = this;
var clientHeight = document.documentElement.clientHeight
var lxHeader_height = 96.5; //
var paginationHeight = 37; //
var topHeight = 50; //
let tableHeight = clientHeight - lxHeader_height - topHeight - paginationHeight - 20;
that.tableHeight = tableHeight;
},
load() {
var that = this;
listdept().then(response => {
that.tableData = response;
}).catch(error => {
//reject(error)
})
},
edit(obj) {
this.form = this.$options.data().form
if (obj) {
var result = Object.assign(this.form, obj);
if (obj.leader)
result.leader = obj.leader.name
if (obj.manager)
result.manager = obj.manager.name
this.form = result;
}
this.dialogFormVisible = true;
},
addchildren(obj) {
this.form = this.$options.data().form
if (obj) {
this.form.pname = obj.name;
this.form.pid = obj.id;
this.dialogFormVisible = true;
}
},
submitForm(formName) {
var that = this;
this.$refs[formName].validate((valid) => {
if (valid) {
save(that.form).then(response => {
console.log(response)
this.$Message.success('操作成功');
that.dialogFormVisible = false;
that.load();
}).catch(error => {
reject(error)
})
} else {
this.$Message.error('数据校验失败');
return false;
}
});
},
resetForm(formName) {
var that = this;
this.$refs[formName].resetFields();
that.dialogFormVisible = false;
},
del(obj) {
var that = this;
if (obj) {
this.$Modal.confirm({
title: '确认要删除数据?',
onOk: () => {
del({
id: obj.id
}).then(response => {
this.$Message.success('操作成功');
that.load();
}).catch(error => {
console.log(error)
reject(error)
})
},
onCancel: () => {
//this.$Message.info('Clicked cancel');
}
});
}
},
}
};
<template>
<div class="container">
<!-- 查询配置 -->
<div >
<div ref="lxHeader">
<LxHeader icon="md-apps" text="部门管理" style="margin-bottom: 10px; border: 0px; margin-top: 15px">
<div slot="content"></div>
<slot>
<div>
<Button type="primary" @click="load" style="margin-left: 10px">查询</Button>
<Button type="primary" @click="edit()" style="margin-left: 10px">新增部门</Button>
</div>
</slot>
</LxHeader>
</div>
<div class="table-tree">
<el-table :data="tableData" :height="tableHeight" class="v-table" style="width: 100%;margin-bottom: 20px;"
row-key="id" border default-expand-all :tree-props="{children: 'children', hasChildren: 'hasChildren'}">
<el-table-column type="index" align="center">
</el-table-column>
<el-table-column prop="name" label="部门名称" sortable>
</el-table-column>
<el-table-column prop="manger" label="部门负责人" sortable width="180">
<template slot-scope="scope">
<el-tag type="primary" disable-transitions>{{scope.row.manager?scope.row.manager.name:"无"}}
</el-tag>
</template>
</el-table-column>
<el-table-column prop="leader" label="部门分管人" sortable width="180">
<template slot-scope="scope">
<el-tag type="success" disable-transitions>{{scope.row.leader?scope.row.leader.name:"无"}}
</el-tag>
</template>
</el-table-column>
<el-table-column prop="sortnumber" align="center" label="排序" sortable width="80">
</el-table-column>
<el-table-column fixed="right" label="操作" width="300">
<template slot-scope="scope">
<Button type="primary" @click="addchildren(scope.row)" size="small" style="margin-left: 10px;"
ghost>下级部门</Button>
<Button type="error" @click="del(scope.row)" size="small" style="margin-left: 10px;" ghost>删除</Button>
<Button type="primary" @click="edit(scope.row)" size="small" style="margin-left: 10px;" ghost>编辑</Button>
</template>
</el-table-column>
</el-table>
</div>
</div>
<el-dialog title="部门编辑" modal-append-to-body append-to-body :visible.sync="dialogFormVisible" width="30%">
<el-form :model="form" :rules="rules" ref="form" label-position="right" :label-width="formLabelWidth">
<el-form-item label="上级部门">
<el-input v-model="form.pname" disabled autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="部门名称" prop="name">
<el-input v-model="form.name" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="部门负责人" prop="manager">
<el-autocomplete class="inline-input" v-model="form.manager" :fetch-suggestions="querySearch"
placeholder="请输入部门负责人" :trigger-on-focus="false" @select="handleSelectManager"></el-autocomplete>
</el-form-item>
<el-form-item label="部门分管人" prop="leader">
<el-autocomplete class="inline-input" v-model="form.leader" :fetch-suggestions="querySearch"
placeholder="请输入部门分管人" :trigger-on-focus="false" @select="handleSelectLeader"></el-autocomplete>
</el-form-item>
<el-form-item label="排序">
<el-input v-model="form.sortnumber" autocomplete="off"></el-input>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="resetForm('form')"> </el-button>
<el-button type="primary" @click="submitForm('form')"> </el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import LxHeader from "@/components/LxHeader/index.vue";
import {
listdept,
save,
del
} from "../../api/system/department.js";
import {
listuser
} from "../../api/system/user.js";
export default {
components: {
LxHeader
},
created() {
this.initLoad();
this.load();
},
mounted() {},
data() {
return {
dialogFormVisible: false,
formLabelWidth: "120px",
form: {
name: "",
id: "",
pid: "0",
manager_id: "",
leader_id: "",
manager: "",
leader: "",
sortnumber: 0,
icon: "",
pname: "上级部门"
},
rules: {
name: [{
required: true,
message: '请输入部门名称',
trigger: 'blur'
}]
},
tableHeight: 0,
//
searchFields: {
KeyWord: ""
},
tableData: []
}
},
methods: {
querySearch(queryString, cb) {
listuser().then(response => {
var data = response.data;
for (var m of data) {
m.value = m.name;
}
cb(data)
}).catch(error => {
//reject(error)
})
},
handleSelectManager(item) {
this.form.manager_id = item.id;
},
handleSelectLeader(item) {
this.form.leader_id = item.id;
},
initLoad() {
var that = this;
var clientHeight = document.documentElement.clientHeight
var lxHeader_height = 96.5; //
var paginationHeight = 37; //
var topHeight = 50; //
let tableHeight = clientHeight - lxHeader_height - topHeight - paginationHeight - 20;
that.tableHeight = tableHeight;
},
load() {
var that = this;
listdept().then(response => {
that.tableData = response;
}).catch(error => {
//reject(error)
})
},
edit(obj) {
this.form = this.$options.data().form
if (obj) {
var result = Object.assign(this.form, obj);
if (obj.leader)
result.leader = obj.leader.name
if (obj.manager)
result.manager = obj.manager.name
this.form = result;
}
this.dialogFormVisible = true;
},
addchildren(obj) {
this.form = this.$options.data().form
if (obj) {
this.form.pname = obj.name;
this.form.pid = obj.id;
this.dialogFormVisible = true;
}
},
submitForm(formName) {
var that = this;
this.$refs[formName].validate((valid) => {
if (valid) {
save(that.form).then(response => {
console.log(response)
this.$Message.success('操作成功');
that.dialogFormVisible = false;
that.load();
}).catch(error => {
reject(error)
})
} else {
this.$Message.error('数据校验失败');
return false;
}
});
},
resetForm(formName) {
var that = this;
this.$refs[formName].resetFields();
that.dialogFormVisible = false;
},
del(obj) {
var that = this;
if (obj) {
this.$Modal.confirm({
title: '确认要删除数据?',
onOk: () => {
del({
id: obj.id
}).then(response => {
this.$Message.success('操作成功');
that.load();
}).catch(error => {
console.log(error)
reject(error)
})
},
onCancel: () => {
//this.$Message.info('Clicked cancel');
}
});
}
},
}
};
</script>

@ -10,9 +10,9 @@
<el-col :span="18" :xs="24">
<el-card>
<el-tabs v-model="activeTab">
<el-tab-pane label="操作日志" name="timeline">
<timeline />
</el-tab-pane>
<!-- <el-tab-pane label="操作日志" name="timeline">-->
<!-- <timeline />-->
<!-- </el-tab-pane>-->
<el-tab-pane label="信息修改" name="account">
<account />
</el-tab-pane>
@ -35,7 +35,7 @@
import {
getInfo
} from '../../api/user.js'
} from '@/api/user'
export default {
name: 'Profile',
@ -47,7 +47,7 @@
data() {
return {
user: {},
activeTab: 'timeline'
activeTab: 'account'
}
},
computed: {

@ -48,9 +48,9 @@
<el-form-item label="数据权限" prop="allow_level">
<el-radio-group v-model="form.allow_level">
<el-radio :label="0">所有</el-radio>
<el-radio :label="1">部门</el-radio>
<el-radio :label="2">私有</el-radio>
<el-radio :label="0">集团</el-radio>
<el-radio :label="1">分公司</el-radio>
<!-- <el-radio :label="2">私有</el-radio>-->
</el-radio-group>
</el-form-item>
<el-form-item label="排序">
@ -63,7 +63,7 @@
</div>
</el-dialog>
<el-dialog title="权限设置" :visible.sync="dialogSetVisible" width="60%">
<el-dialog title="权限设置" modal-append-to-body append-to-body :visible.sync="dialogSetVisible" width="60%">
<el-form label-position="right" :label-width="formLabelWidth">
<el-form-item label="角色名称" prop="name">

@ -23,7 +23,8 @@
</el-table-column>
<el-table-column prop="username" label="用户名">
</el-table-column>
<el-table-column prop="address" label="角色">
<el-table-column prop="department.name" label="公司" width="140" align="center" />
<el-table-column prop="address" label="角色" min-width="140">
<template slot-scope="scope">
<el-tag size="medium" v-for="(item,index) in scope.row.roles" style="margin-right: 10px;">{{ item.name }}
</el-tag>

Loading…
Cancel
Save