init
This commit is contained in:
@@ -0,0 +1,303 @@
|
||||
<template>
|
||||
<!-- 账号锁定配置抽屉 -->
|
||||
<el-drawer title="账号锁定配置" append-to-body v-model="authLockBox" size="60%">
|
||||
<avue-crud
|
||||
:option="authLockOption"
|
||||
:table-loading="authLockLoading"
|
||||
:data="authLockData"
|
||||
ref="authLockCrud"
|
||||
v-model="authLockForm"
|
||||
v-model:page="authLockPage"
|
||||
v-model:search="authLockSearch"
|
||||
:before-open="authLockBeforeOpen"
|
||||
@search-change="authLockSearchChange"
|
||||
@search-reset="authLockSearchReset"
|
||||
@current-change="authLockCurrentChange"
|
||||
@size-change="authLockSizeChange"
|
||||
@refresh-change="authLockRefreshChange"
|
||||
@on-load="authLockOnLoad"
|
||||
>
|
||||
<template #lockTarget="{ row }">
|
||||
<el-tag type="primary" size="small" effect="light">{{ row.lockTarget }}</el-tag>
|
||||
</template>
|
||||
<template #userName="{ row }">
|
||||
{{ row.userName || '-' }}
|
||||
</template>
|
||||
<template #remoteIp="{ row }">
|
||||
<el-tag type="primary" size="small" effect="light">{{ row.remoteIp || '暂无' }}</el-tag>
|
||||
</template>
|
||||
<template #lockType="{ row }">
|
||||
<el-tag :type="row.lockType === 'SYSTEM' ? 'info' : 'danger'" size="small">
|
||||
{{ row.lockTypeName }}
|
||||
</el-tag>
|
||||
</template>
|
||||
<template #lockStatus="{ row }">
|
||||
<el-tag
|
||||
:type="row.expired ? 'info' : row.lockStatus === 'LOCKED' ? 'danger' : row.lockStatus === 'PRE_LOCKED' ? 'warning' : 'success'"
|
||||
size="small"
|
||||
>
|
||||
{{ row.lockStatusName }}
|
||||
</el-tag>
|
||||
</template>
|
||||
<template #lockBeginTime="{ row }">
|
||||
{{ row.lockBeginTime || '立即生效' }}
|
||||
</template>
|
||||
<template #lockEndTime="{ row }">
|
||||
{{ row.lockEndTime || '永久' }}
|
||||
</template>
|
||||
<template #menu="{ row }">
|
||||
<el-button
|
||||
text
|
||||
type="primary"
|
||||
icon="el-icon-view"
|
||||
@click.stop="$refs.authLockCrud.rowView(row)"
|
||||
>查看</el-button
|
||||
>
|
||||
<el-button
|
||||
v-if="(row.lockStatus === 'LOCKED' || row.lockStatus === 'PRE_LOCKED') && !row.expired"
|
||||
text
|
||||
type="primary"
|
||||
icon="el-icon-key"
|
||||
@click.stop="handleAuthLockUnlock(row)"
|
||||
>解锁</el-button
|
||||
>
|
||||
</template>
|
||||
</avue-crud>
|
||||
</el-drawer>
|
||||
|
||||
<!-- 手动锁定用户 -->
|
||||
<el-dialog title="锁定用户" append-to-body v-model="lockUserBox" width="500px">
|
||||
<el-form :model="lockUserForm" label-width="100px" :rules="lockUserRules" ref="lockUserFormRef">
|
||||
<el-form-item label="用户账号">
|
||||
<el-input :model-value="lockUserForm.account" disabled />
|
||||
</el-form-item>
|
||||
<el-form-item label="锁定原因" prop="lockReason">
|
||||
<el-input
|
||||
v-model="lockUserForm.lockReason"
|
||||
type="textarea"
|
||||
:rows="3"
|
||||
placeholder="请输入锁定原因"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="锁定开始" prop="lockBeginTime">
|
||||
<el-date-picker
|
||||
v-model="lockUserForm.lockBeginTime"
|
||||
type="datetime"
|
||||
placeholder="不填则立即生效"
|
||||
value-format="YYYY-MM-DD HH:mm:ss"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="锁定结束" prop="lockEndTime">
|
||||
<el-date-picker
|
||||
v-model="lockUserForm.lockEndTime"
|
||||
type="datetime"
|
||||
placeholder="不填则永久锁定"
|
||||
value-format="YYYY-MM-DD HH:mm:ss"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="lockUserBox = false">取 消</el-button>
|
||||
<el-button type="primary" :loading="lockSubmitLoading" @click="submitLockUser">确 定</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 解锁原因确认 -->
|
||||
<el-dialog title="解锁确认" append-to-body v-model="unlockReasonBox" width="450px">
|
||||
<el-form :model="unlockReasonForm" label-width="80px">
|
||||
<el-form-item label="解锁原因">
|
||||
<el-input
|
||||
v-model="unlockReasonForm.unlockReason"
|
||||
type="textarea"
|
||||
:rows="3"
|
||||
placeholder="请输入解锁原因(可选)"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="unlockReasonBox = false">取 消</el-button>
|
||||
<el-button type="primary" :loading="unlockSubmitLoading" @click="submitUnlockReason">确 定</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {
|
||||
getAuthLockPage,
|
||||
getAuthLockDetail,
|
||||
authLockUnlock,
|
||||
lockUser,
|
||||
} from '@/api/system/authlock';
|
||||
import { validatenull } from '@/utils/validate';
|
||||
import { authLockOption } from '@/option/system/authlock';
|
||||
|
||||
export default {
|
||||
name: 'AuthLock',
|
||||
emits: ['lock-success'],
|
||||
data() {
|
||||
return {
|
||||
authLockOption,
|
||||
// 锁定日志抽屉
|
||||
authLockBox: false,
|
||||
authLockLoading: false,
|
||||
authLockData: [],
|
||||
authLockForm: {},
|
||||
authLockSearch: {},
|
||||
authLockPage: {
|
||||
pageSize: 10,
|
||||
currentPage: 1,
|
||||
total: 0,
|
||||
},
|
||||
// 手动锁定用户
|
||||
lockUserBox: false,
|
||||
lockUserForm: {},
|
||||
lockUserRules: {
|
||||
lockReason: [{ required: true, message: '请输入锁定原因', trigger: 'blur' }],
|
||||
lockEndTime: [
|
||||
{
|
||||
validator: (rule, value, callback) => {
|
||||
if (!value) {
|
||||
callback();
|
||||
} else if (this.lockUserForm.lockBeginTime && value < this.lockUserForm.lockBeginTime) {
|
||||
callback(new Error('结束时间不能早于开始时间'));
|
||||
} else if (!this.lockUserForm.lockBeginTime && value < new Date().toISOString().slice(0, 19).replace('T', ' ')) {
|
||||
callback(new Error('结束时间不能早于当前时间'));
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
},
|
||||
trigger: 'change',
|
||||
},
|
||||
],
|
||||
},
|
||||
// 解锁确认
|
||||
unlockReasonBox: false,
|
||||
unlockReasonForm: {},
|
||||
currentUnlockId: null,
|
||||
lockSubmitLoading: false,
|
||||
unlockSubmitLoading: false,
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
// ========== 对外暴露的入口方法 ==========
|
||||
|
||||
openLockLog() {
|
||||
this.authLockSearch = {};
|
||||
this.authLockPage.currentPage = 1;
|
||||
this.authLockBox = true;
|
||||
this.$nextTick(() => {
|
||||
this.authLockOnLoad(this.authLockPage);
|
||||
});
|
||||
},
|
||||
openLockUser(userId, account) {
|
||||
this.lockUserForm = {
|
||||
userId,
|
||||
account,
|
||||
lockReason: '',
|
||||
lockBeginTime: '',
|
||||
lockEndTime: '',
|
||||
};
|
||||
this.lockUserBox = true;
|
||||
},
|
||||
|
||||
// ========== 锁定日志列表 ==========
|
||||
|
||||
authLockBeforeOpen(done, type) {
|
||||
if (type === 'view') {
|
||||
getAuthLockDetail(this.authLockForm.id).then(res => {
|
||||
this.authLockForm = res.data.data;
|
||||
});
|
||||
}
|
||||
done();
|
||||
},
|
||||
authLockSearchChange(params, done) {
|
||||
this.authLockSearch = params;
|
||||
this.authLockPage.currentPage = 1;
|
||||
this.authLockOnLoad(this.authLockPage, params);
|
||||
done();
|
||||
},
|
||||
authLockSearchReset() {
|
||||
this.authLockSearch = {};
|
||||
this.authLockPage.currentPage = 1;
|
||||
this.authLockOnLoad(this.authLockPage);
|
||||
},
|
||||
authLockSizeChange(pageSize) {
|
||||
this.authLockPage.pageSize = pageSize;
|
||||
},
|
||||
authLockCurrentChange(currentPage) {
|
||||
this.authLockPage.currentPage = currentPage;
|
||||
},
|
||||
authLockRefreshChange() {
|
||||
this.authLockOnLoad(this.authLockPage, this.authLockSearch);
|
||||
},
|
||||
authLockOnLoad(page, params = {}) {
|
||||
this.authLockLoading = true;
|
||||
const merged = Object.assign({}, params, this.authLockSearch);
|
||||
const query = Object.fromEntries(Object.entries(merged).filter(([, val]) => !validatenull(val)));
|
||||
getAuthLockPage(page.currentPage, page.pageSize, query)
|
||||
.then(res => {
|
||||
const data = res.data.data;
|
||||
this.authLockPage.total = data.total;
|
||||
this.authLockData = data.records;
|
||||
this.authLockLoading = false;
|
||||
})
|
||||
.catch(() => {
|
||||
this.authLockLoading = false;
|
||||
});
|
||||
},
|
||||
|
||||
// ========== 解锁操作 ==========
|
||||
|
||||
handleAuthLockUnlock(row) {
|
||||
this.currentUnlockId = row.id;
|
||||
this.unlockReasonForm = { unlockReason: '' };
|
||||
this.unlockReasonBox = true;
|
||||
},
|
||||
submitUnlockReason() {
|
||||
this.unlockSubmitLoading = true;
|
||||
authLockUnlock(this.currentUnlockId, this.unlockReasonForm.unlockReason)
|
||||
.then(() => {
|
||||
this.unlockSubmitLoading = false;
|
||||
this.unlockReasonBox = false;
|
||||
this.$message({ type: 'success', message: '解锁成功!' });
|
||||
this.authLockOnLoad(this.authLockPage, this.authLockSearch);
|
||||
})
|
||||
.catch(() => {
|
||||
this.unlockSubmitLoading = false;
|
||||
this.$message({ type: 'error', message: '解锁失败,请重试!' });
|
||||
});
|
||||
},
|
||||
|
||||
// ========== 手动锁定用户 ==========
|
||||
|
||||
submitLockUser() {
|
||||
this.$refs.lockUserFormRef.validate(valid => {
|
||||
if (!valid) return;
|
||||
this.lockSubmitLoading = true;
|
||||
lockUser(
|
||||
this.lockUserForm.userId,
|
||||
this.lockUserForm.lockReason,
|
||||
this.lockUserForm.lockBeginTime,
|
||||
this.lockUserForm.lockEndTime
|
||||
)
|
||||
.then(() => {
|
||||
this.lockSubmitLoading = false;
|
||||
this.lockUserBox = false;
|
||||
this.$message({ type: 'success', message: '锁定成功!' });
|
||||
this.$emit('lock-success');
|
||||
})
|
||||
.catch(() => {
|
||||
this.lockSubmitLoading = false;
|
||||
this.$message({ type: 'error', message: '锁定失败,请重试!' });
|
||||
});
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@@ -0,0 +1,155 @@
|
||||
<template>
|
||||
<!-- 认证日志抽屉 -->
|
||||
<el-drawer :title="authLogTitle" append-to-body v-model="authLogBox" size="60%">
|
||||
<avue-crud
|
||||
:option="authLogOption"
|
||||
:table-loading="authLogLoading"
|
||||
:data="authLogData"
|
||||
ref="authLogCrud"
|
||||
v-model="authLogForm"
|
||||
v-model:page="authLogPage"
|
||||
v-model:search="authLogSearch"
|
||||
:before-open="authLogBeforeOpen"
|
||||
@search-change="authLogSearchChange"
|
||||
@search-reset="authLogSearchReset"
|
||||
@current-change="authLogCurrentChange"
|
||||
@size-change="authLogSizeChange"
|
||||
@refresh-change="authLogRefreshChange"
|
||||
@on-load="authLogOnLoad"
|
||||
>
|
||||
<template #menu="{ row }">
|
||||
<el-button
|
||||
text
|
||||
type="primary"
|
||||
icon="el-icon-view"
|
||||
@click.stop="$refs.authLogCrud.rowView(row)"
|
||||
>查看</el-button
|
||||
>
|
||||
</template>
|
||||
<template #account="{ row }">
|
||||
<el-tag size="small" effect="light">{{ row.account }}</el-tag>
|
||||
</template>
|
||||
<template #grantType="{ row }">
|
||||
<el-tag size="small" effect="light">{{ getGrantTypeName(row.grantType) }}</el-tag>
|
||||
</template>
|
||||
<template #remoteIp="{ row }">
|
||||
<el-tag size="small" effect="light">{{ row.remoteIp || '-' }}</el-tag>
|
||||
</template>
|
||||
<template #env="{ row }">
|
||||
<el-tag
|
||||
:type="row.env === 'prod' ? 'danger' : row.env === 'test' ? 'warning' : row.env === 'dev' ? 'success' : 'info'"
|
||||
size="small"
|
||||
>{{ row.env || '-' }}</el-tag>
|
||||
</template>
|
||||
</avue-crud>
|
||||
</el-drawer>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getAuthLogPage, getAuthLogDetail } from '@/api/system/authlog';
|
||||
import { validatenull } from '@/utils/validate';
|
||||
import { authLogOption, GRANT_TYPE_DIC } from '@/option/system/authlog';
|
||||
|
||||
export default {
|
||||
name: 'AuthLog',
|
||||
data() {
|
||||
return {
|
||||
authLogOption,
|
||||
authLogTitle: '认证日志',
|
||||
// 抽屉状态
|
||||
authLogBox: false,
|
||||
authLogLoading: false,
|
||||
authLogData: [],
|
||||
authLogForm: {},
|
||||
authLogSearch: {},
|
||||
authLogPage: {
|
||||
pageSize: 10,
|
||||
currentPage: 1,
|
||||
total: 0,
|
||||
},
|
||||
// 用户ID过滤
|
||||
filterUserId: null,
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
// ========== 对外暴露的入口方法 ==========
|
||||
|
||||
openAuthLog() {
|
||||
this.filterUserId = null;
|
||||
this.authLogTitle = '认证日志';
|
||||
this.authLogSearch = {};
|
||||
this.authLogPage.currentPage = 1;
|
||||
this.authLogBox = true;
|
||||
this.$nextTick(() => {
|
||||
this.authLogOnLoad(this.authLogPage);
|
||||
});
|
||||
},
|
||||
openUserAuthLog(userId, userName) {
|
||||
this.filterUserId = userId;
|
||||
this.authLogTitle = userName ? `认证日志 - ${userName}` : '认证日志';
|
||||
this.authLogSearch = {};
|
||||
this.authLogPage.currentPage = 1;
|
||||
this.authLogBox = true;
|
||||
this.$nextTick(() => {
|
||||
this.authLogOnLoad(this.authLogPage);
|
||||
});
|
||||
},
|
||||
|
||||
// ========== 授权类型转译 ==========
|
||||
|
||||
getGrantTypeName(grantType) {
|
||||
const item = GRANT_TYPE_DIC.find(d => d.value === grantType);
|
||||
return item ? item.label : grantType || '-';
|
||||
},
|
||||
|
||||
// ========== 认证日志列表 ==========
|
||||
|
||||
authLogBeforeOpen(done, type) {
|
||||
if (type === 'view') {
|
||||
getAuthLogDetail(this.authLogForm.id).then(res => {
|
||||
this.authLogForm = res.data.data;
|
||||
});
|
||||
}
|
||||
done();
|
||||
},
|
||||
authLogSearchChange(params, done) {
|
||||
this.authLogSearch = params;
|
||||
this.authLogPage.currentPage = 1;
|
||||
this.authLogOnLoad(this.authLogPage, params);
|
||||
done();
|
||||
},
|
||||
authLogSearchReset() {
|
||||
this.authLogSearch = {};
|
||||
this.authLogPage.currentPage = 1;
|
||||
this.authLogOnLoad(this.authLogPage);
|
||||
},
|
||||
authLogSizeChange(pageSize) {
|
||||
this.authLogPage.pageSize = pageSize;
|
||||
},
|
||||
authLogCurrentChange(currentPage) {
|
||||
this.authLogPage.currentPage = currentPage;
|
||||
},
|
||||
authLogRefreshChange() {
|
||||
this.authLogOnLoad(this.authLogPage, this.authLogSearch);
|
||||
},
|
||||
authLogOnLoad(page, params = {}) {
|
||||
this.authLogLoading = true;
|
||||
const merged = Object.assign({}, params, this.authLogSearch);
|
||||
if (this.filterUserId) {
|
||||
merged.userId = this.filterUserId;
|
||||
}
|
||||
const query = Object.fromEntries(Object.entries(merged).filter(([, val]) => !validatenull(val)));
|
||||
getAuthLogPage(page.currentPage, page.pageSize, query)
|
||||
.then(res => {
|
||||
const data = res.data.data;
|
||||
this.authLogPage.total = data.total;
|
||||
this.authLogData = data.records;
|
||||
this.authLogLoading = false;
|
||||
})
|
||||
.catch(() => {
|
||||
this.authLogLoading = false;
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@@ -0,0 +1,385 @@
|
||||
<template>
|
||||
<basic-container>
|
||||
<avue-crud
|
||||
:option="option"
|
||||
:table-loading="loading"
|
||||
:data="data"
|
||||
v-model:page="page"
|
||||
@row-del="rowDel"
|
||||
v-model="form"
|
||||
ref="crud"
|
||||
:permission="permissionList"
|
||||
@row-update="rowUpdate"
|
||||
@row-save="rowSave"
|
||||
:before-open="beforeOpen"
|
||||
@search-change="searchChange"
|
||||
@search-reset="searchReset"
|
||||
@selection-change="selectionChange"
|
||||
@current-change="currentChange"
|
||||
@size-change="sizeChange"
|
||||
@refresh-change="refreshChange"
|
||||
@on-load="onLoad"
|
||||
>
|
||||
<template #menu-left>
|
||||
<el-button
|
||||
type="danger"
|
||||
icon="el-icon-delete"
|
||||
plain
|
||||
v-if="permission.client_delete"
|
||||
@click="handleDelete"
|
||||
>删 除
|
||||
</el-button>
|
||||
</template>
|
||||
</avue-crud>
|
||||
</basic-container>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getList, getDetail, add, update, remove } from '@/api/system/client';
|
||||
import { mapGetters } from 'vuex';
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
form: {},
|
||||
query: {},
|
||||
loading: true,
|
||||
page: {
|
||||
pageSize: 10,
|
||||
currentPage: 1,
|
||||
total: 0,
|
||||
},
|
||||
selectionList: [],
|
||||
option: {
|
||||
height: 'auto',
|
||||
calcHeight: 32,
|
||||
tip: false,
|
||||
searchShow: true,
|
||||
searchMenuSpan: 6,
|
||||
border: true,
|
||||
index: true,
|
||||
viewBtn: true,
|
||||
grid: true,
|
||||
selection: true,
|
||||
dialogClickModal: false,
|
||||
column: [
|
||||
{
|
||||
label: '应用id',
|
||||
prop: 'clientId',
|
||||
search: true,
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '请输入客户端id',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: '应用密钥',
|
||||
prop: 'clientSecret',
|
||||
search: true,
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '请输入客户端密钥',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: '授权类型',
|
||||
prop: 'authorizedGrantTypes',
|
||||
type: 'checkbox',
|
||||
value: 'refresh_token,password,authorization_code,captcha,social,sms_code,register',
|
||||
dicData: [
|
||||
{
|
||||
label: 'refresh_token',
|
||||
value: 'refresh_token',
|
||||
},
|
||||
{
|
||||
label: 'password',
|
||||
value: 'password',
|
||||
},
|
||||
{
|
||||
label: 'authorization_code',
|
||||
value: 'authorization_code',
|
||||
},
|
||||
{
|
||||
label: 'captcha',
|
||||
value: 'captcha',
|
||||
},
|
||||
{
|
||||
label: 'social',
|
||||
value: 'social',
|
||||
},
|
||||
{
|
||||
label: 'sms_code',
|
||||
value: 'sms_code',
|
||||
},
|
||||
{
|
||||
label: 'register',
|
||||
value: 'register',
|
||||
},
|
||||
],
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '请输入授权类型',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: '授权范围',
|
||||
prop: 'scope',
|
||||
value: 'all',
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '请输入授权范围',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: '令牌秒数',
|
||||
prop: 'accessTokenValidity',
|
||||
type: 'number',
|
||||
value: 3600,
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '请输入令牌过期秒数',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: '刷新秒数',
|
||||
prop: 'refreshTokenValidity',
|
||||
type: 'number',
|
||||
value: 604800,
|
||||
hide: true,
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '请输入刷新令牌过期秒数',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: '回调地址',
|
||||
prop: 'webServerRedirectUri',
|
||||
hide: true,
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '请输入回调地址',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: '自动授权',
|
||||
prop: 'autoapprove',
|
||||
hide: true,
|
||||
type: 'radio',
|
||||
dicData: [
|
||||
{
|
||||
label: '是',
|
||||
value: 'true',
|
||||
},
|
||||
{
|
||||
label: '否',
|
||||
value: 'false',
|
||||
},
|
||||
],
|
||||
value: 'true',
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '请输入自动授权',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: '资源集合',
|
||||
prop: 'resourceIds',
|
||||
hide: true,
|
||||
rules: [
|
||||
{
|
||||
message: '请输入资源集合',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: '权限',
|
||||
prop: 'authorities',
|
||||
hide: true,
|
||||
rules: [
|
||||
{
|
||||
message: '请输入权限',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: '附加说明',
|
||||
hide: true,
|
||||
prop: 'additionalInformation',
|
||||
span: 24,
|
||||
rules: [
|
||||
{
|
||||
message: '请输入附加说明',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
data: [],
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['permission']),
|
||||
permissionList() {
|
||||
return {
|
||||
addBtn: this.validData(this.permission.client_add),
|
||||
viewBtn: this.validData(this.permission.client_view),
|
||||
delBtn: this.validData(this.permission.client_delete),
|
||||
editBtn: this.validData(this.permission.client_edit),
|
||||
};
|
||||
},
|
||||
ids() {
|
||||
let ids = [];
|
||||
this.selectionList.forEach(ele => {
|
||||
ids.push(ele.id);
|
||||
});
|
||||
return ids.join(',');
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
rowSave(row, done, loading) {
|
||||
add(row).then(
|
||||
() => {
|
||||
this.onLoad(this.page);
|
||||
this.$message({
|
||||
type: 'success',
|
||||
message: '操作成功!',
|
||||
});
|
||||
done();
|
||||
},
|
||||
error => {
|
||||
window.console.log(error);
|
||||
loading();
|
||||
}
|
||||
);
|
||||
},
|
||||
rowUpdate(row, index, done, loading) {
|
||||
update(row).then(
|
||||
() => {
|
||||
this.onLoad(this.page);
|
||||
this.$message({
|
||||
type: 'success',
|
||||
message: '操作成功!',
|
||||
});
|
||||
done();
|
||||
},
|
||||
error => {
|
||||
window.console.log(error);
|
||||
loading();
|
||||
}
|
||||
);
|
||||
},
|
||||
rowDel(row) {
|
||||
this.$confirm('确定将选择数据删除?', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
})
|
||||
.then(() => {
|
||||
return remove(row.id);
|
||||
})
|
||||
.then(() => {
|
||||
this.onLoad(this.page);
|
||||
this.$message({
|
||||
type: 'success',
|
||||
message: '操作成功!',
|
||||
});
|
||||
});
|
||||
},
|
||||
searchReset() {
|
||||
this.query = {};
|
||||
this.onLoad(this.page);
|
||||
},
|
||||
searchChange(params, done) {
|
||||
this.query = params;
|
||||
this.page.currentPage = 1;
|
||||
this.onLoad(this.page, params);
|
||||
done();
|
||||
},
|
||||
selectionChange(list) {
|
||||
this.selectionList = list;
|
||||
},
|
||||
selectionClear() {
|
||||
this.selectionList = [];
|
||||
this.$refs.crud.toggleSelection();
|
||||
},
|
||||
handleDelete() {
|
||||
if (this.selectionList.length === 0) {
|
||||
this.$message.warning('请选择至少一条数据');
|
||||
return;
|
||||
}
|
||||
this.$confirm('确定将选择数据删除?', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
})
|
||||
.then(() => {
|
||||
return remove(this.ids);
|
||||
})
|
||||
.then(() => {
|
||||
this.onLoad(this.page);
|
||||
this.$message({
|
||||
type: 'success',
|
||||
message: '操作成功!',
|
||||
});
|
||||
this.$refs.crud.toggleSelection();
|
||||
});
|
||||
},
|
||||
beforeOpen(done, type) {
|
||||
if (['edit', 'view'].includes(type)) {
|
||||
getDetail(this.form.id).then(res => {
|
||||
this.form = res.data.data;
|
||||
});
|
||||
}
|
||||
done();
|
||||
},
|
||||
currentChange(currentPage) {
|
||||
this.page.currentPage = currentPage;
|
||||
},
|
||||
sizeChange(pageSize) {
|
||||
this.page.pageSize = pageSize;
|
||||
},
|
||||
refreshChange() {
|
||||
this.onLoad(this.page, this.query);
|
||||
},
|
||||
onLoad(page, params = {}) {
|
||||
this.loading = true;
|
||||
getList(page.currentPage, page.pageSize, Object.assign(params, this.query)).then(res => {
|
||||
const data = res.data.data;
|
||||
this.page.total = data.total;
|
||||
this.data = data.records;
|
||||
this.loading = false;
|
||||
this.selectionClear();
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style></style>
|
||||
@@ -0,0 +1,404 @@
|
||||
<template>
|
||||
<basic-container>
|
||||
<avue-crud
|
||||
:option="option"
|
||||
:table-loading="loading"
|
||||
:data="data"
|
||||
ref="crud"
|
||||
v-model="form"
|
||||
:permission="permissionList"
|
||||
:before-open="beforeOpen"
|
||||
:before-close="beforeClose"
|
||||
@row-del="rowDel"
|
||||
@row-update="rowUpdate"
|
||||
@row-save="rowSave"
|
||||
@search-change="searchChange"
|
||||
@search-reset="searchReset"
|
||||
@selection-change="selectionChange"
|
||||
@current-change="currentChange"
|
||||
@size-change="sizeChange"
|
||||
@refresh-change="refreshChange"
|
||||
@on-load="onLoad"
|
||||
@tree-load="treeLoad"
|
||||
>
|
||||
<template #menu-left>
|
||||
<el-button
|
||||
type="danger"
|
||||
icon="el-icon-delete"
|
||||
v-if="permission.dept_delete"
|
||||
plain
|
||||
@click="handleDelete"
|
||||
>删 除
|
||||
</el-button>
|
||||
</template>
|
||||
<template #menu="scope">
|
||||
<el-button
|
||||
type="primary"
|
||||
text
|
||||
icon="el-icon-circle-plus"
|
||||
@click.stop="handleAdd(scope.row, scope.index)"
|
||||
v-if="userInfo.authority.includes('admin')"
|
||||
>新增子项
|
||||
</el-button>
|
||||
</template>
|
||||
<template #deptCategory="{ row }">
|
||||
<el-tag>{{ row.deptCategoryName }}</el-tag>
|
||||
</template>
|
||||
</avue-crud>
|
||||
</basic-container>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getLazyList, remove, update, add, getDept, getDeptTree } from '@/api/system/dept';
|
||||
import { getLeaderList } from '@/api/system/user';
|
||||
import { mapGetters } from 'vuex';
|
||||
import website from '@/config/website';
|
||||
import func from '@/utils/func';
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
form: {},
|
||||
selectionList: [],
|
||||
query: {},
|
||||
loading: true,
|
||||
parentId: 0,
|
||||
page: {
|
||||
pageSize: 10,
|
||||
currentPage: 1,
|
||||
total: 0,
|
||||
},
|
||||
option: {
|
||||
lazy: true,
|
||||
tip: false,
|
||||
simplePage: true,
|
||||
searchShow: true,
|
||||
searchMenuSpan: 6,
|
||||
tree: true,
|
||||
border: true,
|
||||
index: true,
|
||||
selection: true,
|
||||
viewBtn: true,
|
||||
menuWidth: 320,
|
||||
dialogWidth: 800,
|
||||
dialogClickModal: false,
|
||||
column: [
|
||||
{
|
||||
label: '机构名称',
|
||||
prop: 'deptName',
|
||||
search: true,
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '请输入机构名称',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: '所属租户',
|
||||
prop: 'tenantId',
|
||||
type: 'tree',
|
||||
dicUrl: '/blade-system/tenant/select',
|
||||
addDisplay: false,
|
||||
editDisplay: false,
|
||||
viewDisplay: website.tenantMode,
|
||||
span: 24,
|
||||
props: {
|
||||
label: 'tenantName',
|
||||
value: 'tenantId',
|
||||
},
|
||||
hide: !website.tenantMode,
|
||||
search: website.tenantMode,
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '请输入所属租户',
|
||||
trigger: 'click',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: '机构全称',
|
||||
prop: 'fullName',
|
||||
search: true,
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '请输入机构全称',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: '上级机构',
|
||||
prop: 'parentId',
|
||||
dicData: [],
|
||||
type: 'tree',
|
||||
hide: true,
|
||||
addDisabled: false,
|
||||
props: {
|
||||
label: 'title',
|
||||
},
|
||||
rules: [
|
||||
{
|
||||
required: false,
|
||||
message: '请选择上级机构',
|
||||
trigger: 'click',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: '直属主管',
|
||||
prop: 'leaderId',
|
||||
type: 'tree',
|
||||
multiple: true,
|
||||
filterable: true,
|
||||
dicData: [],
|
||||
props: {
|
||||
label: 'realName',
|
||||
value: 'id',
|
||||
},
|
||||
clearable: true,
|
||||
hide: true,
|
||||
},
|
||||
{
|
||||
label: '机构类型',
|
||||
type: 'select',
|
||||
dicUrl: '/blade-system/dict/dictionary?code=org_category',
|
||||
props: {
|
||||
label: 'dictValue',
|
||||
value: 'dictKey',
|
||||
},
|
||||
dataType: 'number',
|
||||
width: 120,
|
||||
prop: 'deptCategory',
|
||||
slot: true,
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '请输入机构类型',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: '排序',
|
||||
prop: 'sort',
|
||||
type: 'number',
|
||||
align: 'right',
|
||||
width: 80,
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '请输入排序',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: '备注',
|
||||
prop: 'remark',
|
||||
type: 'textarea',
|
||||
span: 24,
|
||||
minRows: 2,
|
||||
hide: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
data: [],
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['userInfo', 'permission']),
|
||||
permissionList() {
|
||||
return {
|
||||
addBtn: this.validData(this.permission.dept_add, false),
|
||||
viewBtn: this.validData(this.permission.dept_view, false),
|
||||
delBtn: this.validData(this.permission.dept_delete, false),
|
||||
editBtn: this.validData(this.permission.dept_edit, false),
|
||||
};
|
||||
},
|
||||
ids() {
|
||||
let ids = [];
|
||||
this.selectionList.forEach(ele => {
|
||||
ids.push(ele.id);
|
||||
});
|
||||
return ids.join(',');
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
initData(tenantId) {
|
||||
getDeptTree(tenantId).then(res => {
|
||||
const column = this.findColumn(this.option.column, 'parentId');
|
||||
column.dicData = res.data.data;
|
||||
});
|
||||
getLeaderList(tenantId).then(res => {
|
||||
const column = this.findColumn(this.option.column, 'leaderId');
|
||||
column.dicData = res.data.data;
|
||||
});
|
||||
},
|
||||
handleAdd(row) {
|
||||
this.parentId = row.id;
|
||||
const column = this.findColumn(this.option.column, 'parentId');
|
||||
column.value = row.id;
|
||||
column.addDisabled = true;
|
||||
this.$refs.crud.rowAdd();
|
||||
},
|
||||
rowSave(row, done, loading) {
|
||||
row.leaderId = func.join(row.leaderId);
|
||||
add(row).then(
|
||||
res => {
|
||||
// 获取新增数据的相关字段
|
||||
const data = res.data.data;
|
||||
row.id = data.id;
|
||||
row.deptCategoryName = data.deptCategoryName;
|
||||
row.tenantId = data.tenantId;
|
||||
this.$message({
|
||||
type: 'success',
|
||||
message: '操作成功!',
|
||||
});
|
||||
// 数据回调进行刷新
|
||||
done(row);
|
||||
},
|
||||
error => {
|
||||
window.console.log(error);
|
||||
loading();
|
||||
}
|
||||
);
|
||||
},
|
||||
rowUpdate(row, index, done, loading) {
|
||||
row.leaderId = func.join(row.leaderId);
|
||||
update(row).then(
|
||||
() => {
|
||||
this.$message({
|
||||
type: 'success',
|
||||
message: '操作成功!',
|
||||
});
|
||||
// 数据回调进行刷新
|
||||
done(row);
|
||||
},
|
||||
error => {
|
||||
window.console.log(error);
|
||||
loading();
|
||||
}
|
||||
);
|
||||
},
|
||||
rowDel(row, index, done) {
|
||||
this.$confirm('确定将选择数据删除?', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
})
|
||||
.then(() => {
|
||||
return remove(row.id);
|
||||
})
|
||||
.then(() => {
|
||||
this.$message({
|
||||
type: 'success',
|
||||
message: '操作成功!',
|
||||
});
|
||||
// 数据回调进行刷新
|
||||
done(row);
|
||||
});
|
||||
},
|
||||
handleDelete() {
|
||||
if (this.selectionList.length === 0) {
|
||||
this.$message.warning('请选择至少一条数据');
|
||||
return;
|
||||
}
|
||||
this.$confirm('确定将选择数据删除?', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
})
|
||||
.then(() => {
|
||||
return remove(this.ids);
|
||||
})
|
||||
.then(() => {
|
||||
// 刷新表格数据并重载
|
||||
this.data = [];
|
||||
this.parentId = 0;
|
||||
this.$refs.crud.refreshTable();
|
||||
this.$refs.crud.toggleSelection();
|
||||
// 表格数据重载
|
||||
this.onLoad(this.page);
|
||||
this.$message({
|
||||
type: 'success',
|
||||
message: '操作成功!',
|
||||
});
|
||||
});
|
||||
},
|
||||
searchReset() {
|
||||
this.query = {};
|
||||
this.parentId = 0;
|
||||
this.onLoad(this.page);
|
||||
},
|
||||
searchChange(params, done) {
|
||||
this.query = params;
|
||||
this.parentId = '';
|
||||
this.page.currentPage = 1;
|
||||
this.onLoad(this.page, params);
|
||||
done();
|
||||
},
|
||||
selectionChange(list) {
|
||||
this.selectionList = list;
|
||||
},
|
||||
selectionClear() {
|
||||
this.selectionList = [];
|
||||
this.$refs.crud.toggleSelection();
|
||||
},
|
||||
beforeOpen(done, type) {
|
||||
if (['add', 'edit'].includes(type)) {
|
||||
this.initData(this.form.tenantId);
|
||||
}
|
||||
if (['edit', 'view'].includes(type)) {
|
||||
getDept(this.form.id).then(res => {
|
||||
this.form = Object.assign(res.data.data, {
|
||||
hasChildren: this.form.hasChildren,
|
||||
});
|
||||
if (this.form.parentId === '0') {
|
||||
this.form.parentId = '';
|
||||
}
|
||||
if (this.form.hasOwnProperty('leaderId')) {
|
||||
this.form.leaderId = func.split(this.form.leaderId);
|
||||
}
|
||||
});
|
||||
}
|
||||
done();
|
||||
},
|
||||
beforeClose(done) {
|
||||
this.parentId = '';
|
||||
const column = this.findColumn(this.option.column, 'parentId');
|
||||
column.value = '';
|
||||
column.addDisabled = false;
|
||||
done();
|
||||
},
|
||||
currentChange(currentPage) {
|
||||
this.page.currentPage = currentPage;
|
||||
},
|
||||
sizeChange(pageSize) {
|
||||
this.page.pageSize = pageSize;
|
||||
},
|
||||
refreshChange() {
|
||||
this.onLoad(this.page, this.query);
|
||||
},
|
||||
onLoad(page, params = {}) {
|
||||
this.loading = true;
|
||||
getLazyList(this.parentId, Object.assign(params, this.query)).then(res => {
|
||||
this.data = res.data.data;
|
||||
this.loading = false;
|
||||
this.selectionClear();
|
||||
});
|
||||
},
|
||||
treeLoad(tree, treeNode, resolve) {
|
||||
const parentId = tree.id;
|
||||
getLazyList(parentId).then(res => {
|
||||
resolve(res.data.data);
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style></style>
|
||||
@@ -0,0 +1,450 @@
|
||||
<template>
|
||||
<basic-container>
|
||||
<avue-crud
|
||||
:option="optionParent"
|
||||
:table-loading="loading"
|
||||
:data="dataParent"
|
||||
:page="pageParent"
|
||||
ref="crud"
|
||||
v-model="formParent"
|
||||
:permission="permissionList"
|
||||
:before-open="beforeOpen"
|
||||
@row-del="rowDel"
|
||||
@row-update="rowUpdate"
|
||||
@row-save="rowSave"
|
||||
@row-click="handleRowClick"
|
||||
@search-change="searchChange"
|
||||
@search-reset="searchReset"
|
||||
@selection-change="selectionChange"
|
||||
@current-change="currentChange"
|
||||
@size-change="sizeChange"
|
||||
@refresh-change="refreshChange"
|
||||
@on-load="onLoadParent"
|
||||
>
|
||||
<template #menu-left>
|
||||
<el-button
|
||||
type="danger"
|
||||
icon="el-icon-delete"
|
||||
v-if="permission.dict_delete"
|
||||
plain
|
||||
@click="handleDelete"
|
||||
>删 除
|
||||
</el-button>
|
||||
</template>
|
||||
<template #menu="scope">
|
||||
<el-button
|
||||
type="primary"
|
||||
text
|
||||
icon="el-icon-setting"
|
||||
@click.stop="handleRowClick(scope.row)"
|
||||
v-if="userInfo.authority.includes('admin')"
|
||||
>字典配置
|
||||
</el-button>
|
||||
</template>
|
||||
<template #code="{ row }">
|
||||
<el-tag @click="handleRowClick(row)" style="cursor: pointer">{{ row.code }}</el-tag>
|
||||
</template>
|
||||
<template #isSealed="{ row }">
|
||||
<el-tag>{{ row.isSealed === 0 ? '否' : '是' }}</el-tag>
|
||||
</template>
|
||||
</avue-crud>
|
||||
<el-dialog :title="`[${dictValue}]字典配置`" append-to-body v-model="box" width="1000px">
|
||||
<avue-crud
|
||||
:option="optionChild"
|
||||
:table-loading="loadingChild"
|
||||
:data="dataChild"
|
||||
ref="crudChild"
|
||||
v-model="formChild"
|
||||
:permission="permissionList"
|
||||
:before-open="beforeOpenChild"
|
||||
:before-close="beforeCloseChild"
|
||||
@row-del="rowDelChild"
|
||||
@row-update="rowUpdateChild"
|
||||
@row-save="rowSaveChild"
|
||||
@search-change="searchChangeChild"
|
||||
@search-reset="searchResetChild"
|
||||
@selection-change="selectionChangeChild"
|
||||
@current-change="currentChangeChild"
|
||||
@size-change="sizeChangeChild"
|
||||
@refresh-change="refreshChangeChild"
|
||||
@on-load="onLoadChild"
|
||||
>
|
||||
<template #menu-left>
|
||||
<el-button
|
||||
type="danger"
|
||||
icon="el-icon-delete"
|
||||
v-if="permission.dict_delete"
|
||||
plain
|
||||
@click="handleDelete"
|
||||
>删 除
|
||||
</el-button>
|
||||
</template>
|
||||
<template #menu="scope">
|
||||
<el-button
|
||||
type="primary"
|
||||
text
|
||||
icon="el-icon-circle-plus"
|
||||
@click.stop="handleAdd(scope.row, scope.index)"
|
||||
v-if="userInfo.authority.includes('admin')"
|
||||
>新增子项
|
||||
</el-button>
|
||||
</template>
|
||||
<template #isSealed="{ row }">
|
||||
<el-tag>{{ row.isSealed === 0 ? '否' : '是' }}</el-tag>
|
||||
</template>
|
||||
</avue-crud>
|
||||
</el-dialog>
|
||||
</basic-container>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {
|
||||
getParentList,
|
||||
getChildList,
|
||||
remove,
|
||||
update,
|
||||
add,
|
||||
getDict,
|
||||
getDictTree,
|
||||
} from '@/api/system/dict';
|
||||
import { optionParent, optionChild } from '@/option/system/dict';
|
||||
import { mapGetters } from 'vuex';
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
dictValue: '暂无',
|
||||
parentId: -1,
|
||||
formParent: {},
|
||||
formChild: {},
|
||||
selectionList: [],
|
||||
query: {},
|
||||
box: false,
|
||||
loading: true,
|
||||
loadingChild: true,
|
||||
pageParent: {
|
||||
pageSize: 10,
|
||||
pageSizes: [10, 30, 50, 100, 200],
|
||||
currentPage: 1,
|
||||
total: 0,
|
||||
},
|
||||
pageChild: {
|
||||
pageSize: 10,
|
||||
pageSizes: [10, 30, 50, 100, 200],
|
||||
currentPage: 1,
|
||||
total: 0,
|
||||
},
|
||||
dataParent: [],
|
||||
dataChild: [],
|
||||
optionParent: optionParent,
|
||||
optionChild: optionChild,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['userInfo', 'permission']),
|
||||
permissionList() {
|
||||
return {
|
||||
addBtn: this.validData(this.permission.dict_add, false),
|
||||
delBtn: this.validData(this.permission.dict_delete, false),
|
||||
editBtn: this.validData(this.permission.dict_edit, false),
|
||||
viewBtn: false,
|
||||
};
|
||||
},
|
||||
ids() {
|
||||
let ids = [];
|
||||
this.selectionList.forEach(ele => {
|
||||
ids.push(ele.id);
|
||||
});
|
||||
return ids.join(',');
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.initData();
|
||||
},
|
||||
methods: {
|
||||
initData() {
|
||||
getDictTree().then(res => {
|
||||
const column = this.findColumn(this.optionChild.column, 'parentId');
|
||||
column.dicData = res.data.data;
|
||||
});
|
||||
},
|
||||
handleAdd(row) {
|
||||
this.formChild.dictValue = '';
|
||||
this.formChild.dictKey = '';
|
||||
this.formChild.sort = 0;
|
||||
this.formChild.isSealed = 0;
|
||||
this.formChild.remark = '';
|
||||
this.formChild.parentId = row.id;
|
||||
this.$refs.crudChild.rowAdd();
|
||||
},
|
||||
rowSave(row, done, loading) {
|
||||
const form = {
|
||||
...row,
|
||||
dictKey: -1,
|
||||
};
|
||||
add(form).then(
|
||||
() => {
|
||||
this.onLoadParent(this.pageParent);
|
||||
this.$message({
|
||||
type: 'success',
|
||||
message: '操作成功!',
|
||||
});
|
||||
done();
|
||||
},
|
||||
error => {
|
||||
window.console.log(error);
|
||||
loading();
|
||||
}
|
||||
);
|
||||
},
|
||||
rowUpdate(row, index, done, loading) {
|
||||
update(row).then(
|
||||
() => {
|
||||
this.onLoadParent(this.pageParent);
|
||||
this.$message({
|
||||
type: 'success',
|
||||
message: '操作成功!',
|
||||
});
|
||||
this.onLoadChild(this.pageChild);
|
||||
done();
|
||||
},
|
||||
error => {
|
||||
window.console.log(error);
|
||||
loading();
|
||||
}
|
||||
);
|
||||
},
|
||||
rowDel(row) {
|
||||
this.$confirm('确定将选择数据删除?', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
})
|
||||
.then(() => {
|
||||
return remove(row.id);
|
||||
})
|
||||
.then(() => {
|
||||
this.onLoadParent(this.pageParent);
|
||||
this.$message({
|
||||
type: 'success',
|
||||
message: '操作成功!',
|
||||
});
|
||||
});
|
||||
},
|
||||
handleRowClick(row) {
|
||||
this.query = {};
|
||||
this.parentId = row.id;
|
||||
this.dictValue = row.dictValue;
|
||||
|
||||
const code = this.findColumn(this.optionChild.column, 'code');
|
||||
code.value = row.code;
|
||||
const parentId = this.findColumn(this.optionChild.column, 'parentId');
|
||||
parentId.value = row.id;
|
||||
|
||||
this.formChild.code = row.code;
|
||||
this.formChild.parentId = row.id;
|
||||
|
||||
this.box = true;
|
||||
this.onLoadChild(this.pageChild);
|
||||
},
|
||||
searchReset() {
|
||||
this.query = {};
|
||||
this.onLoadParent(this.pageParent);
|
||||
},
|
||||
searchChange(params, done) {
|
||||
this.query = params;
|
||||
this.pageParent.currentPage = 1;
|
||||
this.onLoadParent(this.pageParent, params);
|
||||
done();
|
||||
},
|
||||
selectionChange(list) {
|
||||
this.selectionList = list;
|
||||
},
|
||||
selectionClear() {
|
||||
this.selectionList = [];
|
||||
this.$refs.crud.toggleSelection();
|
||||
},
|
||||
handleDelete() {
|
||||
if (this.selectionList.length === 0) {
|
||||
this.$message.warning('请选择至少一条数据');
|
||||
return;
|
||||
}
|
||||
this.$confirm('确定将选择数据删除?', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
})
|
||||
.then(() => {
|
||||
return remove(this.ids);
|
||||
})
|
||||
.then(() => {
|
||||
this.onLoadParent(this.pageParent);
|
||||
this.$message({
|
||||
type: 'success',
|
||||
message: '操作成功!',
|
||||
});
|
||||
this.$refs.crud.toggleSelection();
|
||||
});
|
||||
},
|
||||
beforeOpen(done, type) {
|
||||
if (['edit', 'view'].includes(type)) {
|
||||
getDict(this.formParent.id).then(res => {
|
||||
this.formParent = res.data.data;
|
||||
});
|
||||
}
|
||||
done();
|
||||
},
|
||||
currentChange(currentPage) {
|
||||
this.pageParent.currentPage = currentPage;
|
||||
},
|
||||
sizeChange(pageSize) {
|
||||
this.pageParent.pageSize = pageSize;
|
||||
},
|
||||
refreshChange() {
|
||||
this.onLoadParent(this.pageParent, this.query);
|
||||
},
|
||||
rowSaveChild(row, done, loading) {
|
||||
add(row).then(
|
||||
() => {
|
||||
this.onLoadChild(this.pageChild);
|
||||
this.$message({
|
||||
type: 'success',
|
||||
message: '操作成功!',
|
||||
});
|
||||
done();
|
||||
},
|
||||
error => {
|
||||
window.console.log(error);
|
||||
loading();
|
||||
}
|
||||
);
|
||||
},
|
||||
rowUpdateChild(row, index, done, loading) {
|
||||
update(row).then(
|
||||
() => {
|
||||
this.onLoadChild(this.pageChild);
|
||||
this.$message({
|
||||
type: 'success',
|
||||
message: '操作成功!',
|
||||
});
|
||||
done();
|
||||
},
|
||||
error => {
|
||||
window.console.log(error);
|
||||
loading();
|
||||
}
|
||||
);
|
||||
},
|
||||
rowDelChild(row) {
|
||||
this.$confirm('确定将选择数据删除?', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
})
|
||||
.then(() => {
|
||||
return remove(row.id);
|
||||
})
|
||||
.then(() => {
|
||||
this.onLoadChild(this.pageChild);
|
||||
this.$message({
|
||||
type: 'success',
|
||||
message: '操作成功!',
|
||||
});
|
||||
});
|
||||
},
|
||||
searchResetChild() {
|
||||
this.query = {};
|
||||
this.onLoadChild(this.pageChild);
|
||||
},
|
||||
searchChangeChild(params, done) {
|
||||
this.query = params;
|
||||
this.pageChild.currentPage = 1;
|
||||
this.onLoadChild(this.pageChild, params);
|
||||
done();
|
||||
},
|
||||
selectionChangeChild(list) {
|
||||
this.selectionList = list;
|
||||
},
|
||||
selectionClearChild() {
|
||||
this.selectionList = [];
|
||||
this.$refs.crudChild.toggleSelection();
|
||||
},
|
||||
handleDeleteChild() {
|
||||
if (this.selectionList.length === 0) {
|
||||
this.$message.warning('请选择至少一条数据');
|
||||
return;
|
||||
}
|
||||
this.$confirm('确定将选择数据删除?', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
})
|
||||
.then(() => {
|
||||
return remove(this.ids);
|
||||
})
|
||||
.then(() => {
|
||||
this.onLoadChild(this.pageChild);
|
||||
this.$message({
|
||||
type: 'success',
|
||||
message: '操作成功!',
|
||||
});
|
||||
this.$refs.crudChild.toggleSelection();
|
||||
});
|
||||
},
|
||||
beforeOpenChild(done, type) {
|
||||
if (['add', 'edit'].includes(type)) {
|
||||
this.initData();
|
||||
}
|
||||
if (['edit', 'view'].includes(type)) {
|
||||
getDict(this.formChild.id).then(res => {
|
||||
this.formChild = res.data.data;
|
||||
});
|
||||
}
|
||||
done();
|
||||
},
|
||||
beforeCloseChild(done) {
|
||||
this.$refs.crudChild.modelValue.parentId = this.parentId;
|
||||
this.$refs.crudChild.option.column.filter(item => {
|
||||
if (item.prop === 'parentId') {
|
||||
item.value = this.parentId;
|
||||
}
|
||||
});
|
||||
done();
|
||||
},
|
||||
currentChangeChild(currentPage) {
|
||||
this.pageChild.currentPage = currentPage;
|
||||
},
|
||||
sizeChangeChild(pageSize) {
|
||||
this.pageChild.pageSize = pageSize;
|
||||
},
|
||||
refreshChangeChild() {
|
||||
this.onLoadChild(this.pageChild, this.query);
|
||||
},
|
||||
onLoadParent(page, params = {}) {
|
||||
this.loading = true;
|
||||
getParentList(page.currentPage, page.pageSize, Object.assign(params, this.query)).then(
|
||||
res => {
|
||||
const data = res.data.data;
|
||||
this.pageParent.total = data.total;
|
||||
this.dataParent = data.records;
|
||||
this.loading = false;
|
||||
this.selectionClear();
|
||||
}
|
||||
);
|
||||
},
|
||||
onLoadChild(page, params = {}) {
|
||||
this.loadingChild = true;
|
||||
getChildList(
|
||||
page.currentPage,
|
||||
page.pageSize,
|
||||
this.parentId,
|
||||
Object.assign(params, this.query)
|
||||
).then(res => {
|
||||
this.dataChild = res.data.data;
|
||||
this.loadingChild = false;
|
||||
this.selectionClear();
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@@ -0,0 +1,450 @@
|
||||
<template>
|
||||
<basic-container>
|
||||
<avue-crud
|
||||
:option="optionParent"
|
||||
:table-loading="loading"
|
||||
:data="dataParent"
|
||||
:page="pageParent"
|
||||
ref="crud"
|
||||
v-model="formParent"
|
||||
:permission="permissionList"
|
||||
:before-open="beforeOpen"
|
||||
@row-del="rowDel"
|
||||
@row-update="rowUpdate"
|
||||
@row-save="rowSave"
|
||||
@row-click="handleRowClick"
|
||||
@search-change="searchChange"
|
||||
@search-reset="searchReset"
|
||||
@selection-change="selectionChange"
|
||||
@current-change="currentChange"
|
||||
@size-change="sizeChange"
|
||||
@refresh-change="refreshChange"
|
||||
@on-load="onLoadParent"
|
||||
>
|
||||
<template #menu-left>
|
||||
<el-button
|
||||
type="danger"
|
||||
icon="el-icon-delete"
|
||||
v-if="permission.dictbiz_delete"
|
||||
plain
|
||||
@click="handleDelete"
|
||||
>删 除
|
||||
</el-button>
|
||||
</template>
|
||||
<template #menu="scope">
|
||||
<el-button
|
||||
type="primary"
|
||||
text
|
||||
icon="el-icon-setting"
|
||||
@click.stop="handleRowClick(scope.row)"
|
||||
v-if="userInfo.authority.includes('admin')"
|
||||
>字典配置
|
||||
</el-button>
|
||||
</template>
|
||||
<template #code="{ row }">
|
||||
<el-tag @click="handleRowClick(row)" style="cursor: pointer">{{ row.code }}</el-tag>
|
||||
</template>
|
||||
<template #isSealed="{ row }">
|
||||
<el-tag>{{ row.isSealed === 0 ? '否' : '是' }}</el-tag>
|
||||
</template>
|
||||
</avue-crud>
|
||||
<el-dialog :title="`[${dictValue}]字典配置`" append-to-body v-model="box" width="1000px">
|
||||
<avue-crud
|
||||
:option="optionChild"
|
||||
:table-loading="loadingChild"
|
||||
:data="dataChild"
|
||||
ref="crudChild"
|
||||
v-model="formChild"
|
||||
:permission="permissionList"
|
||||
:before-open="beforeOpenChild"
|
||||
:before-close="beforeCloseChild"
|
||||
@row-del="rowDelChild"
|
||||
@row-update="rowUpdateChild"
|
||||
@row-save="rowSaveChild"
|
||||
@search-change="searchChangeChild"
|
||||
@search-reset="searchResetChild"
|
||||
@selection-change="selectionChangeChild"
|
||||
@current-change="currentChangeChild"
|
||||
@size-change="sizeChangeChild"
|
||||
@refresh-change="refreshChangeChild"
|
||||
@on-load="onLoadChild"
|
||||
>
|
||||
<template #menu-left>
|
||||
<el-button
|
||||
type="danger"
|
||||
icon="el-icon-delete"
|
||||
v-if="permission.dict_delete"
|
||||
plain
|
||||
@click="handleDelete"
|
||||
>删 除
|
||||
</el-button>
|
||||
</template>
|
||||
<template #menu="scope">
|
||||
<el-button
|
||||
type="primary"
|
||||
text
|
||||
icon="el-icon-circle-plus"
|
||||
@click.stop="handleAdd(scope.row, scope.index)"
|
||||
v-if="userInfo.authority.includes('admin')"
|
||||
>新增子项
|
||||
</el-button>
|
||||
</template>
|
||||
<template #isSealed="{ row }">
|
||||
<el-tag>{{ row.isSealed === 0 ? '否' : '是' }}</el-tag>
|
||||
</template>
|
||||
</avue-crud>
|
||||
</el-dialog>
|
||||
</basic-container>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {
|
||||
getParentList,
|
||||
getChildList,
|
||||
remove,
|
||||
update,
|
||||
add,
|
||||
getDict,
|
||||
getDictTree,
|
||||
} from '@/api/system/dictbiz';
|
||||
import { optionParent, optionChild } from '@/option/system/dictbiz';
|
||||
import { mapGetters } from 'vuex';
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
dictValue: '暂无',
|
||||
parentId: -1,
|
||||
formParent: {},
|
||||
formChild: {},
|
||||
selectionList: [],
|
||||
query: {},
|
||||
box: false,
|
||||
loading: true,
|
||||
loadingChild: true,
|
||||
pageParent: {
|
||||
pageSize: 10,
|
||||
pageSizes: [10, 30, 50, 100, 200],
|
||||
currentPage: 1,
|
||||
total: 0,
|
||||
},
|
||||
pageChild: {
|
||||
pageSize: 10,
|
||||
pageSizes: [10, 30, 50, 100, 200],
|
||||
currentPage: 1,
|
||||
total: 0,
|
||||
},
|
||||
dataParent: [],
|
||||
dataChild: [],
|
||||
optionParent: optionParent,
|
||||
optionChild: optionChild,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['userInfo', 'permission']),
|
||||
permissionList() {
|
||||
return {
|
||||
addBtn: this.validData(this.permission.dictbiz_add, false),
|
||||
delBtn: this.validData(this.permission.dictbiz_delete, false),
|
||||
editBtn: this.validData(this.permission.dictbiz_edit, false),
|
||||
viewBtn: false,
|
||||
};
|
||||
},
|
||||
ids() {
|
||||
let ids = [];
|
||||
this.selectionList.forEach(ele => {
|
||||
ids.push(ele.id);
|
||||
});
|
||||
return ids.join(',');
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.initData();
|
||||
},
|
||||
methods: {
|
||||
initData() {
|
||||
getDictTree().then(res => {
|
||||
const column = this.findColumn(this.optionChild.column, 'parentId');
|
||||
column.dicData = res.data.data;
|
||||
});
|
||||
},
|
||||
handleAdd(row) {
|
||||
this.formChild.dictValue = '';
|
||||
this.formChild.dictKey = '';
|
||||
this.formChild.sort = 0;
|
||||
this.formChild.isSealed = 0;
|
||||
this.formChild.remark = '';
|
||||
this.formChild.parentId = row.id;
|
||||
this.$refs.crudChild.rowAdd();
|
||||
},
|
||||
rowSave(row, done, loading) {
|
||||
const form = {
|
||||
...row,
|
||||
dictKey: -1,
|
||||
};
|
||||
add(form).then(
|
||||
() => {
|
||||
this.onLoadParent(this.pageParent);
|
||||
this.$message({
|
||||
type: 'success',
|
||||
message: '操作成功!',
|
||||
});
|
||||
done();
|
||||
},
|
||||
error => {
|
||||
window.console.log(error);
|
||||
loading();
|
||||
}
|
||||
);
|
||||
},
|
||||
rowUpdate(row, index, done, loading) {
|
||||
update(row).then(
|
||||
() => {
|
||||
this.onLoadParent(this.pageParent);
|
||||
this.$message({
|
||||
type: 'success',
|
||||
message: '操作成功!',
|
||||
});
|
||||
this.onLoadChild(this.pageChild);
|
||||
done();
|
||||
},
|
||||
error => {
|
||||
window.console.log(error);
|
||||
loading();
|
||||
}
|
||||
);
|
||||
},
|
||||
rowDel(row) {
|
||||
this.$confirm('确定将选择数据删除?', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
})
|
||||
.then(() => {
|
||||
return remove(row.id);
|
||||
})
|
||||
.then(() => {
|
||||
this.onLoadParent(this.pageParent);
|
||||
this.$message({
|
||||
type: 'success',
|
||||
message: '操作成功!',
|
||||
});
|
||||
});
|
||||
},
|
||||
handleRowClick(row) {
|
||||
this.query = {};
|
||||
this.parentId = row.id;
|
||||
this.dictValue = row.dictValue;
|
||||
|
||||
const code = this.findColumn(this.optionChild.column, 'code');
|
||||
code.value = row.code;
|
||||
const parentId = this.findColumn(this.optionChild.column, 'parentId');
|
||||
parentId.value = row.id;
|
||||
|
||||
this.formChild.code = row.code;
|
||||
this.formChild.parentId = row.id;
|
||||
|
||||
this.box = true;
|
||||
this.onLoadChild(this.pageChild);
|
||||
},
|
||||
searchReset() {
|
||||
this.query = {};
|
||||
this.onLoadParent(this.pageParent);
|
||||
},
|
||||
searchChange(params, done) {
|
||||
this.query = params;
|
||||
this.pageParent.currentPage = 1;
|
||||
this.onLoadParent(this.pageParent, params);
|
||||
done();
|
||||
},
|
||||
selectionChange(list) {
|
||||
this.selectionList = list;
|
||||
},
|
||||
selectionClear() {
|
||||
this.selectionList = [];
|
||||
this.$refs.crud.toggleSelection();
|
||||
},
|
||||
handleDelete() {
|
||||
if (this.selectionList.length === 0) {
|
||||
this.$message.warning('请选择至少一条数据');
|
||||
return;
|
||||
}
|
||||
this.$confirm('确定将选择数据删除?', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
})
|
||||
.then(() => {
|
||||
return remove(this.ids);
|
||||
})
|
||||
.then(() => {
|
||||
this.onLoadParent(this.pageParent);
|
||||
this.$message({
|
||||
type: 'success',
|
||||
message: '操作成功!',
|
||||
});
|
||||
this.$refs.crud.toggleSelection();
|
||||
});
|
||||
},
|
||||
beforeOpen(done, type) {
|
||||
if (['edit', 'view'].includes(type)) {
|
||||
getDict(this.formParent.id).then(res => {
|
||||
this.formParent = res.data.data;
|
||||
});
|
||||
}
|
||||
done();
|
||||
},
|
||||
currentChange(currentPage) {
|
||||
this.pageParent.currentPage = currentPage;
|
||||
},
|
||||
sizeChange(pageSize) {
|
||||
this.pageParent.pageSize = pageSize;
|
||||
},
|
||||
refreshChange() {
|
||||
this.onLoadParent(this.pageParent, this.query);
|
||||
},
|
||||
rowSaveChild(row, done, loading) {
|
||||
add(row).then(
|
||||
() => {
|
||||
this.onLoadChild(this.pageChild);
|
||||
this.$message({
|
||||
type: 'success',
|
||||
message: '操作成功!',
|
||||
});
|
||||
done();
|
||||
},
|
||||
error => {
|
||||
window.console.log(error);
|
||||
loading();
|
||||
}
|
||||
);
|
||||
},
|
||||
rowUpdateChild(row, index, done, loading) {
|
||||
update(row).then(
|
||||
() => {
|
||||
this.onLoadChild(this.pageChild);
|
||||
this.$message({
|
||||
type: 'success',
|
||||
message: '操作成功!',
|
||||
});
|
||||
done();
|
||||
},
|
||||
error => {
|
||||
window.console.log(error);
|
||||
loading();
|
||||
}
|
||||
);
|
||||
},
|
||||
rowDelChild(row) {
|
||||
this.$confirm('确定将选择数据删除?', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
})
|
||||
.then(() => {
|
||||
return remove(row.id);
|
||||
})
|
||||
.then(() => {
|
||||
this.onLoadChild(this.pageChild);
|
||||
this.$message({
|
||||
type: 'success',
|
||||
message: '操作成功!',
|
||||
});
|
||||
});
|
||||
},
|
||||
searchResetChild() {
|
||||
this.query = {};
|
||||
this.onLoadChild(this.pageChild);
|
||||
},
|
||||
searchChangeChild(params, done) {
|
||||
this.query = params;
|
||||
this.pageChild.currentPage = 1;
|
||||
this.onLoadChild(this.pageChild, params);
|
||||
done();
|
||||
},
|
||||
selectionChangeChild(list) {
|
||||
this.selectionList = list;
|
||||
},
|
||||
selectionClearChild() {
|
||||
this.selectionList = [];
|
||||
this.$refs.crudChild.toggleSelection();
|
||||
},
|
||||
handleDeleteChild() {
|
||||
if (this.selectionList.length === 0) {
|
||||
this.$message.warning('请选择至少一条数据');
|
||||
return;
|
||||
}
|
||||
this.$confirm('确定将选择数据删除?', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
})
|
||||
.then(() => {
|
||||
return remove(this.ids);
|
||||
})
|
||||
.then(() => {
|
||||
this.onLoadChild(this.pageChild);
|
||||
this.$message({
|
||||
type: 'success',
|
||||
message: '操作成功!',
|
||||
});
|
||||
this.$refs.crudChild.toggleSelection();
|
||||
});
|
||||
},
|
||||
beforeOpenChild(done, type) {
|
||||
if (['add', 'edit'].includes(type)) {
|
||||
this.initData();
|
||||
}
|
||||
if (['edit', 'view'].includes(type)) {
|
||||
getDict(this.formChild.id).then(res => {
|
||||
this.formChild = res.data.data;
|
||||
});
|
||||
}
|
||||
done();
|
||||
},
|
||||
beforeCloseChild(done) {
|
||||
this.$refs.crudChild.modelValue.parentId = this.parentId;
|
||||
this.$refs.crudChild.option.column.filter(item => {
|
||||
if (item.prop === 'parentId') {
|
||||
item.value = this.parentId;
|
||||
}
|
||||
});
|
||||
done();
|
||||
},
|
||||
currentChangeChild(currentPage) {
|
||||
this.pageChild.currentPage = currentPage;
|
||||
},
|
||||
sizeChangeChild(pageSize) {
|
||||
this.pageChild.pageSize = pageSize;
|
||||
},
|
||||
refreshChangeChild() {
|
||||
this.onLoadChild(this.pageChild, this.query);
|
||||
},
|
||||
onLoadParent(page, params = {}) {
|
||||
this.loading = true;
|
||||
getParentList(page.currentPage, page.pageSize, Object.assign(params, this.query)).then(
|
||||
res => {
|
||||
const data = res.data.data;
|
||||
this.pageParent.total = data.total;
|
||||
this.dataParent = data.records;
|
||||
this.loading = false;
|
||||
this.selectionClear();
|
||||
}
|
||||
);
|
||||
},
|
||||
onLoadChild(page, params = {}) {
|
||||
this.loadingChild = true;
|
||||
getChildList(
|
||||
page.currentPage,
|
||||
page.pageSize,
|
||||
this.parentId,
|
||||
Object.assign(params, this.query)
|
||||
).then(res => {
|
||||
this.dataChild = res.data.data;
|
||||
this.loadingChild = false;
|
||||
this.selectionClear();
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@@ -0,0 +1,438 @@
|
||||
<template>
|
||||
<basic-container>
|
||||
<avue-crud
|
||||
:option="option"
|
||||
:table-loading="loading"
|
||||
:data="data"
|
||||
ref="crud"
|
||||
v-model="form"
|
||||
:permission="permissionList"
|
||||
:before-open="beforeOpen"
|
||||
:before-close="beforeClose"
|
||||
@row-del="rowDel"
|
||||
@row-update="rowUpdate"
|
||||
@row-save="rowSave"
|
||||
@search-change="searchChange"
|
||||
@search-reset="searchReset"
|
||||
@selection-change="selectionChange"
|
||||
@current-change="currentChange"
|
||||
@size-change="sizeChange"
|
||||
@refresh-change="refreshChange"
|
||||
@on-load="onLoad"
|
||||
@tree-load="treeLoad"
|
||||
>
|
||||
<template #menu-left>
|
||||
<el-button
|
||||
type="danger"
|
||||
icon="el-icon-delete"
|
||||
v-if="permission.menu_delete"
|
||||
plain
|
||||
@click="handleDelete"
|
||||
>删 除
|
||||
</el-button>
|
||||
</template>
|
||||
<template #menu="scope">
|
||||
<el-button
|
||||
type="primary"
|
||||
text
|
||||
icon="el-icon-circle-plus"
|
||||
@click.stop="handleAdd(scope.row, scope.index)"
|
||||
v-if="userInfo.authority.includes('admin') && scope.row.category === 1"
|
||||
>新增子项
|
||||
</el-button>
|
||||
</template>
|
||||
<template #name="{ row }">
|
||||
<i :class="row.source" style="margin-right: 5px" />
|
||||
<span>{{ row.name }}</span>
|
||||
</template>
|
||||
<template #source="{ row }">
|
||||
<div style="text-align: center">
|
||||
<i :class="row.source" />
|
||||
</div>
|
||||
</template>
|
||||
</avue-crud>
|
||||
</basic-container>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getLazyList, remove, update, add, getMenu } from '@/api/system/menu';
|
||||
import { mapGetters } from 'vuex';
|
||||
import iconList from '@/config/iconList';
|
||||
import func from '@/utils/func';
|
||||
import { getMenuTree } from '@/api/system/menu';
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
form: {},
|
||||
query: {},
|
||||
loading: true,
|
||||
selectionList: [],
|
||||
parentId: 0,
|
||||
page: {
|
||||
pageSize: 10,
|
||||
currentPage: 1,
|
||||
total: 0,
|
||||
},
|
||||
option: {
|
||||
lazy: true,
|
||||
tip: false,
|
||||
simplePage: true,
|
||||
searchShow: true,
|
||||
searchMenuSpan: 6,
|
||||
dialogWidth: '60%',
|
||||
tree: true,
|
||||
border: true,
|
||||
index: true,
|
||||
selection: true,
|
||||
viewBtn: true,
|
||||
menuWidth: 320,
|
||||
dialogClickModal: false,
|
||||
column: [
|
||||
{
|
||||
label: '菜单名称',
|
||||
prop: 'name',
|
||||
width: 300,
|
||||
search: true,
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '请输入菜单名称',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: '路由地址',
|
||||
prop: 'path',
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '请输入路由地址',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: '上级菜单',
|
||||
prop: 'parentId',
|
||||
type: 'tree',
|
||||
dicData: [],
|
||||
hide: true,
|
||||
addDisabled: false,
|
||||
props: {
|
||||
label: 'title',
|
||||
},
|
||||
rules: [
|
||||
{
|
||||
required: false,
|
||||
message: '请选择上级菜单',
|
||||
trigger: 'click',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: '菜单图标',
|
||||
prop: 'source',
|
||||
type: 'icon',
|
||||
slot: true,
|
||||
iconList: iconList,
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '请输入菜单图标',
|
||||
trigger: 'click',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: '菜单编号',
|
||||
prop: 'code',
|
||||
search: true,
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '请输入菜单编号',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: '菜单类型',
|
||||
prop: 'category',
|
||||
type: 'radio',
|
||||
dicData: [
|
||||
{
|
||||
label: '菜单',
|
||||
value: 1,
|
||||
},
|
||||
{
|
||||
label: '按钮',
|
||||
value: 2,
|
||||
},
|
||||
],
|
||||
hide: true,
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '请选择菜单类型',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: '菜单别名',
|
||||
prop: 'alias',
|
||||
search: true,
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '请输入菜单别名',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: '是否缓存',
|
||||
prop: 'isOpen',
|
||||
type: 'radio',
|
||||
hide: true,
|
||||
dicData: [
|
||||
{
|
||||
label: '否',
|
||||
value: 1,
|
||||
},
|
||||
{
|
||||
label: '是',
|
||||
value: 2,
|
||||
},
|
||||
],
|
||||
value: 1,
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '请选择是否缓存',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: '菜单排序',
|
||||
prop: 'sort',
|
||||
type: 'number',
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '请输入菜单排序',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: '菜单备注',
|
||||
prop: 'remark',
|
||||
type: 'textarea',
|
||||
span: 24,
|
||||
minRows: 2,
|
||||
hide: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
data: [],
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
'form.category'() {
|
||||
const category = func.toInt(this.form.category);
|
||||
this.$refs.crud.option.column.filter(item => {
|
||||
if (item.prop === 'path') {
|
||||
item.rules[0].required = category === 1;
|
||||
}
|
||||
if (item.prop === 'isOpen') {
|
||||
item.disabled = category === 2;
|
||||
}
|
||||
});
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['userInfo', 'permission']),
|
||||
permissionList() {
|
||||
return {
|
||||
addBtn: this.validData(this.permission.menu_add, false),
|
||||
viewBtn: this.validData(this.permission.menu_view, false),
|
||||
delBtn: this.validData(this.permission.menu_delete, false),
|
||||
editBtn: this.validData(this.permission.menu_edit, false),
|
||||
};
|
||||
},
|
||||
ids() {
|
||||
let ids = [];
|
||||
this.selectionList.forEach(ele => {
|
||||
ids.push(ele.id);
|
||||
});
|
||||
return ids.join(',');
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
initData() {
|
||||
getMenuTree().then(res => {
|
||||
const column = this.findColumn(this.option.column, 'parentId');
|
||||
column.dicData = res.data.data;
|
||||
});
|
||||
},
|
||||
handleAdd(row) {
|
||||
this.parentId = row.id;
|
||||
const column = this.findColumn(this.option.column, 'parentId');
|
||||
column.value = row.id;
|
||||
column.addDisabled = true;
|
||||
this.$refs.crud.rowAdd();
|
||||
},
|
||||
rowSave(row, done, loading) {
|
||||
add(row).then(
|
||||
res => {
|
||||
// 获取新增数据的相关字段
|
||||
const data = res.data.data;
|
||||
row.id = data.id;
|
||||
this.$message({
|
||||
type: 'success',
|
||||
message: '操作成功!',
|
||||
});
|
||||
// 数据回调进行刷新
|
||||
done(row);
|
||||
},
|
||||
error => {
|
||||
window.console.log(error);
|
||||
loading();
|
||||
}
|
||||
);
|
||||
},
|
||||
rowUpdate(row, index, done, loading) {
|
||||
update(row).then(
|
||||
() => {
|
||||
this.$message({
|
||||
type: 'success',
|
||||
message: '操作成功!',
|
||||
});
|
||||
// 数据回调进行刷新
|
||||
done(row);
|
||||
},
|
||||
error => {
|
||||
window.console.log(error);
|
||||
loading();
|
||||
}
|
||||
);
|
||||
},
|
||||
rowDel(row, index, done) {
|
||||
this.$confirm('确定将选择数据删除?', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
})
|
||||
.then(() => {
|
||||
return remove(row.id);
|
||||
})
|
||||
.then(() => {
|
||||
this.$message({
|
||||
type: 'success',
|
||||
message: '操作成功!',
|
||||
});
|
||||
// 数据回调进行刷新
|
||||
done(row);
|
||||
});
|
||||
},
|
||||
handleDelete() {
|
||||
if (this.selectionList.length === 0) {
|
||||
this.$message.warning('请选择至少一条数据');
|
||||
return;
|
||||
}
|
||||
this.$confirm('确定将选择数据删除?', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
})
|
||||
.then(() => {
|
||||
return remove(this.ids);
|
||||
})
|
||||
.then(() => {
|
||||
// 刷新表格数据并重载
|
||||
this.data = [];
|
||||
this.parentId = 0;
|
||||
this.$refs.crud.refreshTable();
|
||||
this.$refs.crud.toggleSelection();
|
||||
// 表格数据重载
|
||||
this.onLoad(this.page);
|
||||
this.$message({
|
||||
type: 'success',
|
||||
message: '操作成功!',
|
||||
});
|
||||
});
|
||||
},
|
||||
searchReset() {
|
||||
this.query = {};
|
||||
this.parentId = 0;
|
||||
this.onLoad(this.page);
|
||||
},
|
||||
searchChange(params, done) {
|
||||
this.query = params;
|
||||
this.parentId = '';
|
||||
this.page.currentPage = 1;
|
||||
this.onLoad(this.page, params);
|
||||
done();
|
||||
},
|
||||
selectionChange(list) {
|
||||
this.selectionList = list;
|
||||
},
|
||||
selectionClear() {
|
||||
this.selectionList = [];
|
||||
this.$refs.crud.toggleSelection();
|
||||
},
|
||||
beforeOpen(done, type) {
|
||||
if (['add', 'edit'].includes(type)) {
|
||||
this.initData();
|
||||
}
|
||||
if (['edit', 'view'].includes(type)) {
|
||||
getMenu(this.form.id).then(res => {
|
||||
this.form = Object.assign(res.data.data, {
|
||||
hasChildren: this.form.hasChildren,
|
||||
});
|
||||
if (this.form.parentId === '0') {
|
||||
this.form.parentId = '';
|
||||
}
|
||||
});
|
||||
}
|
||||
done();
|
||||
},
|
||||
beforeClose(done) {
|
||||
this.parentId = '';
|
||||
const column = this.findColumn(this.option.column, 'parentId');
|
||||
column.value = '';
|
||||
column.addDisabled = false;
|
||||
done();
|
||||
},
|
||||
currentChange(currentPage) {
|
||||
this.page.currentPage = currentPage;
|
||||
},
|
||||
sizeChange(pageSize) {
|
||||
this.page.pageSize = pageSize;
|
||||
},
|
||||
refreshChange() {
|
||||
this.onLoad(this.page, this.query);
|
||||
},
|
||||
onLoad(page, params = {}) {
|
||||
this.loading = true;
|
||||
getLazyList(this.parentId, Object.assign(params, this.query)).then(res => {
|
||||
this.data = res.data.data;
|
||||
this.loading = false;
|
||||
this.selectionClear();
|
||||
});
|
||||
},
|
||||
treeLoad(tree, treeNode, resolve) {
|
||||
const parentId = tree.id;
|
||||
getLazyList(parentId).then(res => {
|
||||
resolve(res.data.data);
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style></style>
|
||||
@@ -0,0 +1,404 @@
|
||||
<template>
|
||||
<basic-container>
|
||||
<div class="avue-crud">
|
||||
<el-row :hidden="!search" style="padding: 6px 18px">
|
||||
<!-- 查询模块 -->
|
||||
<el-form :inline="true" :model="query">
|
||||
<el-form-item label="参数名:">
|
||||
<el-input v-model="query.paramName" placeholder="请输入参数名"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="参数键:">
|
||||
<el-input v-model="query.paramKey" placeholder="请输入参数键"></el-input>
|
||||
</el-form-item>
|
||||
<!-- 查询按钮 -->
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="el-icon-search" @click="searchChange">搜 索</el-button>
|
||||
<el-button icon="el-icon-delete" @click="searchReset()">清 空</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<div class="avue-crud__header">
|
||||
<!-- 头部左侧按钮模块 -->
|
||||
<div class="avue-crud__left">
|
||||
<el-button
|
||||
v-if="this.permissionList.addBtn"
|
||||
type="primary"
|
||||
icon="el-icon-plus"
|
||||
@click="handleAdd"
|
||||
>新 增
|
||||
</el-button>
|
||||
<el-button
|
||||
v-if="this.permissionList.delBtn"
|
||||
type="danger"
|
||||
icon="el-icon-delete"
|
||||
@click="handleDelete"
|
||||
plain
|
||||
>删 除
|
||||
</el-button>
|
||||
</div>
|
||||
<!-- 头部右侧按钮模块 -->
|
||||
<div class="avue-crud__right">
|
||||
<el-button icon="el-icon-refresh" @click="searchChange" circle></el-button>
|
||||
<el-button icon="el-icon-search" @click="searchHide" circle></el-button>
|
||||
</div>
|
||||
</div>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<!-- 列表模块 -->
|
||||
<el-table
|
||||
ref="table"
|
||||
v-loading="loading"
|
||||
@selection-change="selectionChange"
|
||||
:data="data"
|
||||
style="width: 100%"
|
||||
:border="option.border"
|
||||
>
|
||||
<el-table-column
|
||||
type="selection"
|
||||
v-if="option.selection"
|
||||
width="55"
|
||||
align="center"
|
||||
></el-table-column>
|
||||
<el-table-column type="expand" v-if="option.expand" align="center"></el-table-column>
|
||||
<el-table-column v-if="option.index" label="#" type="index" width="50" align="center">
|
||||
</el-table-column>
|
||||
<template v-for="(item, index) in option.column">
|
||||
<!-- table字段 -->
|
||||
<el-table-column
|
||||
v-if="item.hide !== true"
|
||||
:prop="item.prop"
|
||||
:label="item.label"
|
||||
:width="item.width"
|
||||
:key="index"
|
||||
>
|
||||
<template v-if="item.tip" #header>
|
||||
<span>{{ item.label }}</span>
|
||||
<el-tooltip :content="item.tip" placement="top">
|
||||
<el-icon style="margin-left: 4px; vertical-align: middle; color: #909399; cursor: pointer"><el-icon-question-filled /></el-icon>
|
||||
</el-tooltip>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</template>
|
||||
<!-- 操作栏模块 -->
|
||||
<el-table-column prop="menu" label="操作" :width="220" align="center">
|
||||
<template #="{ row }">
|
||||
<el-button
|
||||
v-if="this.permissionList.viewBtn"
|
||||
type="primary"
|
||||
text
|
||||
icon="el-icon-view"
|
||||
@click="handleView(row)"
|
||||
>查看
|
||||
</el-button>
|
||||
<el-button
|
||||
v-if="this.permissionList.editBtn"
|
||||
type="primary"
|
||||
text
|
||||
icon="el-icon-edit"
|
||||
@click="handleEdit(row)"
|
||||
>编辑
|
||||
</el-button>
|
||||
<el-button
|
||||
v-if="this.permissionList.delBtn"
|
||||
type="primary"
|
||||
text
|
||||
icon="el-icon-delete"
|
||||
@click="rowDel(row)"
|
||||
>删除
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<div class="avue-crud__pagination" style="width: 100%">
|
||||
<!-- 分页模块 -->
|
||||
<el-pagination
|
||||
align="right"
|
||||
background
|
||||
@size-change="sizeChange"
|
||||
@current-change="currentChange"
|
||||
:current-page="page.currentPage"
|
||||
:page-sizes="[10, 20, 30, 40, 50, 100]"
|
||||
:page-size="page.pageSize"
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
:total="page.total"
|
||||
>
|
||||
</el-pagination>
|
||||
</div>
|
||||
</el-row>
|
||||
<!-- 表单模块 -->
|
||||
<el-dialog
|
||||
:title="title"
|
||||
v-model="box"
|
||||
width="50%"
|
||||
:before-close="beforeClose"
|
||||
append-to-body
|
||||
>
|
||||
<el-form :disabled="view" ref="form" :model="form" label-width="80px">
|
||||
<!-- 表单字段 -->
|
||||
<el-form-item label="参数名:" prop="paramName">
|
||||
<el-input v-model="form.paramName" placeholder="请输入参数名" />
|
||||
</el-form-item>
|
||||
<el-form-item prop="paramKey">
|
||||
<template #label>
|
||||
<el-tooltip content="参数键为系统内部唯一标识,请勿随意修改" placement="top">
|
||||
<el-icon style="margin-right: 4px; vertical-align: middle; color: #909399; cursor: pointer"><el-icon-question-filled /></el-icon>
|
||||
</el-tooltip>
|
||||
<span>参数键:</span>
|
||||
</template>
|
||||
<el-input v-model="form.paramKey" placeholder="请输入参数键" />
|
||||
</el-form-item>
|
||||
<el-form-item prop="paramValue">
|
||||
<template #label>
|
||||
<el-tooltip content="包含敏感关键词的配置不展示具体数值" placement="top">
|
||||
<el-icon style="margin-right: 4px; vertical-align: middle; color: #909399; cursor: pointer"><el-icon-question-filled /></el-icon>
|
||||
</el-tooltip>
|
||||
<span>参数值:</span>
|
||||
</template>
|
||||
<el-input v-model="form.paramValue" placeholder="请输入参数值" />
|
||||
</el-form-item>
|
||||
<el-form-item label="备注:" prop="remark">
|
||||
<el-input v-model="form.remark" placeholder="请输入备注" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<!-- 表单按钮 -->
|
||||
<template #footer>
|
||||
<span v-if="!view" class="dialog-footer">
|
||||
<el-button type="primary" icon="el-icon-circle-check" @click="handleSubmit"
|
||||
>提 交</el-button
|
||||
>
|
||||
<el-button icon="el-icon-circle-close" @click="box = false">取 消</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</basic-container>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getList, getDetail, add, update, remove } from '@/api/system/param';
|
||||
import { mapGetters } from 'vuex';
|
||||
import { sensitive } from '@/utils/sensitive';
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
// 弹框标题
|
||||
title: '',
|
||||
// 是否展示弹框
|
||||
box: false,
|
||||
// 是否显示查询
|
||||
search: true,
|
||||
// 加载中
|
||||
loading: true,
|
||||
// 是否为查看模式
|
||||
view: false,
|
||||
// 脱敏工具实例
|
||||
sensitiveManager: null,
|
||||
// 查询信息
|
||||
query: {},
|
||||
// 分页信息
|
||||
page: {
|
||||
currentPage: 1,
|
||||
pageSize: 10,
|
||||
total: 40,
|
||||
},
|
||||
// 表单数据
|
||||
form: {},
|
||||
// 选择行
|
||||
selectionList: [],
|
||||
// 表单配置
|
||||
option: {
|
||||
expand: false,
|
||||
index: true,
|
||||
border: true,
|
||||
selection: true,
|
||||
column: [
|
||||
{
|
||||
label: '参数名',
|
||||
prop: 'paramName',
|
||||
},
|
||||
{
|
||||
label: '参数键',
|
||||
prop: 'paramKey',
|
||||
tip: '参数键为系统内部唯一标识,请勿随意修改',
|
||||
},
|
||||
{
|
||||
label: '参数值',
|
||||
prop: 'paramValue',
|
||||
tip: '包含敏感关键词的配置不展示具体数值',
|
||||
},
|
||||
{
|
||||
label: '备注',
|
||||
prop: 'remark',
|
||||
},
|
||||
],
|
||||
},
|
||||
// 表单列表
|
||||
data: [],
|
||||
};
|
||||
},
|
||||
created() {
|
||||
// 创建脱敏工具实例
|
||||
this.sensitiveManager = sensitive.create({
|
||||
fields: ['paramValue'], // 配置需要脱敏的字段
|
||||
});
|
||||
},
|
||||
mounted() {
|
||||
this.init();
|
||||
this.onLoad(this.page);
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['permission']),
|
||||
permissionList() {
|
||||
return {
|
||||
addBtn: this.validData(this.permission.param_add, false),
|
||||
viewBtn: this.validData(this.permission.param_view, false),
|
||||
delBtn: this.validData(this.permission.param_delete, false),
|
||||
editBtn: this.validData(this.permission.param_edit, false),
|
||||
};
|
||||
},
|
||||
ids() {
|
||||
let ids = [];
|
||||
this.selectionList.forEach(ele => {
|
||||
ids.push(ele.id);
|
||||
});
|
||||
return ids.join(',');
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
init() {
|
||||
this.height = this.setPx(document.body.clientHeight - 340);
|
||||
},
|
||||
searchHide() {
|
||||
this.search = !this.search;
|
||||
},
|
||||
searchChange() {
|
||||
this.onLoad(this.page);
|
||||
},
|
||||
searchReset() {
|
||||
this.query = {};
|
||||
this.page.currentPage = 1;
|
||||
this.onLoad(this.page);
|
||||
},
|
||||
handleSubmit() {
|
||||
if (!this.form.id) {
|
||||
add(this.form).then(() => {
|
||||
this.box = false;
|
||||
this.onLoad(this.page);
|
||||
this.$message({
|
||||
type: 'success',
|
||||
message: '操作成功!',
|
||||
});
|
||||
});
|
||||
} else {
|
||||
// 获取需要提交的数据
|
||||
const submitData = this.sensitiveManager.getSubmitData(this.form);
|
||||
update(submitData).then(() => {
|
||||
this.box = false;
|
||||
this.onLoad(this.page);
|
||||
this.$message({
|
||||
type: 'success',
|
||||
message: '操作成功!',
|
||||
});
|
||||
});
|
||||
}
|
||||
},
|
||||
handleAdd() {
|
||||
this.title = '新增';
|
||||
this.form = {};
|
||||
this.box = true;
|
||||
},
|
||||
handleEdit(row) {
|
||||
this.title = '编辑';
|
||||
this.box = true;
|
||||
getDetail(row.id).then(res => {
|
||||
this.form = res.data.data;
|
||||
// 保存初始脱敏数据
|
||||
this.sensitiveManager.saveInitialData(this.form);
|
||||
});
|
||||
},
|
||||
handleView(row) {
|
||||
this.title = '查看';
|
||||
this.view = true;
|
||||
this.box = true;
|
||||
getDetail(row.id).then(res => {
|
||||
this.form = res.data.data;
|
||||
// 保存初始脱敏数据
|
||||
this.sensitiveManager.saveInitialData(this.form);
|
||||
});
|
||||
},
|
||||
handleDelete() {
|
||||
if (this.selectionList.length === 0) {
|
||||
this.$message.warning('请选择至少一条数据');
|
||||
return;
|
||||
}
|
||||
this.$confirm('确定将选择数据删除?', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
})
|
||||
.then(() => {
|
||||
return remove(this.ids);
|
||||
})
|
||||
.then(() => {
|
||||
this.selectionClear();
|
||||
this.onLoad(this.page);
|
||||
this.$message({
|
||||
type: 'success',
|
||||
message: '操作成功!',
|
||||
});
|
||||
});
|
||||
},
|
||||
rowDel(row) {
|
||||
this.$confirm('确定将选择数据删除?', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
})
|
||||
.then(() => {
|
||||
return remove(row.id);
|
||||
})
|
||||
.then(() => {
|
||||
this.onLoad(this.page);
|
||||
this.$message({
|
||||
type: 'success',
|
||||
message: '操作成功!',
|
||||
});
|
||||
});
|
||||
},
|
||||
beforeClose(done) {
|
||||
done();
|
||||
this.form = {};
|
||||
this.view = false;
|
||||
},
|
||||
selectionChange(list) {
|
||||
this.selectionList = list;
|
||||
},
|
||||
selectionClear() {
|
||||
this.selectionList = [];
|
||||
this.$refs.table.clearSelection();
|
||||
},
|
||||
currentChange(currentPage) {
|
||||
this.page.currentPage = currentPage;
|
||||
this.onLoad(this.page);
|
||||
},
|
||||
sizeChange(pageSize) {
|
||||
this.page.pageSize = pageSize;
|
||||
this.onLoad(this.page);
|
||||
},
|
||||
onLoad(page, params = {}) {
|
||||
this.loading = true;
|
||||
getList(page.currentPage, page.pageSize, Object.assign(params, this.query)).then(res => {
|
||||
const data = res.data.data;
|
||||
this.page.total = data.total;
|
||||
this.data = data.records;
|
||||
this.loading = false;
|
||||
this.selectionClear();
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@@ -0,0 +1,298 @@
|
||||
<template>
|
||||
<basic-container>
|
||||
<avue-crud
|
||||
:option="option"
|
||||
:table-loading="loading"
|
||||
:data="data"
|
||||
v-model:page="page"
|
||||
:permission="permissionList"
|
||||
:before-open="beforeOpen"
|
||||
v-model="form"
|
||||
ref="crud"
|
||||
@row-update="rowUpdate"
|
||||
@row-save="rowSave"
|
||||
@row-del="rowDel"
|
||||
@search-change="searchChange"
|
||||
@search-reset="searchReset"
|
||||
@selection-change="selectionChange"
|
||||
@current-change="currentChange"
|
||||
@size-change="sizeChange"
|
||||
@refresh-change="refreshChange"
|
||||
@on-load="onLoad"
|
||||
>
|
||||
<template #menu-left>
|
||||
<el-button
|
||||
type="danger"
|
||||
icon="el-icon-delete"
|
||||
plain
|
||||
v-if="permission.post_delete"
|
||||
@click="handleDelete"
|
||||
>删 除
|
||||
</el-button>
|
||||
</template>
|
||||
<template #category="{ row }">
|
||||
<el-tag>{{ row.categoryName }}</el-tag>
|
||||
</template>
|
||||
</avue-crud>
|
||||
</basic-container>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getList, getDetail, add, update, remove } from '@/api/system/post';
|
||||
import { mapGetters } from 'vuex';
|
||||
import website from '@/config/website';
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
form: {},
|
||||
query: {},
|
||||
loading: true,
|
||||
page: {
|
||||
pageSize: 10,
|
||||
currentPage: 1,
|
||||
total: 0,
|
||||
},
|
||||
selectionList: [],
|
||||
option: {
|
||||
height: 'auto',
|
||||
calcHeight: 32,
|
||||
tip: false,
|
||||
searchShow: true,
|
||||
searchMenuSpan: 6,
|
||||
border: true,
|
||||
index: true,
|
||||
viewBtn: true,
|
||||
selection: true,
|
||||
dialogClickModal: false,
|
||||
column: [
|
||||
{
|
||||
label: '所属租户',
|
||||
prop: 'tenantId',
|
||||
type: 'tree',
|
||||
dicUrl: '/blade-system/tenant/select',
|
||||
addDisplay: false,
|
||||
editDisplay: false,
|
||||
viewDisplay: website.tenantMode,
|
||||
span: 24,
|
||||
props: {
|
||||
label: 'tenantName',
|
||||
value: 'tenantId',
|
||||
},
|
||||
hide: !website.tenantMode,
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '请输入所属租户',
|
||||
trigger: 'click',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: '岗位类型',
|
||||
prop: 'category',
|
||||
type: 'select',
|
||||
dicUrl: '/blade-system/dict/dictionary?code=post_category',
|
||||
props: {
|
||||
label: 'dictValue',
|
||||
value: 'dictKey',
|
||||
},
|
||||
dataType: 'number',
|
||||
slot: true,
|
||||
search: true,
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '请选择岗位类型',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: '岗位编号',
|
||||
prop: 'postCode',
|
||||
search: true,
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '请输入岗位编号',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: '岗位名称',
|
||||
prop: 'postName',
|
||||
search: true,
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '请输入岗位名称',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: '岗位排序',
|
||||
prop: 'sort',
|
||||
type: 'number',
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '请输入岗位排序',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: '岗位描述',
|
||||
prop: 'remark',
|
||||
type: 'textarea',
|
||||
span: 24,
|
||||
minRows: 6,
|
||||
hide: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
data: [],
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['permission']),
|
||||
permissionList() {
|
||||
return {
|
||||
addBtn: this.validData(this.permission.post_add, false),
|
||||
viewBtn: this.validData(this.permission.post_view, false),
|
||||
delBtn: this.validData(this.permission.post_delete, false),
|
||||
editBtn: this.validData(this.permission.post_edit, false),
|
||||
};
|
||||
},
|
||||
ids() {
|
||||
let ids = [];
|
||||
this.selectionList.forEach(ele => {
|
||||
ids.push(ele.id);
|
||||
});
|
||||
return ids.join(',');
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
rowSave(row, done, loading) {
|
||||
add(row).then(
|
||||
() => {
|
||||
this.onLoad(this.page);
|
||||
this.$message({
|
||||
type: 'success',
|
||||
message: '操作成功!',
|
||||
});
|
||||
done();
|
||||
},
|
||||
error => {
|
||||
window.console.log(error);
|
||||
loading();
|
||||
}
|
||||
);
|
||||
},
|
||||
rowUpdate(row, index, done, loading) {
|
||||
update(row).then(
|
||||
() => {
|
||||
this.onLoad(this.page);
|
||||
this.$message({
|
||||
type: 'success',
|
||||
message: '操作成功!',
|
||||
});
|
||||
done();
|
||||
},
|
||||
error => {
|
||||
window.console.log(error);
|
||||
loading();
|
||||
}
|
||||
);
|
||||
},
|
||||
rowDel(row) {
|
||||
this.$confirm('确定将选择数据删除?', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
})
|
||||
.then(() => {
|
||||
return remove(row.id);
|
||||
})
|
||||
.then(() => {
|
||||
this.onLoad(this.page);
|
||||
this.$message({
|
||||
type: 'success',
|
||||
message: '操作成功!',
|
||||
});
|
||||
});
|
||||
},
|
||||
handleDelete() {
|
||||
if (this.selectionList.length === 0) {
|
||||
this.$message.warning('请选择至少一条数据');
|
||||
return;
|
||||
}
|
||||
this.$confirm('确定将选择数据删除?', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
})
|
||||
.then(() => {
|
||||
return remove(this.ids);
|
||||
})
|
||||
.then(() => {
|
||||
this.onLoad(this.page);
|
||||
this.$message({
|
||||
type: 'success',
|
||||
message: '操作成功!',
|
||||
});
|
||||
this.$refs.crud.toggleSelection();
|
||||
});
|
||||
},
|
||||
beforeOpen(done, type) {
|
||||
if (['edit', 'view'].includes(type)) {
|
||||
getDetail(this.form.id).then(res => {
|
||||
this.form = res.data.data;
|
||||
});
|
||||
}
|
||||
done();
|
||||
},
|
||||
searchReset() {
|
||||
this.query = {};
|
||||
this.onLoad(this.page);
|
||||
},
|
||||
searchChange(params, done) {
|
||||
this.query = params;
|
||||
this.page.currentPage = 1;
|
||||
this.onLoad(this.page, params);
|
||||
done();
|
||||
},
|
||||
selectionChange(list) {
|
||||
this.selectionList = list;
|
||||
},
|
||||
selectionClear() {
|
||||
this.selectionList = [];
|
||||
this.$refs.crud.toggleSelection();
|
||||
},
|
||||
currentChange(currentPage) {
|
||||
this.page.currentPage = currentPage;
|
||||
},
|
||||
sizeChange(pageSize) {
|
||||
this.page.pageSize = pageSize;
|
||||
},
|
||||
refreshChange() {
|
||||
this.onLoad(this.page, this.query);
|
||||
},
|
||||
onLoad(page, params = {}) {
|
||||
this.loading = true;
|
||||
getList(page.currentPage, page.pageSize, Object.assign(params, this.query)).then(res => {
|
||||
const data = res.data.data;
|
||||
this.page.total = data.total;
|
||||
this.data = data.records;
|
||||
this.loading = false;
|
||||
this.selectionClear();
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style></style>
|
||||
@@ -0,0 +1,811 @@
|
||||
<template>
|
||||
<basic-container>
|
||||
<avue-crud
|
||||
:option="option"
|
||||
:table-loading="loading"
|
||||
:data="data"
|
||||
ref="crud"
|
||||
v-model="form"
|
||||
v-model:page="page"
|
||||
:permission="permissionList"
|
||||
:before-open="beforeOpen"
|
||||
@row-del="rowDel"
|
||||
@row-update="rowUpdate"
|
||||
@row-save="rowSave"
|
||||
@search-change="searchChange"
|
||||
@search-reset="searchReset"
|
||||
@selection-change="selectionChange"
|
||||
@current-change="currentChange"
|
||||
@size-change="sizeChange"
|
||||
@refresh-change="refreshChange"
|
||||
@on-load="onLoad"
|
||||
>
|
||||
<template #menu-left>
|
||||
<el-button
|
||||
v-if="permission.tenant_add && !recycleMode"
|
||||
type="primary"
|
||||
icon="el-icon-plus"
|
||||
@click="$refs.crud.rowAdd()"
|
||||
>新 增
|
||||
</el-button>
|
||||
<el-button
|
||||
type="danger"
|
||||
icon="el-icon-delete"
|
||||
v-if="permission.tenant_delete && !recycleMode"
|
||||
plain
|
||||
@click="handleDelete"
|
||||
>删 除
|
||||
</el-button>
|
||||
<el-button
|
||||
type="primary"
|
||||
plain
|
||||
icon="el-icon-refresh"
|
||||
v-if="userInfo.authority.includes('administrator') && !recycleMode"
|
||||
@click="handleRecycle"
|
||||
>回收站
|
||||
</el-button>
|
||||
<el-button
|
||||
type="success"
|
||||
plain
|
||||
icon="el-icon-check"
|
||||
v-if="userInfo.authority.includes('administrator') && recycleMode"
|
||||
@click="handleRecyclePass"
|
||||
>恢 复
|
||||
</el-button>
|
||||
<el-button
|
||||
type="danger"
|
||||
plain
|
||||
icon="el-icon-close"
|
||||
v-if="userInfo.authority.includes('administrator') && recycleMode"
|
||||
@click="handleRecycleRemove"
|
||||
>删 除
|
||||
</el-button>
|
||||
<el-button
|
||||
type="primary"
|
||||
plain
|
||||
icon="el-icon-refresh-left"
|
||||
v-if="userInfo.authority.includes('administrator') && recycleMode"
|
||||
@click="handleRecycleBack"
|
||||
>返 回
|
||||
</el-button>
|
||||
<el-tooltip
|
||||
class="item"
|
||||
effect="dark"
|
||||
content="给租户配置账号额度、过期时间等授权信息"
|
||||
placement="top"
|
||||
>
|
||||
<el-button
|
||||
plain
|
||||
type="info"
|
||||
v-if="userInfo.authority.includes('administrator') && !recycleMode"
|
||||
icon="el-icon-setting"
|
||||
@click="handleSetting"
|
||||
>批量授权配置
|
||||
</el-button>
|
||||
</el-tooltip>
|
||||
</template>
|
||||
<template #menu-right>
|
||||
<el-tooltip
|
||||
class="item"
|
||||
effect="dark"
|
||||
content="将自定义的数据源定制为租户绑定的独立数据源"
|
||||
placement="top"
|
||||
>
|
||||
<el-button
|
||||
plain
|
||||
v-if="userInfo.authority.includes('administrator') && !recycleMode"
|
||||
icon="el-icon-message-box"
|
||||
@click="handleDatasourceSetting"
|
||||
>数据源管理
|
||||
</el-button>
|
||||
</el-tooltip>
|
||||
<el-tooltip
|
||||
class="item"
|
||||
effect="dark"
|
||||
content="将自定义的菜单集合定制为租户绑定的菜单产品包"
|
||||
placement="top"
|
||||
>
|
||||
<el-button
|
||||
plain
|
||||
v-if="userInfo.authority.includes('administrator') && !recycleMode"
|
||||
icon="el-icon-set-up"
|
||||
@click="handlePackageSetting"
|
||||
>产品包管理
|
||||
</el-button>
|
||||
</el-tooltip>
|
||||
</template>
|
||||
<template #menu="scope">
|
||||
<el-button
|
||||
v-if="userInfo.authority.includes('administrator') && !recycleMode"
|
||||
type="primary"
|
||||
text
|
||||
icon="el-icon-coin"
|
||||
@click.stop="handleRowDatasource(scope.row)"
|
||||
>数据源
|
||||
</el-button>
|
||||
<el-button
|
||||
v-if="userInfo.authority.includes('administrator') && !recycleMode"
|
||||
type="primary"
|
||||
text
|
||||
icon="el-icon-notebook"
|
||||
@click.stop="handleRowPackage(scope.row)"
|
||||
>产品包
|
||||
</el-button>
|
||||
</template>
|
||||
<template #accountNumber="{ row }">
|
||||
<el-tag>{{ row.accountNumber > 0 ? row.accountNumber : '不限制' }}</el-tag>
|
||||
</template>
|
||||
<template #expireTime="{ row }">
|
||||
<el-tag>{{ row.expireTime ? row.expireTime : '不限制' }}</el-tag>
|
||||
</template>
|
||||
</avue-crud>
|
||||
<el-dialog title="租户授权配置" append-to-body v-model="box" width="450px">
|
||||
<avue-form :option="settingOption" v-model="settingForm" @submit="handleSubmit" />
|
||||
</el-dialog>
|
||||
<el-dialog title="租户数据源配置" append-to-body v-model="datasourceBox" width="450px">
|
||||
<avue-form
|
||||
ref="formDatasource"
|
||||
:option="datasourceOption"
|
||||
v-model="datasourceForm"
|
||||
@submit="handleDatasourceSubmit"
|
||||
/>
|
||||
</el-dialog>
|
||||
<el-drawer
|
||||
title="租户数据源管理"
|
||||
append-to-body
|
||||
v-model="datasourceSettingBox"
|
||||
direction="rtl"
|
||||
size="50%"
|
||||
>
|
||||
<tenant-datasource></tenant-datasource>
|
||||
</el-drawer>
|
||||
<el-dialog title="租户产品包配置" append-to-body v-model="packageBox" width="450px">
|
||||
<avue-form
|
||||
ref="formPackage"
|
||||
:option="packageOption"
|
||||
v-model="packageForm"
|
||||
@submit="handlePackageSubmit"
|
||||
>
|
||||
<template #menuId>
|
||||
<el-tree
|
||||
ref="packageMenuTree"
|
||||
:data="packageMenuTreeData"
|
||||
:props="packageMenuTreeProps"
|
||||
node-key="id"
|
||||
default-expand-all
|
||||
/>
|
||||
</template>
|
||||
</avue-form>
|
||||
</el-dialog>
|
||||
<el-drawer
|
||||
title="租户产品包管理"
|
||||
append-to-body
|
||||
v-model="packageSettingBox"
|
||||
direction="rtl"
|
||||
size="50%"
|
||||
>
|
||||
<tenant-package></tenant-package>
|
||||
</el-drawer>
|
||||
</basic-container>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {
|
||||
getList,
|
||||
getDetail,
|
||||
update,
|
||||
add,
|
||||
setting,
|
||||
datasource,
|
||||
packageInfo,
|
||||
packageSetting,
|
||||
recycle,
|
||||
pass,
|
||||
remove,
|
||||
} from '@/api/system/tenant';
|
||||
import { getDetail as packageDetail } from '@/api/system/tenantpackage';
|
||||
import { mapGetters } from 'vuex';
|
||||
import { getMenuTree } from '@/api/system/menu';
|
||||
import { validatenull } from '@/utils/validate';
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
form: {},
|
||||
selectionList: [],
|
||||
query: {},
|
||||
loading: true,
|
||||
box: false,
|
||||
datasourceBox: false,
|
||||
datasourceSettingBox: false,
|
||||
packageBox: false,
|
||||
packageSettingBox: false,
|
||||
recycleMode: false,
|
||||
page: {
|
||||
pageSize: 10,
|
||||
currentPage: 1,
|
||||
total: 0,
|
||||
},
|
||||
option: {
|
||||
height: 'auto',
|
||||
calcHeight: 32,
|
||||
tip: false,
|
||||
searchShow: true,
|
||||
searchMenuSpan: 6,
|
||||
border: true,
|
||||
index: true,
|
||||
selection: true,
|
||||
addBtn: false,
|
||||
viewBtn: true,
|
||||
menuWidth: 380,
|
||||
dialogWidth: 900,
|
||||
dialogClickModal: false,
|
||||
column: [
|
||||
{
|
||||
label: '租户ID',
|
||||
prop: 'tenantId',
|
||||
width: 100,
|
||||
search: true,
|
||||
addDisplay: false,
|
||||
editDisplay: false,
|
||||
span: 24,
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '请输入租户ID',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: '租户名称',
|
||||
prop: 'tenantName',
|
||||
search: true,
|
||||
width: 180,
|
||||
span: 24,
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '请输入参数名称',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: '联系人',
|
||||
prop: 'linkman',
|
||||
width: 100,
|
||||
search: true,
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '请输入联系人',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: '联系电话',
|
||||
prop: 'contactNumber',
|
||||
width: 150,
|
||||
},
|
||||
{
|
||||
label: '联系地址',
|
||||
prop: 'address',
|
||||
span: 24,
|
||||
minRows: 2,
|
||||
type: 'textarea',
|
||||
hide: true,
|
||||
},
|
||||
{
|
||||
label: '账号额度',
|
||||
prop: 'accountNumber',
|
||||
width: 90,
|
||||
slot: true,
|
||||
addDisplay: false,
|
||||
editDisplay: false,
|
||||
},
|
||||
{
|
||||
label: '过期时间',
|
||||
prop: 'expireTime',
|
||||
width: 180,
|
||||
slot: true,
|
||||
addDisplay: false,
|
||||
editDisplay: false,
|
||||
},
|
||||
{
|
||||
label: '绑定域名',
|
||||
prop: 'domainUrl',
|
||||
span: 24,
|
||||
},
|
||||
{
|
||||
label: '系统背景',
|
||||
prop: 'backgroundUrl',
|
||||
type: 'upload',
|
||||
listType: 'picture-img',
|
||||
dataType: 'string',
|
||||
action: '/blade-resource/oss/endpoint/put-file',
|
||||
propsHttp: {
|
||||
res: 'data',
|
||||
url: 'link',
|
||||
},
|
||||
hide: true,
|
||||
span: 24,
|
||||
},
|
||||
],
|
||||
},
|
||||
data: [],
|
||||
settingForm: {},
|
||||
settingOption: {
|
||||
column: [
|
||||
{
|
||||
label: '账号额度',
|
||||
labelTip: '代表租户可创建的最大额度,若不限制则默认为-1',
|
||||
prop: 'accountNumber',
|
||||
type: 'number',
|
||||
span: 24,
|
||||
},
|
||||
{
|
||||
label: '过期时间',
|
||||
labelTip: '代表租户可使用的最后日期,若不限制则默认为空',
|
||||
prop: 'expireTime',
|
||||
type: 'date',
|
||||
format: 'YYYY-MM-DD HH:mm:ss',
|
||||
valueFormat: 'YYYY-MM-DD HH:mm:ss',
|
||||
span: 24,
|
||||
},
|
||||
],
|
||||
},
|
||||
datasourceForm: {},
|
||||
datasourceOption: {
|
||||
column: [
|
||||
{
|
||||
label: '数据源',
|
||||
prop: 'datasourceId',
|
||||
search: true,
|
||||
span: 24,
|
||||
type: 'select',
|
||||
dicUrl: '/blade-system/tenant-datasource/select',
|
||||
props: {
|
||||
label: 'name',
|
||||
value: 'id',
|
||||
},
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '请选择数据源',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
packageForm: {},
|
||||
packageMenuTreeData: [],
|
||||
packageMenuTreeProps: {
|
||||
label: 'title',
|
||||
value: 'key',
|
||||
children: 'children',
|
||||
},
|
||||
packageOption: {
|
||||
column: [
|
||||
{
|
||||
label: '产品包',
|
||||
prop: 'packageId',
|
||||
search: true,
|
||||
span: 24,
|
||||
type: 'select',
|
||||
dicUrl: '/blade-system/tenant-package/select',
|
||||
props: {
|
||||
label: 'packageName',
|
||||
value: 'id',
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '菜单预览',
|
||||
prop: 'menuId',
|
||||
span: 24,
|
||||
formslot: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
'packageForm.packageId'() {
|
||||
if (!validatenull(this.packageForm.packageId)) {
|
||||
packageDetail(this.packageForm.packageId).then(res => {
|
||||
const menuId = res.data.data.menuId;
|
||||
this.packageForm.menuId = menuId;
|
||||
|
||||
// 解析选中的菜单ID列表
|
||||
const selectedIds = this.parseMenuIds(menuId);
|
||||
|
||||
// 先加载完整菜单树,再根据选中ID筛选
|
||||
getMenuTree().then(treeRes => {
|
||||
const fullTreeData = treeRes.data.data;
|
||||
const selectedIdSet = new Set(selectedIds);
|
||||
// 筛选树:只保留选中节点及其所有祖先节点
|
||||
this.packageMenuTreeData = this.filterTreeBySelectedIds(fullTreeData, selectedIdSet);
|
||||
});
|
||||
});
|
||||
}
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['userInfo', 'permission']),
|
||||
permissionList() {
|
||||
return {
|
||||
addBtn: this.validData(this.permission.tenant_add, false),
|
||||
viewBtn: this.validData(this.permission.tenant_view, false),
|
||||
delBtn: this.validData(this.permission.tenant_delete, false),
|
||||
editBtn: this.validData(this.permission.tenant_edit, false),
|
||||
};
|
||||
},
|
||||
ids() {
|
||||
let ids = [];
|
||||
this.selectionList.forEach(ele => {
|
||||
ids.push(ele.id);
|
||||
});
|
||||
return ids.join(',');
|
||||
},
|
||||
tenantId() {
|
||||
return this.selectionList[0].tenantId;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
initData() {
|
||||
getMenuTree().then(res => {
|
||||
this.packageMenuTreeData = res.data.data;
|
||||
});
|
||||
},
|
||||
rowSave(row, done, loading) {
|
||||
add(row).then(
|
||||
() => {
|
||||
this.onLoad(this.page);
|
||||
this.$message({
|
||||
type: 'success',
|
||||
message: '操作成功!',
|
||||
});
|
||||
done();
|
||||
},
|
||||
error => {
|
||||
window.console.log(error);
|
||||
loading();
|
||||
}
|
||||
);
|
||||
},
|
||||
rowUpdate(row, index, done, loading) {
|
||||
update(row).then(
|
||||
() => {
|
||||
this.onLoad(this.page);
|
||||
this.$message({
|
||||
type: 'success',
|
||||
message: '操作成功!',
|
||||
});
|
||||
done();
|
||||
},
|
||||
error => {
|
||||
window.console.log(error);
|
||||
loading();
|
||||
}
|
||||
);
|
||||
},
|
||||
rowDel(row) {
|
||||
this.$confirm('删除后所选租户将进入回收站,是否继续?', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
})
|
||||
.then(() => {
|
||||
return recycle(row.id);
|
||||
})
|
||||
.then(() => {
|
||||
this.onLoad(this.page);
|
||||
this.$message({
|
||||
type: 'success',
|
||||
message: '操作成功!',
|
||||
});
|
||||
});
|
||||
},
|
||||
beforeOpen(done, type) {
|
||||
if (['view'].includes(type)) {
|
||||
getDetail(this.form.id).then(res => {
|
||||
const data = res.data.data;
|
||||
if (!(data.accountNumber > 0)) {
|
||||
data.accountNumber = '不限制';
|
||||
}
|
||||
if (!data.expireTime) {
|
||||
data.expireTime = '不限制';
|
||||
}
|
||||
this.form = data;
|
||||
});
|
||||
}
|
||||
done();
|
||||
},
|
||||
searchReset() {
|
||||
this.query = {};
|
||||
this.onLoad(this.page);
|
||||
},
|
||||
searchChange(params, done) {
|
||||
this.query = params;
|
||||
this.page.currentPage = 1;
|
||||
this.onLoad(this.page, params);
|
||||
done();
|
||||
},
|
||||
selectionChange(list) {
|
||||
this.selectionList = list;
|
||||
},
|
||||
selectionClear() {
|
||||
this.selectionList = [];
|
||||
this.$refs.crud.toggleSelection();
|
||||
},
|
||||
handleDelete() {
|
||||
if (this.selectionList.length === 0) {
|
||||
this.$message.warning('请选择至少一条数据');
|
||||
return;
|
||||
}
|
||||
this.$confirm('删除后所选租户将进入回收站,是否继续?', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
})
|
||||
.then(() => {
|
||||
return recycle(this.ids);
|
||||
})
|
||||
.then(() => {
|
||||
this.onLoad(this.page);
|
||||
this.$message({
|
||||
type: 'success',
|
||||
message: '操作成功!',
|
||||
});
|
||||
this.$refs.crud.toggleSelection();
|
||||
});
|
||||
},
|
||||
handleRecycle() {
|
||||
this.recycleMode = true;
|
||||
this.$refs.crud.option.editBtn = false;
|
||||
this.$refs.crud.option.delBtn = false;
|
||||
this.onLoad(this.page, this.query);
|
||||
},
|
||||
handleRecyclePass() {
|
||||
if (this.selectionList.length === 0) {
|
||||
this.$message.warning('请选择至少一条数据');
|
||||
return;
|
||||
}
|
||||
this.$confirm('确定将所选租户进行恢复?', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
})
|
||||
.then(() => {
|
||||
return pass(this.ids);
|
||||
})
|
||||
.then(() => {
|
||||
this.onLoad(this.page);
|
||||
this.$message({
|
||||
type: 'success',
|
||||
message: '操作成功!',
|
||||
});
|
||||
this.$refs.crud.toggleSelection();
|
||||
});
|
||||
},
|
||||
handleRecycleRemove() {
|
||||
if (this.selectionList.length === 0) {
|
||||
this.$message.warning('请选择至少一条数据');
|
||||
return;
|
||||
}
|
||||
this.$confirm('确定将所选租户永久删除?', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
})
|
||||
.then(() => {
|
||||
return remove(this.ids);
|
||||
})
|
||||
.then(() => {
|
||||
this.onLoad(this.page);
|
||||
this.$message({
|
||||
type: 'success',
|
||||
message: '操作成功!',
|
||||
});
|
||||
this.$refs.crud.toggleSelection();
|
||||
});
|
||||
},
|
||||
handleRecycleBack() {
|
||||
this.recycleMode = false;
|
||||
this.$refs.crud.option.editBtn = true;
|
||||
this.$refs.crud.option.delBtn = true;
|
||||
this.onLoad(this.page, this.query);
|
||||
},
|
||||
handleSetting() {
|
||||
if (this.selectionList.length === 0) {
|
||||
this.$message.warning('请选择至少一条数据');
|
||||
return;
|
||||
}
|
||||
if (this.selectionList.length === 1) {
|
||||
getDetail(this.selectionList[0].id).then(res => {
|
||||
const data = res.data.data;
|
||||
this.settingForm.accountNumber = data.accountNumber;
|
||||
this.settingForm.expireTime = data.expireTime;
|
||||
});
|
||||
} else {
|
||||
this.settingForm.accountNumber = -1;
|
||||
this.settingForm.expireTime = '';
|
||||
}
|
||||
this.box = true;
|
||||
},
|
||||
handleRowDatasource(row) {
|
||||
getDetail(row.id).then(res => {
|
||||
const data = res.data.data;
|
||||
this.datasourceForm.tenantId = row.tenantId;
|
||||
this.datasourceForm.datasourceId = data.datasourceId;
|
||||
});
|
||||
this.datasourceBox = true;
|
||||
this.$nextTick(() => {
|
||||
this.$refs.formDatasource.updateDic('datasourceId');
|
||||
});
|
||||
},
|
||||
handleDatasource() {
|
||||
if (this.selectionList.length === 0) {
|
||||
this.$message.warning('请选择至少一条数据');
|
||||
return;
|
||||
}
|
||||
if (this.selectionList.length !== 1) {
|
||||
this.$message.warning('只能选择一条数据');
|
||||
return;
|
||||
}
|
||||
getDetail(this.selectionList[0].id).then(res => {
|
||||
const data = res.data.data;
|
||||
this.datasourceForm.tenantId = this.selectionList[0].tenantId;
|
||||
this.datasourceForm.datasourceId = data.datasourceId;
|
||||
});
|
||||
this.datasourceBox = true;
|
||||
},
|
||||
handleRowPackage(row) {
|
||||
// 重置数据
|
||||
this.packageMenuTreeData = [];
|
||||
packageInfo(row.id).then(res => {
|
||||
const data = res.data.data;
|
||||
this.packageForm.tenantId = row.tenantId;
|
||||
this.packageForm.packageId = data.id;
|
||||
this.packageForm.menuId = data.menuId;
|
||||
// 加载菜单树数据
|
||||
this.initData();
|
||||
});
|
||||
this.packageBox = true;
|
||||
//更新字典远程数据
|
||||
setTimeout(() => {
|
||||
const form = this.$refs.formPackage;
|
||||
form.updateDic('packageId');
|
||||
}, 10);
|
||||
},
|
||||
handleDatasourceSetting() {
|
||||
this.datasourceSettingBox = true;
|
||||
},
|
||||
handlePackageSetting() {
|
||||
this.packageSettingBox = true;
|
||||
},
|
||||
handleSubmit(form, done) {
|
||||
setting(this.ids, form).then(
|
||||
() => {
|
||||
this.onLoad(this.page);
|
||||
this.$message({
|
||||
type: 'success',
|
||||
message: '配置成功!',
|
||||
});
|
||||
done();
|
||||
this.box = false;
|
||||
},
|
||||
error => {
|
||||
window.console.log(error);
|
||||
done();
|
||||
}
|
||||
);
|
||||
},
|
||||
handleDatasourceSubmit(form, done) {
|
||||
datasource(form.tenantId, form.datasourceId).then(
|
||||
() => {
|
||||
this.$message({
|
||||
type: 'success',
|
||||
message: '配置成功!',
|
||||
});
|
||||
done();
|
||||
this.datasourceBox = false;
|
||||
},
|
||||
error => {
|
||||
window.console.log(error);
|
||||
done();
|
||||
}
|
||||
);
|
||||
},
|
||||
handlePackageSubmit(form, done) {
|
||||
packageSetting(form.tenantId, form.packageId).then(
|
||||
() => {
|
||||
this.onLoad(this.page);
|
||||
this.$message({
|
||||
type: 'success',
|
||||
message: '配置成功!',
|
||||
});
|
||||
done();
|
||||
this.packageBox = false;
|
||||
},
|
||||
error => {
|
||||
window.console.log(error);
|
||||
done();
|
||||
}
|
||||
);
|
||||
},
|
||||
currentChange(currentPage) {
|
||||
this.page.currentPage = currentPage;
|
||||
},
|
||||
sizeChange(pageSize) {
|
||||
this.page.pageSize = pageSize;
|
||||
},
|
||||
refreshChange() {
|
||||
this.onLoad(this.page, this.query);
|
||||
},
|
||||
onLoad(page, params = {}) {
|
||||
this.loading = true;
|
||||
getList(
|
||||
page.currentPage,
|
||||
page.pageSize,
|
||||
Object.assign(params, this.query, {
|
||||
status_equal: this.recycleMode ? -1 : 1,
|
||||
})
|
||||
).then(res => {
|
||||
const data = res.data.data;
|
||||
this.page.total = data.total;
|
||||
this.data = data.records;
|
||||
this.loading = false;
|
||||
this.selectionClear();
|
||||
});
|
||||
},
|
||||
/**
|
||||
* 解析菜单ID为字符串数组
|
||||
* @param {string|Array} menuId - 菜单ID,可能是逗号分隔的字符串或数组
|
||||
* @returns {string[]} - 菜单ID字符串数组
|
||||
*/
|
||||
parseMenuIds(menuId) {
|
||||
if (!menuId) return [];
|
||||
if (Array.isArray(menuId)) {
|
||||
return menuId.map(id => String(id).trim());
|
||||
}
|
||||
return menuId
|
||||
.split(',')
|
||||
.map(id => id.trim())
|
||||
.filter(Boolean);
|
||||
},
|
||||
/**
|
||||
* 递归筛选树节点,只保留选中的节点及其所有祖先节点
|
||||
* @param {Array} tree - 原始树数据
|
||||
* @param {Set<string>} selectedIdSet - 选中的节点ID集合
|
||||
* @returns {Array} - 筛选后的树数据
|
||||
*/
|
||||
filterTreeBySelectedIds(tree, selectedIdSet) {
|
||||
if (!tree || !tree.length) return [];
|
||||
|
||||
return tree.reduce((result, node) => {
|
||||
// 递归处理子节点
|
||||
const filteredChildren = this.filterTreeBySelectedIds(node.children, selectedIdSet);
|
||||
|
||||
// 判断当前节点是否需要保留:自身被选中 或 有子节点被保留(作为祖先节点)
|
||||
const nodeId = String(node.id);
|
||||
const isSelected = selectedIdSet.has(nodeId);
|
||||
const hasRetainedChildren = filteredChildren.length > 0;
|
||||
|
||||
if (isSelected || hasRetainedChildren) {
|
||||
result.push({
|
||||
...node,
|
||||
children: hasRetainedChildren ? filteredChildren : undefined,
|
||||
});
|
||||
}
|
||||
|
||||
return result;
|
||||
}, []);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style></style>
|
||||
@@ -0,0 +1,408 @@
|
||||
<template>
|
||||
<basic-container>
|
||||
<avue-crud
|
||||
:option="option"
|
||||
:table-loading="loading"
|
||||
:data="data"
|
||||
v-model:page="page"
|
||||
:permission="permissionList"
|
||||
:before-open="beforeOpen"
|
||||
v-model="form"
|
||||
ref="crud"
|
||||
@row-update="rowUpdate"
|
||||
@row-save="rowSave"
|
||||
@row-del="rowDel"
|
||||
@search-change="searchChange"
|
||||
@search-reset="searchReset"
|
||||
@selection-change="selectionChange"
|
||||
@current-change="currentChange"
|
||||
@size-change="sizeChange"
|
||||
@refresh-change="refreshChange"
|
||||
@on-load="onLoad"
|
||||
>
|
||||
<template #menu-left>
|
||||
<el-button type="danger" icon="el-icon-delete" plain @click="handleDelete"
|
||||
>删 除
|
||||
</el-button>
|
||||
</template>
|
||||
<template #shardingConfig-form="{}">
|
||||
<code-editor v-model="form.shardingConfig" height="300px" />
|
||||
</template>
|
||||
</avue-crud>
|
||||
</basic-container>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getList, getDetail, add, update, remove } from '@/api/system/tenantdatasource';
|
||||
import { mapGetters } from 'vuex';
|
||||
import func from '@/utils/func';
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
form: {},
|
||||
query: {},
|
||||
loading: true,
|
||||
page: {
|
||||
pageSize: 10,
|
||||
currentPage: 1,
|
||||
total: 0,
|
||||
},
|
||||
selectionList: [],
|
||||
option: {
|
||||
height: 'auto',
|
||||
calcHeight: 32,
|
||||
dialogWidth: 900,
|
||||
tip: false,
|
||||
searchShow: true,
|
||||
searchMenuSpan: 6,
|
||||
border: true,
|
||||
index: true,
|
||||
viewBtn: true,
|
||||
grid: true,
|
||||
selection: true,
|
||||
dialogClickModal: false,
|
||||
column: [
|
||||
{
|
||||
label: '名称',
|
||||
prop: 'name',
|
||||
width: 120,
|
||||
span: 24,
|
||||
search: true,
|
||||
gridRow: true,
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '请输入数据源名称',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: '数据类型',
|
||||
type: 'radio',
|
||||
value: 1,
|
||||
span: 24,
|
||||
width: 120,
|
||||
searchLabelWidth: 100,
|
||||
row: true,
|
||||
gridRow: true,
|
||||
dicUrl: '/blade-system/dict/dictionary?code=datasource_category',
|
||||
props: {
|
||||
label: 'dictValue',
|
||||
value: 'dictKey',
|
||||
},
|
||||
dataType: 'number',
|
||||
prop: 'category',
|
||||
search: true,
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '请选择分类',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: 'YAML',
|
||||
prop: 'shardingConfig',
|
||||
span: 24,
|
||||
minRows: 5,
|
||||
hide: true,
|
||||
display: false,
|
||||
gridRow: true,
|
||||
slot: true,
|
||||
type: 'textarea',
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '请输入YAML配置',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: '驱动类',
|
||||
prop: 'driverClass',
|
||||
type: 'select',
|
||||
span: 24,
|
||||
gridRow: true,
|
||||
dicData: [
|
||||
{
|
||||
label: 'com.mysql.cj.jdbc.Driver',
|
||||
value: 'com.mysql.cj.jdbc.Driver',
|
||||
},
|
||||
{
|
||||
label: 'org.postgresql.Driver',
|
||||
value: 'org.postgresql.Driver',
|
||||
},
|
||||
{
|
||||
label: 'oracle.jdbc.OracleDriver',
|
||||
value: 'oracle.jdbc.OracleDriver',
|
||||
},
|
||||
{
|
||||
label: 'com.microsoft.sqlserver.jdbc.SQLServerDriver',
|
||||
value: 'com.microsoft.sqlserver.jdbc.SQLServerDriver',
|
||||
},
|
||||
{
|
||||
label: 'dm.jdbc.driver.DmDriver',
|
||||
value: 'dm.jdbc.driver.DmDriver',
|
||||
},
|
||||
{
|
||||
label: 'com.yashandb.jdbc.Driver',
|
||||
value: 'com.yashandb.jdbc.Driver',
|
||||
},
|
||||
{
|
||||
label: 'com.kingbase8.Driver',
|
||||
value: 'com.kingbase8.Driver',
|
||||
},
|
||||
],
|
||||
width: 200,
|
||||
display: true,
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '请输入驱动类',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: '连接地址',
|
||||
prop: 'url',
|
||||
span: 24,
|
||||
display: true,
|
||||
gridRow: true,
|
||||
hide: true,
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '请输入连接地址',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: '用户名',
|
||||
prop: 'username',
|
||||
width: 120,
|
||||
display: true,
|
||||
gridRow: true,
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '请输入用户名',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: '密码',
|
||||
prop: 'password',
|
||||
hide: true,
|
||||
display: true,
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '请输入密码',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: '备注',
|
||||
prop: 'remark',
|
||||
span: 24,
|
||||
minRows: 3,
|
||||
hide: true,
|
||||
type: 'textarea',
|
||||
},
|
||||
],
|
||||
},
|
||||
data: [],
|
||||
driverUrlTemplates: {
|
||||
'com.mysql.cj.jdbc.Driver':
|
||||
'jdbc:mysql://localhost:3306/bladex?useSSL=false&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&transformedBitIsBoolean=true&serverTimezone=GMT%2B8&nullCatalogMeansCurrent=true&allowPublicKeyRetrieval=true',
|
||||
'org.postgresql.Driver': 'jdbc:postgresql://127.0.0.1:5432/bladex',
|
||||
'oracle.jdbc.OracleDriver': 'jdbc:oracle:thin:@//127.0.0.1:1521/ORCLPDB',
|
||||
'com.microsoft.sqlserver.jdbc.SQLServerDriver':
|
||||
'jdbc:sqlserver://127.0.0.1:1433;DatabaseName=bladex',
|
||||
'dm.jdbc.driver.DmDriver':
|
||||
'jdbc:dm://127.0.0.1:5236/bladex?zeroDateTimeBehavior=convertToNull&useUnicode=true&characterEncoding=utf-8',
|
||||
'com.yashandb.jdbc.Driver': 'jdbc:yasdb://127.0.0.1:1688/bladex',
|
||||
'com.kingbase8.Driver': 'jdbc:kingbase8://localhost:4321/bladex',
|
||||
},
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
'form.category'() {
|
||||
const category = func.toInt(this.form.category);
|
||||
this.$refs.crud.option.column.filter(item => {
|
||||
if (item.prop === 'driverClass') {
|
||||
item.display = category === 1;
|
||||
}
|
||||
if (item.prop === 'url') {
|
||||
item.display = category === 1;
|
||||
}
|
||||
if (item.prop === 'username') {
|
||||
item.display = category === 1;
|
||||
}
|
||||
if (item.prop === 'password') {
|
||||
item.display = category === 1;
|
||||
}
|
||||
if (item.prop === 'shardingConfig') {
|
||||
item.display = category === 2;
|
||||
}
|
||||
});
|
||||
},
|
||||
'form.driverClass'(newDriverClass) {
|
||||
// 当驱动类发生变化时,自动设置对应的默认URL
|
||||
if (newDriverClass && this.driverUrlTemplates[newDriverClass]) {
|
||||
// 只在URL为空或者是其他驱动的默认URL时才自动填充
|
||||
const isDefaultUrl =
|
||||
!this.form.url || Object.values(this.driverUrlTemplates).includes(this.form.url);
|
||||
if (isDefaultUrl) {
|
||||
this.form.url = this.driverUrlTemplates[newDriverClass];
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['permission']),
|
||||
permissionList() {
|
||||
return {
|
||||
addBtn: true,
|
||||
viewBtn: true,
|
||||
delBtn: true,
|
||||
editBtn: true,
|
||||
};
|
||||
},
|
||||
ids() {
|
||||
let ids = [];
|
||||
this.selectionList.forEach(ele => {
|
||||
ids.push(ele.id);
|
||||
});
|
||||
return ids.join(',');
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
rowSave(row, done, loading) {
|
||||
add(row).then(
|
||||
() => {
|
||||
this.onLoad(this.page);
|
||||
this.$message({
|
||||
type: 'success',
|
||||
message: '操作成功!',
|
||||
});
|
||||
done();
|
||||
},
|
||||
error => {
|
||||
window.console.log(error);
|
||||
loading();
|
||||
}
|
||||
);
|
||||
},
|
||||
rowUpdate(row, index, done, loading) {
|
||||
update(row).then(
|
||||
() => {
|
||||
this.onLoad(this.page);
|
||||
this.$message({
|
||||
type: 'success',
|
||||
message: '操作成功!',
|
||||
});
|
||||
done();
|
||||
},
|
||||
error => {
|
||||
window.console.log(error);
|
||||
loading();
|
||||
}
|
||||
);
|
||||
},
|
||||
rowDel(row) {
|
||||
this.$confirm('确定将选择数据删除?', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
})
|
||||
.then(() => {
|
||||
return remove(row.id);
|
||||
})
|
||||
.then(() => {
|
||||
this.onLoad(this.page);
|
||||
this.$message({
|
||||
type: 'success',
|
||||
message: '操作成功!',
|
||||
});
|
||||
});
|
||||
},
|
||||
handleDelete() {
|
||||
if (this.selectionList.length === 0) {
|
||||
this.$message.warning('请选择至少一条数据');
|
||||
return;
|
||||
}
|
||||
this.$confirm('确定将选择数据删除?', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
})
|
||||
.then(() => {
|
||||
return remove(this.ids);
|
||||
})
|
||||
.then(() => {
|
||||
this.onLoad(this.page);
|
||||
this.$message({
|
||||
type: 'success',
|
||||
message: '操作成功!',
|
||||
});
|
||||
this.$refs.crud.toggleSelection();
|
||||
});
|
||||
},
|
||||
beforeOpen(done, type) {
|
||||
if (['edit', 'view'].includes(type)) {
|
||||
getDetail(this.form.id).then(res => {
|
||||
this.form = res.data.data;
|
||||
});
|
||||
}
|
||||
done();
|
||||
},
|
||||
searchReset() {
|
||||
this.query = {};
|
||||
this.onLoad(this.page);
|
||||
},
|
||||
searchChange(params, done) {
|
||||
this.query = params;
|
||||
this.page.currentPage = 1;
|
||||
this.onLoad(this.page, params);
|
||||
done();
|
||||
},
|
||||
selectionChange(list) {
|
||||
this.selectionList = list;
|
||||
},
|
||||
selectionClear() {
|
||||
this.selectionList = [];
|
||||
this.$refs.crud.toggleSelection();
|
||||
},
|
||||
currentChange(currentPage) {
|
||||
this.page.currentPage = currentPage;
|
||||
},
|
||||
sizeChange(pageSize) {
|
||||
this.page.pageSize = pageSize;
|
||||
},
|
||||
refreshChange() {
|
||||
this.onLoad(this.page, this.query);
|
||||
},
|
||||
onLoad(page, params = {}) {
|
||||
this.loading = true;
|
||||
getList(page.currentPage, page.pageSize, Object.assign(params, this.query)).then(res => {
|
||||
const data = res.data.data;
|
||||
this.page.total = data.total;
|
||||
this.data = data.records;
|
||||
this.loading = false;
|
||||
this.selectionClear();
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style></style>
|
||||
@@ -0,0 +1,368 @@
|
||||
<template>
|
||||
<avue-crud
|
||||
:option="option"
|
||||
:table-loading="loading"
|
||||
:data="data"
|
||||
v-model:page="page"
|
||||
:permission="permissionList"
|
||||
:before-open="beforeOpen"
|
||||
v-model="form"
|
||||
ref="crud"
|
||||
@row-update="rowUpdate"
|
||||
@row-save="rowSave"
|
||||
@row-del="rowDel"
|
||||
@search-change="searchChange"
|
||||
@search-reset="searchReset"
|
||||
@selection-change="selectionChange"
|
||||
@current-change="currentChange"
|
||||
@size-change="sizeChange"
|
||||
@refresh-change="refreshChange"
|
||||
@on-load="onLoad"
|
||||
>
|
||||
<template #menu-left>
|
||||
<el-button type="danger" icon="el-icon-delete" plain @click="handleDelete">删 除</el-button>
|
||||
</template>
|
||||
<template #menuId-form>
|
||||
<el-row
|
||||
justify="space-between"
|
||||
align="middle"
|
||||
style="margin-bottom: 12px; background: #f5f7fa; padding: 6px 10px; border-radius: 4px"
|
||||
>
|
||||
<span style="display: inline-flex; align-items: center">
|
||||
<el-switch
|
||||
v-model="menuLinked"
|
||||
active-text="节点联动"
|
||||
size="small"
|
||||
@change="handleLinkedChange"
|
||||
/>
|
||||
<el-tooltip content="开启后勾选父节点会自动勾选所有子节点,关闭则可独立勾选任意节点" placement="top">
|
||||
<el-icon style="margin-left: 4px; color: #909399; cursor: pointer"><el-icon-question-filled /></el-icon>
|
||||
</el-tooltip>
|
||||
</span>
|
||||
<el-button-group>
|
||||
<el-button size="small" plain @click="handleSelectAll">全选</el-button>
|
||||
<el-button size="small" plain @click="handleInvertSelect">反选</el-button>
|
||||
</el-button-group>
|
||||
</el-row>
|
||||
<el-tree
|
||||
ref="menuTree"
|
||||
:data="menuTreeData"
|
||||
:props="menuTreeProps"
|
||||
show-checkbox
|
||||
node-key="id"
|
||||
:default-checked-keys="checkedMenuKeys"
|
||||
:default-expand-all="false"
|
||||
:check-strictly="!menuLinked"
|
||||
@check="handleMenuCheck"
|
||||
/>
|
||||
</template>
|
||||
</avue-crud>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getList, getDetail, add, update, remove } from '@/api/system/tenantpackage';
|
||||
import { mapGetters } from 'vuex';
|
||||
import { getMenuTree } from '@/api/system/menu';
|
||||
|
||||
export default {
|
||||
name: 'tenantPackage',
|
||||
data() {
|
||||
return {
|
||||
form: {},
|
||||
query: {},
|
||||
loading: true,
|
||||
page: {
|
||||
pageSize: 10,
|
||||
currentPage: 1,
|
||||
total: 0,
|
||||
},
|
||||
selectionList: [],
|
||||
menuTreeData: [],
|
||||
checkedMenuKeys: [],
|
||||
menuLinked: false,
|
||||
menuTreeProps: {
|
||||
label: 'title',
|
||||
value: 'key',
|
||||
children: 'children',
|
||||
},
|
||||
option: {
|
||||
height: 'auto',
|
||||
calcHeight: 32,
|
||||
tip: false,
|
||||
searchShow: true,
|
||||
searchMenuSpan: 6,
|
||||
border: true,
|
||||
index: true,
|
||||
viewBtn: true,
|
||||
selection: true,
|
||||
dialogClickModal: false,
|
||||
dialogWidth: 600,
|
||||
column: [
|
||||
{
|
||||
label: '产品包名',
|
||||
prop: 'packageName',
|
||||
search: true,
|
||||
span: 24,
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '请输入产品包名称',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: '菜单列表',
|
||||
prop: 'menuId',
|
||||
span: 24,
|
||||
hide: true,
|
||||
formslot: true,
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '请选择菜单',
|
||||
trigger: 'change',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: '备注',
|
||||
prop: 'remark',
|
||||
span: 24,
|
||||
},
|
||||
],
|
||||
},
|
||||
data: [],
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['permission']),
|
||||
permissionList() {
|
||||
return {
|
||||
addBtn: true,
|
||||
viewBtn: false,
|
||||
delBtn: true,
|
||||
editBtn: true,
|
||||
};
|
||||
},
|
||||
ids() {
|
||||
let ids = [];
|
||||
this.selectionList.forEach(ele => {
|
||||
ids.push(ele.id);
|
||||
});
|
||||
return ids.join(',');
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
initData() {
|
||||
getMenuTree().then(res => {
|
||||
this.menuTreeData = res.data.data;
|
||||
this.$nextTick(() => this.applyCheckedKeys());
|
||||
});
|
||||
},
|
||||
// el-tree 会把 setCheckedKeys 的入参记录为默认勾选集并在树数据重载时回放,
|
||||
// 复用的树实例需在打开表单时整体覆盖勾选状态,避免残留上一次配置的勾选
|
||||
applyCheckedKeys() {
|
||||
const tree = this.$refs.menuTree;
|
||||
if (!tree) return;
|
||||
tree.setCheckedKeys(this.checkedMenuKeys);
|
||||
},
|
||||
handleMenuCheck(node, data) {
|
||||
// 只保存全选的节点,不保存半选的节点
|
||||
// 恢复时半选状态会根据子节点自动计算
|
||||
this.form.menuId = data.checkedKeys;
|
||||
},
|
||||
getAllNodeKeys(nodes) {
|
||||
let keys = [];
|
||||
nodes.forEach(node => {
|
||||
keys.push(node.id);
|
||||
if (node.children && node.children.length > 0) {
|
||||
keys = keys.concat(this.getAllNodeKeys(node.children));
|
||||
}
|
||||
});
|
||||
return keys;
|
||||
},
|
||||
getLeafKeys(nodes) {
|
||||
let keys = [];
|
||||
nodes.forEach(node => {
|
||||
if (!node.children || node.children.length === 0) {
|
||||
keys.push(node.id);
|
||||
} else {
|
||||
keys = keys.concat(this.getLeafKeys(node.children));
|
||||
}
|
||||
});
|
||||
return keys;
|
||||
},
|
||||
handleSelectAll() {
|
||||
const tree = this.$refs.menuTree;
|
||||
if (!tree) return;
|
||||
const allKeys = this.getAllNodeKeys(this.menuTreeData);
|
||||
tree.setCheckedKeys(allKeys);
|
||||
this.form.menuId = tree.getCheckedKeys();
|
||||
},
|
||||
handleInvertSelect() {
|
||||
const tree = this.$refs.menuTree;
|
||||
if (!tree) return;
|
||||
const checkedKeys = new Set(tree.getCheckedKeys());
|
||||
if (this.menuLinked) {
|
||||
const leafKeys = this.getLeafKeys(this.menuTreeData);
|
||||
const invertedKeys = leafKeys.filter(key => !checkedKeys.has(key));
|
||||
tree.setCheckedKeys(invertedKeys);
|
||||
} else {
|
||||
const allKeys = this.getAllNodeKeys(this.menuTreeData);
|
||||
const invertedKeys = allKeys.filter(key => !checkedKeys.has(key));
|
||||
tree.setCheckedKeys(invertedKeys);
|
||||
}
|
||||
this.form.menuId = tree.getCheckedKeys();
|
||||
},
|
||||
handleLinkedChange() {
|
||||
const tree = this.$refs.menuTree;
|
||||
if (!tree) return;
|
||||
const checkedKeys = tree.getCheckedKeys();
|
||||
const halfCheckedKeys = tree.getHalfCheckedKeys();
|
||||
this.$nextTick(() => {
|
||||
tree.setCheckedKeys([...checkedKeys, ...halfCheckedKeys]);
|
||||
this.form.menuId = tree.getCheckedKeys();
|
||||
});
|
||||
},
|
||||
rowSave(row, done, loading) {
|
||||
// 将 menuId 数组转为逗号分隔的字符串
|
||||
if (Array.isArray(row.menuId)) {
|
||||
row.menuId = row.menuId.join(',');
|
||||
}
|
||||
add(row).then(
|
||||
() => {
|
||||
this.onLoad(this.page);
|
||||
this.$message({
|
||||
type: 'success',
|
||||
message: '操作成功!',
|
||||
});
|
||||
done();
|
||||
},
|
||||
error => {
|
||||
loading();
|
||||
window.console.log(error);
|
||||
}
|
||||
);
|
||||
},
|
||||
rowUpdate(row, index, done, loading) {
|
||||
// 将 menuId 数组转为逗号分隔的字符串
|
||||
if (Array.isArray(row.menuId)) {
|
||||
row.menuId = row.menuId.join(',');
|
||||
}
|
||||
update(row).then(
|
||||
() => {
|
||||
this.onLoad(this.page);
|
||||
this.$message({
|
||||
type: 'success',
|
||||
message: '操作成功!',
|
||||
});
|
||||
done();
|
||||
},
|
||||
error => {
|
||||
loading();
|
||||
window.console.log(error);
|
||||
}
|
||||
);
|
||||
},
|
||||
rowDel(row) {
|
||||
this.$confirm('确定将选择数据删除?', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
})
|
||||
.then(() => {
|
||||
return remove(row.id);
|
||||
})
|
||||
.then(() => {
|
||||
this.onLoad(this.page);
|
||||
this.$message({
|
||||
type: 'success',
|
||||
message: '操作成功!',
|
||||
});
|
||||
});
|
||||
},
|
||||
handleDelete() {
|
||||
if (this.selectionList.length === 0) {
|
||||
this.$message.warning('请选择至少一条数据');
|
||||
return;
|
||||
}
|
||||
this.$confirm('确定将选择数据删除?', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
})
|
||||
.then(() => {
|
||||
return remove(this.ids);
|
||||
})
|
||||
.then(() => {
|
||||
this.onLoad(this.page);
|
||||
this.$message({
|
||||
type: 'success',
|
||||
message: '操作成功!',
|
||||
});
|
||||
this.$refs.crud.toggleSelection();
|
||||
});
|
||||
},
|
||||
beforeOpen(done, type) {
|
||||
// 重置选中状态和树数据
|
||||
this.checkedMenuKeys = [];
|
||||
this.menuTreeData = [];
|
||||
this.menuLinked = false;
|
||||
if (['add', 'edit'].includes(type)) {
|
||||
this.initData();
|
||||
}
|
||||
if (['edit'].includes(type)) {
|
||||
getDetail(this.form.id).then(res => {
|
||||
this.form = res.data.data;
|
||||
// 设置选中的菜单
|
||||
if (this.form.menuId) {
|
||||
this.checkedMenuKeys = Array.isArray(this.form.menuId)
|
||||
? this.form.menuId
|
||||
: this.form.menuId.split(',').map(id => id.trim());
|
||||
}
|
||||
});
|
||||
}
|
||||
done();
|
||||
},
|
||||
searchReset() {
|
||||
this.query = {};
|
||||
this.onLoad(this.page);
|
||||
},
|
||||
searchChange(params, done) {
|
||||
this.query = params;
|
||||
this.page.currentPage = 1;
|
||||
this.onLoad(this.page, params);
|
||||
done();
|
||||
},
|
||||
selectionChange(list) {
|
||||
this.selectionList = list;
|
||||
},
|
||||
selectionClear() {
|
||||
this.selectionList = [];
|
||||
this.$refs.crud.toggleSelection();
|
||||
},
|
||||
currentChange(currentPage) {
|
||||
this.page.currentPage = currentPage;
|
||||
},
|
||||
sizeChange(pageSize) {
|
||||
this.page.pageSize = pageSize;
|
||||
},
|
||||
refreshChange() {
|
||||
this.onLoad(this.page, this.query);
|
||||
},
|
||||
onLoad(page, params = {}) {
|
||||
this.loading = true;
|
||||
getList(page.currentPage, page.pageSize, Object.assign(params, this.query)).then(res => {
|
||||
const data = res.data.data;
|
||||
this.page.total = data.total;
|
||||
this.data = data.records;
|
||||
this.loading = false;
|
||||
this.selectionClear();
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style></style>
|
||||
@@ -0,0 +1,531 @@
|
||||
<template>
|
||||
<basic-container>
|
||||
<avue-crud
|
||||
:option="option"
|
||||
:table-loading="loading"
|
||||
:data="data"
|
||||
v-model:page="page"
|
||||
:permission="permissionList"
|
||||
:before-open="beforeOpen"
|
||||
v-model="form"
|
||||
ref="crud"
|
||||
@row-update="rowUpdate"
|
||||
@row-save="rowSave"
|
||||
@row-del="rowDel"
|
||||
@search-change="searchChange"
|
||||
@search-reset="searchReset"
|
||||
@selection-change="selectionChange"
|
||||
@current-change="currentChange"
|
||||
@size-change="sizeChange"
|
||||
@refresh-change="refreshChange"
|
||||
@on-load="onLoad"
|
||||
>
|
||||
<template #menu-left>
|
||||
<el-button
|
||||
type="danger"
|
||||
icon="el-icon-delete"
|
||||
plain
|
||||
v-if="permission.topmenu_delete"
|
||||
@click="handleDelete"
|
||||
>删 除
|
||||
</el-button>
|
||||
<el-button
|
||||
icon="el-icon-setting"
|
||||
@click="handleMenuSetting"
|
||||
v-if="permission.topmenu_setting"
|
||||
plain
|
||||
>菜单配置
|
||||
</el-button>
|
||||
</template>
|
||||
<template #menu="scope">
|
||||
<el-button
|
||||
v-if="permission.topmenu_setting"
|
||||
type="primary"
|
||||
text
|
||||
icon="el-icon-setting"
|
||||
@click.stop="handleRowMenuSetting(scope.row)"
|
||||
>配置
|
||||
</el-button>
|
||||
</template>
|
||||
<template #name="{ row }">
|
||||
<i :class="row.source" style="margin-right: 5px" />
|
||||
<span>{{ row.name }}</span>
|
||||
</template>
|
||||
<template #source="{ row }">
|
||||
<div style="text-align: center">
|
||||
<i :class="row.source"></i>
|
||||
</div>
|
||||
</template>
|
||||
<template #sort="{ row }">
|
||||
<el-input-number
|
||||
v-model="row.sort"
|
||||
@change="sortChange(row)"
|
||||
:min="1"
|
||||
:max="100"
|
||||
></el-input-number>
|
||||
</template>
|
||||
<template #isMain="{ row }">
|
||||
<el-switch
|
||||
v-model="row.isMain"
|
||||
inline-prompt
|
||||
:before-change="() => isMainChange(row)"
|
||||
active-text="是"
|
||||
inactive-text="否"
|
||||
:active-value="1"
|
||||
:inactive-value="0"
|
||||
/>
|
||||
</template>
|
||||
</avue-crud>
|
||||
<el-dialog
|
||||
title="下级菜单配置"
|
||||
append-to-body
|
||||
v-model="box"
|
||||
width="345px"
|
||||
@closed="handleDialogClose"
|
||||
>
|
||||
<el-row
|
||||
justify="space-between"
|
||||
align="middle"
|
||||
style="margin-bottom: 12px; background: #f5f7fa; padding: 6px 10px; border-radius: 4px"
|
||||
>
|
||||
<span style="display: inline-flex; align-items: center">
|
||||
<el-switch
|
||||
v-model="menuLinked"
|
||||
active-text="节点联动"
|
||||
size="small"
|
||||
@change="handleLinkedChange"
|
||||
/>
|
||||
<el-tooltip content="开启后勾选父节点会自动勾选所有子节点,关闭则可独立勾选任意节点" placement="top">
|
||||
<el-icon style="margin-left: 4px; color: #909399; cursor: pointer"><el-icon-question-filled /></el-icon>
|
||||
</el-tooltip>
|
||||
</span>
|
||||
<el-button-group>
|
||||
<el-button size="small" plain @click="handleSelectAll">全选</el-button>
|
||||
<el-button size="small" plain @click="handleInvertSelect">反选</el-button>
|
||||
</el-button-group>
|
||||
</el-row>
|
||||
<el-tree
|
||||
:data="menuGrantList"
|
||||
show-checkbox
|
||||
:check-strictly="!menuLinked"
|
||||
node-key="id"
|
||||
ref="treeMenu"
|
||||
:default-checked-keys="menuTreeObj"
|
||||
:props="props"
|
||||
>
|
||||
</el-tree>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="box = false">取 消</el-button>
|
||||
<el-button type="primary" @click="submit">确 定</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</basic-container>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {
|
||||
getList,
|
||||
getDetail,
|
||||
add,
|
||||
update,
|
||||
remove,
|
||||
grant,
|
||||
grantTree,
|
||||
getTopTree,
|
||||
enable,
|
||||
} from '@/api/system/topmenu';
|
||||
import { mapGetters } from 'vuex';
|
||||
import iconList from '@/config/iconList';
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
form: {},
|
||||
box: false,
|
||||
query: {},
|
||||
loading: true,
|
||||
currentMenuIds: [],
|
||||
props: {
|
||||
label: 'title',
|
||||
value: 'key',
|
||||
},
|
||||
page: {
|
||||
pageSize: 10,
|
||||
currentPage: 1,
|
||||
total: 0,
|
||||
},
|
||||
selectionList: [],
|
||||
menuGrantList: [],
|
||||
menuTreeObj: [],
|
||||
menuLinked: false,
|
||||
option: {
|
||||
height: 'auto',
|
||||
calcHeight: 32,
|
||||
tip: false,
|
||||
searchShow: true,
|
||||
searchMenuSpan: 6,
|
||||
border: true,
|
||||
index: true,
|
||||
viewBtn: true,
|
||||
selection: true,
|
||||
menuWidth: 300,
|
||||
dialogWidth: 900,
|
||||
dialogClickModal: false,
|
||||
column: [
|
||||
{
|
||||
label: '菜单名',
|
||||
prop: 'name',
|
||||
search: true,
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '请输入菜单名',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: '菜单图标',
|
||||
prop: 'source',
|
||||
type: 'icon',
|
||||
slot: true,
|
||||
iconList: iconList,
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '请输入菜单图标',
|
||||
trigger: 'click',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: '菜单编号',
|
||||
prop: 'code',
|
||||
search: true,
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '请输入菜单编号',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: '菜单排序',
|
||||
prop: 'sort',
|
||||
type: 'number',
|
||||
slot: true,
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '请输入菜单排序',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: '是否主页',
|
||||
prop: 'isMain',
|
||||
slot: true,
|
||||
align: 'center',
|
||||
width: 100,
|
||||
value: 0,
|
||||
display: false,
|
||||
dicData: [
|
||||
{ label: '否', value: 0 },
|
||||
{ label: '是', value: 1 },
|
||||
],
|
||||
},
|
||||
{
|
||||
label: '菜单路由',
|
||||
prop: 'path',
|
||||
span: 24,
|
||||
hide: true,
|
||||
rules: [
|
||||
{
|
||||
required: false,
|
||||
message: '请输入菜单路由',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
data: [],
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['permission', 'userInfo']),
|
||||
permissionList() {
|
||||
return {
|
||||
addBtn: this.validData(this.permission.topmenu_add, false),
|
||||
viewBtn: this.validData(this.permission.topmenu_view, false),
|
||||
delBtn: this.validData(this.permission.topmenu_delete, false),
|
||||
editBtn: this.validData(this.permission.topmenu_edit, false),
|
||||
};
|
||||
},
|
||||
ids() {
|
||||
let ids = [];
|
||||
this.selectionList.forEach(ele => {
|
||||
ids.push(ele.id);
|
||||
});
|
||||
return ids.join(',');
|
||||
},
|
||||
idsArray() {
|
||||
let ids = [];
|
||||
this.selectionList.forEach(ele => {
|
||||
ids.push(ele.id);
|
||||
});
|
||||
return ids;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
getAllNodeKeys(nodes) {
|
||||
let keys = [];
|
||||
nodes.forEach(node => {
|
||||
keys.push(node.id);
|
||||
if (node.children && node.children.length > 0) {
|
||||
keys = keys.concat(this.getAllNodeKeys(node.children));
|
||||
}
|
||||
});
|
||||
return keys;
|
||||
},
|
||||
getLeafKeys(nodes) {
|
||||
let keys = [];
|
||||
nodes.forEach(node => {
|
||||
if (!node.children || node.children.length === 0) {
|
||||
keys.push(node.id);
|
||||
} else {
|
||||
keys = keys.concat(this.getLeafKeys(node.children));
|
||||
}
|
||||
});
|
||||
return keys;
|
||||
},
|
||||
handleSelectAll() {
|
||||
const tree = this.$refs.treeMenu;
|
||||
if (!tree) return;
|
||||
const allKeys = this.getAllNodeKeys(this.menuGrantList);
|
||||
tree.setCheckedKeys(allKeys);
|
||||
},
|
||||
handleInvertSelect() {
|
||||
const tree = this.$refs.treeMenu;
|
||||
if (!tree) return;
|
||||
const checkedKeys = new Set(tree.getCheckedKeys());
|
||||
if (this.menuLinked) {
|
||||
const leafKeys = this.getLeafKeys(this.menuGrantList);
|
||||
const invertedKeys = leafKeys.filter(key => !checkedKeys.has(key));
|
||||
tree.setCheckedKeys(invertedKeys);
|
||||
} else {
|
||||
const allKeys = this.getAllNodeKeys(this.menuGrantList);
|
||||
const invertedKeys = allKeys.filter(key => !checkedKeys.has(key));
|
||||
tree.setCheckedKeys(invertedKeys);
|
||||
}
|
||||
},
|
||||
handleLinkedChange() {
|
||||
const tree = this.$refs.treeMenu;
|
||||
if (!tree) return;
|
||||
const checkedKeys = tree.getCheckedKeys();
|
||||
const halfCheckedKeys = tree.getHalfCheckedKeys();
|
||||
this.$nextTick(() => {
|
||||
tree.setCheckedKeys([...checkedKeys, ...halfCheckedKeys]);
|
||||
});
|
||||
},
|
||||
// el-tree 会把 setCheckedKeys 的入参记录为默认勾选集并在树数据重载时回放,
|
||||
// 复用的树实例需在打开配置时整体覆盖勾选状态,避免残留上一次配置的勾选
|
||||
applyCheckedKeys() {
|
||||
const tree = this.$refs.treeMenu;
|
||||
if (!tree) return;
|
||||
tree.setCheckedKeys(this.menuTreeObj);
|
||||
},
|
||||
isMainChange(row) {
|
||||
const newValue = row.isMain === 1 ? 0 : 1;
|
||||
const request = newValue === 1 ? enable(row.id) : update({ ...row, isMain: newValue });
|
||||
return request.then(() => {
|
||||
this.onLoad(this.page);
|
||||
this.$message({ type: 'success', message: '操作成功!' });
|
||||
return true;
|
||||
}).catch(error => {
|
||||
window.console.log(error);
|
||||
return false;
|
||||
});
|
||||
},
|
||||
submit() {
|
||||
const menuList = this.$refs.treeMenu.getCheckedKeys();
|
||||
grant(this.currentMenuIds, menuList).then(() => {
|
||||
this.box = false;
|
||||
this.$message({
|
||||
type: 'success',
|
||||
message: '操作成功!',
|
||||
});
|
||||
this.onLoad(this.page);
|
||||
});
|
||||
},
|
||||
rowSave(row, done, loading) {
|
||||
add(row).then(
|
||||
() => {
|
||||
this.onLoad(this.page);
|
||||
this.$message({
|
||||
type: 'success',
|
||||
message: '操作成功!',
|
||||
});
|
||||
done();
|
||||
},
|
||||
error => {
|
||||
window.console.log(error);
|
||||
loading();
|
||||
}
|
||||
);
|
||||
},
|
||||
rowUpdate(row, index, done, loading) {
|
||||
update(row).then(
|
||||
() => {
|
||||
this.onLoad(this.page);
|
||||
this.$message({
|
||||
type: 'success',
|
||||
message: '操作成功!',
|
||||
});
|
||||
done();
|
||||
},
|
||||
error => {
|
||||
window.console.log(error);
|
||||
loading();
|
||||
}
|
||||
);
|
||||
},
|
||||
rowDel(row) {
|
||||
this.$confirm('确定将选择数据删除?', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
})
|
||||
.then(() => {
|
||||
return remove(row.id);
|
||||
})
|
||||
.then(() => {
|
||||
this.onLoad(this.page);
|
||||
this.$message({
|
||||
type: 'success',
|
||||
message: '操作成功!',
|
||||
});
|
||||
});
|
||||
},
|
||||
handleDelete() {
|
||||
if (this.selectionList.length === 0) {
|
||||
this.$message.warning('请选择至少一条数据');
|
||||
return;
|
||||
}
|
||||
this.$confirm('确定将选择数据删除?', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
})
|
||||
.then(() => {
|
||||
return remove(this.ids);
|
||||
})
|
||||
.then(() => {
|
||||
this.onLoad(this.page);
|
||||
this.$message({
|
||||
type: 'success',
|
||||
message: '操作成功!',
|
||||
});
|
||||
this.$refs.crud.toggleSelection();
|
||||
});
|
||||
},
|
||||
handleMenuSetting() {
|
||||
if (this.selectionList.length !== 1) {
|
||||
this.$message.warning('只能选择一条数据');
|
||||
return;
|
||||
}
|
||||
this.currentMenuIds = this.idsArray;
|
||||
this.menuTreeObj = [];
|
||||
grantTree().then(res => {
|
||||
this.menuGrantList = res.data.data.menu;
|
||||
getTopTree(this.ids).then(res => {
|
||||
this.menuTreeObj = res.data.data.menu;
|
||||
this.box = true;
|
||||
this.$nextTick(() => this.applyCheckedKeys());
|
||||
});
|
||||
});
|
||||
},
|
||||
handleRowMenuSetting(row) {
|
||||
this.currentMenuIds = [row.id];
|
||||
this.menuTreeObj = [];
|
||||
grantTree().then(res => {
|
||||
this.menuGrantList = res.data.data.menu;
|
||||
getTopTree(row.id).then(res => {
|
||||
this.menuTreeObj = res.data.data.menu;
|
||||
this.box = true;
|
||||
this.$nextTick(() => this.applyCheckedKeys());
|
||||
});
|
||||
});
|
||||
},
|
||||
handleDialogClose() {
|
||||
this.currentMenuIds = [];
|
||||
this.menuLinked = false;
|
||||
},
|
||||
beforeOpen(done, type) {
|
||||
if (['edit', 'view'].includes(type)) {
|
||||
getDetail(this.form.id).then(res => {
|
||||
this.form = res.data.data;
|
||||
});
|
||||
}
|
||||
done();
|
||||
},
|
||||
sortChange(row) {
|
||||
update(row).then(
|
||||
() => {
|
||||
this.onLoad(this.page);
|
||||
},
|
||||
error => {
|
||||
window.console.log(error);
|
||||
}
|
||||
);
|
||||
},
|
||||
searchReset() {
|
||||
this.query = {};
|
||||
this.onLoad(this.page);
|
||||
},
|
||||
searchChange(params, done) {
|
||||
this.query = params;
|
||||
this.page.currentPage = 1;
|
||||
this.onLoad(this.page, params);
|
||||
done();
|
||||
},
|
||||
selectionChange(list) {
|
||||
this.selectionList = list;
|
||||
},
|
||||
selectionClear() {
|
||||
this.selectionList = [];
|
||||
this.$refs.crud.toggleSelection();
|
||||
},
|
||||
currentChange(currentPage) {
|
||||
this.page.currentPage = currentPage;
|
||||
},
|
||||
sizeChange(pageSize) {
|
||||
this.page.pageSize = pageSize;
|
||||
},
|
||||
refreshChange() {
|
||||
this.onLoad(this.page, this.query);
|
||||
},
|
||||
onLoad(page, params = {}) {
|
||||
this.loading = true;
|
||||
getList(page.currentPage, page.pageSize, Object.assign(params, this.query)).then(res => {
|
||||
const data = res.data.data;
|
||||
this.page.total = data.total;
|
||||
this.data = data.records;
|
||||
this.loading = false;
|
||||
this.selectionClear();
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.none-border {
|
||||
border: 0;
|
||||
background-color: transparent !important;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,863 @@
|
||||
<template>
|
||||
<el-row>
|
||||
<el-col :span="5">
|
||||
<div class="box">
|
||||
<el-scrollbar>
|
||||
<basic-container>
|
||||
<avue-tree :option="treeOption" :data="treeData" @node-click="nodeClick" />
|
||||
</basic-container>
|
||||
</el-scrollbar>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="19">
|
||||
<basic-container>
|
||||
<avue-crud
|
||||
:option="userOption"
|
||||
v-model:search="search"
|
||||
:table-loading="loading"
|
||||
:data="data"
|
||||
ref="crud"
|
||||
v-model="form"
|
||||
:permission="permissionList"
|
||||
@row-del="rowDel"
|
||||
@row-update="rowUpdate"
|
||||
@row-save="rowSave"
|
||||
:before-open="beforeOpen"
|
||||
v-model:page="page"
|
||||
@search-change="searchChange"
|
||||
@search-reset="searchReset"
|
||||
@selection-change="selectionChange"
|
||||
@current-change="currentChange"
|
||||
@size-change="sizeChange"
|
||||
@refresh-change="refreshChange"
|
||||
@on-load="onLoad"
|
||||
>
|
||||
<template #menu-left>
|
||||
<el-button
|
||||
v-if="permission.user_add && !auditMode"
|
||||
type="primary"
|
||||
icon="el-icon-plus"
|
||||
@click="$refs.crud.rowAdd()"
|
||||
>新 增
|
||||
</el-button>
|
||||
<el-button
|
||||
type="danger"
|
||||
plain
|
||||
icon="el-icon-delete"
|
||||
v-if="permission.user_delete && !auditMode"
|
||||
@click="handleDelete"
|
||||
>删 除
|
||||
</el-button>
|
||||
<el-button
|
||||
type="primary"
|
||||
plain
|
||||
icon="el-icon-operation"
|
||||
v-if="userInfo.authority.includes('admin') && !auditMode"
|
||||
@click="handleAudit"
|
||||
>审 核
|
||||
</el-button>
|
||||
<el-button
|
||||
type="success"
|
||||
plain
|
||||
icon="el-icon-check"
|
||||
v-if="userInfo.authority.includes('admin') && auditMode"
|
||||
@click="handleAuditPass"
|
||||
>通 过
|
||||
</el-button>
|
||||
<el-button
|
||||
type="danger"
|
||||
plain
|
||||
icon="el-icon-close"
|
||||
v-if="userInfo.authority.includes('admin') && auditMode"
|
||||
@click="handleAuditRefuse"
|
||||
>拒 绝
|
||||
</el-button>
|
||||
<el-button
|
||||
type="primary"
|
||||
plain
|
||||
icon="el-icon-refresh-left"
|
||||
v-if="userInfo.authority.includes('admin') && auditMode"
|
||||
@click="handleAuditBack"
|
||||
>返 回
|
||||
</el-button>
|
||||
<el-button
|
||||
type="info"
|
||||
plain
|
||||
v-if="permission.user_role && !auditMode"
|
||||
icon="el-icon-user"
|
||||
@click="handleGrant"
|
||||
>角色配置
|
||||
</el-button>
|
||||
<el-dropdown
|
||||
v-if="userInfo.authority.includes('admin') && !auditMode"
|
||||
@command="handleDataManageCommand"
|
||||
style="margin-left: 10px"
|
||||
>
|
||||
<el-button type="primary" plain icon="el-icon-files">
|
||||
数据管理<i class="el-icon-arrow-down el-icon--right"></i>
|
||||
</el-button>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item command="import">
|
||||
<el-icon><upload /></el-icon>
|
||||
导入数据
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item command="export">
|
||||
<el-icon><download /></el-icon>
|
||||
导出数据
|
||||
</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
</template>
|
||||
<template #menu-right>
|
||||
<el-button
|
||||
v-if="userInfo.authority.includes('admin') && !auditMode"
|
||||
icon="el-icon-document"
|
||||
@click="$refs.authLog.openAuthLog()"
|
||||
>认证日志
|
||||
</el-button>
|
||||
<el-button
|
||||
v-if="userInfo.authority.includes('admin') && !auditMode"
|
||||
icon="el-icon-lock"
|
||||
@click="$refs.authLock.openLockLog()"
|
||||
>锁定管理
|
||||
</el-button>
|
||||
</template>
|
||||
<template #menu="{ row, index, size }">
|
||||
<el-button
|
||||
text
|
||||
type="primary"
|
||||
icon="el-icon-view"
|
||||
v-if="this.permission.user_view"
|
||||
@click.stop="$refs.crud.rowView(row, index)"
|
||||
>查 看
|
||||
</el-button>
|
||||
<el-button
|
||||
text
|
||||
type="primary"
|
||||
icon="el-icon-edit"
|
||||
v-if="this.permission.user_edit"
|
||||
@click.stop="$refs.crud.rowEdit(row, index)"
|
||||
>编 辑
|
||||
</el-button>
|
||||
<el-dropdown @command="command => handleDropdownCommand(command, row, index)">
|
||||
<el-button text type="primary" icon="el-icon-setting">更 多 </el-button>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item command="setLeader" v-if="userInfo.authority.includes('admin')">
|
||||
<el-icon><circle-close v-if="row.isLeader === 1" /><coordinate v-else /></el-icon>
|
||||
{{ row.isLeader === 1 ? '取消主管' : '设置主管' }}
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item command="grantRole" v-if="permission.user_role">
|
||||
<el-icon><user /></el-icon>
|
||||
角色配置
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item
|
||||
command="platformConfig"
|
||||
v-if="userInfo.authority.includes('admin')"
|
||||
>
|
||||
<el-icon><setting /></el-icon>
|
||||
平台配置
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item command="authLog" v-if="userInfo.authority.includes('admin')">
|
||||
<el-icon><document /></el-icon>
|
||||
认证日志
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item command="lockUser" v-if="userInfo.authority.includes('admin')">
|
||||
<el-icon><lock /></el-icon>
|
||||
锁定账号
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item command="resetPassword" v-if="permission.user_reset">
|
||||
<el-icon><refresh /></el-icon>
|
||||
密码重置
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item command="delete" v-if="this.permission.user_delete">
|
||||
<el-icon><delete /></el-icon>
|
||||
删除用户
|
||||
</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
</template>
|
||||
<template #tenantName="{ row }">
|
||||
<el-tag>{{ row.tenantName }}</el-tag>
|
||||
</template>
|
||||
<template #roleName="{ row }">
|
||||
<el-tag>{{ row.roleName }}</el-tag>
|
||||
</template>
|
||||
<template #deptName="{ row }">
|
||||
<el-tag>{{ row.deptName }}</el-tag>
|
||||
</template>
|
||||
<template #userTypeName="{ row }">
|
||||
<el-tag>{{ row.userTypeName }}</el-tag>
|
||||
</template>
|
||||
</avue-crud>
|
||||
|
||||
<!-- 用户角色配置 -->
|
||||
<el-dialog title="用户角色配置" append-to-body v-model="roleBox" width="345px">
|
||||
<el-row
|
||||
justify="space-between"
|
||||
align="middle"
|
||||
style="margin-bottom: 12px; background: #f5f7fa; padding: 6px 10px; border-radius: 4px"
|
||||
>
|
||||
<span style="display: inline-flex; align-items: center">
|
||||
<el-switch
|
||||
v-model="roleLinked"
|
||||
active-text="节点联动"
|
||||
size="small"
|
||||
@change="handleLinkedChange('treeRole')"
|
||||
/>
|
||||
<el-tooltip content="开启后勾选父节点会自动勾选所有子节点,关闭则可独立勾选任意节点" placement="top">
|
||||
<el-icon style="margin-left: 4px; color: #909399; cursor: pointer"><el-icon-question-filled /></el-icon>
|
||||
</el-tooltip>
|
||||
</span>
|
||||
<el-button-group>
|
||||
<el-button size="small" plain @click="handleSelectAll('treeRole', roleGrantList)"
|
||||
>全选</el-button
|
||||
>
|
||||
<el-button
|
||||
size="small"
|
||||
plain
|
||||
@click="handleInvertSelect('treeRole', roleGrantList, roleLinked)"
|
||||
>反选</el-button
|
||||
>
|
||||
</el-button-group>
|
||||
</el-row>
|
||||
<el-tree
|
||||
:data="roleGrantList"
|
||||
show-checkbox
|
||||
:check-strictly="!roleLinked"
|
||||
default-expand-all
|
||||
node-key="id"
|
||||
ref="treeRole"
|
||||
:default-checked-keys="roleTreeObj"
|
||||
:props="props"
|
||||
>
|
||||
</el-tree>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="roleBox = false">取 消</el-button>
|
||||
<el-button type="primary" @click="submitRole">确 定</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 用户数据导入 -->
|
||||
<el-dialog title="用户数据导入" append-to-body v-model="excelBox" width="555px">
|
||||
<avue-form :option="excelOption" v-model="excelForm" :upload-after="uploadAfter">
|
||||
<template #excelTemplate>
|
||||
<el-button type="primary" @click="handleTemplate">
|
||||
点击下载<i class="el-icon-download el-icon--right"></i>
|
||||
</el-button>
|
||||
</template>
|
||||
</avue-form>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 用户平台配置(行级别) -->
|
||||
<el-dialog title="用户平台配置" append-to-body v-model="platformBox" width="600px">
|
||||
<avue-form ref="platformFormRef" :option="platformFormOption" v-model="platformForm" />
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="platformBox = false">取 消</el-button>
|
||||
<el-button type="primary" @click="submitPlatformConfig">确 定</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 认证日志组件 -->
|
||||
<auth-log ref="authLog" />
|
||||
<!-- 认证锁定配置组件 -->
|
||||
<auth-lock ref="authLock" @lock-success="onLoad(page)" />
|
||||
</basic-container>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {
|
||||
getList,
|
||||
getUser,
|
||||
getUserPlatform,
|
||||
remove,
|
||||
update,
|
||||
updatePlatform,
|
||||
add,
|
||||
grant,
|
||||
resetPassword,
|
||||
auditPass,
|
||||
auditRefuse,
|
||||
setLeader,
|
||||
getLeaderList,
|
||||
} from '@/api/system/user';
|
||||
import { exportBlob } from '@/api/common';
|
||||
import { getDeptTree } from '@/api/system/dept';
|
||||
import { getRoleTree } from '@/api/system/role';
|
||||
import { getPostList } from '@/api/system/post';
|
||||
import { mapGetters } from 'vuex';
|
||||
import website from '@/config/website';
|
||||
import { getToken } from '@/utils/auth';
|
||||
import { downloadXls } from '@/utils/util';
|
||||
import NProgress from 'nprogress';
|
||||
import 'nprogress/nprogress.css';
|
||||
import func from '@/utils/func';
|
||||
import { sensitive } from '@/utils/sensitive';
|
||||
import { excelOption, platformFormOption, treeOption, userOption } from '@/option/system/user';
|
||||
import AuthLog from './authlog.vue';
|
||||
import AuthLock from './authlock.vue';
|
||||
|
||||
export default {
|
||||
components: { AuthLog, AuthLock },
|
||||
data() {
|
||||
return {
|
||||
form: {},
|
||||
search: {},
|
||||
sensitiveManager: null,
|
||||
roleBox: false,
|
||||
roleLinked: false,
|
||||
grantUserId: '',
|
||||
excelBox: false,
|
||||
platformBox: false,
|
||||
initFlag: true,
|
||||
auditMode: false,
|
||||
selectionList: [],
|
||||
query: {},
|
||||
loading: true,
|
||||
page: {
|
||||
pageSize: 10,
|
||||
currentPage: 1,
|
||||
total: 0,
|
||||
},
|
||||
props: {
|
||||
label: 'title',
|
||||
value: 'key',
|
||||
},
|
||||
roleGrantList: [],
|
||||
roleTreeObj: [],
|
||||
treeDeptId: '',
|
||||
treeData: [],
|
||||
treeOption: treeOption,
|
||||
userOption: userOption(this),
|
||||
platformFormOption: platformFormOption,
|
||||
data: [],
|
||||
platformForm: {},
|
||||
excelForm: {},
|
||||
excelOption: excelOption,
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
'form.tenantId'() {
|
||||
if (this.form.tenantId !== '' && this.initFlag) {
|
||||
this.initData(this.form.tenantId);
|
||||
}
|
||||
},
|
||||
'excelForm.isCovered'() {
|
||||
if (this.excelForm.isCovered !== '') {
|
||||
const column = this.findColumn(this.excelOption.column, 'excelFile');
|
||||
column.action = `/blade-system/user/import-user?isCovered=${this.excelForm.isCovered}`;
|
||||
}
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['userInfo', 'permission']),
|
||||
permissionList() {
|
||||
return {
|
||||
addBtn: this.validData(this.permission.user_add, false),
|
||||
viewBtn: false,
|
||||
delBtn: false,
|
||||
editBtn: false,
|
||||
};
|
||||
},
|
||||
ids() {
|
||||
let ids = [];
|
||||
this.selectionList.forEach(ele => {
|
||||
ids.push(ele.id);
|
||||
});
|
||||
return ids.join(',');
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
// 非租户模式默认加载管理组数据
|
||||
if (!website.tenantMode) {
|
||||
this.initData(website.tenantId);
|
||||
} else {
|
||||
this.initData();
|
||||
}
|
||||
},
|
||||
created() {
|
||||
// 创建脱敏工具实例
|
||||
this.sensitiveManager = sensitive.create({
|
||||
fields: ['phone', 'email'], // 配置需要脱敏的字段
|
||||
});
|
||||
},
|
||||
methods: {
|
||||
nodeClick(data) {
|
||||
this.treeDeptId = data.id;
|
||||
this.page.currentPage = 1;
|
||||
this.onLoad(this.page);
|
||||
},
|
||||
handleDropdownCommand(command, row, index) {
|
||||
if (command === 'setLeader') {
|
||||
this.handleSetLeader(row);
|
||||
} else if (command === 'grantRole') {
|
||||
this.handleGrantForRow(row);
|
||||
} else if (command === 'authLog') {
|
||||
this.$refs.authLog.openUserAuthLog(row.id, row.name);
|
||||
} else if (command === 'lockUser') {
|
||||
this.$refs.authLock.openLockUser(row.id, row.account);
|
||||
} else if (command === 'platformConfig') {
|
||||
this.handlePlatformForRow(row);
|
||||
} else if (command === 'resetPassword') {
|
||||
this.handleResetForRow(row);
|
||||
} else if (command === 'delete') {
|
||||
this.$refs.crud.rowDel(row, index);
|
||||
}
|
||||
},
|
||||
handleResetForRow(row) {
|
||||
this.$confirm(`确定将账号【${row.account}】的密码重置为初始密码?`, '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
})
|
||||
.then(() => {
|
||||
return resetPassword(row.id);
|
||||
})
|
||||
.then(() => {
|
||||
this.$message({
|
||||
type: 'success',
|
||||
message: '密码重置成功!',
|
||||
});
|
||||
});
|
||||
},
|
||||
handleDataManageCommand(command) {
|
||||
if (command === 'import') {
|
||||
this.handleImport();
|
||||
} else if (command === 'export') {
|
||||
this.handleExport();
|
||||
}
|
||||
},
|
||||
handleSetLeader(row) {
|
||||
const tip = row.isLeader === 1 ? '确定取消用户的主管职务?' : '确定设置用户为主管职务?';
|
||||
const message = row.isLeader === 1 ? '取消主管成功!' : '设置主管成功!';
|
||||
this.$confirm(tip, {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
})
|
||||
.then(() => {
|
||||
return setLeader(row.id);
|
||||
})
|
||||
.then(() => {
|
||||
this.$message({
|
||||
type: 'success',
|
||||
message: message,
|
||||
});
|
||||
this.onLoad(this.page);
|
||||
});
|
||||
},
|
||||
initData(tenantId) {
|
||||
getRoleTree(tenantId).then(res => {
|
||||
const column = this.findColumn(this.userOption.group, 'roleId');
|
||||
column.dicData = res.data.data;
|
||||
});
|
||||
getDeptTree(tenantId).then(res => {
|
||||
const column = this.findColumn(this.userOption.group, 'deptId');
|
||||
column.dicData = res.data.data;
|
||||
});
|
||||
getPostList(tenantId).then(res => {
|
||||
const column = this.findColumn(this.userOption.group, 'postId');
|
||||
column.dicData = res.data.data;
|
||||
});
|
||||
getLeaderList(tenantId).then(res => {
|
||||
const column = this.findColumn(this.userOption.group, 'leaderId');
|
||||
column.dicData = res.data.data;
|
||||
});
|
||||
},
|
||||
submitRole() {
|
||||
const roleList = this.$refs.treeRole.getCheckedKeys().join(',');
|
||||
grant(this.grantUserId, roleList).then(() => {
|
||||
this.roleBox = false;
|
||||
this.$message({
|
||||
type: 'success',
|
||||
message: '操作成功!',
|
||||
});
|
||||
this.onLoad(this.page);
|
||||
});
|
||||
},
|
||||
rowSave(row, done, loading) {
|
||||
row.deptId = func.join(row.deptId);
|
||||
row.roleId = func.join(row.roleId);
|
||||
row.postId = func.join(row.postId);
|
||||
row.leaderId = func.join(row.leaderId);
|
||||
add(row).then(
|
||||
() => {
|
||||
this.initFlag = false;
|
||||
this.onLoad(this.page);
|
||||
this.$message({
|
||||
type: 'success',
|
||||
message: '操作成功!',
|
||||
});
|
||||
done();
|
||||
},
|
||||
error => {
|
||||
window.console.log(error);
|
||||
loading();
|
||||
}
|
||||
);
|
||||
},
|
||||
rowUpdate(row, index, done, loading) {
|
||||
row.deptId = func.join(row.deptId);
|
||||
row.roleId = func.join(row.roleId);
|
||||
row.postId = func.join(row.postId);
|
||||
row.leaderId = func.join(row.leaderId);
|
||||
// 获取需要提交的数据
|
||||
const submitData = this.sensitiveManager.getSubmitData(row);
|
||||
update(submitData).then(
|
||||
() => {
|
||||
this.initFlag = false;
|
||||
this.onLoad(this.page);
|
||||
this.$message({
|
||||
type: 'success',
|
||||
message: '操作成功!',
|
||||
});
|
||||
done();
|
||||
},
|
||||
error => {
|
||||
window.console.log(error);
|
||||
loading();
|
||||
}
|
||||
);
|
||||
},
|
||||
rowDel(row) {
|
||||
this.$confirm('确定将选择数据删除?', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
})
|
||||
.then(() => {
|
||||
return remove(row.id);
|
||||
})
|
||||
.then(() => {
|
||||
this.onLoad(this.page);
|
||||
this.$message({
|
||||
type: 'success',
|
||||
message: '操作成功!',
|
||||
});
|
||||
});
|
||||
},
|
||||
searchReset() {
|
||||
this.query = {};
|
||||
this.treeDeptId = '';
|
||||
this.onLoad(this.page);
|
||||
},
|
||||
searchChange(params, done) {
|
||||
this.query = params;
|
||||
this.page.currentPage = 1;
|
||||
this.onLoad(this.page, params);
|
||||
done();
|
||||
},
|
||||
selectionChange(list) {
|
||||
this.selectionList = list;
|
||||
},
|
||||
selectionClear() {
|
||||
this.selectionList = [];
|
||||
this.$refs.crud.toggleSelection();
|
||||
},
|
||||
handleDelete() {
|
||||
if (this.selectionList.length === 0) {
|
||||
this.$message.warning('请选择至少一条数据');
|
||||
return;
|
||||
}
|
||||
this.$confirm('确定将选择数据删除?', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
})
|
||||
.then(() => {
|
||||
return remove(this.ids);
|
||||
})
|
||||
.then(() => {
|
||||
this.onLoad(this.page);
|
||||
this.$message({
|
||||
type: 'success',
|
||||
message: '操作成功!',
|
||||
});
|
||||
this.$refs.crud.toggleSelection();
|
||||
});
|
||||
},
|
||||
handleAudit() {
|
||||
this.auditMode = true;
|
||||
this.onLoad(this.page, this.query);
|
||||
},
|
||||
handleAuditPass() {
|
||||
if (this.selectionList.length === 0) {
|
||||
this.$message.warning('请选择至少一条数据');
|
||||
return;
|
||||
}
|
||||
this.$confirm('确定将选择数据通过审核?', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
})
|
||||
.then(() => {
|
||||
return auditPass(this.ids);
|
||||
})
|
||||
.then(() => {
|
||||
this.onLoad(this.page);
|
||||
this.$message({
|
||||
type: 'success',
|
||||
message: '操作成功!',
|
||||
});
|
||||
this.$refs.crud.toggleSelection();
|
||||
});
|
||||
},
|
||||
handleAuditRefuse() {
|
||||
if (this.selectionList.length === 0) {
|
||||
this.$message.warning('请选择至少一条数据');
|
||||
return;
|
||||
}
|
||||
this.$confirm('确定将选择数据拒绝审核?', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
})
|
||||
.then(() => {
|
||||
return auditRefuse(this.ids);
|
||||
})
|
||||
.then(() => {
|
||||
this.onLoad(this.page);
|
||||
this.$message({
|
||||
type: 'success',
|
||||
message: '操作成功!',
|
||||
});
|
||||
this.$refs.crud.toggleSelection();
|
||||
});
|
||||
},
|
||||
handleAuditBack() {
|
||||
this.auditMode = false;
|
||||
this.onLoad(this.page, this.query);
|
||||
},
|
||||
handleReset() {
|
||||
if (this.selectionList.length === 0) {
|
||||
this.$message.warning('请选择至少一条数据');
|
||||
return;
|
||||
}
|
||||
this.$confirm('确定将选择账号密码重置为初始密码?', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
})
|
||||
.then(() => {
|
||||
return resetPassword(this.ids);
|
||||
})
|
||||
.then(() => {
|
||||
this.$message({
|
||||
type: 'success',
|
||||
message: '操作成功!',
|
||||
});
|
||||
this.$refs.crud.toggleSelection();
|
||||
});
|
||||
},
|
||||
handleGrant() {
|
||||
if (this.selectionList.length === 0) {
|
||||
this.$message.warning('请选择至少一条数据');
|
||||
return;
|
||||
}
|
||||
this.roleTreeObj = [];
|
||||
this.roleLinked = false;
|
||||
this.grantUserId = this.ids;
|
||||
if (this.selectionList.length === 1) {
|
||||
this.roleTreeObj = this.selectionList[0].roleId.split(',');
|
||||
}
|
||||
getRoleTree().then(res => {
|
||||
this.roleGrantList = res.data.data;
|
||||
this.roleBox = true;
|
||||
this.$nextTick(() => this.applyCheckedKeys('treeRole', this.roleTreeObj));
|
||||
});
|
||||
},
|
||||
handleGrantForRow(row) {
|
||||
this.roleTreeObj = row.roleId ? row.roleId.split(',') : [];
|
||||
this.roleLinked = false;
|
||||
this.grantUserId = row.id;
|
||||
getRoleTree().then(res => {
|
||||
this.roleGrantList = res.data.data;
|
||||
this.roleBox = true;
|
||||
this.$nextTick(() => this.applyCheckedKeys('treeRole', this.roleTreeObj));
|
||||
});
|
||||
},
|
||||
getAllNodeKeys(nodes) {
|
||||
let keys = [];
|
||||
nodes.forEach(node => {
|
||||
keys.push(node.id);
|
||||
if (node.children && node.children.length > 0) {
|
||||
keys = keys.concat(this.getAllNodeKeys(node.children));
|
||||
}
|
||||
});
|
||||
return keys;
|
||||
},
|
||||
getLeafKeys(nodes) {
|
||||
let keys = [];
|
||||
nodes.forEach(node => {
|
||||
if (!node.children || node.children.length === 0) {
|
||||
keys.push(node.id);
|
||||
} else {
|
||||
keys = keys.concat(this.getLeafKeys(node.children));
|
||||
}
|
||||
});
|
||||
return keys;
|
||||
},
|
||||
handleSelectAll(treeRef, dataList) {
|
||||
const tree = this.$refs[treeRef];
|
||||
if (!tree) return;
|
||||
const allKeys = this.getAllNodeKeys(dataList);
|
||||
tree.setCheckedKeys(allKeys);
|
||||
},
|
||||
handleInvertSelect(treeRef, dataList, isLinked) {
|
||||
const tree = this.$refs[treeRef];
|
||||
if (!tree) return;
|
||||
const checkedKeys = new Set(tree.getCheckedKeys());
|
||||
if (isLinked) {
|
||||
const leafKeys = this.getLeafKeys(dataList);
|
||||
const invertedKeys = leafKeys.filter(key => !checkedKeys.has(key));
|
||||
tree.setCheckedKeys(invertedKeys);
|
||||
} else {
|
||||
const allKeys = this.getAllNodeKeys(dataList);
|
||||
const invertedKeys = allKeys.filter(key => !checkedKeys.has(key));
|
||||
tree.setCheckedKeys(invertedKeys);
|
||||
}
|
||||
},
|
||||
handleLinkedChange(treeRef) {
|
||||
const tree = this.$refs[treeRef];
|
||||
if (!tree) return;
|
||||
const checkedKeys = tree.getCheckedKeys();
|
||||
const halfCheckedKeys = tree.getHalfCheckedKeys();
|
||||
this.$nextTick(() => {
|
||||
tree.setCheckedKeys([...checkedKeys, ...halfCheckedKeys]);
|
||||
});
|
||||
},
|
||||
// el-tree 会把 setCheckedKeys 的入参记录为默认勾选集并在树数据重载时回放,
|
||||
// 复用的树实例需在打开配置时整体覆盖勾选状态,避免残留上一次配置的勾选
|
||||
applyCheckedKeys(treeRef, keys) {
|
||||
const tree = this.$refs[treeRef];
|
||||
if (!tree) return;
|
||||
tree.setCheckedKeys(keys);
|
||||
},
|
||||
// ========== 平台配置(行级别) ==========
|
||||
handlePlatformForRow(row) {
|
||||
getUserPlatform(row.id).then(res => {
|
||||
this.platformForm = { ...res.data.data, account: row.account };
|
||||
this.platformBox = true;
|
||||
});
|
||||
},
|
||||
submitPlatformConfig() {
|
||||
updatePlatform(
|
||||
this.platformForm.id,
|
||||
this.platformForm.userType,
|
||||
this.platformForm.userExt
|
||||
).then(() => {
|
||||
this.platformBox = false;
|
||||
this.$message({ type: 'success', message: '操作成功!' });
|
||||
});
|
||||
},
|
||||
handleImport() {
|
||||
this.excelBox = true;
|
||||
},
|
||||
uploadAfter(res, done, loading, column) {
|
||||
window.console.log(column);
|
||||
this.excelBox = false;
|
||||
this.refreshChange();
|
||||
done();
|
||||
},
|
||||
handleExport() {
|
||||
const account = func.toStr(this.search.account);
|
||||
const realName = func.toStr(this.search.realName);
|
||||
this.$confirm('是否导出用户数据?', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
}).then(() => {
|
||||
NProgress.start();
|
||||
exportBlob(
|
||||
`/blade-system/user/export-user?${
|
||||
this.website.tokenHeader
|
||||
}=${getToken()}&account=${account}&realName=${realName}`
|
||||
).then(res => {
|
||||
downloadXls(res.data, `用户数据表${this.$dayjs().format('YYYY-MM-DD')}.xlsx`);
|
||||
NProgress.done();
|
||||
});
|
||||
});
|
||||
},
|
||||
handleTemplate() {
|
||||
exportBlob(
|
||||
`/blade-system/user/export-template?${this.website.tokenHeader}=${getToken()}`
|
||||
).then(res => {
|
||||
downloadXls(res.data, '用户数据模板.xlsx');
|
||||
});
|
||||
},
|
||||
beforeOpen(done, type) {
|
||||
if (['edit', 'view'].includes(type)) {
|
||||
getUser(this.form.id).then(res => {
|
||||
this.form = res.data.data;
|
||||
if (this.form.hasOwnProperty('deptId')) {
|
||||
this.form.deptId = func.split(this.form.deptId);
|
||||
}
|
||||
if (this.form.hasOwnProperty('roleId')) {
|
||||
this.form.roleId = func.split(this.form.roleId);
|
||||
}
|
||||
if (this.form.hasOwnProperty('postId')) {
|
||||
this.form.postId = func.split(this.form.postId);
|
||||
}
|
||||
if (this.form.hasOwnProperty('leaderId')) {
|
||||
this.form.leaderId = func.split(this.form.leaderId);
|
||||
}
|
||||
if (this.form.sex === -1) {
|
||||
this.form.sex = '';
|
||||
}
|
||||
// 保存初始脱敏数据
|
||||
this.sensitiveManager.saveInitialData(this.form);
|
||||
});
|
||||
}
|
||||
this.initFlag = true;
|
||||
done();
|
||||
},
|
||||
currentChange(currentPage) {
|
||||
this.page.currentPage = currentPage;
|
||||
},
|
||||
sizeChange(pageSize) {
|
||||
this.page.pageSize = pageSize;
|
||||
},
|
||||
refreshChange() {
|
||||
this.onLoad(this.page, this.query);
|
||||
},
|
||||
onLoad(page, params = {}) {
|
||||
this.loading = true;
|
||||
getList(
|
||||
page.currentPage,
|
||||
page.pageSize,
|
||||
Object.assign(params, this.query, { status: this.auditMode ? 0 : 1 }),
|
||||
this.treeDeptId
|
||||
).then(res => {
|
||||
const data = res.data.data;
|
||||
this.page.total = data.total;
|
||||
this.data = data.records;
|
||||
this.loading = false;
|
||||
this.selectionClear();
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.box {
|
||||
height: 800px;
|
||||
}
|
||||
|
||||
.el-scrollbar {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.box .el-scrollbar__wrap {
|
||||
overflow: scroll;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,485 @@
|
||||
<template>
|
||||
<div>
|
||||
<basic-container>
|
||||
<el-tabs v-model="activeTab" @tab-change="handleTabChange">
|
||||
<!-- 个人信息 Tab -->
|
||||
<el-tab-pane label="个人信息" name="info">
|
||||
<el-form ref="infoForm" :model="infoForm" label-width="100px">
|
||||
<el-form-item label="头像">
|
||||
<div class="avatar-upload-container">
|
||||
<div class="avatar-wrapper" v-if="infoForm.avatar">
|
||||
<img :src="infoForm.avatar" alt="用户头像" class="avatar" />
|
||||
<div class="avatar-overlay">
|
||||
<el-icon class="avatar-action" @click="previewAvatar"><View /></el-icon>
|
||||
<el-icon class="avatar-action" @click="deleteAvatar"><Delete /></el-icon>
|
||||
</div>
|
||||
</div>
|
||||
<el-upload
|
||||
v-else
|
||||
class="avatar-uploader"
|
||||
action="/api/blade-resource/oss/endpoint/put-file"
|
||||
:headers="uploadHeaders"
|
||||
:show-file-list="false"
|
||||
:on-success="handleAvatarSuccess"
|
||||
:before-upload="beforeAvatarUpload"
|
||||
accept=".jpg,.jpeg,.png,.gif"
|
||||
>
|
||||
<el-icon class="avatar-uploader-icon"><Plus /></el-icon>
|
||||
</el-upload>
|
||||
<div class="el-upload__tip">支持 JPG/PNG/GIF 格式,文件大小不超过 1MB</div>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="姓名">
|
||||
<el-input v-model="infoForm.realName" placeholder="请输入姓名">
|
||||
<template #prefix>
|
||||
<el-icon><Bell /></el-icon>
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="用户名">
|
||||
<el-input v-model="infoForm.name" placeholder="请输入用户名">
|
||||
<template #prefix>
|
||||
<el-icon><User /></el-icon>
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="手机号">
|
||||
<el-input v-model="infoForm.phone" placeholder="请输入手机号">
|
||||
<template #prefix>
|
||||
<el-icon><Iphone /></el-icon>
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="邮箱">
|
||||
<el-input v-model="infoForm.email" placeholder="请输入邮箱">
|
||||
<template #prefix>
|
||||
<el-icon><Message /></el-icon>
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<div class="button-group">
|
||||
<el-button type="primary" @click="submitInfo" :loading="loading">
|
||||
<el-icon><Check /></el-icon>
|
||||
<span>提交</span>
|
||||
</el-button>
|
||||
<el-button @click="resetForm">
|
||||
<el-icon><RefreshRight /></el-icon>
|
||||
<span>清空</span>
|
||||
</el-button>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-tab-pane>
|
||||
|
||||
<!-- 修改密码 Tab -->
|
||||
<el-tab-pane label="修改密码" name="password">
|
||||
<el-form ref="passwordForm" :model="passwordForm" label-width="100px">
|
||||
<el-form-item label="原密码">
|
||||
<el-input
|
||||
v-model="passwordForm.oldPassword"
|
||||
type="password"
|
||||
placeholder="请输入原密码"
|
||||
show-password
|
||||
>
|
||||
<template #prefix>
|
||||
<el-icon><Lock /></el-icon>
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="新密码">
|
||||
<el-input
|
||||
v-model="passwordForm.newPassword"
|
||||
type="password"
|
||||
placeholder="请输入新密码"
|
||||
show-password
|
||||
>
|
||||
<template #prefix>
|
||||
<el-icon><Lock /></el-icon>
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="确认密码">
|
||||
<el-input
|
||||
v-model="passwordForm.newPassword1"
|
||||
type="password"
|
||||
placeholder="请确认新密码"
|
||||
show-password
|
||||
>
|
||||
<template #prefix>
|
||||
<el-icon><Lock /></el-icon>
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<div class="button-group">
|
||||
<el-button type="primary" @click="submitPassword" :loading="loading">
|
||||
<el-icon><Check /></el-icon>
|
||||
<span>提交</span>
|
||||
</el-button>
|
||||
<el-button @click="resetForm">
|
||||
<el-icon><RefreshRight /></el-icon>
|
||||
<span>清空</span>
|
||||
</el-button>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</basic-container>
|
||||
<!-- 头像预览组件 -->
|
||||
<el-image-viewer
|
||||
v-if="showAvatarPreview"
|
||||
:url-list="avatarPreviewList"
|
||||
:initial-index="0"
|
||||
:hide-on-click-modal="true"
|
||||
:teleported="true"
|
||||
@close="showAvatarPreview = false"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getUserInfo, updateInfo, updatePassword } from '@/api/system/user';
|
||||
import md5 from 'js-md5';
|
||||
import { sensitive } from '@/utils/sensitive';
|
||||
import {
|
||||
Plus,
|
||||
Bell,
|
||||
User,
|
||||
Iphone,
|
||||
Message,
|
||||
Lock,
|
||||
Check,
|
||||
RefreshRight,
|
||||
View,
|
||||
Delete,
|
||||
} from '@element-plus/icons-vue';
|
||||
import { ElImageViewer } from 'element-plus';
|
||||
import { getToken } from '@/utils/auth';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
ElImageViewer,
|
||||
Plus,
|
||||
Bell,
|
||||
User,
|
||||
Iphone,
|
||||
Message,
|
||||
Lock,
|
||||
Check,
|
||||
RefreshRight,
|
||||
View,
|
||||
Delete,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
activeTab: 'info',
|
||||
loading: false,
|
||||
infoForm: {
|
||||
id: '',
|
||||
avatar: '',
|
||||
name: '',
|
||||
realName: '',
|
||||
phone: '',
|
||||
email: '',
|
||||
},
|
||||
passwordForm: {
|
||||
oldPassword: '',
|
||||
newPassword: '',
|
||||
newPassword1: '',
|
||||
},
|
||||
sensitiveManager: null,
|
||||
showAvatarPreview: false,
|
||||
avatarPreviewList: [],
|
||||
uploadHeaders: {
|
||||
'Blade-Auth': `bearer ${getToken()}`,
|
||||
'Blade-Requested-With': 'BladeHttpRequest',
|
||||
},
|
||||
};
|
||||
},
|
||||
created() {
|
||||
// 初始化脱敏工具
|
||||
this.sensitiveManager = sensitive.create({
|
||||
fields: ['phone', 'email'],
|
||||
});
|
||||
// 初始化时根据默认tab加载数据
|
||||
if (this.activeTab === 'info') {
|
||||
this.loadUserInfo();
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
// Tab切换处理
|
||||
handleTabChange(name) {
|
||||
if (name === 'info') {
|
||||
this.loadUserInfo();
|
||||
}
|
||||
},
|
||||
// 加载用户信息
|
||||
loadUserInfo() {
|
||||
getUserInfo().then(res => {
|
||||
const user = res.data.data;
|
||||
this.infoForm = {
|
||||
id: user.id,
|
||||
avatar: user.avatar,
|
||||
name: user.name,
|
||||
realName: user.realName,
|
||||
phone: user.phone,
|
||||
email: user.email,
|
||||
};
|
||||
// 保存初始脱敏数据
|
||||
this.sensitiveManager.saveInitialData(this.infoForm);
|
||||
});
|
||||
},
|
||||
// 提交个人信息
|
||||
submitInfo() {
|
||||
this.loading = true;
|
||||
const submitData = this.sensitiveManager.getSubmitData(this.infoForm);
|
||||
updateInfo(submitData).then(
|
||||
res => {
|
||||
if (res.data.success) {
|
||||
this.$message({
|
||||
type: 'success',
|
||||
message: '修改信息成功!',
|
||||
});
|
||||
} else {
|
||||
this.$message({
|
||||
type: 'error',
|
||||
message: res.data.msg,
|
||||
});
|
||||
}
|
||||
this.loading = false;
|
||||
},
|
||||
error => {
|
||||
window.console.log(error);
|
||||
this.loading = false;
|
||||
}
|
||||
);
|
||||
},
|
||||
// 提交密码修改
|
||||
submitPassword() {
|
||||
this.loading = true;
|
||||
updatePassword(
|
||||
md5(this.passwordForm.oldPassword),
|
||||
md5(this.passwordForm.newPassword),
|
||||
md5(this.passwordForm.newPassword1)
|
||||
).then(
|
||||
res => {
|
||||
if (res.data.success) {
|
||||
this.$message({
|
||||
type: 'success',
|
||||
message: '修改密码成功!',
|
||||
});
|
||||
// 清空密码表单
|
||||
this.passwordForm = {
|
||||
oldPassword: '',
|
||||
newPassword: '',
|
||||
newPassword1: '',
|
||||
};
|
||||
} else {
|
||||
this.$message({
|
||||
type: 'error',
|
||||
message: res.data.msg,
|
||||
});
|
||||
}
|
||||
this.loading = false;
|
||||
},
|
||||
error => {
|
||||
window.console.log(error);
|
||||
this.loading = false;
|
||||
}
|
||||
);
|
||||
},
|
||||
// 头像上传成功处理
|
||||
handleAvatarSuccess(response) {
|
||||
if (response && response.data) {
|
||||
this.infoForm.avatar = response.data.link || response.data;
|
||||
}
|
||||
},
|
||||
// 头像上传前验证
|
||||
beforeAvatarUpload(file) {
|
||||
const isValidType = ['image/jpeg', 'image/png', 'image/gif'].includes(file.type);
|
||||
const isLt1M = file.size / 1024 < 1024;
|
||||
|
||||
if (!isValidType) {
|
||||
this.$message.error('上传头像只支持 JPG/PNG/GIF 格式!');
|
||||
}
|
||||
if (!isLt1M) {
|
||||
this.$message.error('上传头像大小不能超过 1MB!');
|
||||
}
|
||||
return isValidType && isLt1M;
|
||||
},
|
||||
// 重置表单
|
||||
resetForm() {
|
||||
if (this.activeTab === 'info') {
|
||||
// 清空个人信息表单,但保留id
|
||||
const id = this.infoForm.id;
|
||||
this.infoForm = {
|
||||
id: id,
|
||||
avatar: '',
|
||||
name: '',
|
||||
realName: '',
|
||||
phone: '',
|
||||
email: '',
|
||||
};
|
||||
} else if (this.activeTab === 'password') {
|
||||
// 清空密码表单
|
||||
this.passwordForm = {
|
||||
oldPassword: '',
|
||||
newPassword: '',
|
||||
newPassword1: '',
|
||||
};
|
||||
}
|
||||
},
|
||||
// 预览头像
|
||||
previewAvatar() {
|
||||
if (this.infoForm.avatar) {
|
||||
this.avatarPreviewList = [this.infoForm.avatar];
|
||||
this.showAvatarPreview = true;
|
||||
} else {
|
||||
this.$message.warning('暂无头像可预览');
|
||||
}
|
||||
},
|
||||
// 删除头像
|
||||
deleteAvatar() {
|
||||
this.$confirm('确定要删除头像吗?', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
})
|
||||
.then(() => {
|
||||
this.infoForm.avatar = '';
|
||||
this.$message.success('头像已删除');
|
||||
})
|
||||
.catch(() => {});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.avatar-upload-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.avatar-wrapper {
|
||||
position: relative;
|
||||
width: 200px;
|
||||
height: 200px;
|
||||
border-radius: 12px;
|
||||
overflow: hidden;
|
||||
cursor: pointer;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||
transition: box-shadow 0.3s ease, transform 0.3s ease;
|
||||
}
|
||||
|
||||
.avatar-wrapper:hover {
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
.avatar-wrapper .avatar {
|
||||
width: 200px;
|
||||
height: 200px;
|
||||
display: block;
|
||||
border-radius: 12px;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.avatar-overlay {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: linear-gradient(180deg, rgba(0, 0, 0, 0.3) 0%, rgba(0, 0, 0, 0.6) 100%);
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
gap: 20px;
|
||||
opacity: 0;
|
||||
transition: opacity 0.3s ease;
|
||||
backdrop-filter: blur(2px);
|
||||
}
|
||||
|
||||
.avatar-wrapper:hover .avatar-overlay {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.avatar-action {
|
||||
font-size: 20px;
|
||||
color: #fff;
|
||||
cursor: pointer;
|
||||
padding: 8px;
|
||||
border-radius: 50%;
|
||||
background-color: rgba(255, 255, 255, 0.2);
|
||||
transition: all 0.3s ease;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.avatar-action:hover {
|
||||
background-color: rgba(255, 255, 255, 0.3);
|
||||
transform: scale(1.1);
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
.avatar-uploader :deep(.el-upload) {
|
||||
border: 2px dashed #d9d9d9;
|
||||
border-radius: 12px;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
transition: all 0.3s ease;
|
||||
width: 200px;
|
||||
height: 200px;
|
||||
background-color: #fafafa;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.avatar-uploader :deep(.el-upload:hover) {
|
||||
border-color: var(--el-color-primary);
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
|
||||
.avatar-uploader-icon {
|
||||
font-size: 40px;
|
||||
color: #8c939d;
|
||||
transition: color 0.3s ease;
|
||||
}
|
||||
|
||||
.avatar-uploader :deep(.el-upload:hover) .avatar-uploader-icon {
|
||||
color: var(--el-color-primary);
|
||||
}
|
||||
|
||||
.el-upload__tip {
|
||||
font-size: 12px;
|
||||
color: #969799;
|
||||
margin-top: 10px;
|
||||
line-height: 1.5;
|
||||
padding-left: 4px;
|
||||
}
|
||||
|
||||
.button-group {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
gap: 16px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
@keyframes fadeIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(10px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user