mirror of
https://github.com/nsnail/NetAdmin.git
synced 2025-07-05 10:08:15 +08:00
feat: ✨ 框架代码同步 (#148)
[skip ci] Co-authored-by: tk <fiyne1a@dingtalk.com>
This commit is contained in:
@ -68,7 +68,7 @@
|
||||
}
|
||||
|
||||
.app-loading__title {
|
||||
font-family: 'Arial', 'Microsoft YaHei', 'monospace';
|
||||
font-family: 'Microsoft YaHei', sans-serif;
|
||||
font-size: 24px;
|
||||
color: #333;
|
||||
margin-top: 30px;
|
||||
@ -125,7 +125,7 @@
|
||||
|
||||
<script type="text/javascript">
|
||||
// 黑夜模式
|
||||
if (window.localStorage.getItem('APP_DARK')) {
|
||||
if (window.localStorage.getItem('APP_SET_DARK')) {
|
||||
document.documentElement.classList.add('dark')
|
||||
}
|
||||
|
||||
|
@ -43,8 +43,17 @@ export default {
|
||||
},
|
||||
},
|
||||
async created() {
|
||||
await this.$TOOL.data.downloadConfig()
|
||||
|
||||
//设置深色模式
|
||||
if (this.$TOOL.data.get('APP_SET_DARK') || this.$CONFIG.APP_SET_DARK) {
|
||||
document.documentElement.classList.add('dark')
|
||||
} else {
|
||||
document.documentElement.classList.remove('dark')
|
||||
}
|
||||
|
||||
//设置主题颜色
|
||||
const app_color = this.$TOOL.data.get('APP_COLOR') ?? this.$CONFIG.COLOR
|
||||
const app_color = this.$TOOL.data.get('APP_SET_COLOR') || this.$CONFIG.APP_SET_COLOR
|
||||
if (app_color) {
|
||||
document.documentElement.style.setProperty('--el-color-primary', app_color)
|
||||
for (let i = 1; i <= 9; i++) {
|
||||
@ -56,28 +65,31 @@ export default {
|
||||
}
|
||||
|
||||
//设置布局
|
||||
const layout = this.$TOOL.data.get('LAYOUT') ?? this.$CONFIG.LAYOUT
|
||||
const layout = this.$TOOL.data.get('APP_SET_LAYOUT') || this.$CONFIG.APP_SET_LAYOUT
|
||||
if (layout) {
|
||||
this.$store.commit('SET_layout', layout)
|
||||
}
|
||||
|
||||
//菜单是否折叠
|
||||
const menuIsCollapse = this.$TOOL.data.get('MENU_IS_COLLAPSE') ?? this.$CONFIG.MENU_IS_COLLAPSE
|
||||
const menuIsCollapse = this.$TOOL.data.get('APP_SET_MENU_IS_COLLAPSE') || this.$CONFIG.APP_SET_MENU_IS_COLLAPSE
|
||||
if (menuIsCollapse !== this.$store.state.global.menuIsCollapse) {
|
||||
this.$store.commit('TOGGLE_menuIsCollapse')
|
||||
}
|
||||
|
||||
//是否开启多标签
|
||||
const layoutTags = this.$TOOL.data.get('LAYOUT_TAGS') ?? this.$CONFIG.LAYOUT_TAGS
|
||||
const layoutTags = this.$TOOL.data.get('APP_SET_MULTI_TAGS') || this.$CONFIG.APP_SET_MULTI_TAGS
|
||||
if (layoutTags !== this.$store.state.global.layoutTags) {
|
||||
this.$store.commit('TOGGLE_layoutTags')
|
||||
}
|
||||
|
||||
//是否开启手风琴菜单
|
||||
const menuUniqueOpened = this.$TOOL.data.get('MENU_UNIQUE_OPENED') ?? this.$CONFIG.MENU_UNIQUE_OPENED
|
||||
if (menuUniqueOpened !== this.$CONFIG.MENU_UNIQUE_OPENED) {
|
||||
this.$CONFIG.MENU_UNIQUE_OPENED = menuUniqueOpened
|
||||
const menuUniqueOpened = this.$TOOL.data.get('APP_SET_MENU_UNIQUE_OPENED') || this.$CONFIG.APP_SET_MENU_UNIQUE_OPENED
|
||||
if (menuUniqueOpened !== this.$CONFIG.APP_SET_MENU_UNIQUE_OPENED) {
|
||||
this.$CONFIG.APP_SET_MENU_UNIQUE_OPENED = menuUniqueOpened
|
||||
}
|
||||
|
||||
// 设置语言
|
||||
this.$i18n.locale = this.$TOOL.data.get('APP_SET_LANG') || this.$CONFIG.APP_SET_LANG
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
@ -103,4 +103,15 @@ export default {
|
||||
return await http.post(this.url, data, config)
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* 设置配置启用状态
|
||||
*/
|
||||
setEnabled: {
|
||||
url: `${config.API_URL}/api/sys/config/set.enabled`,
|
||||
name: `设置配置启用状态`,
|
||||
post: async function (data = {}, config = {}) {
|
||||
return await http.post(this.url, data, config)
|
||||
},
|
||||
},
|
||||
}
|
@ -93,6 +93,17 @@ export default {
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* 设置是否显示仪表板
|
||||
*/
|
||||
setDisplayDashboard: {
|
||||
url: `${config.API_URL}/api/sys/role/set.display.dashboard`,
|
||||
name: `设置是否显示仪表板`,
|
||||
post: async function (data = {}, config = {}) {
|
||||
return await http.post(this.url, data, config)
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* 启用/禁用角色
|
||||
*/
|
||||
@ -103,4 +114,15 @@ export default {
|
||||
return await http.post(this.url, data, config)
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* 设置是否忽略权限控制
|
||||
*/
|
||||
setIgnorePermissionControl: {
|
||||
url: `${config.API_URL}/api/sys/role/set.ignore.permission.control`,
|
||||
name: `设置是否忽略权限控制`,
|
||||
post: async function (data = {}, config = {}) {
|
||||
return await http.post(this.url, data, config)
|
||||
},
|
||||
},
|
||||
}
|
@ -82,6 +82,17 @@ export default {
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* 获取当前用户应用配置
|
||||
*/
|
||||
getSessionUserAppConfig: {
|
||||
url: `${config.API_URL}/api/sys/user/get.session.user.app.config`,
|
||||
name: `获取当前用户应用配置`,
|
||||
post: async function (data = {}, config = {}) {
|
||||
return await http.post(this.url, data, config)
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* 密码登录
|
||||
*/
|
||||
@ -214,6 +225,17 @@ export default {
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* 设置当前用户应用配置
|
||||
*/
|
||||
setSessionUserAppConfig: {
|
||||
url: `${config.API_URL}/api/sys/user/set.session.user.app.config`,
|
||||
name: `设置当前用户应用配置`,
|
||||
post: async function (data = {}, config = {}) {
|
||||
return await http.post(this.url, data, config)
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* 当前用户信息
|
||||
*/
|
||||
|
@ -1,25 +0,0 @@
|
||||
<template>
|
||||
<el-button @click="add" icon="el-icon-plus" type="primary"></el-button>
|
||||
</template>
|
||||
<style scoped></style>
|
||||
<script>
|
||||
export default {
|
||||
emits: [],
|
||||
props: { vue: { type: Object }, data: { type: Object } },
|
||||
data() {
|
||||
return {}
|
||||
},
|
||||
mounted() {},
|
||||
created() {},
|
||||
components: {},
|
||||
computed: {},
|
||||
methods: {
|
||||
//添加
|
||||
async add() {
|
||||
this.vue.dialog.save = true
|
||||
await this.vue.$nextTick()
|
||||
this.vue.$refs.saveDialog.open('add', this.data)
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
@ -1,9 +1,9 @@
|
||||
<template>
|
||||
<el-table-column :label="label" :prop="prop" sortable="custom">
|
||||
<template #default="scope">
|
||||
<template #default="{ row }">
|
||||
<div class="avatar">
|
||||
<el-avatar :src="getAvatar(scope, prop)" size="small"></el-avatar>
|
||||
<span>{{ tool.getNestedProperty(scope.row, prop) }}</span>
|
||||
<el-avatar :src="getAvatar(row, prop)" size="small"></el-avatar>
|
||||
<span>{{ tool.getNestedProperty(row, prop) }}</span>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
@ -36,8 +36,8 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
//获取头像
|
||||
getAvatar(scope, prop) {
|
||||
return scope.row.avatar ? scope.row.avatar : this.$CONFIG.DEFAULT_AVATAR(tool.getNestedProperty(scope.row, prop))
|
||||
getAvatar(row, prop) {
|
||||
return row.avatar ? row.avatar : this.$CONFIG.DEFAULT_AVATAR(tool.getNestedProperty(row, prop))
|
||||
},
|
||||
},
|
||||
}
|
||||
|
@ -1,33 +1,33 @@
|
||||
<template>
|
||||
<el-table-column v-bind="$attrs">
|
||||
<template #default="scope">
|
||||
<el-text @click="click(scope.row)" style="cursor: pointer" tag="ins">
|
||||
{{ tool.getNestedProperty(scope.row, $attrs.prop) }}
|
||||
</el-text>
|
||||
<template #default="{ row }">
|
||||
<p>{{ row.id }}</p>
|
||||
<p v-if="showTime" class="time">{{ row.createdTime }}</p>
|
||||
<slot :data="row"></slot>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</template>
|
||||
<script>
|
||||
import tool from '@/utils/tool'
|
||||
export default {
|
||||
emits: ['click'],
|
||||
props: {},
|
||||
emits: [],
|
||||
props: {
|
||||
showTime: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {}
|
||||
},
|
||||
mounted() {},
|
||||
created() {},
|
||||
components: {},
|
||||
computed: {
|
||||
tool() {
|
||||
return tool
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
async click(row) {
|
||||
this.$emit('click', row)
|
||||
},
|
||||
},
|
||||
computed: {},
|
||||
methods: {},
|
||||
}
|
||||
</script>
|
||||
<style scoped></style>
|
||||
<style scoped>
|
||||
.time {
|
||||
color: var(--el-text-color-secondary);
|
||||
}
|
||||
</style>
|
@ -2,6 +2,7 @@
|
||||
<el-table-column v-bind:="$attrs">
|
||||
<template #default="{ row }">
|
||||
<na-indicator :data="row" :options="options" :prop="$attrs.prop" />
|
||||
<slot :data="row" name="info"></slot>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</template>
|
||||
|
@ -1,31 +1,23 @@
|
||||
<template>
|
||||
<el-table-column align="right">
|
||||
<template #default="scope">
|
||||
<template #default="{ row }">
|
||||
<el-button-group>
|
||||
<template v-for="(item, i) in buttons?.filter((x) => !x.condition || x.condition(scope))" :key="i">
|
||||
<template v-for="(item, i) in buttons?.filter((x) => !x.condition || x.condition(row))" :key="i">
|
||||
<el-popconfirm
|
||||
v-if="item.confirm"
|
||||
:title="this.$t(`确定 {title}?`, { title: item.title })"
|
||||
@confirm="item.click(scope.row, vue)"
|
||||
@confirm="item.click(row, vue)"
|
||||
width="20rem">
|
||||
<template #reference>
|
||||
<el-button :icon="item.icon" :title="item.title" :type="item.type" @click.native.stop size="small"></el-button>
|
||||
</template>
|
||||
</el-popconfirm>
|
||||
<el-button v-else :icon="item.icon" :title="item.title" @click="item.click(scope.row, vue)" size="small"
|
||||
>{{ item.title }}
|
||||
</el-button>
|
||||
<el-button v-else :icon="item.icon" :title="item.title" @click="item.click(row, vue)" size="small">{{ item.title }} </el-button>
|
||||
</template>
|
||||
</el-button-group>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</template>
|
||||
<style scoped>
|
||||
.avatar {
|
||||
display: flex;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
import naColOperation from '@/config/naColOperation'
|
||||
|
||||
@ -48,4 +40,5 @@ export default {
|
||||
computed: {},
|
||||
methods: {},
|
||||
}
|
||||
</script>
|
||||
</script>
|
||||
<style scoped></style>
|
@ -1,15 +1,16 @@
|
||||
<template>
|
||||
<el-table-column :label="label" :prop="`${prop}.${field}`">
|
||||
<template #default="scope">
|
||||
<template v-for="(item, i) in Array.isArray(scope.row[prop]) ? scope.row[prop] : [scope.row[prop]]" :key="i">
|
||||
<el-tag v-if="item" @click="$emit('click', item)">
|
||||
{{ item ? item[field] : '' }}
|
||||
</el-tag>
|
||||
</template>
|
||||
<template #default="{ row }">
|
||||
<div class="flex">
|
||||
<template v-for="(item, i) in Array.isArray(row[prop]) ? row[prop] : [row[prop]]" :key="i">
|
||||
<el-tag v-if="item" @click="$emit('click', item)">
|
||||
{{ item ? item[field] : '' }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</template>
|
||||
<style scoped></style>
|
||||
<script>
|
||||
export default {
|
||||
emits: ['click'],
|
||||
@ -27,4 +28,9 @@ export default {
|
||||
computed: {},
|
||||
methods: {},
|
||||
}
|
||||
</script>
|
||||
</script>
|
||||
<style scoped>
|
||||
.el-tag {
|
||||
cursor: pointer;
|
||||
}
|
||||
</style>
|
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<el-table-column :label="label" :prop="prop">
|
||||
<template #default="scope">
|
||||
{{ tool.dateFormat(scope.row[prop]) }}
|
||||
<template #default="{ row }">
|
||||
{{ tool.dateFormat(row[prop]) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
</template>
|
||||
|
@ -1,24 +1,50 @@
|
||||
<template>
|
||||
<el-table-column v-bind="$attrs">
|
||||
<template #default="scope">
|
||||
<div @click="click(tool.getNestedProperty(scope.row, $attrs.prop))" class="avatar">
|
||||
<el-avatar
|
||||
v-if="tool.getNestedProperty(scope.row, $attrs.nestProp)"
|
||||
:src="getAvatar(scope, $attrs.nestProp)"
|
||||
size="small"></el-avatar>
|
||||
<template #default="{ row }">
|
||||
<div @click="click($TOOL.getNestedProperty(row, $attrs.prop))" class="avatar">
|
||||
<el-avatar v-if="$TOOL.getNestedProperty(row, $attrs.nestProp)" :src="getAvatar(row, $attrs.nestProp)" size="small"></el-avatar>
|
||||
<div>
|
||||
<p>{{ tool.getNestedProperty(scope.row, $attrs.nestProp) }}</p>
|
||||
<p v-if="$attrs.nestProp2">{{ tool.getNestedProperty(scope.row, $attrs.nestProp2) }}</p>
|
||||
<p>{{ $TOOL.getNestedProperty(row, $attrs.nestProp) }}</p>
|
||||
<p v-if="$attrs.nestProp2">{{ $TOOL.getNestedProperty(row, $attrs.nestProp2) }}</p>
|
||||
</div>
|
||||
</div>
|
||||
<save-dialog v-if="dialog.save" @closed="dialog.save = false" ref="saveDialog"></save-dialog>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</template>
|
||||
<script>
|
||||
import saveDialog from '@/views/sys/user/save.vue'
|
||||
|
||||
export default {
|
||||
components: { saveDialog },
|
||||
computed: {},
|
||||
created() {},
|
||||
data() {
|
||||
return {
|
||||
dialog: { save: false },
|
||||
}
|
||||
},
|
||||
emits: ['click'],
|
||||
methods: {
|
||||
async click(id) {
|
||||
this.dialog.save = true
|
||||
await this.$nextTick()
|
||||
await this.$refs.saveDialog.open({ mode: 'view', row: { id: id } })
|
||||
},
|
||||
//获取头像
|
||||
getAvatar(row, prop) {
|
||||
return row.avatar ? row.avatar : this.$CONFIG.DEFAULT_AVATAR(this.$TOOL.getNestedProperty(row, prop))
|
||||
},
|
||||
},
|
||||
mounted() {},
|
||||
props: {},
|
||||
watch: {},
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.avatar {
|
||||
div:last-child {
|
||||
line-height: 1rem;
|
||||
line-height: 1.2rem;
|
||||
p:last-child {
|
||||
color: var(--el-color-info-light-3);
|
||||
}
|
||||
@ -29,37 +55,4 @@
|
||||
display: flex;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
import saveDialog from '@/views/sys/user/save.vue'
|
||||
import tool from '@/utils/tool'
|
||||
|
||||
export default {
|
||||
emits: ['click'],
|
||||
props: {},
|
||||
data() {
|
||||
return {
|
||||
dialog: { save: false },
|
||||
}
|
||||
},
|
||||
mounted() {},
|
||||
created() {},
|
||||
components: { saveDialog },
|
||||
computed: {
|
||||
tool() {
|
||||
return tool
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
async click(id) {
|
||||
this.dialog.save = true
|
||||
await this.$nextTick()
|
||||
await this.$refs.saveDialog.open('view', { id: id })
|
||||
},
|
||||
//获取头像
|
||||
getAvatar(scope, prop) {
|
||||
return scope.row.avatar ? scope.row.avatar : this.$CONFIG.DEFAULT_AVATAR(tool.getNestedProperty(scope.row, prop))
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
</style>
|
@ -36,7 +36,8 @@ export default {
|
||||
},
|
||||
mounted() {},
|
||||
async created() {
|
||||
this.options = (await this.$API.sys_dept.query.post()).data
|
||||
const res = await this.$API.sys_dept.query.post()
|
||||
this.options = res.data
|
||||
},
|
||||
components: {},
|
||||
computed: {},
|
||||
|
@ -41,7 +41,8 @@ export default {
|
||||
},
|
||||
mounted() {},
|
||||
async created() {
|
||||
this.options = (await this.$API.sys_dic.queryCatalog.post()).data
|
||||
const res = await this.$API.sys_dic.queryCatalog.post()
|
||||
this.options = res.data
|
||||
},
|
||||
components: {},
|
||||
computed: {},
|
||||
|
@ -82,13 +82,16 @@ export default {
|
||||
async captchaSuccess(obj) {
|
||||
this.sendDisabled = true
|
||||
try {
|
||||
await this.$API.sys_verifycode.sendVerifyCode.post({
|
||||
const res = await this.$API.sys_verifycode.sendVerifyCode.post({
|
||||
destDevice: this.form[Array.isArray(this.phoneField) ? this.phoneField[1] : this.phoneField],
|
||||
type: 'login',
|
||||
deviceType: 'mobile',
|
||||
verifyCaptchaReq: obj,
|
||||
})
|
||||
this.$message.success(this.$t('发送成功'))
|
||||
if (res.data?.code) {
|
||||
this.$message.success(res.data.code.toString())
|
||||
}
|
||||
this.waitSecs = 60
|
||||
const t = setInterval(() => {
|
||||
this.waitSecs -= 1
|
||||
|
@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<template v-for="(item, i) in options" :key="i">
|
||||
<div v-if="tool.getNestedProperty(data, this.prop) === item.value">
|
||||
<div v-if="this.$TOOL.getNestedProperty(data, this.prop)?.toLowerCase() === item.value?.toLowerCase()">
|
||||
<sc-status-indicator
|
||||
:pulse="item.pulse"
|
||||
:style="item.type ? '' : `background: #${Math.abs(this.$TOOL.crypto.hashCode(item.value)).toString(16).substring(0, 6)}`"
|
||||
@ -9,11 +9,8 @@
|
||||
<slot :data="data" :text="item.text"></slot>
|
||||
</div>
|
||||
</template>
|
||||
<slot :data="data" name="info"></slot>
|
||||
</template>
|
||||
<script>
|
||||
import tool from '@/utils/tool'
|
||||
|
||||
export default {
|
||||
emits: [],
|
||||
props: {
|
||||
@ -27,11 +24,7 @@ export default {
|
||||
mounted() {},
|
||||
created() {},
|
||||
components: {},
|
||||
computed: {
|
||||
tool() {
|
||||
return tool
|
||||
},
|
||||
},
|
||||
computed: {},
|
||||
methods: {},
|
||||
}
|
||||
</script>
|
@ -66,7 +66,7 @@
|
||||
<el-button @click="reset" icon="el-icon-refresh-left">{{ $t('重置') }}</el-button>
|
||||
</template>
|
||||
<v-ace-editor
|
||||
:theme="this.$TOOL.data.get('APP_DARK') ? 'github_dark' : 'github'"
|
||||
:theme="this.$TOOL.data.get('APP_SET_DARK') || this.$CONFIG.APP_SET_DARK ? 'github_dark' : 'github'"
|
||||
:value="vkbeautify().json(vue.query, 2)"
|
||||
lang="json"
|
||||
style="height: 20rem; width: 100%" />
|
||||
@ -323,6 +323,7 @@ export default {
|
||||
casLoaded: false,
|
||||
keepKeywords: null,
|
||||
keepCreatedTime: null,
|
||||
keepHttpStatusCode: null,
|
||||
form: {
|
||||
root: {},
|
||||
filter: {},
|
||||
@ -404,6 +405,9 @@ export default {
|
||||
if (this.keepCreatedTime) {
|
||||
this.form.dy.createdTime = this.keepCreatedTime
|
||||
}
|
||||
if (this.keepHttpStatusCode) {
|
||||
this.form.dy.httpStatusCode = this.keepHttpStatusCode
|
||||
}
|
||||
this.$emit('reset')
|
||||
this.search()
|
||||
},
|
||||
|
@ -25,7 +25,7 @@ export default {
|
||||
const contents = []
|
||||
const msg = h('p', { style: 'width:230px;display:flex;justify-content:space-between' }, [
|
||||
h('span', {}, this.$t('即将开始更新……')),
|
||||
h('a', { style: 'color:#409eff', href: 'javascript:window.location.reload()' }, this.$t('立即更新')),
|
||||
h('a', { style: 'color:#21A675', href: 'javascript:window.location.reload()' }, this.$t('立即更新')),
|
||||
])
|
||||
const task = h('p', { style: 'font-weight:bold' }, version)
|
||||
const progress = h(
|
||||
@ -37,7 +37,7 @@ export default {
|
||||
style: {
|
||||
width: '230px',
|
||||
height: '6px',
|
||||
'background-color': '#409eff',
|
||||
'background-color': '#21A675',
|
||||
'margin-top': '6px',
|
||||
'border-radius': '6px',
|
||||
},
|
||||
|
@ -1,5 +1,5 @@
|
||||
const T = {
|
||||
color: ['#409EFF', '#36CE9E', '#f56e6a', '#626c91', '#edb00d', '#909399'],
|
||||
color: ['#21A675', '#36CE9E', '#f56e6a', '#626c91', '#edb00d', '#909399'],
|
||||
grid: {
|
||||
left: '3%',
|
||||
right: '3%',
|
||||
|
@ -8,15 +8,13 @@
|
||||
</el-tag>
|
||||
</el-table-column>
|
||||
<el-table-column :label="$t('列名')" prop="label">
|
||||
<template #default="scope">
|
||||
<el-tag :effect="scope.row.hide ? 'light' : 'dark'" :type="scope.row.hide ? 'info' : ''" disable-transitions round
|
||||
>{{ scope.row.label }}
|
||||
</el-tag>
|
||||
<template #default="{ row }">
|
||||
<el-tag :effect="row.hide ? 'light' : 'dark'" :type="row.hide ? 'info' : ''" disable-transitions round>{{ row.label }} </el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column :label="$t('显示')" prop="hide" width="60">
|
||||
<template #default="scope">
|
||||
<el-switch v-model="scope.row.hide" :active-value="false" :inactive-value="true" size="small" />
|
||||
<template #default="{ row }">
|
||||
<el-switch v-model="row.hide" :active-value="false" :inactive-value="true" size="small" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
@ -440,7 +440,7 @@ export default {
|
||||
}
|
||||
|
||||
.sc-file-select__item__file .item-file.item-file-doc {
|
||||
color: #409eff;
|
||||
color: #21a675;
|
||||
}
|
||||
|
||||
.sc-file-select__item__upload {
|
||||
|
@ -125,7 +125,7 @@ export default {
|
||||
|
||||
.sc-filter-my-list li:hover {
|
||||
background: #ecf5ff;
|
||||
color: #409eff;
|
||||
color: #21a675;
|
||||
}
|
||||
|
||||
.sc-filter-my-list li label {
|
||||
|
@ -53,7 +53,7 @@ export default {
|
||||
.sc-page-header__icon span {
|
||||
width: 2.5rem;
|
||||
height: 2.5rem;
|
||||
background: #409eff;
|
||||
background: #21a675;
|
||||
border-radius: 40%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
@ -76,6 +76,7 @@ export default {
|
||||
}
|
||||
|
||||
.sc-statistic-content-value {
|
||||
font-family: 'Lucida Console', 'Microsoft YaHei', monospace;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
|
@ -43,11 +43,11 @@ export default {
|
||||
files: {
|
||||
doc: {
|
||||
icon: 'sc-icon-file-word-2-fill',
|
||||
color: '#409eff',
|
||||
color: '#21A675',
|
||||
},
|
||||
docx: {
|
||||
icon: 'sc-icon-file-word-2-fill',
|
||||
color: '#409eff',
|
||||
color: '#21A675',
|
||||
},
|
||||
xls: {
|
||||
icon: 'sc-icon-file-excel-2-fill',
|
||||
|
@ -10,57 +10,51 @@ const DEFAULT_CONFIG = {
|
||||
//首页地址
|
||||
DASHBOARD_URL: '/home',
|
||||
|
||||
//版本号
|
||||
APP_VER: '1.0.0',
|
||||
|
||||
//内核版本号
|
||||
CORE_VER: '1.6.9',
|
||||
|
||||
//接口地址
|
||||
API_URL: '',
|
||||
|
||||
//请求超时
|
||||
TIMEOUT: 10000,
|
||||
|
||||
//TokenName
|
||||
TOKEN_NAME: 'Authorization',
|
||||
|
||||
//Token前缀,注意最后有个空格,如不需要需设置空字符串
|
||||
TOKEN_PREFIX: 'Bearer ',
|
||||
|
||||
//追加其他头
|
||||
HEADERS: {},
|
||||
|
||||
//请求是否开启缓存
|
||||
REQUEST_CACHE: false,
|
||||
|
||||
//布局 默认:default | 通栏:header | 经典:menu | 功能坞:dock
|
||||
//dock将关闭标签和面包屑栏
|
||||
LAYOUT: 'menu',
|
||||
|
||||
//菜单是否折叠
|
||||
MENU_IS_COLLAPSE: false,
|
||||
|
||||
//菜单是否启用手风琴效果
|
||||
MENU_UNIQUE_OPENED: false,
|
||||
|
||||
//是否开启多标签
|
||||
LAYOUT_TAGS: true,
|
||||
|
||||
//语言
|
||||
LANG: 'zh-cn',
|
||||
|
||||
//主题颜色
|
||||
COLOR: '#21A675',
|
||||
|
||||
//是否加密localStorage, 为空不加密,可填写AES(模式ECB,移位Pkcs7)加密
|
||||
LS_ENCRYPTION: '',
|
||||
|
||||
//localStorageAES加密秘钥,位数建议填写8的倍数
|
||||
LS_ENCRYPTION_key: '2XNN4K8LC0ELVWN4',
|
||||
|
||||
//控制台首页默认布局
|
||||
DEFAULT_GRID: {
|
||||
//布局 默认:default | 通栏:header | 经典:menu | 功能坞:dock
|
||||
//dock将关闭标签和面包屑栏
|
||||
APP_SET_LAYOUT: 'menu',
|
||||
|
||||
//菜单是否折叠
|
||||
APP_SET_MENU_IS_COLLAPSE: false,
|
||||
|
||||
//菜单是否启用手风琴效果
|
||||
APP_SET_MENU_UNIQUE_OPENED: false,
|
||||
|
||||
//是否开启多标签
|
||||
APP_SET_MULTI_TAGS: true,
|
||||
|
||||
//语言
|
||||
APP_SET_LANG: 'zh-cn',
|
||||
|
||||
//自动退出
|
||||
APP_SET_AUTO_EXIT: 0,
|
||||
|
||||
//深色模式
|
||||
APP_SET_DARK: false,
|
||||
|
||||
//主题颜色
|
||||
APP_SET_COLOR: '#21A675',
|
||||
|
||||
//控制台首页布局
|
||||
APP_SET_HOME_GRID: {
|
||||
//默认分栏数量和宽度 例如 [24] [18,6] [8,8,8] [6,12,6]
|
||||
layout: [8, 8, 8, 12, 12, 12, 12],
|
||||
//小组件分布,com取值:views/home/components 文件名
|
||||
|
@ -3,21 +3,13 @@ export default {
|
||||
{
|
||||
icon: 'el-icon-view',
|
||||
click: async (row, vue) => {
|
||||
vue.loading = true
|
||||
vue.dialog.save = true
|
||||
await vue.$nextTick()
|
||||
await vue.$refs.saveDialog.open('view', row)
|
||||
vue.loading = false
|
||||
vue.dialog.save = { row, mode: 'view' }
|
||||
},
|
||||
},
|
||||
{
|
||||
icon: 'el-icon-edit',
|
||||
click: async (row, vue) => {
|
||||
vue.loading = true
|
||||
vue.dialog.save = true
|
||||
await vue.$nextTick()
|
||||
await vue.$refs.saveDialog.open('edit', row)
|
||||
vue.loading = false
|
||||
vue.dialog.save = { row, mode: 'edit' }
|
||||
},
|
||||
},
|
||||
],
|
||||
|
@ -46,7 +46,6 @@ import scWaterMark from '@/components/scWaterMark'
|
||||
|
||||
// net-admin组件
|
||||
import naArea from '@/components/naArea/index.vue'
|
||||
import naButtonAdd from '@/components/naButtonAdd/index.vue'
|
||||
import naButtonBulkDel from '@/components/naButtonBulkDel/index.vue'
|
||||
import naColAvatar from '@/components/naColAvatar'
|
||||
import naColId from '@/components/naColId/index.vue'
|
||||
@ -87,7 +86,6 @@ export default {
|
||||
|
||||
// net-admin组件
|
||||
app.component('naArea', naArea)
|
||||
app.component('naButtonAdd', naButtonAdd)
|
||||
app.component('naButtonBulkDel', naButtonBulkDel)
|
||||
app.component('naColAvatar', naColAvatar)
|
||||
app.component('naColId', naColId)
|
||||
|
@ -17,7 +17,7 @@
|
||||
<el-menu
|
||||
:default-active="$route.meta.active || $route.fullPath"
|
||||
@select="select"
|
||||
active-text-color="#409EFF"
|
||||
active-text-color="#21A675"
|
||||
background-color="#424c50"
|
||||
router
|
||||
text-color="#fff">
|
||||
|
@ -45,27 +45,25 @@
|
||||
<el-button @click="refresh" circle icon="el-icon-refresh"></el-button>
|
||||
</el-footer>
|
||||
</el-container>
|
||||
<save-dialog v-if="dialog.save" @closed="dialog.save = false" ref="saveDialog"></save-dialog>
|
||||
|
||||
<save-dialog v-if="dialog.save" @closed="dialog.save = null" @mounted="$refs.saveDialog.open(dialog.save)" ref="saveDialog"></save-dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import saveDialog from '@/views/sys/job/save.vue'
|
||||
import { defineAsyncComponent } from 'vue'
|
||||
const saveDialog = defineAsyncComponent(() => import('@/views/sys/job/all/save.vue'))
|
||||
export default {
|
||||
components: {
|
||||
saveDialog,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
dialog: {
|
||||
save: false,
|
||||
},
|
||||
dialog: {},
|
||||
loading: false,
|
||||
jobs: [],
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.getData()
|
||||
},
|
||||
inject: ['reload'],
|
||||
methods: {
|
||||
async getData() {
|
||||
this.loading = true
|
||||
@ -77,11 +75,14 @@ export default {
|
||||
this.getData()
|
||||
},
|
||||
async view(job) {
|
||||
this.dialog.save = true
|
||||
await this.$nextTick()
|
||||
await this.$refs.saveDialog.open('view', { id: job.id })
|
||||
this.dialog.save = { mode: 'view', row: { id: job.id }, tabId: 'record' }
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.getData()
|
||||
},
|
||||
props: [],
|
||||
watch: {},
|
||||
}
|
||||
</script>
|
||||
|
||||
|
@ -78,37 +78,31 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import search from './search.vue'
|
||||
import tasks from './tasks.vue'
|
||||
import message from '@/views/profile/message/components/list.vue'
|
||||
import { defineAsyncComponent } from 'vue'
|
||||
import avatar from '../../utils/avatar'
|
||||
|
||||
const search = defineAsyncComponent(() => import('./search.vue'))
|
||||
const tasks = defineAsyncComponent(() => import('./tasks.vue'))
|
||||
const message = defineAsyncComponent(() => import('@/views/profile/message/components/list.vue'))
|
||||
export default {
|
||||
computed: {
|
||||
avatar() {
|
||||
return avatar
|
||||
},
|
||||
},
|
||||
components: {
|
||||
search,
|
||||
tasks,
|
||||
message,
|
||||
},
|
||||
watch: {
|
||||
'config.dark'(val) {
|
||||
if (val) {
|
||||
document.documentElement.classList.add('dark')
|
||||
this.$TOOL.data.set('APP_DARK', val)
|
||||
} else {
|
||||
document.documentElement.classList.remove('dark')
|
||||
this.$TOOL.data.remove('APP_DARK')
|
||||
}
|
||||
computed: {
|
||||
avatar() {
|
||||
return avatar
|
||||
},
|
||||
},
|
||||
async created() {
|
||||
this.user = this.$GLOBAL.user
|
||||
const res = await this.$API.sys_sitemsg.unreadCount.post()
|
||||
this.unreadCnt = res.data
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
config: {
|
||||
dark: this.$TOOL.data.get('APP_DARK') || false,
|
||||
dark: this.$TOOL.data.get('APP_SET_DARK') || this.$CONFIG.APP_SET_DARK,
|
||||
},
|
||||
user: {},
|
||||
userName: '',
|
||||
@ -119,12 +113,21 @@ export default {
|
||||
unreadCnt: 0,
|
||||
}
|
||||
},
|
||||
async created() {
|
||||
this.user = this.$GLOBAL.user
|
||||
const res = await this.$API.sys_sitemsg.unreadCount.post()
|
||||
this.unreadCnt = res.data
|
||||
},
|
||||
methods: {
|
||||
clearData(fullClear) {
|
||||
const loading = this.$loading()
|
||||
this.$TOOL.cookie.clear()
|
||||
if (fullClear) {
|
||||
this.$TOOL.data.clear()
|
||||
} else {
|
||||
this.$TOOL.data.clearAppSet()
|
||||
}
|
||||
this.$router.replace({ path: '/guest/login' })
|
||||
setTimeout(() => {
|
||||
loading.close()
|
||||
location.reload()
|
||||
}, 1000)
|
||||
},
|
||||
configDark() {
|
||||
this.config.dark = !this.config.dark
|
||||
},
|
||||
@ -133,7 +136,7 @@ export default {
|
||||
this.msg = false
|
||||
},
|
||||
//个人信息
|
||||
handleUser(command) {
|
||||
async handleUser(command) {
|
||||
if (command === 'uc') {
|
||||
this.$router.push({ path: '/profile/account' })
|
||||
}
|
||||
@ -141,36 +144,22 @@ export default {
|
||||
this.$router.push({ path: '/cmd' })
|
||||
}
|
||||
if (command === 'clearCache') {
|
||||
this.$confirm(this.$t('清除缓存会将系统初始化,包括登录状态、主题、语言设置等,是否继续?'), this.$t('提示'), {
|
||||
type: 'info',
|
||||
})
|
||||
.then(() => {
|
||||
const loading = this.$loading()
|
||||
this.$TOOL.data.clear()
|
||||
this.$TOOL.cookie.clear()
|
||||
this.$router.replace({ path: '/guest/login' })
|
||||
setTimeout(() => {
|
||||
loading.close()
|
||||
location.reload()
|
||||
}, 1000)
|
||||
})
|
||||
.catch(() => {
|
||||
//取消
|
||||
try {
|
||||
await this.$confirm(this.$t('清除缓存会将系统初始化,包括登录状态、主题、语言设置等,是否继续?'), this.$t('提示'), {
|
||||
type: 'info',
|
||||
})
|
||||
this.clearData(true)
|
||||
} catch {}
|
||||
}
|
||||
if (command === 'outLogin') {
|
||||
this.$confirm(this.$t('确认是否退出当前用户?'), this.$t('提示'), {
|
||||
type: 'warning',
|
||||
confirmButtonText: this.$t('退出'),
|
||||
confirmButtonClass: 'el-button--danger',
|
||||
})
|
||||
.then(() => {
|
||||
this.$TOOL.cookie.clear()
|
||||
this.$router.replace({ path: '/guest/login' })
|
||||
})
|
||||
.catch(() => {
|
||||
//取消退出
|
||||
try {
|
||||
await this.$confirm(this.$t('确认是否退出当前用户?'), this.$t('提示'), {
|
||||
type: 'warning',
|
||||
confirmButtonText: this.$t('退出'),
|
||||
confirmButtonClass: 'el-button--danger',
|
||||
})
|
||||
this.clearData(false)
|
||||
} catch {}
|
||||
}
|
||||
},
|
||||
//全屏
|
||||
@ -190,6 +179,18 @@ export default {
|
||||
this.tasksVisible = true
|
||||
},
|
||||
},
|
||||
props: [],
|
||||
watch: {
|
||||
'config.dark'(val) {
|
||||
if (val) {
|
||||
document.documentElement.classList.add('dark')
|
||||
this.$TOOL.data.set('APP_SET_DARK', val)
|
||||
} else {
|
||||
document.documentElement.classList.remove('dark')
|
||||
this.$TOOL.data.remove('APP_SET_DARK')
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
|
@ -29,7 +29,7 @@
|
||||
</div>
|
||||
<div class="adminui-side-scroll">
|
||||
<el-scrollbar>
|
||||
<el-menu :collapse="menuIsCollapse" :default-active="active" :unique-opened="$CONFIG.MENU_UNIQUE_OPENED" router>
|
||||
<el-menu :collapse="menuIsCollapse" :default-active="active" :unique-opened="$CONFIG.APP_SET_MENU_UNIQUE_OPENED" router>
|
||||
<NavMenu :navMenus="nextMenu"></NavMenu>
|
||||
</el-menu>
|
||||
</el-scrollbar>
|
||||
@ -74,7 +74,7 @@
|
||||
<div v-if="!ismobile" :class="menuIsCollapse ? 'aminui-side isCollapse' : 'aminui-side'">
|
||||
<div class="adminui-side-scroll">
|
||||
<el-scrollbar>
|
||||
<el-menu :collapse="menuIsCollapse" :default-active="active" :unique-opened="$CONFIG.MENU_UNIQUE_OPENED" router>
|
||||
<el-menu :collapse="menuIsCollapse" :default-active="active" :unique-opened="$CONFIG.APP_SET_MENU_UNIQUE_OPENED" router>
|
||||
<NavMenu :navMenus="menu"></NavMenu>
|
||||
</el-menu>
|
||||
</el-scrollbar>
|
||||
@ -172,7 +172,7 @@
|
||||
</div>
|
||||
<div class="adminui-side-scroll">
|
||||
<el-scrollbar>
|
||||
<el-menu :collapse="menuIsCollapse" :default-active="active" :unique-opened="$CONFIG.MENU_UNIQUE_OPENED" router>
|
||||
<el-menu :collapse="menuIsCollapse" :default-active="active" :unique-opened="$CONFIG.APP_SET_MENU_UNIQUE_OPENED" router>
|
||||
<NavMenu :navMenus="nextMenu"></NavMenu>
|
||||
</el-menu>
|
||||
</el-scrollbar>
|
||||
|
@ -2,7 +2,7 @@ export default {
|
||||
render() {},
|
||||
data() {
|
||||
return {
|
||||
logoutCount: this.$TOOL.data.get('AUTO_EXIT'),
|
||||
logoutCount: this.$TOOL.data.get('APP_SET_AUTO_EXIT') || this.$CONFIG.APP_SET_AUTO_EXIT,
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
|
@ -19,7 +19,7 @@ const messages = {
|
||||
}
|
||||
|
||||
const i18n = createI18n({
|
||||
locale: tool.data.get('APP_LANG') || sysConfig.LANG,
|
||||
locale: tool.data.get('APP_SET_LANG') || sysConfig.APP_SET_LANG,
|
||||
fallbackLocale: 'zh-cn',
|
||||
globalInjection: true,
|
||||
messages,
|
||||
|
@ -74,7 +74,7 @@ export default {
|
||||
启用状态: 'Enabled status',
|
||||
响应状态码: 'Response status code',
|
||||
响应码: 'Response code',
|
||||
唯一编码: 'Unique code',
|
||||
唯一编码: 'Unique ID',
|
||||
图标名称: 'Icon name',
|
||||
图标选择器: 'Icon selector',
|
||||
地区: 'Region',
|
||||
@ -448,4 +448,28 @@ export default {
|
||||
返回首页: 'Return to homepage',
|
||||
重新登录: 'Re-login',
|
||||
返回上一页: 'Return to previous page',
|
||||
批量操作: 'Batch operation',
|
||||
启用用户: 'Enable user',
|
||||
禁用用户: 'Disable user',
|
||||
'确定要 {operator} 选中的 {count} 项吗?': 'Are you sure you want to {operator} the selected {count} items?',
|
||||
'操作成功 {count}/{total} 项': '{count}/{total} items operation successful',
|
||||
启用角色: 'Enable role',
|
||||
禁用角色: 'Disable role',
|
||||
启用部门: 'Enable department',
|
||||
禁用部门: 'Disable department',
|
||||
启用配置: 'Enable configuration',
|
||||
禁用配置: 'Disable configuration',
|
||||
启用作业: 'Enable job',
|
||||
禁用作业: 'Disable job',
|
||||
重置为默认值: 'Reset to default value',
|
||||
'确定将当前主题设置恢复默认值吗?': 'Are you sure you want to reset the current theme settings to default?',
|
||||
'确定将当前设置恢复默认值吗?': 'Are you sure you want to reset the current settings to default?',
|
||||
作业信息: 'Job information',
|
||||
查看作业记录: 'View job records',
|
||||
异常作业: 'Abnormal jobs',
|
||||
所有作业: 'All jobs',
|
||||
用户列表: 'User list',
|
||||
是: 'Yes',
|
||||
否: 'No',
|
||||
手机: 'Mobile',
|
||||
}
|
@ -447,4 +447,27 @@ export default {
|
||||
返回首页: '返回首页',
|
||||
重新登录: '重新登录',
|
||||
返回上一页: '返回上一页',
|
||||
批量操作: '批量操作',
|
||||
启用用户: '启用用户',
|
||||
禁用用户: '禁用用户',
|
||||
'确定要 {operator} 选中的 {count} 项吗?': '确定要 {operator} 选中的 {count} 项吗?',
|
||||
'操作成功 {count}/{total} 项': '操作成功 {count}/{total} 项',
|
||||
启用角色: '启用角色',
|
||||
禁用角色: '禁用角色',
|
||||
启用部门: '启用部门',
|
||||
禁用部门: '禁用部门',
|
||||
启用配置: '启用配置',
|
||||
禁用配置: '禁用配置',
|
||||
启用作业: '启用作业',
|
||||
禁用作业: '禁用作业',
|
||||
'确定将当前主题设置恢复默认值吗?': '确定将当前主题设置恢复默认值吗?',
|
||||
'确定将当前设置恢复默认值吗?': '确定将当前设置恢复默认值吗?',
|
||||
作业信息: '作业信息',
|
||||
查看作业记录: '查看作业记录',
|
||||
异常作业: '异常作业',
|
||||
所有作业: '所有作业',
|
||||
用户列表: '用户列表',
|
||||
是: '是',
|
||||
否: '否',
|
||||
手机: '手机',
|
||||
}
|
@ -5,11 +5,11 @@ export default {
|
||||
//移动端布局
|
||||
ismobile: false,
|
||||
//布局
|
||||
layout: config.LAYOUT,
|
||||
layout: config.APP_SET_LAYOUT,
|
||||
//菜单是否折叠 toggle
|
||||
menuIsCollapse: config.MENU_IS_COLLAPSE,
|
||||
menuIsCollapse: config.APP_SET_MENU_IS_COLLAPSE,
|
||||
//多标签栏
|
||||
layoutTags: config.LAYOUT_TAGS,
|
||||
layoutTags: config.APP_SET_MULTI_TAGS,
|
||||
//主题
|
||||
theme: config.THEME,
|
||||
},
|
||||
|
@ -6,7 +6,7 @@ html {
|
||||
height: 100%;
|
||||
background-color: #f6f8f9;
|
||||
font-size: var(--el-font-size-base);
|
||||
font-family: 'Arial', 'Microsoft YaHei', 'monospace';
|
||||
font-family: 'Microsoft YaHei', sans-serif;
|
||||
}
|
||||
|
||||
a {
|
||||
@ -92,7 +92,7 @@ textarea {
|
||||
bottom: 10rem;
|
||||
right: 0;
|
||||
z-index: 100;
|
||||
background: #409eff;
|
||||
background: #21a675;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
@ -235,7 +235,7 @@ textarea {
|
||||
}
|
||||
|
||||
.aminui-side-split li.active {
|
||||
background: #409eff;
|
||||
background: #21a675;
|
||||
}
|
||||
|
||||
.adminui-side-split-scroll::-webkit-scrollbar-thumb {
|
||||
@ -410,7 +410,7 @@ textarea {
|
||||
}
|
||||
|
||||
.adminui-tags li.active {
|
||||
background: #409eff;
|
||||
background: #21a675;
|
||||
}
|
||||
|
||||
.adminui-tags li.active a {
|
||||
|
@ -1,7 +1,7 @@
|
||||
/* 覆盖element-plus样式 */
|
||||
|
||||
:root {
|
||||
--el-color-primary: #409eff;
|
||||
--el-color-primary: #21a675;
|
||||
--el-color-primary-light-1: #53a7ff;
|
||||
--el-color-primary-light-2: #66b1ff;
|
||||
--el-color-primary-light-3: #79bbff;
|
||||
@ -44,6 +44,7 @@
|
||||
|
||||
.el-date-editor {
|
||||
--el-date-editor-daterange-width: 20rem;
|
||||
--el-date-editor-datetimerange-width: 30rem;
|
||||
}
|
||||
|
||||
.el-menu {
|
||||
@ -167,7 +168,7 @@
|
||||
|
||||
.el-table {
|
||||
td {
|
||||
font-family: 'Lucida Console', 'Microsoft YaHei', 'monospace';
|
||||
font-family: 'Lucida Console', 'Microsoft YaHei', monospace;
|
||||
}
|
||||
|
||||
.el-link:after {
|
||||
|
@ -26,7 +26,6 @@ export default {
|
||||
text.setAttribute('text-anchor', 'middle')
|
||||
text.setAttribute('font-size', '16')
|
||||
text.setAttribute('font-weight', '900')
|
||||
text.setAttribute('font-family', 'monospace')
|
||||
|
||||
// IE/Edge don't support alignment-baseline
|
||||
// @see https://msdn.microsoft.com/en-us/library/gg558060(v=vs.85).aspx
|
||||
|
@ -12,7 +12,35 @@ const tool = {}
|
||||
|
||||
/* localStorage */
|
||||
tool.data = {
|
||||
set(key, data, datetime = 0) {
|
||||
configJson: null,
|
||||
async uploadConfig() {
|
||||
try {
|
||||
const json = JSON.stringify(Object.entries(localStorage).filter((x) => x[0].indexOf('APP_SET_') === 0))
|
||||
if (this.configJson !== json) {
|
||||
this.configJson = json
|
||||
const userApi = await import('@/api/sys/user')
|
||||
await userApi.default.setSessionUserAppConfig.post({
|
||||
appConfig: this.configJson,
|
||||
})
|
||||
}
|
||||
} catch {}
|
||||
},
|
||||
clearAppSet() {
|
||||
Object.entries(localStorage)
|
||||
.filter((x) => x[0].indexOf('APP_SET_') === 0)
|
||||
.map((x) => localStorage.removeItem(x[0]))
|
||||
},
|
||||
async downloadConfig() {
|
||||
try {
|
||||
const userApi = await import('@/api/sys/user')
|
||||
const res = await userApi.default.getSessionUserAppConfig.post({})
|
||||
this.clearAppSet()
|
||||
for (const item of JSON.parse(res.data.appConfig)) {
|
||||
localStorage.setItem(item[0], item[1])
|
||||
}
|
||||
} catch {}
|
||||
},
|
||||
async set(key, data, datetime = 0) {
|
||||
//加密
|
||||
if (sysConfig.LS_ENCRYPTION === 'AES') {
|
||||
data = tool.crypto.AES.encrypt(JSON.stringify(data), sysConfig.LS_ENCRYPTION_key)
|
||||
@ -21,7 +49,9 @@ tool.data = {
|
||||
content: data,
|
||||
datetime: parseInt(datetime) === 0 ? 0 : new Date().getTime() + parseInt(datetime) * 1000,
|
||||
}
|
||||
return localStorage.setItem(key, JSON.stringify(cacheValue))
|
||||
const ret = localStorage.setItem(key, JSON.stringify(cacheValue))
|
||||
await this.uploadConfig()
|
||||
return ret
|
||||
},
|
||||
get(key) {
|
||||
try {
|
||||
@ -43,11 +73,15 @@ tool.data = {
|
||||
return null
|
||||
}
|
||||
},
|
||||
remove(key) {
|
||||
return localStorage.removeItem(key)
|
||||
async remove(key) {
|
||||
const ret = localStorage.removeItem(key)
|
||||
await this.uploadConfig()
|
||||
return ret
|
||||
},
|
||||
clear() {
|
||||
return localStorage.clear()
|
||||
async clear() {
|
||||
const ret = localStorage.clear()
|
||||
await this.uploadConfig()
|
||||
return ret
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -49,7 +49,7 @@ export default {
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.autoLogin = this.$TOOL.data.get('AUTO_LOGIN')
|
||||
this.autoLogin = this.$TOOL.data.get('AUTO_LOGIN') || false
|
||||
},
|
||||
methods: {
|
||||
async login() {
|
||||
|
@ -69,8 +69,8 @@ export default {
|
||||
data() {
|
||||
return {
|
||||
config: {
|
||||
lang: this.$TOOL.data.get('APP_LANG') || this.$CONFIG.LANG,
|
||||
dark: this.$TOOL.data.get('APP_DARK') || false,
|
||||
lang: this.$TOOL.data.get('APP_SET_LANG') || this.$CONFIG.APP_SET_LANG,
|
||||
dark: this.$TOOL.data.get('APP_SET_DARK') || this.$CONFIG.APP_SET_DARK,
|
||||
},
|
||||
lang: [
|
||||
{
|
||||
@ -88,15 +88,15 @@ export default {
|
||||
'config.dark'(val) {
|
||||
if (val) {
|
||||
document.documentElement.classList.add('dark')
|
||||
this.$TOOL.data.set('APP_DARK', val)
|
||||
this.$TOOL.data.set('APP_SET_DARK', val)
|
||||
} else {
|
||||
document.documentElement.classList.remove('dark')
|
||||
this.$TOOL.data.remove('APP_DARK')
|
||||
this.$TOOL.data.remove('APP_SET_DARK')
|
||||
}
|
||||
},
|
||||
'config.lang'(val) {
|
||||
this.$i18n.locale = val
|
||||
this.$TOOL.data.set('APP_LANG', val)
|
||||
this.$TOOL.data.set('APP_SET_LANG', val)
|
||||
},
|
||||
},
|
||||
created: function () {
|
||||
@ -105,7 +105,7 @@ export default {
|
||||
this.$TOOL.data.remove('MENU')
|
||||
this.$TOOL.data.remove('PERMISSIONS')
|
||||
this.$TOOL.data.remove('DASHBOARD_GRID')
|
||||
this.$TOOL.data.remove('grid')
|
||||
this.$TOOL.data.remove('APP_SET_HOME_GRID')
|
||||
this.$store.commit('clearViewTags')
|
||||
this.$store.commit('clearKeepLive')
|
||||
this.$store.commit('clearIframeList')
|
||||
|
@ -1,7 +1,8 @@
|
||||
<template>
|
||||
<el-main>
|
||||
<widgets v-if="dashboard" @on-mounted="onMounted"></widgets>
|
||||
<work v-else @on-mounted="onMounted"></work>
|
||||
<div v-if="loading" v-loading="true" style="height: 100%"></div>
|
||||
<el-main v-else>
|
||||
<widgets v-if="dashboard"></widgets>
|
||||
<work v-else></work>
|
||||
</el-main>
|
||||
</template>
|
||||
|
||||
@ -18,20 +19,19 @@ export default {
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
pageLoading: true,
|
||||
loading: true,
|
||||
dashboard: false,
|
||||
}
|
||||
},
|
||||
created() {
|
||||
async created() {
|
||||
//下载配置
|
||||
await this.$TOOL.data.downloadConfig()
|
||||
this.dashboard = this.$GLOBAL.user.roles.findIndex((x) => x.displayDashboard) >= 0
|
||||
this.loading = false
|
||||
},
|
||||
mounted() {},
|
||||
methods: {
|
||||
onMounted() {
|
||||
this.pageLoading = false
|
||||
},
|
||||
},
|
||||
methods: {},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style></style>
|
||||
<style scoped></style>
|
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<el-card v-loading="loading" class="main" shadow="never">
|
||||
<div class="wrap">
|
||||
<img alt="" src="@/assets/img/logo.png" />
|
||||
<img alt="" src="@/assets/img/logo.png" width="200" />
|
||||
<h2>{{ packageJson.name }}</h2>
|
||||
<p>{{ ver }}</p>
|
||||
<el-link href="https://github.com/nsnail/NetAdmin" target="_blank">{{ $t('喜欢就点个 Star⭐️ 吧!') }}</el-link>
|
||||
|
@ -146,7 +146,7 @@ export default {
|
||||
customizing: false,
|
||||
allComps: allComps,
|
||||
selectLayout: [],
|
||||
defaultGrid: this.$CONFIG.DEFAULT_GRID,
|
||||
defaultGrid: this.$CONFIG.APP_SET_HOME_GRID,
|
||||
grid: [],
|
||||
}
|
||||
},
|
||||
@ -225,14 +225,14 @@ export default {
|
||||
save() {
|
||||
this.customizing = false
|
||||
this.$refs.widgets.style.removeProperty('transform')
|
||||
this.$TOOL.data.set('grid', this.grid)
|
||||
this.$TOOL.data.set('APP_SET_HOME_GRID', this.grid)
|
||||
},
|
||||
//恢复默认
|
||||
backDefault() {
|
||||
this.customizing = false
|
||||
this.$refs.widgets.style.removeProperty('transform')
|
||||
this.grid = JSON.parse(JSON.stringify(this.defaultGrid))
|
||||
this.$TOOL.data.remove('grid')
|
||||
this.$TOOL.data.remove('APP_SET_HOME_GRID')
|
||||
},
|
||||
//关闭
|
||||
close() {
|
||||
@ -241,7 +241,7 @@ export default {
|
||||
this.loadGrid()
|
||||
},
|
||||
loadGrid() {
|
||||
this.grid = this.$TOOL.data.get('grid') || JSON.parse(JSON.stringify(this.defaultGrid))
|
||||
this.grid = this.$TOOL.data.get('APP_SET_HOME_GRID') || JSON.parse(JSON.stringify(this.defaultGrid))
|
||||
},
|
||||
},
|
||||
}
|
||||
@ -259,6 +259,7 @@ export default {
|
||||
flex: 1;
|
||||
overflow: auto;
|
||||
overflow-x: hidden;
|
||||
font-family: 'Lucida Console', 'Microsoft YaHei', monospace;
|
||||
}
|
||||
|
||||
.widgets-aside {
|
||||
|
@ -84,7 +84,7 @@ export default {
|
||||
},
|
||||
getMods() {
|
||||
//这里可用改为读取远程数据
|
||||
this.myModsName = this.$TOOL.data.get('MY_MODS') || []
|
||||
this.myModsName = this.$TOOL.data.get('APP_SET_MY_MODS') || []
|
||||
this.filterMenu(this.$GLOBAL.menu)
|
||||
this.myMods = this.mods.filter((item) => {
|
||||
return this.myModsName.includes(item.name)
|
||||
@ -110,7 +110,7 @@ export default {
|
||||
},
|
||||
saveMods() {
|
||||
this.$TOOL.data.set(
|
||||
'MY_MODS',
|
||||
'APP_SET_MY_MODS',
|
||||
this.myMods.map((v) => v.name),
|
||||
)
|
||||
this.$message.success(this.$t('设置常用成功'))
|
||||
@ -178,8 +178,8 @@ export default {
|
||||
|
||||
.modItem-add:hover,
|
||||
.modItem-add:hover i {
|
||||
border-color: #409eff;
|
||||
color: #409eff !important;
|
||||
border-color: #21a675;
|
||||
color: #21a675 !important;
|
||||
}
|
||||
|
||||
.setMods {
|
||||
|
@ -34,18 +34,42 @@
|
||||
</el-form>
|
||||
</el-card>
|
||||
|
||||
<set-mobile-dialog v-if="dialog.setMobile" @closed="dialog.setMobile = false" @success="setSuccess" ref="setMobileDialog"></set-mobile-dialog>
|
||||
<set-password-dialog v-if="dialog.setPassword" @closed="dialog.setPassword = false" ref="setPasswordDialog"></set-password-dialog>
|
||||
<set-email-dialog v-if="dialog.setEmail" @closed="dialog.setEmail = false" @success="setSuccess" ref="setEmailDialog"></set-email-dialog>
|
||||
<set-mobile-dialog
|
||||
v-if="dialog.setMobile"
|
||||
@closed="dialog.setMobile = null"
|
||||
@mounted="$refs.setMobileDialog.open(dialog.setMobile)"
|
||||
@success="setSuccess"
|
||||
ref="setMobileDialog"></set-mobile-dialog>
|
||||
<set-password-dialog
|
||||
v-if="dialog.setPassword"
|
||||
@closed="dialog.setPassword = null"
|
||||
@mounted="$refs.setPasswordDialog.open(dialog.setPassword)"
|
||||
ref="setPasswordDialog"></set-password-dialog>
|
||||
<set-email-dialog
|
||||
v-if="dialog.setEmail"
|
||||
@closed="dialog.setEmail = null"
|
||||
@mounted="$refs.setEmailDialog.open(dialog.setEmail)"
|
||||
@success="setSuccess"
|
||||
ref="setEmailDialog"></set-email-dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import setMobileDialog from '@/views/profile/account/set-mobile.vue'
|
||||
import setPasswordDialog from '@/views/profile/account/set-password.vue'
|
||||
import setEmailDialog from '@/views/profile/account/set-email.vue'
|
||||
import { defineAsyncComponent } from 'vue'
|
||||
const setMobileDialog = defineAsyncComponent(() => import('@/views/profile/account/set-mobile.vue'))
|
||||
const setPasswordDialog = defineAsyncComponent(() => import('@/views/profile/account/set-password.vue'))
|
||||
const setEmailDialog = defineAsyncComponent(() => import('@/views/profile/account/set-email.vue'))
|
||||
|
||||
export default {
|
||||
components: { setMobileDialog, setPasswordDialog, setEmailDialog },
|
||||
created() {
|
||||
this.form = this.$GLOBAL.user
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
dialog: {},
|
||||
form: {},
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
updateUser(res) {
|
||||
try {
|
||||
@ -59,34 +83,17 @@ export default {
|
||||
this.form = this.$GLOBAL.user = data
|
||||
},
|
||||
async setPasswordClick() {
|
||||
this.dialog.setPassword = true
|
||||
await this.$nextTick()
|
||||
this.$refs.setPasswordDialog.open()
|
||||
this.dialog.setPassword = {}
|
||||
},
|
||||
async setEmailClick() {
|
||||
this.dialog.setEmail = true
|
||||
await this.$nextTick()
|
||||
this.$refs.setEmailDialog.open()
|
||||
this.dialog.setEmail = {}
|
||||
},
|
||||
async setMobileClick() {
|
||||
this.dialog.setMobile = true
|
||||
await this.$nextTick()
|
||||
this.$refs.setMobileDialog.open(this.form.mobile ? 'edit' : 'add')
|
||||
this.dialog.setMobile = { mode: this.form.mobile ? 'edit' : 'add' }
|
||||
},
|
||||
},
|
||||
|
||||
created() {
|
||||
this.form = this.$GLOBAL.user
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
dialog: {
|
||||
setPassword: false,
|
||||
setMobile: false,
|
||||
},
|
||||
form: {},
|
||||
}
|
||||
},
|
||||
props: [],
|
||||
watch: {},
|
||||
}
|
||||
</script>
|
||||
|
||||
|
@ -29,7 +29,7 @@
|
||||
|
||||
<template #footer>
|
||||
<el-button @click="visible = false">{{ $t('取消') }}</el-button>
|
||||
<el-button :loading="loading" @click="submit" type="primary">{{ $t('保存') }}</el-button>
|
||||
<el-button :disabled="loading" :loading="loading" @click="submit" type="primary">{{ $t('保存') }}</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
@ -40,17 +40,42 @@ import phoneConfig from '@/config/naFormPhone'
|
||||
import emailConfig from '@/config/naFormEmail'
|
||||
|
||||
export default {
|
||||
created() {},
|
||||
components: {
|
||||
naFormPhone,
|
||||
},
|
||||
created() {},
|
||||
|
||||
data() {
|
||||
return {
|
||||
//表单数据
|
||||
form: {
|
||||
verifySmsCodeReq: {},
|
||||
},
|
||||
loading: false,
|
||||
//验证规则
|
||||
rules: {
|
||||
verifySmsCodeReq: {
|
||||
destDevice: phoneConfig.mobile(this),
|
||||
code: phoneConfig.code(this),
|
||||
},
|
||||
|
||||
destDevice: [emailConfig.email(this)],
|
||||
code: emailConfig.code(),
|
||||
},
|
||||
visible: false,
|
||||
}
|
||||
},
|
||||
emits: ['success', 'closed', 'mounted'],
|
||||
methods: {
|
||||
//显示
|
||||
open() {
|
||||
this.visible = true
|
||||
return this
|
||||
},
|
||||
//表单提交方法
|
||||
async submit() {
|
||||
if (!(await this.$refs.form.validate().catch(() => {}))) {
|
||||
const valid = await this.$refs.form.validate().catch(() => {})
|
||||
if (!valid) {
|
||||
return false
|
||||
}
|
||||
|
||||
@ -64,23 +89,8 @@ export default {
|
||||
this.loading = false
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
visible: false,
|
||||
loading: false,
|
||||
form: {
|
||||
verifySmsCodeReq: {},
|
||||
},
|
||||
rules: {
|
||||
verifySmsCodeReq: {
|
||||
destDevice: phoneConfig.mobile(this),
|
||||
code: phoneConfig.code(this),
|
||||
},
|
||||
|
||||
destDevice: [emailConfig.email(this)],
|
||||
code: emailConfig.code(),
|
||||
},
|
||||
}
|
||||
mounted() {
|
||||
this.$emit('mounted')
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<el-dialog v-model="visible" :title="`${titleMap[mode]}:${form?.id ?? '...'}`" :width="800" @closed="$emit('closed')" destroy-on-close>
|
||||
<el-dialog v-model="visible" :title="`${titleMap[mode]}`" :width="800" @closed="$emit('closed')" destroy-on-close>
|
||||
<el-form :model="form" :rules="rules" label-position="top" ref="form">
|
||||
<el-row class="items-center justify-content-center">
|
||||
<el-col v-if="mode === 'edit'" :lg="10">
|
||||
@ -34,7 +34,7 @@
|
||||
|
||||
<template #footer>
|
||||
<el-button @click="visible = false">{{ $t('取消') }}</el-button>
|
||||
<el-button :loading="loading" @click="submit" type="primary">{{ $t('保存') }}</el-button>
|
||||
<el-button :disabled="loading" :loading="loading" @click="submit" type="primary">{{ $t('保存') }}</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
@ -44,18 +44,50 @@ import naFormPhone from '@/components/naFormPhone/index.vue'
|
||||
import phoneConfig from '@/config/naFormPhone'
|
||||
|
||||
export default {
|
||||
created() {},
|
||||
components: {
|
||||
naFormPhone,
|
||||
},
|
||||
created() {},
|
||||
|
||||
data() {
|
||||
return {
|
||||
//表单数据
|
||||
form: {
|
||||
newverifySmsCodeReq: {},
|
||||
originverifySmsCodeReq: {},
|
||||
},
|
||||
loading: false,
|
||||
mode: 'add',
|
||||
//验证规则
|
||||
rules: {
|
||||
originverifySmsCodeReq: {
|
||||
destDevice: phoneConfig.mobile(this),
|
||||
code: phoneConfig.code(this),
|
||||
},
|
||||
newverifySmsCodeReq: {
|
||||
destDevice: [phoneConfig.mobile(this), phoneConfig.mobileNoUsed(this, () => this.$GLOBAL.user.id)],
|
||||
code: phoneConfig.code(this),
|
||||
},
|
||||
},
|
||||
titleMap: {
|
||||
add: this.$t('绑定手机'),
|
||||
edit: this.$t('更换手机'),
|
||||
},
|
||||
visible: false,
|
||||
}
|
||||
},
|
||||
emits: ['success', 'closed', 'mounted'],
|
||||
methods: {
|
||||
open(mode = 'add') {
|
||||
this.mode = mode
|
||||
//显示
|
||||
open(data) {
|
||||
this.mode = data.mode
|
||||
this.visible = true
|
||||
return this
|
||||
},
|
||||
//表单提交方法
|
||||
async submit() {
|
||||
if (!(await this.$refs.form.validate().catch(() => {}))) {
|
||||
const valid = await this.$refs.form.validate().catch(() => {})
|
||||
if (!valid) {
|
||||
return false
|
||||
}
|
||||
|
||||
@ -69,30 +101,8 @@ export default {
|
||||
this.loading = false
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
mode: 'add',
|
||||
titleMap: {
|
||||
add: this.$t('绑定手机'),
|
||||
edit: this.$t('更换手机'),
|
||||
},
|
||||
visible: false,
|
||||
loading: false,
|
||||
form: {
|
||||
newverifySmsCodeReq: {},
|
||||
originverifySmsCodeReq: {},
|
||||
},
|
||||
rules: {
|
||||
originverifySmsCodeReq: {
|
||||
destDevice: phoneConfig.mobile(this),
|
||||
code: phoneConfig.code(this),
|
||||
},
|
||||
newverifySmsCodeReq: {
|
||||
destDevice: [phoneConfig.mobile(this), phoneConfig.mobileNoUsed(this, () => this.$GLOBAL.user.id)],
|
||||
code: phoneConfig.code(this),
|
||||
},
|
||||
},
|
||||
}
|
||||
mounted() {
|
||||
this.$emit('mounted')
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
@ -32,9 +32,10 @@
|
||||
type="password"></el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<template #footer>
|
||||
<el-button @click="visible = false">{{ $t('取消') }}</el-button>
|
||||
<el-button :loading="loading" @click="submit" type="primary">{{ $t('保存') }}</el-button>
|
||||
<el-button :disabled="loading" :loading="loading" @click="submit" type="primary">{{ $t('保存') }}</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
@ -44,43 +45,51 @@ import scPasswordStrength from '@/components/scPasswordStrength/index.vue'
|
||||
import naFormPassword from '@/config/naFormPassword'
|
||||
|
||||
export default {
|
||||
created() {},
|
||||
components: {
|
||||
scPasswordStrength,
|
||||
},
|
||||
created() {},
|
||||
|
||||
data() {
|
||||
return {
|
||||
form: {},
|
||||
loading: false,
|
||||
//验证规则
|
||||
rules: {
|
||||
oldPassword: naFormPassword.passwordText(this),
|
||||
newPassword: naFormPassword.passwordText(this),
|
||||
confirmNewPassword: naFormPassword.passwordText2(() => this.form.newPassword),
|
||||
},
|
||||
visible: false,
|
||||
}
|
||||
},
|
||||
emits: ['success', 'closed', 'mounted'],
|
||||
methods: {
|
||||
//显示
|
||||
open() {
|
||||
this.visible = true
|
||||
return this
|
||||
},
|
||||
//表单提交方法
|
||||
async submit() {
|
||||
if (!(await this.$refs.form.validate().catch(() => {}))) {
|
||||
const valid = await this.$refs.form.validate().catch(() => {})
|
||||
if (!valid) {
|
||||
return false
|
||||
}
|
||||
|
||||
this.loading = true
|
||||
try {
|
||||
const res = await this.$API.sys_user.setPassword.post(this.form)
|
||||
this.$emit('success', res.data, this.mode)
|
||||
this.$emit('success', res.data)
|
||||
this.visible = false
|
||||
this.$message.success(this.$t('操作成功'))
|
||||
} catch {
|
||||
//
|
||||
}
|
||||
} catch {}
|
||||
this.loading = false
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
visible: false,
|
||||
loading: false,
|
||||
form: {},
|
||||
rules: {
|
||||
oldPassword: naFormPassword.passwordText(this),
|
||||
newPassword: naFormPassword.passwordText(this),
|
||||
confirmNewPassword: naFormPassword.passwordText2(() => this.form.newPassword),
|
||||
},
|
||||
}
|
||||
mounted() {
|
||||
this.$emit('mounted')
|
||||
},
|
||||
}
|
||||
</script>
|
||||
</script>
|
||||
<style scoped></style>
|
@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<el-card :header="$t('主题样式')" shadow="never">
|
||||
<el-form class="mt-4" label-width="15rem">
|
||||
<el-form class="mt-4" label-width="10rem">
|
||||
<el-form-item :label="$t('黑夜模式')">
|
||||
<el-switch v-model="config.dark" active-icon="el-icon-moon" inactive-icon="el-icon-sunny" inline-prompt />
|
||||
</el-form-item>
|
||||
@ -24,10 +24,17 @@
|
||||
<el-form-item :label="$t('标签栏')">
|
||||
<el-switch v-model="config.layoutTags"></el-switch>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-popconfirm :title="$t('确定将当前主题设置恢复默认值吗?')" @confirm="themeReset" width="20rem">
|
||||
<template #reference>
|
||||
<el-button>{{ $t('重置为默认值') }}</el-button>
|
||||
</template>
|
||||
</el-popconfirm>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
<el-card :header="$t('个人设置')" class="mt-4" shadow="never">
|
||||
<el-form class="mt-4" label-width="15rem">
|
||||
<el-form class="mt-4" label-width="10rem">
|
||||
<el-form-item :label="$t('界面语言')">
|
||||
<el-select v-model="config.lang">
|
||||
<el-option :label="$t('简体中文')" value="zh-cn" />
|
||||
@ -52,6 +59,13 @@
|
||||
<el-option :label="$t('60分钟')" :value="60" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-popconfirm :title="$t('确定将当前设置恢复默认值吗?')" @confirm="personalReset" width="20rem">
|
||||
<template #reference>
|
||||
<el-button>{{ $t('重置为默认值') }}</el-button>
|
||||
</template>
|
||||
</el-popconfirm>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
</template>
|
||||
@ -62,16 +76,16 @@ import colorTool from '@/utils/color'
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
colorList: ['#409EFF', '#009688', '#536dfe', '#ff5c93', '#c62f2f', '#fd726d'],
|
||||
colorList: ['#21A675', '#009688', '#536dfe', '#ff5c93', '#c62f2f', '#fd726d'],
|
||||
config: {
|
||||
layout: this.$TOOL.data.get('LAYOUT') ?? this.$CONFIG.LAYOUT,
|
||||
menuIsCollapse: this.$TOOL.data.get('MENU_IS_COLLAPSE') ?? this.$CONFIG.MENU_IS_COLLAPSE,
|
||||
menuUniqueOpened: this.$TOOL.data.get('MENU_UNIQUE_OPENED') ?? this.$CONFIG.MENU_UNIQUE_OPENED,
|
||||
layoutTags: this.$TOOL.data.get('LAYOUT_TAGS') ?? this.$CONFIG.LAYOUT_TAGS,
|
||||
lang: this.$TOOL.data.get('APP_LANG') ?? this.$CONFIG.LANG,
|
||||
dark: this.$TOOL.data.get('APP_DARK') ?? false,
|
||||
colorPrimary: this.$TOOL.data.get('APP_COLOR') ?? this.$CONFIG.COLOR ?? '#409EFF',
|
||||
autoExit: this.$TOOL.data.get('AUTO_EXIT') ?? 0,
|
||||
layout: this.$TOOL.data.get('APP_SET_LAYOUT') || this.$CONFIG.APP_SET_LAYOUT,
|
||||
menuIsCollapse: this.$TOOL.data.get('APP_SET_MENU_IS_COLLAPSE') || this.$CONFIG.APP_SET_MENU_IS_COLLAPSE,
|
||||
menuUniqueOpened: this.$TOOL.data.get('APP_SET_MENU_UNIQUE_OPENED') || this.$CONFIG.APP_SET_MENU_UNIQUE_OPENED,
|
||||
layoutTags: this.$TOOL.data.get('APP_SET_MULTI_TAGS') || this.$CONFIG.APP_SET_MULTI_TAGS,
|
||||
lang: this.$TOOL.data.get('APP_SET_LANG') || this.$CONFIG.APP_SET_LANG,
|
||||
dark: this.$TOOL.data.get('APP_SET_DARK') || this.$CONFIG.APP_SET_DARK,
|
||||
colorPrimary: this.$TOOL.data.get('APP_SET_COLOR') || this.$CONFIG.APP_SET_COLOR || '#17ABE3',
|
||||
autoExit: this.$TOOL.data.get('APP_SET_AUTO_EXIT') || this.$CONFIG.APP_SET_AUTO_EXIT,
|
||||
},
|
||||
}
|
||||
},
|
||||
@ -79,51 +93,51 @@ export default {
|
||||
'config.dark'(val) {
|
||||
if (val) {
|
||||
document.documentElement.classList.add('dark')
|
||||
this.$TOOL.data.set('APP_DARK', val)
|
||||
this.$TOOL.data.set('APP_SET_DARK', val)
|
||||
} else {
|
||||
document.documentElement.classList.remove('dark')
|
||||
this.$TOOL.data.remove('APP_DARK')
|
||||
this.$TOOL.data.remove('APP_SET_DARK')
|
||||
}
|
||||
},
|
||||
'config.layout'(val) {
|
||||
if (val) {
|
||||
this.$TOOL.data.set('LAYOUT', val)
|
||||
this.$TOOL.data.set('APP_SET_LAYOUT', val)
|
||||
this.$store.commit('SET_layout', val)
|
||||
} else {
|
||||
this.$TOOL.data.remove('LAYOUT')
|
||||
this.$TOOL.data.remove('APP_SET_LAYOUT')
|
||||
}
|
||||
},
|
||||
'config.menuIsCollapse'(val) {
|
||||
if (typeof val === 'boolean') {
|
||||
this.$TOOL.data.set('MENU_IS_COLLAPSE', val)
|
||||
this.$TOOL.data.set('APP_SET_MENU_IS_COLLAPSE', val)
|
||||
this.$store.commit('TOGGLE_menuIsCollapse')
|
||||
} else {
|
||||
this.$TOOL.data.remove('MENU_IS_COLLAPSE')
|
||||
this.$TOOL.data.remove('APP_SET_MENU_IS_COLLAPSE')
|
||||
}
|
||||
},
|
||||
'config.layoutTags'(val) {
|
||||
if (typeof val === 'boolean') {
|
||||
this.$TOOL.data.set('LAYOUT_TAGS', val)
|
||||
this.$TOOL.data.set('APP_SET_MULTI_TAGS', val)
|
||||
this.$store.commit('TOGGLE_layoutTags')
|
||||
} else {
|
||||
this.$TOOL.data.remove('LAYOUT_TAGS')
|
||||
this.$TOOL.data.remove('APP_SET_MULTI_TAGS')
|
||||
}
|
||||
},
|
||||
'config.menuUniqueOpened'(val) {
|
||||
if (typeof val === 'boolean') {
|
||||
this.$TOOL.data.set('MENU_UNIQUE_OPENED', val)
|
||||
this.$TOOL.data.set('APP_SET_MENU_UNIQUE_OPENED', val)
|
||||
} else {
|
||||
this.$TOOL.data.remove('MENU_UNIQUE_OPENED')
|
||||
this.$TOOL.data.remove('APP_SET_MENU_UNIQUE_OPENED')
|
||||
}
|
||||
},
|
||||
'config.lang'(val) {
|
||||
this.$i18n.locale = val
|
||||
this.$TOOL.data.set('APP_LANG', val)
|
||||
this.$TOOL.data.set('APP_SET_LANG', val)
|
||||
},
|
||||
'config.colorPrimary'(val) {
|
||||
if (!val) {
|
||||
val = '#409EFF'
|
||||
this.config.colorPrimary = '#409EFF'
|
||||
val = '#21A675'
|
||||
this.config.colorPrimary = '#21A675'
|
||||
}
|
||||
document.documentElement.style.setProperty('--el-color-primary', val)
|
||||
for (let i = 1; i <= 9; i++) {
|
||||
@ -132,16 +146,38 @@ export default {
|
||||
for (let i = 1; i <= 9; i++) {
|
||||
document.documentElement.style.setProperty(`--el-color-primary-dark-${i}`, colorTool.darken(val, i / 10))
|
||||
}
|
||||
this.$TOOL.data.set('APP_COLOR', val)
|
||||
this.$TOOL.data.set('APP_SET_COLOR', val)
|
||||
},
|
||||
'config.autoExit'(val) {
|
||||
if (val === 0) {
|
||||
this.$TOOL.data.remove('AUTO_EXIT')
|
||||
this.$TOOL.data.remove('APP_SET_AUTO_EXIT')
|
||||
} else {
|
||||
this.$TOOL.data.set('AUTO_EXIT', val)
|
||||
this.$TOOL.data.set('APP_SET_AUTO_EXIT', val)
|
||||
}
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
async themeReset() {
|
||||
this.$loading()
|
||||
this.$message.success(this.$t('操作成功'))
|
||||
localStorage.removeItem('APP_SET_LAYOUT')
|
||||
localStorage.removeItem('APP_SET_MENU_IS_COLLAPSE')
|
||||
localStorage.removeItem('APP_SET_MENU_UNIQUE_OPENED')
|
||||
localStorage.removeItem('APP_SET_MULTI_TAGS')
|
||||
localStorage.removeItem('APP_SET_DARK')
|
||||
localStorage.removeItem('APP_SET_COLOR')
|
||||
await this.$TOOL.data.uploadConfig()
|
||||
window.location.reload()
|
||||
},
|
||||
async personalReset() {
|
||||
this.$loading()
|
||||
this.$message.success(this.$t('操作成功'))
|
||||
localStorage.removeItem('APP_SET_AUTO_EXIT')
|
||||
localStorage.removeItem('APP_SET_LANG')
|
||||
await this.$TOOL.data.uploadConfig()
|
||||
window.location.reload()
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
|
31
src/frontend/admin/src/views/sys/cache/index.vue
vendored
31
src/frontend/admin/src/views/sys/cache/index.vue
vendored
@ -66,25 +66,22 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import scStatistic from '@/components/scStatistic'
|
||||
import naInfo from '@/components/naInfo/index.vue'
|
||||
import tool from '@/utils/tool'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
scStatistic,
|
||||
naInfo,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
dialog: {
|
||||
info: false,
|
||||
},
|
||||
query: {
|
||||
filter: {
|
||||
dbIndex: 1,
|
||||
},
|
||||
},
|
||||
dialog: {
|
||||
info: false,
|
||||
},
|
||||
statistics: {
|
||||
keyspaceHits: 0,
|
||||
keyspaceMisses: 0,
|
||||
@ -95,21 +92,11 @@ export default {
|
||||
},
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.cacheStatistics()
|
||||
},
|
||||
watch: {
|
||||
'query.filter.dbIndex': {
|
||||
handler() {
|
||||
this.$refs.table.upData()
|
||||
},
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
async rowClick(row) {
|
||||
this.dialog.info = true
|
||||
await this.$nextTick()
|
||||
this.$refs.info.open(tool.sortProperties(row), `缓存详情`)
|
||||
this.$refs.info.open(this.$TOOL.sortProperties(row), this.$t('缓存详情'))
|
||||
},
|
||||
async cacheStatistics() {
|
||||
try {
|
||||
@ -122,6 +109,16 @@ export default {
|
||||
}
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.cacheStatistics()
|
||||
},
|
||||
watch: {
|
||||
'query.filter.dbIndex': {
|
||||
handler() {
|
||||
this.$refs.table.upData()
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
|
@ -13,8 +13,8 @@
|
||||
],
|
||||
},
|
||||
]"
|
||||
:label-width="10"
|
||||
@on-change="filterChange"
|
||||
label-width="10"
|
||||
ref="selectFilter"></sc-select-filter>
|
||||
</el-header>
|
||||
<el-header>
|
||||
@ -27,13 +27,26 @@
|
||||
ref="search" />
|
||||
</div>
|
||||
<div class="right-panel">
|
||||
<na-button-add :vue="this" />
|
||||
<el-button @click="this.dialog.save = { mode: 'add' }" icon="el-icon-plus" type="primary"></el-button>
|
||||
<na-button-bulk-del :api="$API.sys_config.bulkDelete" :vue="this" />
|
||||
<el-dropdown v-show="this.selection.length > 0">
|
||||
<el-button type="primary">
|
||||
{{ $t('批量操作') }}
|
||||
<el-icon>
|
||||
<el-icon-arrow-down />
|
||||
</el-icon>
|
||||
</el-button>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item @click="setEnabled(true)">{{ $t('启用配置') }}</el-dropdown-item>
|
||||
<el-dropdown-item @click="setEnabled(false)">{{ $t('禁用配置') }}</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
</div>
|
||||
</el-header>
|
||||
<el-main class="nopadding">
|
||||
<sc-table
|
||||
v-loading="loading"
|
||||
:apiObj="$API.sys_config.pagedQuery"
|
||||
:context-menus="['id', 'userRegisterConfirm', 'enabled', 'createdTime']"
|
||||
:params="query"
|
||||
@ -47,22 +60,21 @@
|
||||
row-key="id"
|
||||
stripe>
|
||||
<el-table-column type="selection" />
|
||||
<el-table-column :label="$t('配置编号')" align="center" prop="id" width="170" />
|
||||
<na-col-id :label="$t('配置编号')" prop="id" width="170" />
|
||||
<el-table-column :label="$t('用户注册')" align="center">
|
||||
<el-table-column :label="$t('默认部门')" align="center" prop="userRegisterDept.name" width="150" />
|
||||
<el-table-column :label="$t('默认角色')" align="center" prop="userRegisterRole.name" width="150" />
|
||||
<el-table-column :label="$t('人工审核')" align="center" prop="userRegisterConfirm" width="120">
|
||||
<template #default="scope">
|
||||
<el-switch v-model="scope.row.userRegisterConfirm" @change="changeSwitch($event, scope.row)"></el-switch>
|
||||
<template #default="{ row }">
|
||||
<el-switch v-model="row.userRegisterConfirm" @change="changeSwitch($event, row)"></el-switch>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table-column>
|
||||
<el-table-column :label="$t('启用')" align="center" prop="enabled" width="100">
|
||||
<template #default="scope">
|
||||
<el-switch v-model="scope.row.enabled" @change="changeSwitch($event, scope.row)"></el-switch>
|
||||
<template #default="{ row }">
|
||||
<el-switch v-model="row.enabled" @change="changeSwitch($event, row)"></el-switch>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column :label="$t('创建时间')" align="center" prop="createdTime" width="170" />
|
||||
<na-col-operation
|
||||
:buttons="
|
||||
naColOperation.buttons.concat({
|
||||
@ -73,25 +85,25 @@
|
||||
type: 'danger',
|
||||
})
|
||||
"
|
||||
:vue="this"
|
||||
width="170" />
|
||||
:vue="this" />
|
||||
</sc-table>
|
||||
</el-main>
|
||||
</el-container>
|
||||
|
||||
<save-dialog
|
||||
v-if="dialog.save"
|
||||
@closed="dialog.save = false"
|
||||
@success="(data, mode) => table.handleUpdate($refs.table, data, mode)"
|
||||
@closed="dialog.save = null"
|
||||
@mounted="$refs.saveDialog.open(dialog.save)"
|
||||
@success="(data, mode) => $refs.table.upData()"
|
||||
ref="saveDialog"></save-dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import saveDialog from './save'
|
||||
import naColOperation from '@/config/naColOperation'
|
||||
import { defineAsyncComponent } from 'vue'
|
||||
import table from '@/config/table'
|
||||
import tool from '@/utils/tool'
|
||||
import naColOperation from '@/config/naColOperation'
|
||||
|
||||
const saveDialog = defineAsyncComponent(() => import('./save.vue'))
|
||||
export default {
|
||||
components: {
|
||||
saveDialog,
|
||||
@ -104,13 +116,14 @@ export default {
|
||||
return table
|
||||
},
|
||||
},
|
||||
created() {},
|
||||
created() {
|
||||
if (this.keywords) {
|
||||
this.query.keywords = this.keywords
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
dialog: {
|
||||
info: false,
|
||||
save: false,
|
||||
},
|
||||
dialog: {},
|
||||
loading: false,
|
||||
query: {
|
||||
dynamicFilter: {
|
||||
@ -123,6 +136,33 @@ export default {
|
||||
},
|
||||
inject: ['reload'],
|
||||
methods: {
|
||||
async setEnabled(enabled) {
|
||||
let loading
|
||||
try {
|
||||
await this.$confirm(
|
||||
this.$t('确定要 {operator} 选中的 {count} 项吗?', {
|
||||
operator: enabled ? this.$t('启用') : this.$t('禁用'),
|
||||
count: this.selection.length,
|
||||
}),
|
||||
this.$t('提示'),
|
||||
{
|
||||
type: 'warning',
|
||||
},
|
||||
)
|
||||
loading = this.$loading()
|
||||
const res = await Promise.all(this.selection.map((x) => this.$API.sys_config.setEnabled.post(Object.assign(x, { enabled: enabled }))))
|
||||
this.$message.success(
|
||||
this.$t('操作成功 {count}/{total} 项', {
|
||||
count: res.map((x) => x.data ?? 0).reduce((a, b) => a + b, 0),
|
||||
total: this.selection.length,
|
||||
}),
|
||||
)
|
||||
} catch {
|
||||
//
|
||||
}
|
||||
this.$refs.table.refresh()
|
||||
loading?.close()
|
||||
},
|
||||
async changeSwitch(event, row) {
|
||||
try {
|
||||
await this.$API.sys_config.edit.post(row)
|
||||
@ -135,10 +175,9 @@ export default {
|
||||
filterChange(data) {
|
||||
Object.entries(data).forEach(([key, value]) => {
|
||||
this.$refs.search.form.dy[key] = value === 'true' ? true : value === 'false' ? false : value
|
||||
this.$refs.search.search()
|
||||
})
|
||||
this.$refs.search.search()
|
||||
},
|
||||
|
||||
async rowDel(row) {
|
||||
try {
|
||||
const res = await this.$API.sys_config.delete.post({ id: row.id })
|
||||
@ -168,7 +207,14 @@ export default {
|
||||
this.$refs.table.upData()
|
||||
},
|
||||
},
|
||||
mounted() {},
|
||||
mounted() {
|
||||
if (this.keywords) {
|
||||
this.$refs.search.form.root.keywords = this.keywords
|
||||
this.$refs.search.keepKeywords = this.keywords
|
||||
}
|
||||
},
|
||||
props: ['keywords'],
|
||||
watch: {},
|
||||
}
|
||||
</script>
|
||||
|
||||
|
@ -35,7 +35,7 @@
|
||||
<el-tab-pane v-if="mode === 'view'" :label="$t('原始数据')">
|
||||
<json-viewer
|
||||
:expand-depth="5"
|
||||
:theme="this.$TOOL.data.get('APP_DARK') ? 'dark' : 'light'"
|
||||
:theme="this.$TOOL.data.get('APP_SET_DARK') || this.$CONFIG.APP_SET_DARK ? 'dark' : 'light'"
|
||||
:value="form"
|
||||
copyable
|
||||
expanded
|
||||
@ -45,7 +45,7 @@
|
||||
</div>
|
||||
<template #footer>
|
||||
<el-button @click="visible = false">{{ $t('取消') }}</el-button>
|
||||
<el-button v-if="mode !== 'view'" :loading="loading" @click="submit" type="primary">{{ $t('保存') }}</el-button>
|
||||
<el-button v-if="mode !== 'view'" :disabled="loading" :loading="loading" @click="submit" type="primary">{{ $t('保存') }}</el-button>
|
||||
</template>
|
||||
</sc-dialog>
|
||||
</template>
|
||||
@ -53,37 +53,37 @@
|
||||
<script>
|
||||
export default {
|
||||
components: {},
|
||||
emits: ['success', 'closed'],
|
||||
data() {
|
||||
return {
|
||||
//表单数据
|
||||
form: {
|
||||
enabled: true,
|
||||
},
|
||||
loading: false,
|
||||
mode: 'add',
|
||||
//验证规则
|
||||
rules: {
|
||||
userRegisterDeptId: [{ required: true, message: '请选择默认部门' }],
|
||||
userRegisterRoleId: [{ required: true, message: '请选择默认角色' }],
|
||||
},
|
||||
titleMap: {
|
||||
add: this.$t('新增配置'),
|
||||
edit: this.$t('编辑配置'),
|
||||
view: this.$t('查看配置'),
|
||||
},
|
||||
visible: false,
|
||||
loading: false,
|
||||
//表单数据
|
||||
form: {
|
||||
enabled: true,
|
||||
},
|
||||
//验证规则
|
||||
rules: {
|
||||
userRegisterDeptId: [{ required: true, message: '请选择默认部门' }],
|
||||
userRegisterRoleId: [{ required: true, message: '请选择默认角色' }],
|
||||
},
|
||||
}
|
||||
},
|
||||
mounted() {},
|
||||
emits: ['success', 'closed', 'mounted'],
|
||||
methods: {
|
||||
//显示
|
||||
async open(mode = 'add', data) {
|
||||
async open(data) {
|
||||
this.visible = true
|
||||
this.loading = true
|
||||
this.mode = mode
|
||||
if (data) {
|
||||
Object.assign(this.form, (await this.$API.sys_config.get.post({ id: data.id })).data)
|
||||
this.mode = data.mode
|
||||
if (data.row?.id) {
|
||||
const res = await this.$API.sys_config.get.post({ id: data.row.id })
|
||||
Object.assign(this.form, res.data)
|
||||
}
|
||||
this.loading = false
|
||||
return this
|
||||
@ -95,20 +95,21 @@ export default {
|
||||
if (!valid) {
|
||||
return false
|
||||
}
|
||||
|
||||
this.loading = true
|
||||
|
||||
const method = this.mode === 'add' ? this.$API.sys_config.create : this.$API.sys_config.edit
|
||||
try {
|
||||
const method = this.mode === 'add' ? this.$API.sys_config.create : this.$API.sys_config.edit
|
||||
const res = await method.post(this.form)
|
||||
this.$emit('success', res.data, this.mode)
|
||||
this.visible = false
|
||||
this.$message.success(this.$t('操作成功'))
|
||||
} catch {
|
||||
///
|
||||
}
|
||||
} catch {}
|
||||
this.loading = false
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.$emit('mounted')
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
|
@ -34,13 +34,26 @@
|
||||
ref="search" />
|
||||
</div>
|
||||
<div class="right-panel">
|
||||
<na-button-add :vue="this" />
|
||||
<el-button @click="this.dialog.save = { mode: 'add' }" icon="el-icon-plus" type="primary"></el-button>
|
||||
<na-button-bulk-del :api="$API.sys_dept.bulkDelete" :vue="this" />
|
||||
<el-dropdown v-show="this.selection.length > 0">
|
||||
<el-button type="primary">
|
||||
{{ $t('批量操作') }}
|
||||
<el-icon>
|
||||
<el-icon-arrow-down />
|
||||
</el-icon>
|
||||
</el-button>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item @click="setEnabled(true)">{{ $t('启用部门') }}</el-dropdown-item>
|
||||
<el-dropdown-item @click="setEnabled(false)">{{ $t('禁用部门') }}</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
</div>
|
||||
</el-header>
|
||||
<el-main class="nopadding">
|
||||
<sc-table
|
||||
v-loading="loading"
|
||||
:apiObj="$API.sys_dept.query"
|
||||
:context-menus="['id', 'name', 'sort', 'enabled', 'createdTime', 'summary']"
|
||||
:default-sort="{ prop: 'sort', order: 'descending' }"
|
||||
@ -58,17 +71,16 @@
|
||||
remote-sort
|
||||
row-key="id"
|
||||
stripe>
|
||||
<el-table-column type="selection" width="50" />
|
||||
<el-table-column :label="$t('部门编号')" prop="id" sortable="custom" />
|
||||
<el-table-column type="selection" />
|
||||
<na-col-id :label="$t('部门编号')" prop="id" sortable="custom" width="170" />
|
||||
<el-table-column :label="$t('部门名称')" prop="name" sortable="custom" />
|
||||
<el-table-column :label="$t('排序')" align="right" prop="sort" sortable="custom" />
|
||||
<el-table-column :label="$t('备注')" prop="summary" />
|
||||
<el-table-column :label="$t('启用')" align="center" prop="enabled" sortable="custom" width="100">
|
||||
<template #default="scope">
|
||||
<el-switch v-model="scope.row.enabled" @change="changeSwitch($event, scope.row)"></el-switch>
|
||||
<template #default="{ row }">
|
||||
<el-switch v-model="row.enabled" @change="changeSwitch($event, row)"></el-switch>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column :label="$t('备注')" prop="summary" />
|
||||
<el-table-column :label="$t('创建时间')" align="right" prop="createdTime" sortable="custom" />
|
||||
<na-col-operation
|
||||
:buttons="
|
||||
naColOperation.buttons.concat({
|
||||
@ -86,16 +98,18 @@
|
||||
|
||||
<save-dialog
|
||||
v-if="dialog.save"
|
||||
@closed="dialog.save = false"
|
||||
@closed="dialog.save = null"
|
||||
@mounted="$refs.saveDialog.open(dialog.save)"
|
||||
@success="(data, mode) => table.handleUpdate($refs.table, data, mode)"
|
||||
ref="saveDialog"></save-dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import saveDialog from './save'
|
||||
import naColOperation from '@/config/naColOperation'
|
||||
import { defineAsyncComponent } from 'vue'
|
||||
import table from '@/config/table'
|
||||
import naColOperation from '@/config/naColOperation'
|
||||
|
||||
const saveDialog = defineAsyncComponent(() => import('./save.vue'))
|
||||
export default {
|
||||
components: {
|
||||
saveDialog,
|
||||
@ -108,12 +122,14 @@ export default {
|
||||
return table
|
||||
},
|
||||
},
|
||||
created() {},
|
||||
created() {
|
||||
if (this.keywords) {
|
||||
this.query.keywords = this.keywords
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
dialog: {
|
||||
save: false,
|
||||
},
|
||||
dialog: {},
|
||||
loading: false,
|
||||
query: {
|
||||
dynamicFilter: {
|
||||
@ -126,6 +142,33 @@ export default {
|
||||
},
|
||||
inject: ['reload'],
|
||||
methods: {
|
||||
async setEnabled(enabled) {
|
||||
let loading
|
||||
try {
|
||||
await this.$confirm(
|
||||
this.$t('确定要 {operator} 选中的 {count} 项吗?', {
|
||||
operator: enabled ? this.$t('启用') : this.$t('禁用'),
|
||||
count: this.selection.length,
|
||||
}),
|
||||
this.$t('提示'),
|
||||
{
|
||||
type: 'warning',
|
||||
},
|
||||
)
|
||||
loading = this.$loading()
|
||||
const res = await Promise.all(this.selection.map((x) => this.$API.sys_dept.setEnabled.post(Object.assign(x, { enabled: enabled }))))
|
||||
this.$message.success(
|
||||
this.$t('操作成功 {count}/{total} 项', {
|
||||
count: res.map((x) => x.data ?? 0).reduce((a, b) => a + b, 0),
|
||||
total: this.selection.length,
|
||||
}),
|
||||
)
|
||||
} catch {
|
||||
//
|
||||
}
|
||||
this.$refs.table.refresh()
|
||||
loading?.close()
|
||||
},
|
||||
async changeSwitch(event, row) {
|
||||
try {
|
||||
await this.$API.sys_dept.setEnabled.post(row)
|
||||
@ -138,8 +181,8 @@ export default {
|
||||
filterChange(data) {
|
||||
Object.entries(data).forEach(([key, value]) => {
|
||||
this.$refs.search.form.dy[key] = value === 'true' ? true : value === 'false' ? false : value
|
||||
this.$refs.search.search()
|
||||
})
|
||||
this.$refs.search.search()
|
||||
},
|
||||
async rowDel(row) {
|
||||
try {
|
||||
@ -170,7 +213,13 @@ export default {
|
||||
this.$refs.table.upData()
|
||||
},
|
||||
},
|
||||
mounted() {},
|
||||
mounted() {
|
||||
if (this.keywords) {
|
||||
this.$refs.search.form.root.keywords = this.keywords
|
||||
this.$refs.search.keepKeywords = this.keywords
|
||||
}
|
||||
},
|
||||
props: ['keywords'],
|
||||
watch: {},
|
||||
}
|
||||
</script>
|
||||
|
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<sc-dialog v-model="visible" :title="`${titleMap[mode]}:${form?.id ?? '...'}`" :width="800" @closed="$emit('closed')" destroy-on-close>
|
||||
<sc-dialog v-model="visible" :title="`${titleMap[mode]}:${form?.id ?? '...'}`" @closed="$emit('closed')" destroy-on-close full-screen>
|
||||
<div v-loading="loading">
|
||||
<el-tabs tab-position="top">
|
||||
<el-tabs v-model="tabId" tab-position="top">
|
||||
<el-tab-pane :label="$t('基本信息')">
|
||||
<el-form :disabled="mode === 'view'" :model="form" :rules="rules" label-width="15rem" ref="dialogForm">
|
||||
<el-form-item :label="$t('上级部门')" prop="parentId">
|
||||
@ -27,10 +27,13 @@
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane v-if="mode === 'view'" :label="$t('用户列表')" name="user">
|
||||
<user v-if="tabId === 'user'" :dept-id="form.id"></user>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane v-if="mode === 'view'" :label="$t('原始数据')">
|
||||
<json-viewer
|
||||
:expand-depth="5"
|
||||
:theme="this.$TOOL.data.get('APP_DARK') ? 'dark' : 'light'"
|
||||
:theme="this.$TOOL.data.get('APP_SET_DARK') || this.$CONFIG.APP_SET_DARK ? 'dark' : 'light'"
|
||||
:value="form"
|
||||
copyable
|
||||
expanded
|
||||
@ -40,27 +43,31 @@
|
||||
</div>
|
||||
<template #footer>
|
||||
<el-button @click="visible = false">{{ $t('取消') }}</el-button>
|
||||
<el-button v-if="mode !== 'view'" :loading="loading" @click="submit" type="primary">{{ $t('保存') }}</el-button>
|
||||
<el-button v-if="mode !== 'view'" :disabled="loading" :loading="loading" @click="submit" type="primary">{{ $t('保存') }}</el-button>
|
||||
</template>
|
||||
</sc-dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { defineAsyncComponent } from 'vue'
|
||||
|
||||
const User = defineAsyncComponent(() => import('@/views/sys/user/index.vue'))
|
||||
export default {
|
||||
components: {},
|
||||
emits: ['success', 'closed'],
|
||||
components: { User },
|
||||
data() {
|
||||
return {
|
||||
mode: 'add',
|
||||
titleMap: {
|
||||
add: this.$t('新增部门'),
|
||||
edit: this.$t('编辑部门'),
|
||||
view: this.$t('查看部门'),
|
||||
//所需数据选项
|
||||
depts: [],
|
||||
deptsProps: {
|
||||
label: 'name',
|
||||
value: 'id',
|
||||
emitPath: false,
|
||||
checkStrictly: true,
|
||||
},
|
||||
visible: false,
|
||||
loading: false,
|
||||
//表单数据
|
||||
form: { enabled: true, sort: 100 },
|
||||
loading: false,
|
||||
mode: 'add',
|
||||
//验证规则
|
||||
rules: {
|
||||
sort: [
|
||||
@ -72,27 +79,25 @@ export default {
|
||||
],
|
||||
name: [{ required: true, message: '请输入部门名称' }],
|
||||
},
|
||||
//所需数据选项
|
||||
depts: [],
|
||||
deptsProps: {
|
||||
label: 'name',
|
||||
value: 'id',
|
||||
emitPath: false,
|
||||
checkStrictly: true,
|
||||
tabId: '0',
|
||||
titleMap: {
|
||||
add: this.$t('新增部门'),
|
||||
edit: this.$t('编辑部门'),
|
||||
view: this.$t('查看部门'),
|
||||
},
|
||||
visible: false,
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.getGroup()
|
||||
},
|
||||
emits: ['success', 'closed', 'mounted'],
|
||||
methods: {
|
||||
//显示
|
||||
async open(mode = 'add', data) {
|
||||
async open(data) {
|
||||
this.visible = true
|
||||
this.loading = true
|
||||
this.mode = mode
|
||||
if (data) {
|
||||
Object.assign(this.form, (await this.$API.sys_dept.get.post({ id: data.id })).data)
|
||||
this.mode = data.mode
|
||||
if (data.row?.id) {
|
||||
const res = await this.$API.sys_dept.get.post({ id: data.row.id })
|
||||
Object.assign(this.form, res.data)
|
||||
}
|
||||
this.loading = false
|
||||
return this
|
||||
@ -103,25 +108,27 @@ export default {
|
||||
this.depts = res.data
|
||||
},
|
||||
//表单提交方法
|
||||
submit() {
|
||||
this.$refs.dialogForm.validate(async (valid) => {
|
||||
if (valid) {
|
||||
this.loading = true
|
||||
try {
|
||||
const method = this.mode === 'add' ? this.$API.sys_dept.create : this.$API.sys_dept.edit
|
||||
const res = await method.post(this.form)
|
||||
this.$emit('success', res.data, this.mode)
|
||||
this.visible = false
|
||||
this.$message.success(this.$t('操作成功'))
|
||||
} catch {
|
||||
//
|
||||
}
|
||||
this.loading = false
|
||||
}
|
||||
})
|
||||
async submit() {
|
||||
const valid = await this.$refs.dialogForm.validate().catch(() => {})
|
||||
if (!valid) {
|
||||
return false
|
||||
}
|
||||
this.loading = true
|
||||
const method = this.mode === 'add' ? this.$API.sys_dept.create : this.$API.sys_dept.edit
|
||||
try {
|
||||
const res = await method.post(this.form)
|
||||
this.$emit('success', res.data, this.mode)
|
||||
this.visible = false
|
||||
this.$message.success(this.$t('操作成功'))
|
||||
} catch {}
|
||||
this.loading = false
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.$emit('mounted')
|
||||
this.getGroup()
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style></style>
|
||||
<style scoped></style>
|
@ -42,27 +42,38 @@
|
||||
</el-aside>
|
||||
<list :catalogId="form.catalogId" />
|
||||
</el-container>
|
||||
<save-dialog v-if="dialog.save" @closed="dialog.save = false" @success="getData" ref="saveDialog"></save-dialog>
|
||||
|
||||
<save-dialog
|
||||
v-if="dialog.save"
|
||||
@closed="dialog.save = null"
|
||||
@mounted="$refs.saveDialog.open(dialog.save)"
|
||||
@success="(data, mode) => getData()"
|
||||
ref="saveDialog"></save-dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import saveDialog from './save'
|
||||
import { defineAsyncComponent } from 'vue'
|
||||
import list from './list'
|
||||
|
||||
const saveDialog = defineAsyncComponent(() => import('./save.vue'))
|
||||
export default {
|
||||
components: {
|
||||
list,
|
||||
saveDialog,
|
||||
},
|
||||
computed: {},
|
||||
created() {
|
||||
if (this.keywords) {
|
||||
this.query.keywords = this.keywords
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
form: {},
|
||||
dialog: {
|
||||
save: false,
|
||||
},
|
||||
loading: false,
|
||||
data: [],
|
||||
dialog: {},
|
||||
filterText: '',
|
||||
form: {},
|
||||
loading: false,
|
||||
query: {
|
||||
dynamicFilter: {
|
||||
filters: [],
|
||||
@ -71,14 +82,7 @@ export default {
|
||||
},
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
filterText(val) {
|
||||
this.$refs.dic.filter(val)
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.getData()
|
||||
},
|
||||
inject: ['reload'],
|
||||
methods: {
|
||||
// 获取字典目录
|
||||
async getData() {
|
||||
@ -102,15 +106,11 @@ export default {
|
||||
},
|
||||
//字典目录增加
|
||||
async add() {
|
||||
this.dialog.save = true
|
||||
await this.$nextTick()
|
||||
await this.$refs.saveDialog.open()
|
||||
this.dialog.save = { mode: 'add' }
|
||||
},
|
||||
//字典目录编辑
|
||||
async edit(data) {
|
||||
this.dialog.save = true
|
||||
await this.$nextTick()
|
||||
await this.$refs.saveDialog.open('edit', data)
|
||||
this.dialog.save = { mode: 'edit', row: data }
|
||||
},
|
||||
//字典目录点击
|
||||
click(data) {
|
||||
@ -131,6 +131,15 @@ export default {
|
||||
await this.getData()
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.getData()
|
||||
},
|
||||
props: ['keywords'],
|
||||
watch: {
|
||||
filterText(val) {
|
||||
this.$refs.dic.filter(val)
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
|
@ -16,7 +16,7 @@
|
||||
ref="search" />
|
||||
</div>
|
||||
<div class="right-panel">
|
||||
<na-button-add :data="{ catalogId: this.catalogId }" :vue="this" />
|
||||
<el-button @click="this.dialog.save = { mode: 'add' }" icon="el-icon-plus" type="primary"></el-button>
|
||||
<na-button-bulk-del :api="$API.sys_dic.bulkDeleteContent" :vue="this" />
|
||||
</div>
|
||||
</el-header>
|
||||
@ -55,18 +55,25 @@
|
||||
</sc-table>
|
||||
</el-main>
|
||||
</el-container>
|
||||
|
||||
<save-dialog
|
||||
v-if="dialog.save"
|
||||
@closed="dialog.save = false"
|
||||
@closed="dialog.save = null"
|
||||
@mounted="$refs.saveDialog.open(dialog.save)"
|
||||
@success="(data, mode) => table.handleUpdate($refs.table, data, mode)"
|
||||
ref="saveDialog"></save-dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import saveDialog from './save'
|
||||
import { defineAsyncComponent } from 'vue'
|
||||
import table from '@/config/table'
|
||||
import naColOperation from '@/config/naColOperation'
|
||||
|
||||
const saveDialog = defineAsyncComponent(() => import('./save.vue'))
|
||||
export default {
|
||||
components: {
|
||||
saveDialog,
|
||||
},
|
||||
computed: {
|
||||
naColOperation() {
|
||||
return naColOperation
|
||||
@ -75,28 +82,25 @@ export default {
|
||||
return table
|
||||
},
|
||||
},
|
||||
components: { saveDialog },
|
||||
props: { catalogId: Number },
|
||||
inject: ['reload'],
|
||||
created() {
|
||||
if (this.keywords) {
|
||||
this.query.keywords = this.keywords
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
dialog: {
|
||||
save: false,
|
||||
},
|
||||
selection: [],
|
||||
dialog: {},
|
||||
loading: false,
|
||||
query: {
|
||||
dynamicFilter: {
|
||||
filters: [],
|
||||
},
|
||||
filter: {},
|
||||
},
|
||||
selection: [],
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
catalogId() {
|
||||
this.$refs.search.reset()
|
||||
},
|
||||
},
|
||||
inject: ['reload'],
|
||||
methods: {
|
||||
//搜索
|
||||
onSearch(form) {
|
||||
@ -146,5 +150,19 @@ export default {
|
||||
this.$refs.table.refresh()
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
if (this.keywords) {
|
||||
this.$refs.search.form.root.keywords = this.keywords
|
||||
this.$refs.search.keepKeywords = this.keywords
|
||||
}
|
||||
},
|
||||
props: { catalogId: Number, keywords: String },
|
||||
watch: {
|
||||
catalogId() {
|
||||
this.$refs.search.reset()
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
@ -18,7 +18,7 @@
|
||||
<el-tab-pane v-if="mode === 'view'" :label="$t('原始数据')">
|
||||
<json-viewer
|
||||
:expand-depth="5"
|
||||
:theme="this.$TOOL.data.get('APP_DARK') ? 'dark' : 'light'"
|
||||
:theme="this.$TOOL.data.get('APP_SET_DARK') || this.$CONFIG.APP_SET_DARK ? 'dark' : 'light'"
|
||||
:value="form"
|
||||
copyable
|
||||
expanded
|
||||
@ -28,7 +28,7 @@
|
||||
</div>
|
||||
<template #footer>
|
||||
<el-button @click="visible = false">{{ $t('取消') }}</el-button>
|
||||
<el-button v-if="mode !== 'view'" :loading="loading" @click="submit" type="primary">{{ $t('保存') }}</el-button>
|
||||
<el-button v-if="mode !== 'view'" :disabled="loading" :loading="loading" @click="submit" type="primary">{{ $t('保存') }}</el-button>
|
||||
</template>
|
||||
</sc-dialog>
|
||||
</template>
|
||||
@ -36,58 +36,62 @@
|
||||
<script>
|
||||
export default {
|
||||
components: {},
|
||||
emits: ['success', 'closed'],
|
||||
data() {
|
||||
return {
|
||||
mode: 'add',
|
||||
titleMap: {
|
||||
view: this.$t('查看字典项'),
|
||||
add: this.$t('新增字典项'),
|
||||
edit: this.$t('编辑字典项'),
|
||||
},
|
||||
visible: false,
|
||||
loading: false,
|
||||
//表单数据
|
||||
form: {},
|
||||
loading: false,
|
||||
mode: 'add',
|
||||
//验证规则
|
||||
rules: {
|
||||
catalogId: [{ required: true, message: '请选择所属字典' }],
|
||||
key: [{ required: true, message: '请输入项名' }],
|
||||
value: [{ required: true, message: '请输入项值' }],
|
||||
},
|
||||
titleMap: {
|
||||
add: this.$t('新增字典项'),
|
||||
edit: this.$t('编辑字典项'),
|
||||
view: this.$t('查看字典项'),
|
||||
},
|
||||
visible: false,
|
||||
}
|
||||
},
|
||||
mounted() {},
|
||||
emits: ['success', 'closed', 'mounted'],
|
||||
methods: {
|
||||
//显示
|
||||
async open(mode = 'add', data) {
|
||||
async open(data) {
|
||||
this.visible = true
|
||||
this.loading = true
|
||||
this.mode = mode
|
||||
if (data) {
|
||||
Object.assign(this.form, (await this.$API.sys_dic.getContent.post({ id: data.id })).data)
|
||||
this.mode = data.mode
|
||||
if (data.row?.id) {
|
||||
const res = await this.$API.sys_dic.getContent.post({ id: data.row.id })
|
||||
Object.assign(this.form, res.data)
|
||||
}
|
||||
this.loading = false
|
||||
return this
|
||||
},
|
||||
|
||||
//表单提交方法
|
||||
async submit() {
|
||||
const valid = await this.$refs.dialogForm.validate().catch(() => {})
|
||||
if (!valid) {
|
||||
return false
|
||||
}
|
||||
|
||||
this.loading = true
|
||||
|
||||
const method = this.mode === 'add' ? this.$API.sys_dic.createContent : this.$API.sys_dic.editContent
|
||||
try {
|
||||
const method = this.mode === 'add' ? this.$API.sys_dic.createContent : this.$API.sys_dic.editContent
|
||||
const res = await method.post(this.form)
|
||||
this.$emit('success', res.data, this.mode)
|
||||
this.visible = false
|
||||
this.$message.success(this.$t('操作成功'))
|
||||
} catch {
|
||||
//
|
||||
}
|
||||
} catch {}
|
||||
this.loading = false
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.$emit('mounted')
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
|
@ -13,39 +13,41 @@
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button @click="visible = false">{{ $t('取消') }}</el-button>
|
||||
<el-button :loading="loading" @click="submit" type="primary">{{ $t('保存') }}</el-button>
|
||||
<el-button v-if="mode !== 'view'" :disabled="loading" :loading="loading" @click="submit" type="primary">{{ $t('保存') }}</el-button>
|
||||
</template>
|
||||
</sc-dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
emits: ['success', 'closed'],
|
||||
data() {
|
||||
return {
|
||||
//表单数据
|
||||
form: {},
|
||||
loading: false,
|
||||
mode: 'add',
|
||||
//验证规则
|
||||
rules: {
|
||||
code: [{ required: true, message: '请输入编码' }],
|
||||
name: [{ required: true, message: '请输入字典名称' }],
|
||||
},
|
||||
titleMap: {
|
||||
add: this.$t('新增字典'),
|
||||
edit: this.$t('编辑字典'),
|
||||
},
|
||||
visible: false,
|
||||
loading: false,
|
||||
form: {},
|
||||
rules: {
|
||||
code: [{ required: true, message: '请输入编码' }],
|
||||
name: [{ required: true, message: '请输入字典名称' }],
|
||||
},
|
||||
}
|
||||
},
|
||||
mounted() {},
|
||||
emits: ['success', 'closed', 'mounted'],
|
||||
methods: {
|
||||
//显示
|
||||
async open(mode = 'add', data) {
|
||||
async open(data) {
|
||||
this.visible = true
|
||||
this.loading = true
|
||||
this.mode = mode
|
||||
if (data) {
|
||||
Object.assign(this.form, (await this.$API.sys_dic.getCatalog.post({ id: data.id })).data)
|
||||
this.mode = data.mode
|
||||
if (data.row?.id) {
|
||||
const res = await this.$API.sys_dic.getCatalog.post({ id: data.row.id })
|
||||
Object.assign(this.form, res.data)
|
||||
}
|
||||
this.loading = false
|
||||
return this
|
||||
@ -57,21 +59,21 @@ export default {
|
||||
if (!valid) {
|
||||
return false
|
||||
}
|
||||
|
||||
this.loading = true
|
||||
const method = this.mode === 'add' ? this.$API.sys_dic.createCatalog : this.$API.sys_dic.editCatalog
|
||||
try {
|
||||
const method = this.mode === 'add' ? this.$API.sys_dic.createCatalog : this.$API.sys_dic.editCatalog
|
||||
const res = await method.post(this.form)
|
||||
this.$emit('success', res.data, this.mode)
|
||||
this.visible = false
|
||||
this.$message.success(this.$t('操作成功'))
|
||||
} catch {
|
||||
//
|
||||
}
|
||||
} catch {}
|
||||
this.loading = false
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.$emit('mounted')
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style></style>
|
||||
<style scoped></style>
|
352
src/frontend/admin/src/views/sys/job/all/index.vue
Normal file
352
src/frontend/admin/src/views/sys/job/all/index.vue
Normal file
@ -0,0 +1,352 @@
|
||||
<template>
|
||||
<el-container>
|
||||
<el-header style="height: auto; padding: 0 1rem">
|
||||
<sc-select-filter
|
||||
:data="[
|
||||
{
|
||||
title: $t('作业状态'),
|
||||
key: 'status',
|
||||
options: [
|
||||
{ label: $t('全部'), value: '' },
|
||||
...Object.entries(this.$GLOBAL.enums.jobStatues).map((x) => {
|
||||
return { value: x[0], label: x[1][1] }
|
||||
}),
|
||||
],
|
||||
},
|
||||
{
|
||||
title: $t('启用状态'),
|
||||
key: 'enabled',
|
||||
options: [
|
||||
{ label: $t('全部'), value: '' },
|
||||
{ label: $t('启用'), value: true },
|
||||
{ label: $t('禁用'), value: false },
|
||||
],
|
||||
},
|
||||
]"
|
||||
:label-width="10"
|
||||
@on-change="filterChange"
|
||||
ref="selectFilter"></sc-select-filter>
|
||||
</el-header>
|
||||
<el-header>
|
||||
<div class="left-panel">
|
||||
<na-search
|
||||
:controls="[
|
||||
{
|
||||
type: 'input',
|
||||
field: ['root', 'keywords'],
|
||||
placeholder: $t('作业编号 / 作业名称'),
|
||||
style: 'width:20rem',
|
||||
},
|
||||
{
|
||||
type: 'select',
|
||||
field: ['dy', 'httpMethod'],
|
||||
options: Object.entries(this.$GLOBAL.enums.httpMethods).map((x) => {
|
||||
return { value: x[0], label: x[1][1] }
|
||||
}),
|
||||
placeholder: $t('请求方式'),
|
||||
style: 'width:15rem',
|
||||
},
|
||||
]"
|
||||
:vue="this"
|
||||
@reset="Object.entries(this.$refs.selectFilter.selected).forEach(([key, _]) => (this.$refs.selectFilter.selected[key] = ['']))"
|
||||
@search="onSearch"
|
||||
ref="search" />
|
||||
</div>
|
||||
<div class="right-panel">
|
||||
<el-button @click="this.dialog.save = { mode: 'add' }" icon="el-icon-plus" type="primary"></el-button>
|
||||
<na-button-bulk-del :api="$API.sys_job.bulkDelete" :vue="this" />
|
||||
<el-dropdown v-show="this.selection.length > 0">
|
||||
<el-button type="primary">
|
||||
{{ $t('批量操作') }}
|
||||
<el-icon>
|
||||
<el-icon-arrow-down />
|
||||
</el-icon>
|
||||
</el-button>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item @click="setEnabled(true)">{{ $t('启用作业') }}</el-dropdown-item>
|
||||
<el-dropdown-item @click="setEnabled(false)">{{ $t('禁用作业') }}</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
</div>
|
||||
</el-header>
|
||||
<el-main class="nopadding">
|
||||
<sc-table
|
||||
:apiObj="$API.sys_job.pagedQuery"
|
||||
:context-menus="[
|
||||
'id',
|
||||
'jobName',
|
||||
'executionCron',
|
||||
'status',
|
||||
'httpMethod',
|
||||
'lastExecTime',
|
||||
'lastStatusCode',
|
||||
'nextExecTime',
|
||||
'enabled',
|
||||
'createdTime',
|
||||
]"
|
||||
:default-sort="{ prop: 'lastExecTime', order: 'descending' }"
|
||||
:page-size="100"
|
||||
:params="query"
|
||||
:vue="this"
|
||||
@selection-change="
|
||||
(items) => {
|
||||
selection = items
|
||||
}
|
||||
"
|
||||
ref="table"
|
||||
remote-filter
|
||||
remote-sort
|
||||
row-key="id"
|
||||
stripe>
|
||||
<el-table-column type="selection" />
|
||||
<na-col-id :label="$t('作业编号')" prop="id" sortable="custom" width="170" />
|
||||
<el-table-column :label="$t('作业名称')" prop="jobName" show-overflow-tooltip sortable="custom" />
|
||||
<el-table-column :label="$t('执行计划')" align="right" prop="executionCron" sortable="custom" width="150" />
|
||||
<na-col-indicator
|
||||
:label="$t('作业状态')"
|
||||
:options="
|
||||
Object.entries(this.$GLOBAL.enums.jobStatues).map((x) => {
|
||||
return { value: x[0], text: x[1][1], type: x[1][2] }
|
||||
})
|
||||
"
|
||||
align="center"
|
||||
prop="status"
|
||||
sortable="custom"
|
||||
width="100" />
|
||||
<na-col-indicator
|
||||
:label="$t('请求方式')"
|
||||
:options="
|
||||
Object.entries(this.$GLOBAL.enums.httpMethods).map((x) => {
|
||||
return { value: x[0], text: x[1][1], type: x[1][2] }
|
||||
})
|
||||
"
|
||||
align="center"
|
||||
prop="httpMethod"
|
||||
sortable="custom"
|
||||
width="150" />
|
||||
<el-table-column :label="$t('上次执行')" align="center">
|
||||
<el-table-column :label="$t('状态')" align="center" prop="lastExecTime" sortable="custom" width="100">
|
||||
<template #default="{ row }">
|
||||
<na-indicator
|
||||
:data="row"
|
||||
:options="
|
||||
Object.entries(this.$GLOBAL.enums.httpStatusCodes).map((x) => {
|
||||
return { value: x[0], text: `${x[1][1]}`, type: x[1][2] }
|
||||
})
|
||||
"
|
||||
prop="lastStatusCode" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column :label="$t('时间')" align="right" prop="lastExecTime" sortable="custom" width="100">
|
||||
<template #default="{ row }">
|
||||
<span v-if="row.lastExecTime" v-time.tip="row.lastExecTime"></span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
:formatter="(row) => (row.lastDuration ? `${$TOOL.groupSeparator(row.lastDuration.toFixed(0))} ms` : `-`)"
|
||||
:label="$t('耗时')"
|
||||
align="right"
|
||||
prop="lastDuration"
|
||||
sortable="custom"
|
||||
width="100">
|
||||
</el-table-column>
|
||||
</el-table-column>
|
||||
<el-table-column :label="$t('下次执行时间')" align="right" prop="nextExecTime" sortable="custom" width="170" />
|
||||
<el-table-column :label="$t('启用')" align="center" prop="enabled" sortable="custom" width="100">
|
||||
<template #default="{ row }">
|
||||
<el-switch v-model="row.enabled" @change="changeSwitch($event, row)"></el-switch>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<na-col-operation
|
||||
:buttons="
|
||||
naColOperation.buttons.concat(
|
||||
{
|
||||
icon: 'el-icon-video-play',
|
||||
click: execute,
|
||||
},
|
||||
{
|
||||
icon: 'el-icon-delete',
|
||||
confirm: true,
|
||||
title: $t('删除作业'),
|
||||
click: rowDel,
|
||||
type: 'danger',
|
||||
},
|
||||
)
|
||||
"
|
||||
:vue="this" />
|
||||
</sc-table>
|
||||
</el-main>
|
||||
</el-container>
|
||||
|
||||
<save-dialog
|
||||
v-if="dialog.save"
|
||||
@closed="dialog.save = null"
|
||||
@mounted="$refs.saveDialog.open(dialog.save)"
|
||||
@success="(data, mode) => table.handleUpdate($refs.table, data, mode)"
|
||||
ref="saveDialog"></save-dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { defineAsyncComponent } from 'vue'
|
||||
import table from '@/config/table'
|
||||
import naColOperation from '@/config/naColOperation'
|
||||
import naIndicator from '@/components/naIndicator/index.vue'
|
||||
|
||||
const saveDialog = defineAsyncComponent(() => import('./save.vue'))
|
||||
export default {
|
||||
components: {
|
||||
naIndicator,
|
||||
saveDialog,
|
||||
},
|
||||
computed: {
|
||||
naColOperation() {
|
||||
return naColOperation
|
||||
},
|
||||
table() {
|
||||
return table
|
||||
},
|
||||
},
|
||||
created() {
|
||||
if (this.keywords || this.$route.query.keywords) {
|
||||
this.query.keywords = this.keywords || this.$route.query.keywords
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
dialog: {},
|
||||
loading: false,
|
||||
query: {
|
||||
dynamicFilter: {
|
||||
filters: [],
|
||||
},
|
||||
filter: {},
|
||||
},
|
||||
selection: [],
|
||||
timer: null,
|
||||
}
|
||||
},
|
||||
inject: ['reload'],
|
||||
methods: {
|
||||
async setEnabled(enabled) {
|
||||
let loading
|
||||
try {
|
||||
await this.$confirm(
|
||||
this.$t('确定要 {operator} 选中的 {count} 项吗?', {
|
||||
operator: enabled ? this.$t('启用') : this.$t('禁用'),
|
||||
count: this.selection.length,
|
||||
}),
|
||||
this.$t('提示'),
|
||||
{
|
||||
type: 'warning',
|
||||
},
|
||||
)
|
||||
loading = this.$loading()
|
||||
const res = await Promise.all(this.selection.map((x) => this.$API.sys_job.setEnabled.post(Object.assign(x, { enabled: enabled }))))
|
||||
this.$message.success(
|
||||
this.$t('操作成功 {count}/{total} 项', {
|
||||
count: res.map((x) => x.data ?? 0).reduce((a, b) => a + b, 0),
|
||||
total: this.selection.length,
|
||||
}),
|
||||
)
|
||||
} catch {
|
||||
//
|
||||
}
|
||||
this.$refs.table.refresh()
|
||||
loading?.close()
|
||||
},
|
||||
filterChange(data) {
|
||||
Object.entries(data).forEach(([key, value]) => {
|
||||
this.$refs.search.form.dy[key] = value === 'true' ? true : value === 'false' ? false : value
|
||||
})
|
||||
this.$refs.search.search()
|
||||
},
|
||||
//表格内开关事件
|
||||
async changeSwitch(event, row) {
|
||||
try {
|
||||
await this.$API.sys_job.setEnabled.post(row)
|
||||
this.$message.success(this.$t('操作成功'))
|
||||
} catch {
|
||||
//
|
||||
}
|
||||
this.$refs.table.refresh()
|
||||
},
|
||||
async execute(row) {
|
||||
try {
|
||||
await this.$API.sys_job.execute.post({ id: row.id })
|
||||
this.$notify.success({
|
||||
dangerouslyUseHTMLString: true,
|
||||
message: `<div id="countdown">${this.$t('已发起执行请求,5 秒后弹出执行结果')}</div>`,
|
||||
onClose: async () => {
|
||||
clearInterval(this.timer)
|
||||
this.dialog.save = { row, mode: 'view', tabId: 'record' }
|
||||
},
|
||||
})
|
||||
|
||||
this.timer = setInterval(() => {
|
||||
const countdown = new RegExp('\\d+').exec(document.getElementById('countdown').innerText)[0]
|
||||
const num = parseInt(countdown) - 1
|
||||
document.getElementById('countdown').innerText = document
|
||||
.getElementById('countdown')
|
||||
.innerText.replace(countdown, `${num < 0 ? 0 : num}`)
|
||||
}, 1000)
|
||||
} catch {}
|
||||
this.$refs.table.refresh()
|
||||
},
|
||||
async rowDel(row) {
|
||||
try {
|
||||
const res = await this.$API.sys_job.delete.post({ id: row.id })
|
||||
this.$message.success(this.$t('删除 {count} 项', { count: res.data }))
|
||||
} catch {
|
||||
//
|
||||
}
|
||||
this.$refs.table.refresh()
|
||||
},
|
||||
onSearch(form) {
|
||||
if (Array.isArray(form.dy.createdTime)) {
|
||||
this.query.dynamicFilter.filters.push({
|
||||
field: 'createdTime',
|
||||
operator: 'dateRange',
|
||||
value: form.dy.createdTime,
|
||||
})
|
||||
}
|
||||
|
||||
if (typeof form.dy.status === 'string' && form.dy.status.trim() !== '') {
|
||||
this.query.dynamicFilter.filters.push({
|
||||
field: 'status',
|
||||
operator: 'eq',
|
||||
value: form.dy.status,
|
||||
})
|
||||
}
|
||||
|
||||
if (typeof form.dy.enabled === 'boolean') {
|
||||
this.query.dynamicFilter.filters.push({
|
||||
field: 'enabled',
|
||||
operator: 'eq',
|
||||
value: form.dy.enabled,
|
||||
})
|
||||
}
|
||||
|
||||
if (typeof form.dy.httpMethod === 'string' && form.dy.httpMethod.trim() !== '') {
|
||||
this.query.dynamicFilter.filters.push({
|
||||
field: 'httpMethod',
|
||||
operator: 'eq',
|
||||
value: form.dy.httpMethod,
|
||||
})
|
||||
}
|
||||
this.$refs.table.upData()
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
if (this.keywords || this.$route.query.keywords) {
|
||||
this.$refs.search.form.root.keywords = this.keywords || this.$route.query.keywords
|
||||
this.$refs.search.keepKeywords = this.keywords || this.$route.query.keywords
|
||||
}
|
||||
},
|
||||
props: ['keywords'],
|
||||
watch: {},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
@ -1,13 +1,7 @@
|
||||
<template>
|
||||
<sc-dialog
|
||||
v-model="visible"
|
||||
:title="`${titleMap[mode]}:${form?.id ?? '...'}`"
|
||||
:width="800"
|
||||
@closed="$emit('closed')"
|
||||
destroy-on-close
|
||||
full-screen>
|
||||
<el-tabs v-model="tabIndex" tab-position="top">
|
||||
<el-tab-pane :label="$t('基本信息')" :name="0">
|
||||
<sc-dialog v-model="visible" :title="`${titleMap[mode]}:${form?.id ?? '...'}`" @closed="$emit('closed')" destroy-on-close full-screen>
|
||||
<el-tabs v-model="tabId" tab-position="top">
|
||||
<el-tab-pane :label="$t('基本信息')">
|
||||
<el-form
|
||||
v-loading="loading"
|
||||
:disabled="mode === 'view'"
|
||||
@ -48,7 +42,7 @@
|
||||
<el-form-item :label="$t('请求头')" prop="requestHeader">
|
||||
<v-ace-editor
|
||||
v-model:value="form.requestHeader"
|
||||
:theme="this.$TOOL.data.get('APP_DARK') ? 'github_dark' : 'github'"
|
||||
:theme="this.$TOOL.data.get('APP_SET_DARK') || this.$CONFIG.APP_SET_DARK ? 'github_dark' : 'github'"
|
||||
lang="json"
|
||||
style="height: 5rem; width: 100%" />
|
||||
<el-button @click="form.requestHeader = jsonFormat(form.requestHeader)" type="text">{{ $t('JSON格式化') }}</el-button>
|
||||
@ -56,7 +50,7 @@
|
||||
<el-form-item :label="$t('请求体')" prop="requestBody">
|
||||
<v-ace-editor
|
||||
v-model:value="form.requestBody"
|
||||
:theme="this.$TOOL.data.get('APP_DARK') ? 'github_dark' : 'github'"
|
||||
:theme="this.$TOOL.data.get('APP_SET_DARK') || this.$CONFIG.APP_SET_DARK ? 'github_dark' : 'github'"
|
||||
lang="json"
|
||||
style="height: 10rem; width: 100%" />
|
||||
<el-button @click="form.requestBody = jsonFormat(form.requestBody)" type="text">{{ $t('JSON格式化') }}</el-button>
|
||||
@ -96,13 +90,13 @@
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane v-if="mode === 'view'" :label="$t('执行记录')" :name="1">
|
||||
<record v-if="tabIndex === 1" :keywords="form.id" />
|
||||
<el-tab-pane v-if="mode === 'view'" :label="$t('执行记录')" name="record">
|
||||
<record v-if="tabId === 'record'" :keywords="form.id" />
|
||||
</el-tab-pane>
|
||||
<el-tab-pane v-if="mode === 'view'" :label="$t('原始数据')" :name="2">
|
||||
<el-tab-pane v-if="mode === 'view'" :label="$t('原始数据')">
|
||||
<json-viewer
|
||||
:expand-depth="5"
|
||||
:theme="this.$TOOL.data.get('APP_DARK') ? 'dark' : 'light'"
|
||||
:theme="this.$TOOL.data.get('APP_SET_DARK') || this.$CONFIG.APP_SET_DARK ? 'dark' : 'light'"
|
||||
:value="form"
|
||||
copyable
|
||||
expanded
|
||||
@ -112,31 +106,20 @@
|
||||
|
||||
<template #footer>
|
||||
<el-button @click="visible = false">{{ $t('取消') }}</el-button>
|
||||
<el-button v-if="mode !== 'view'" :loading="loading" @click="submit" type="primary">{{ $t('保存') }}</el-button>
|
||||
<el-button v-if="mode !== 'view'" :disabled="loading" :loading="loading" @click="submit" type="primary">{{ $t('保存') }}</el-button>
|
||||
</template>
|
||||
</sc-dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Record from '@/views/sys/job/record/index.vue'
|
||||
import { defineAsyncComponent } from 'vue'
|
||||
import vkbeautify from 'vkbeautify/index'
|
||||
|
||||
const Record = defineAsyncComponent(() => import('@/views/sys/job/record/index.vue'))
|
||||
export default {
|
||||
components: {
|
||||
Record,
|
||||
},
|
||||
emits: ['success', 'closed'],
|
||||
components: { Record },
|
||||
data() {
|
||||
return {
|
||||
tabIndex: 0,
|
||||
mode: 'add',
|
||||
titleMap: {
|
||||
view: this.$t('查看作业'),
|
||||
add: this.$t('新增作业'),
|
||||
edit: this.$t('编辑作业'),
|
||||
},
|
||||
visible: false,
|
||||
loading: false,
|
||||
//表单数据
|
||||
form: {
|
||||
executionCron: '0 * * * * ?',
|
||||
@ -144,6 +127,8 @@ export default {
|
||||
requestHeader: `{ "Content-Type": "application/json" }`,
|
||||
requestBody: '{}',
|
||||
},
|
||||
loading: false,
|
||||
mode: 'add',
|
||||
//验证规则
|
||||
rules: {
|
||||
executionCron: [
|
||||
@ -197,9 +182,16 @@ export default {
|
||||
},
|
||||
],
|
||||
},
|
||||
tabId: '0',
|
||||
titleMap: {
|
||||
add: this.$t('新增作业'),
|
||||
edit: this.$t('编辑作业'),
|
||||
view: this.$t('查看作业'),
|
||||
},
|
||||
visible: false,
|
||||
}
|
||||
},
|
||||
mounted() {},
|
||||
emits: ['success', 'closed', 'mounted'],
|
||||
methods: {
|
||||
jsonFormat(obj) {
|
||||
try {
|
||||
@ -213,16 +205,16 @@ export default {
|
||||
return vkbeautify
|
||||
},
|
||||
//显示
|
||||
async open(mode = 'add', data, tabIndex = 0) {
|
||||
async open(data) {
|
||||
this.visible = true
|
||||
this.loading = true
|
||||
this.mode = mode
|
||||
if (data) {
|
||||
const res = await this.$API.sys_job.get.post({ id: data.id })
|
||||
this.mode = data.mode
|
||||
if (data.row?.id) {
|
||||
const res = await this.$API.sys_job.get.post({ id: data.row.id })
|
||||
Object.assign(this.form, res.data)
|
||||
}
|
||||
this.loading = false
|
||||
this.tabIndex = tabIndex
|
||||
this.tabId = data.tabId ?? '0'
|
||||
return this
|
||||
},
|
||||
|
||||
@ -232,14 +224,12 @@ export default {
|
||||
if (!valid) {
|
||||
return false
|
||||
}
|
||||
|
||||
this.loading = true
|
||||
const method = this.mode === 'add' ? this.$API.sys_job.create : this.$API.sys_job.edit
|
||||
try {
|
||||
const method = this.mode === 'add' ? this.$API.sys_job.create : this.$API.sys_job.edit
|
||||
this.loading = true
|
||||
const res = await method.post(
|
||||
Object.assign({}, this.form, { userId: this.form.user.id, requestHeaders: JSON.parse(this.form.requestHeader) }),
|
||||
)
|
||||
this.loading = false
|
||||
if (res.data) {
|
||||
this.$emit('success', res.data, this.mode)
|
||||
this.$message.success(this.$t('操作成功'))
|
||||
@ -247,11 +237,14 @@ export default {
|
||||
this.$message.error(this.$t('操作失败'))
|
||||
}
|
||||
this.visible = false
|
||||
} catch {
|
||||
//
|
||||
this.loading = false
|
||||
}
|
||||
} catch {}
|
||||
this.loading = false
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.$emit('mounted')
|
||||
},
|
||||
}
|
||||
</script>
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
@ -1,326 +1,35 @@
|
||||
<template>
|
||||
<el-container>
|
||||
<el-header style="height: auto; padding: 0 1rem">
|
||||
<sc-select-filter
|
||||
:data="[
|
||||
{
|
||||
title: $t('作业状态'),
|
||||
key: 'status',
|
||||
options: [
|
||||
{ label: $t('全部'), value: '' },
|
||||
...Object.entries(this.$GLOBAL.enums.jobStatues).map((x) => {
|
||||
return { value: x[0], label: x[1][1] }
|
||||
}),
|
||||
],
|
||||
},
|
||||
{
|
||||
title: $t('启用状态'),
|
||||
key: 'enabled',
|
||||
options: [
|
||||
{ label: $t('全部'), value: '' },
|
||||
{ label: $t('启用'), value: true },
|
||||
{ label: $t('禁用'), value: false },
|
||||
],
|
||||
},
|
||||
]"
|
||||
:label-width="10"
|
||||
@on-change="filterChange"
|
||||
ref="selectFilter"></sc-select-filter>
|
||||
</el-header>
|
||||
<el-header>
|
||||
<div class="left-panel">
|
||||
<na-search
|
||||
:controls="[
|
||||
{
|
||||
type: 'input',
|
||||
field: ['root', 'keywords'],
|
||||
placeholder: $t('作业编号 / 作业名称'),
|
||||
style: 'width:20rem',
|
||||
},
|
||||
{
|
||||
type: 'select',
|
||||
field: ['dy', 'httpMethod'],
|
||||
options: Object.entries(this.$GLOBAL.enums.httpMethods).map((x) => {
|
||||
return { value: x[0], label: x[1][1] }
|
||||
}),
|
||||
placeholder: $t('请求方式'),
|
||||
style: 'width:15rem',
|
||||
},
|
||||
]"
|
||||
:vue="this"
|
||||
@reset="Object.entries(this.$refs.selectFilter.selected).forEach(([key, _]) => (this.$refs.selectFilter.selected[key] = ['']))"
|
||||
@search="onSearch"
|
||||
ref="search" />
|
||||
</div>
|
||||
<div class="right-panel">
|
||||
<na-button-add :vue="this" />
|
||||
<na-button-bulk-del :api="$API.sys_job.bulkDelete" :vue="this" />
|
||||
</div>
|
||||
<el-header style="border: none">
|
||||
<el-tabs v-model="tabId" class="w100p">
|
||||
<el-tab-pane :label="$t('所有作业')" name="all"></el-tab-pane>
|
||||
<el-tab-pane :label="$t('异常作业')" name="fail"></el-tab-pane>
|
||||
</el-tabs>
|
||||
</el-header>
|
||||
<el-main class="nopadding">
|
||||
<sc-table
|
||||
v-loading="loading"
|
||||
:apiObj="$API.sys_job.pagedQuery"
|
||||
:context-menus="[
|
||||
'id',
|
||||
'jobName',
|
||||
'executionCron',
|
||||
'status',
|
||||
'httpMethod',
|
||||
'lastExecTime',
|
||||
'lastStatusCode',
|
||||
'nextExecTime',
|
||||
'enabled',
|
||||
'createdTime',
|
||||
]"
|
||||
:default-sort="{ prop: 'lastExecTime', order: 'descending' }"
|
||||
:page-size="100"
|
||||
:params="query"
|
||||
:vue="this"
|
||||
@selection-change="
|
||||
(items) => {
|
||||
selection = items
|
||||
}
|
||||
"
|
||||
ref="table"
|
||||
remote-filter
|
||||
remote-sort
|
||||
row-key="id"
|
||||
stripe>
|
||||
<el-table-column type="selection" />
|
||||
<el-table-column :label="$t('作业编号')" prop="id" sortable="custom" width="150" />
|
||||
<el-table-column :label="$t('作业名称')" prop="jobName" show-overflow-tooltip sortable="custom" />
|
||||
<el-table-column :label="$t('执行计划')" align="center" prop="executionCron" sortable="custom" width="150" />
|
||||
<na-col-indicator
|
||||
:label="$t('作业状态')"
|
||||
:options="
|
||||
Object.entries(this.$GLOBAL.enums.jobStatues).map((x) => {
|
||||
return { value: x[0], text: x[1][1], type: x[1][2] }
|
||||
})
|
||||
"
|
||||
align="center"
|
||||
prop="status"
|
||||
sortable="custom"
|
||||
width="100" />
|
||||
<na-col-indicator
|
||||
:label="$t('请求方式')"
|
||||
:options="
|
||||
Object.entries(this.$GLOBAL.enums.httpMethods).map((x) => {
|
||||
return { value: x[0], text: x[1][1], type: x[1][2] }
|
||||
})
|
||||
"
|
||||
align="center"
|
||||
prop="httpMethod"
|
||||
sortable="custom"
|
||||
width="150" />
|
||||
<el-table-column :label="$t('上次执行')" align="center">
|
||||
<el-table-column :label="$t('状态')" align="center" prop="lastExecTime" sortable="custom" width="100">
|
||||
<template #default="scope">
|
||||
<sc-status-indicator :type="scope.row.lastStatusCode === 'ok' ? 'success' : 'danger'" />
|
||||
{{
|
||||
this.$GLOBAL.enums.httpStatusCodes[scope.row.lastStatusCode]
|
||||
? this.$GLOBAL.enums.httpStatusCodes[scope.row.lastStatusCode][1]
|
||||
: scope.row.lastStatusCode
|
||||
}}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column :label="$t('时间')" align="right" prop="lastExecTime" sortable="custom" width="100">
|
||||
<template #default="scope">
|
||||
<span v-if="scope.row.lastExecTime" v-time.tip="scope.row.lastExecTime"></span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
:formatter="(row) => (row.lastDuration ? `${tool.groupSeparator(row.lastDuration.toFixed(0))} ms` : `-`)"
|
||||
:label="$t('耗时')"
|
||||
align="right"
|
||||
prop="lastDuration"
|
||||
sortable="custom"
|
||||
width="100">
|
||||
</el-table-column>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column :label="$t('下次执行时间')" align="right" prop="nextExecTime" sortable="custom" width="170" />
|
||||
<el-table-column :label="$t('启用')" align="center" prop="enabled" sortable="custom" width="100">
|
||||
<template #default="scope">
|
||||
<el-switch v-model="scope.row.enabled" @change="changeSwitch($event, scope.row)"></el-switch>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column :label="$t('创建时间')" align="right" prop="createdTime" sortable="custom" width="130">
|
||||
<template #default="scope">
|
||||
<span v-if="scope.row.createdTime" v-time.tip="scope.row.createdTime"></span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<na-col-operation
|
||||
:buttons="
|
||||
naColOperation.buttons.concat(
|
||||
{
|
||||
icon: 'el-icon-video-play',
|
||||
click: execute,
|
||||
},
|
||||
{
|
||||
icon: 'el-icon-delete',
|
||||
confirm: true,
|
||||
type: 'danger',
|
||||
title: $t('删除作业'),
|
||||
click: rowDel,
|
||||
},
|
||||
)
|
||||
"
|
||||
:vue="this"
|
||||
width="180" />
|
||||
</sc-table>
|
||||
<component :is="tabId" :status-codes="['300,399', '400,499', '500,599', '900,999']" />
|
||||
</el-main>
|
||||
</el-container>
|
||||
|
||||
<save-dialog
|
||||
v-if="dialog.save"
|
||||
@closed="dialog.save = false"
|
||||
@success="(data, mode) => table.handleUpdate($refs.table, data, mode)"
|
||||
ref="saveDialog"></save-dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import saveDialog from './save'
|
||||
import table from '@/config/table'
|
||||
import naColOperation from '@/config/naColOperation'
|
||||
import ScSelectFilter from '@/components/scSelectFilter/index.vue'
|
||||
import tool from '@/utils/tool'
|
||||
import { defineAsyncComponent } from 'vue'
|
||||
const fail = defineAsyncComponent(() => import('@/views/sys/job/record/index.vue'))
|
||||
const all = defineAsyncComponent(() => import('@/views/sys/job/all/index.vue'))
|
||||
|
||||
export default {
|
||||
components: {
|
||||
ScSelectFilter,
|
||||
saveDialog,
|
||||
},
|
||||
inject: ['reload'],
|
||||
components: { all, fail },
|
||||
computed: {},
|
||||
created() {},
|
||||
data() {
|
||||
return {
|
||||
timer: null,
|
||||
loading: false,
|
||||
query: {
|
||||
dynamicFilter: {
|
||||
filters: [
|
||||
{
|
||||
field: 'enabled',
|
||||
operator: 'eq',
|
||||
value: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
filter: {},
|
||||
},
|
||||
dialog: {
|
||||
save: false,
|
||||
},
|
||||
selection: [],
|
||||
tabId: 'all',
|
||||
}
|
||||
},
|
||||
inject: ['reload'],
|
||||
methods: {},
|
||||
mounted() {},
|
||||
watch: {},
|
||||
computed: {
|
||||
tool() {
|
||||
return tool
|
||||
},
|
||||
naColOperation() {
|
||||
return naColOperation
|
||||
},
|
||||
table() {
|
||||
return table
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.$refs.search.form.dy.enabled = true
|
||||
},
|
||||
created() {},
|
||||
methods: {
|
||||
filterChange(data) {
|
||||
Object.entries(data).forEach(([key, value]) => {
|
||||
this.$refs.search.form.dy[key] = value === 'true' ? true : value === 'false' ? false : value
|
||||
})
|
||||
this.$refs.search.search()
|
||||
},
|
||||
//表格内开关事件
|
||||
async changeSwitch(event, row) {
|
||||
try {
|
||||
await this.$API.sys_job.setEnabled.post(row)
|
||||
this.$message.success(this.$t('操作成功'))
|
||||
} catch {
|
||||
//
|
||||
}
|
||||
this.$refs.table.refresh()
|
||||
},
|
||||
async execute(row) {
|
||||
try {
|
||||
await this.$API.sys_job.execute.post({ id: row.id })
|
||||
this.$notify.success({
|
||||
dangerouslyUseHTMLString: true,
|
||||
message: `<div id="countdown">${this.$t('已发起执行请求,5 秒后弹出执行结果')}</div>`,
|
||||
onClose: async () => {
|
||||
clearInterval(this.timer)
|
||||
this.loading = true
|
||||
this.dialog.save = true
|
||||
await this.$nextTick()
|
||||
await this.$refs.saveDialog.open('view', row, 1)
|
||||
this.loading = false
|
||||
},
|
||||
})
|
||||
|
||||
this.timer = setInterval(() => {
|
||||
const countdown = new RegExp('\\d+').exec(document.getElementById('countdown').innerText)[0]
|
||||
document.getElementById('countdown').innerText = document
|
||||
.getElementById('countdown')
|
||||
.innerText.replace(countdown, `${parseInt(countdown) - 1}`)
|
||||
}, 1000)
|
||||
} catch {}
|
||||
this.$refs.table.refresh()
|
||||
},
|
||||
//删除
|
||||
async rowDel(row) {
|
||||
try {
|
||||
const res = await this.$API.sys_job.delete.post({ id: row.id })
|
||||
this.$message.success(this.$t('删除 {count} 项', { count: res.data }))
|
||||
} catch {
|
||||
//
|
||||
}
|
||||
this.$refs.table.refresh()
|
||||
},
|
||||
|
||||
//搜索
|
||||
onSearch(form) {
|
||||
if (Array.isArray(form.dy.createdTime)) {
|
||||
this.query.dynamicFilter.filters.push({
|
||||
field: 'createdTime',
|
||||
operator: 'dateRange',
|
||||
value: form.dy.createdTime,
|
||||
})
|
||||
}
|
||||
|
||||
if (typeof form.dy.status === 'string' && form.dy.status.trim() !== '') {
|
||||
this.query.dynamicFilter.filters.push({
|
||||
field: 'status',
|
||||
operator: 'eq',
|
||||
value: form.dy.status,
|
||||
})
|
||||
}
|
||||
|
||||
if (typeof form.dy.enabled === 'boolean') {
|
||||
this.query.dynamicFilter.filters.push({
|
||||
field: 'enabled',
|
||||
operator: 'eq',
|
||||
value: form.dy.enabled,
|
||||
})
|
||||
}
|
||||
|
||||
if (typeof form.dy.httpMethod === 'string' && form.dy.httpMethod.trim() !== '') {
|
||||
this.query.dynamicFilter.filters.push({
|
||||
field: 'httpMethod',
|
||||
operator: 'eq',
|
||||
value: form.dy.httpMethod,
|
||||
})
|
||||
}
|
||||
|
||||
this.$refs.table.upData()
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
@ -17,7 +17,7 @@
|
||||
return { value: x[0], label: x[1][1] }
|
||||
}),
|
||||
placeholder: $t('请求方式'),
|
||||
style: 'width:10rem',
|
||||
style: 'width:15rem',
|
||||
},
|
||||
{
|
||||
multiple: true,
|
||||
@ -45,9 +45,8 @@
|
||||
</el-header>
|
||||
<el-main class="nopadding">
|
||||
<sc-table
|
||||
v-loading="loading"
|
||||
:apiObj="$API.sys_job.recordPagedQuery"
|
||||
:context-menus="['id', 'duration', 'httpMethod', 'requestUrl', 'httpStatusCode', 'createdTime']"
|
||||
:context-menus="['id', 'duration', 'httpMethod', 'requestUrl', 'httpStatusCode', 'createdTime', 'jobId']"
|
||||
:default-sort="{ prop: 'createdTime', order: 'descending' }"
|
||||
:params="query"
|
||||
:vue="this"
|
||||
@ -56,37 +55,51 @@
|
||||
remote-sort
|
||||
row-key="id"
|
||||
stripe>
|
||||
<el-table-column :label="$t('唯一编码')" prop="id" sortable="custom" width="150" />
|
||||
<na-col-id :label="$t('唯一编码')" prop="id" sortable="custom" width="170" />
|
||||
<el-table-column :label="$t('响应状态码')" prop="httpStatusCode" sortable="custom" width="200">
|
||||
<template #default="{ row }">
|
||||
<p>
|
||||
<na-indicator
|
||||
:data="row"
|
||||
:options="
|
||||
Object.entries(this.$GLOBAL.enums.httpMethods).map((x) => {
|
||||
return { value: x[0], text: `${x[1][1]}`, type: x[1][2] }
|
||||
})
|
||||
"
|
||||
prop="httpMethod" />
|
||||
</p>
|
||||
<p>
|
||||
<na-indicator
|
||||
:data="row"
|
||||
:options="
|
||||
Object.entries(this.$GLOBAL.enums.httpStatusCodes).map((x) => {
|
||||
return { value: x[0], text: `${x[1][1]}`, type: x[1][2] }
|
||||
})
|
||||
"
|
||||
prop="httpStatusCode" />
|
||||
</p>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
:formatter="(row) => `${tool.groupSeparator(row.duration.toFixed(0))} ms`"
|
||||
:formatter="(row) => `${$TOOL.groupSeparator(row.duration.toFixed(0))} ms`"
|
||||
:label="$t('执行耗时')"
|
||||
align="right"
|
||||
prop="duration"
|
||||
sortable="custom"
|
||||
width="150" />
|
||||
<na-col-indicator
|
||||
:label="$t('请求方式')"
|
||||
:options="
|
||||
Object.entries(this.$GLOBAL.enums.httpMethods).map((x) => {
|
||||
return { value: x[0], text: x[1][1], type: x[1][2] }
|
||||
})
|
||||
"
|
||||
align="center"
|
||||
prop="httpMethod"
|
||||
sortable="custom"
|
||||
width="150" />
|
||||
<el-table-column :label="$t('响应状态码')" align="center" prop="httpStatusCode" sortable="custom" width="200">
|
||||
<template #default="scope">
|
||||
<sc-status-indicator :type="scope.row.httpStatusCode === 'ok' ? 'success' : 'danger'" />
|
||||
{{
|
||||
this.$GLOBAL.enums.httpStatusCodes[scope.row.httpStatusCode]
|
||||
? this.$GLOBAL.enums.httpStatusCodes[scope.row.httpStatusCode][1]
|
||||
: scope.row.httpStatusCode
|
||||
}}
|
||||
<el-table-column :label="$t('作业信息')" prop="jobId" show-overflow-tooltip sortable="custom" width="500">
|
||||
<template #default="{ row }">
|
||||
<p>
|
||||
<el-link :href="`/sys/job?keywords=${row.jobId}`" target="_blank">
|
||||
{{ row.job.jobName }}
|
||||
</el-link>
|
||||
</p>
|
||||
<p>
|
||||
{{ row.requestUrl }}
|
||||
</p>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column :label="$t('请求的网络地址')" prop="requestUrl" sortable="custom" />
|
||||
<el-table-column :label="$t('创建时间')" align="right" prop="createdTime" sortable="custom" width="170" />
|
||||
<el-table-column :label="$t('响应体')" prop="responseBody" show-overflow-tooltip sortable="custom" />
|
||||
<na-col-operation :buttons="[naColOperation.buttons[0]]" :vue="this" width="100" />
|
||||
</sc-table>
|
||||
</el-main>
|
||||
@ -94,48 +107,25 @@
|
||||
|
||||
<save-dialog
|
||||
v-if="dialog.save"
|
||||
@closed="dialog.save = false"
|
||||
@closed="dialog.save = null"
|
||||
@mounted="$refs.saveDialog.open(dialog.save)"
|
||||
@success="(data, mode) => table.handleUpdate($refs.table, data, mode)"
|
||||
ref="saveDialog"></save-dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import saveDialog from './save'
|
||||
import { defineAsyncComponent } from 'vue'
|
||||
import table from '@/config/table'
|
||||
import naColOperation from '@/config/naColOperation'
|
||||
import tool from '@/utils/tool'
|
||||
import naIndicator from '@/components/naIndicator/index.vue'
|
||||
|
||||
const saveDialog = defineAsyncComponent(() => import('./save.vue'))
|
||||
export default {
|
||||
props: ['keywords'],
|
||||
components: {
|
||||
naIndicator,
|
||||
saveDialog,
|
||||
},
|
||||
inject: ['reload'],
|
||||
data() {
|
||||
return {
|
||||
loading: false,
|
||||
query: {
|
||||
dynamicFilter: {
|
||||
filters: [
|
||||
{
|
||||
field: 'createdTime',
|
||||
operator: 'dateRange',
|
||||
value: [tool.dateFormat(new Date(), 'yyyy-MM-dd'), tool.dateFormat(new Date(), 'yyyy-MM-dd')],
|
||||
},
|
||||
],
|
||||
},
|
||||
filter: {},
|
||||
},
|
||||
dialog: {
|
||||
save: false,
|
||||
},
|
||||
}
|
||||
},
|
||||
watch: {},
|
||||
computed: {
|
||||
tool() {
|
||||
return tool
|
||||
},
|
||||
naColOperation() {
|
||||
return naColOperation
|
||||
},
|
||||
@ -143,21 +133,42 @@ export default {
|
||||
return table
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
if (this.keywords) {
|
||||
this.$refs.search.form.root.keywords = this.keywords
|
||||
this.$refs.search.keepKeywords = this.keywords
|
||||
}
|
||||
this.$refs.search.form.dy.createdTime = this.$refs.search.keepCreatedTime = [
|
||||
`${tool.dateFormat(new Date(), 'yyyy-MM-dd')} 00:00:00`,
|
||||
`${tool.dateFormat(new Date(), 'yyyy-MM-dd')} 00:00:00`,
|
||||
]
|
||||
},
|
||||
created() {
|
||||
if (this.keywords) {
|
||||
this.query.keywords = this.keywords
|
||||
}
|
||||
if (this.statusCodes) {
|
||||
this.query.dynamicFilter.filters.push({
|
||||
logic: 'or',
|
||||
filters: this.statusCodes.map((x) => {
|
||||
return {
|
||||
field: 'httpStatusCode',
|
||||
operator: 'range',
|
||||
value: x,
|
||||
}
|
||||
}),
|
||||
})
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
dialog: {},
|
||||
loading: false,
|
||||
query: {
|
||||
dynamicFilter: {
|
||||
filters: [
|
||||
{
|
||||
field: 'createdTime',
|
||||
operator: 'dateRange',
|
||||
value: [this.$TOOL.dateFormat(new Date(), 'yyyy-MM-dd'), this.$TOOL.dateFormat(new Date(), 'yyyy-MM-dd')],
|
||||
},
|
||||
],
|
||||
},
|
||||
filter: {},
|
||||
},
|
||||
}
|
||||
},
|
||||
inject: ['reload'],
|
||||
methods: {
|
||||
//搜索
|
||||
onSearch(form) {
|
||||
@ -191,6 +202,7 @@ export default {
|
||||
filters: filters,
|
||||
})
|
||||
}
|
||||
|
||||
if (typeof form.dy.httpMethod === 'string' && form.dy.httpMethod.trim() !== '') {
|
||||
this.query.dynamicFilter.filters.push({
|
||||
field: 'httpMethod',
|
||||
@ -198,10 +210,25 @@ export default {
|
||||
value: form.dy.httpMethod,
|
||||
})
|
||||
}
|
||||
|
||||
this.$refs.table.upData()
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
if (this.keywords) {
|
||||
this.$refs.search.form.root.keywords = this.keywords
|
||||
this.$refs.search.keepKeywords = this.keywords
|
||||
}
|
||||
if (this.statusCodes) {
|
||||
this.$refs.search.form.dy.httpStatusCode = this.statusCodes
|
||||
this.$refs.search.keepHttpStatusCode = this.statusCodes
|
||||
}
|
||||
this.$refs.search.form.dy.createdTime = this.$refs.search.keepCreatedTime = [
|
||||
`${this.$TOOL.dateFormat(new Date(), 'yyyy-MM-dd')} 00:00:00`,
|
||||
`${this.$TOOL.dateFormat(new Date(), 'yyyy-MM-dd')} 00:00:00`,
|
||||
]
|
||||
},
|
||||
props: ['keywords', 'statusCodes'],
|
||||
watch: {},
|
||||
}
|
||||
</script>
|
||||
|
||||
|
@ -1,11 +1,5 @@
|
||||
<template>
|
||||
<sc-dialog
|
||||
v-model="visible"
|
||||
:title="`${titleMap[mode]}:${form?.id ?? '...'}`"
|
||||
:width="800"
|
||||
@closed="$emit('closed')"
|
||||
destroy-on-close
|
||||
full-screen>
|
||||
<sc-dialog v-model="visible" :title="`${titleMap[mode]}:${form?.id ?? '...'}`" @closed="$emit('closed')" destroy-on-close full-screen>
|
||||
<el-form
|
||||
v-loading="loading"
|
||||
:disabled="mode === 'view'"
|
||||
@ -36,7 +30,7 @@
|
||||
<el-tab-pane v-if="mode === 'view'" :label="$t('原始数据')">
|
||||
<json-viewer
|
||||
:expand-depth="5"
|
||||
:theme="this.$TOOL.data.get('APP_DARK') ? 'dark' : 'light'"
|
||||
:theme="this.$TOOL.data.get('APP_SET_DARK') || this.$CONFIG.APP_SET_DARK ? 'dark' : 'light'"
|
||||
:value="form"
|
||||
copyable
|
||||
expanded
|
||||
@ -53,37 +47,41 @@
|
||||
<script>
|
||||
export default {
|
||||
components: {},
|
||||
emits: ['success', 'closed'],
|
||||
data() {
|
||||
return {
|
||||
mode: 'add',
|
||||
titleMap: {
|
||||
view: this.$t('查看作业记录'),
|
||||
add: this.$t('新增作业记录'),
|
||||
edit: this.$t('编辑作业记录'),
|
||||
},
|
||||
visible: false,
|
||||
loading: false,
|
||||
//表单数据
|
||||
form: {},
|
||||
loading: false,
|
||||
mode: 'add',
|
||||
//验证规则
|
||||
rules: {},
|
||||
titleMap: {
|
||||
add: this.$t('新增作业记录'),
|
||||
edit: this.$t('编辑作业记录'),
|
||||
view: this.$t('查看作业记录'),
|
||||
},
|
||||
visible: false,
|
||||
}
|
||||
},
|
||||
mounted() {},
|
||||
emits: ['success', 'closed', 'mounted'],
|
||||
methods: {
|
||||
//显示
|
||||
async open(mode = 'add', data) {
|
||||
async open(data) {
|
||||
this.visible = true
|
||||
this.loading = true
|
||||
this.mode = mode
|
||||
if (data) {
|
||||
const res = await this.$API.sys_job.recordGet.post({ id: data.id })
|
||||
this.mode = data.mode
|
||||
if (data.row?.id) {
|
||||
const res = await this.$API.sys_job.recordGet.post({ id: data.row.id })
|
||||
Object.assign(this.form, res.data)
|
||||
}
|
||||
this.loading = false
|
||||
return this
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.$emit('mounted')
|
||||
},
|
||||
}
|
||||
</script>
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
@ -40,7 +40,6 @@
|
||||
</el-header>
|
||||
<el-main class="nopadding">
|
||||
<sc-table
|
||||
v-loading="loading"
|
||||
:apiObj="$API.sys_log.pagedQuery"
|
||||
:context-menus="['id', 'httpStatusCode', 'createdClientIp', 'createdUserAgent', 'createdTime']"
|
||||
:context-opers="['view']"
|
||||
@ -53,18 +52,17 @@
|
||||
remote-sort
|
||||
row-key="id"
|
||||
stripe>
|
||||
<el-table-column :label="$t('日志编号')" prop="id" sortable="custom" width="150" />
|
||||
<el-table-column :label="$t('创建时间')" prop="createdTime" sortable="custom" width="170" />
|
||||
<na-col-id label="日志编号" prop="id" sortable="custom" width="170" />
|
||||
<el-table-column :label="$t('结果')" align="center" prop="httpStatusCode" sortable="custom" width="100">
|
||||
<template #default="scope">
|
||||
<sc-status-indicator :type="scope.row.httpStatusCode === 200 ? 'success' : 'danger'" />
|
||||
{{ scope.row.httpStatusCode === 200 ? '成功' : '失败' }}
|
||||
<template #default="{ row }">
|
||||
<sc-status-indicator :type="row.httpStatusCode === 200 ? 'success' : 'danger'" />
|
||||
{{ row.httpStatusCode === 200 ? '成功' : '失败' }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column :label="$t('登录名')" prop="loginName" width="150" />
|
||||
<el-table-column :label="$t('客户端IP')" prop="createdClientIp" show-overflow-tooltip sortable="custom" width="200">
|
||||
<template #default="scope">
|
||||
<na-ip :ip="scope.row.createdClientIp"></na-ip>
|
||||
<template #default="{ row }">
|
||||
<na-ip :ip="row.createdClientIp"></na-ip>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column :label="$t('操作系统')" align="center" prop="os" width="150" />
|
||||
@ -78,47 +76,12 @@
|
||||
|
||||
<script>
|
||||
import naInfo from '@/components/naInfo/index.vue'
|
||||
import tool from '@/utils/tool'
|
||||
import ScTable from '@/components/scTable/index.vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
ScTable,
|
||||
naInfo,
|
||||
},
|
||||
watch: {},
|
||||
inject: ['reload'],
|
||||
data() {
|
||||
return {
|
||||
loading: false,
|
||||
query: {
|
||||
dynamicFilter: {
|
||||
filters: [
|
||||
{
|
||||
field: 'createdTime',
|
||||
operator: 'dateRange',
|
||||
value: [tool.dateFormat(new Date(), 'yyyy-MM-dd'), tool.dateFormat(new Date(), 'yyyy-MM-dd')],
|
||||
},
|
||||
],
|
||||
},
|
||||
filter: {},
|
||||
},
|
||||
dialog: {
|
||||
info: false,
|
||||
},
|
||||
}
|
||||
},
|
||||
async mounted() {
|
||||
if (this.keywords) {
|
||||
this.$refs.search.form.root.keywords = this.keywords
|
||||
this.$refs.search.keepKeywords = this.keywords
|
||||
}
|
||||
this.$refs.search.form.dy.apiId = 'api/sys/user/login.by.pwd'
|
||||
this.$refs.search.form.dy.createdTime = this.$refs.search.keepCreatedTime = [
|
||||
`${tool.dateFormat(new Date(), 'yyyy-MM-dd')} 00:00:00`,
|
||||
`${tool.dateFormat(new Date(), 'yyyy-MM-dd')} 00:00:00`,
|
||||
]
|
||||
},
|
||||
computed: {},
|
||||
created() {
|
||||
if (this.keywords) {
|
||||
this.query.keywords = this.keywords
|
||||
@ -129,6 +92,28 @@ export default {
|
||||
value: 'api/sys/user/login.by.pwd',
|
||||
})
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
dialog: {
|
||||
info: false,
|
||||
},
|
||||
loading: false,
|
||||
query: {
|
||||
dynamicFilter: {
|
||||
filters: [
|
||||
{
|
||||
field: 'createdTime',
|
||||
operator: 'dateRange',
|
||||
value: [this.$TOOL.dateFormat(new Date(), 'yyyy-MM-dd'), this.$TOOL.dateFormat(new Date(), 'yyyy-MM-dd')],
|
||||
},
|
||||
],
|
||||
},
|
||||
filter: {},
|
||||
},
|
||||
selection: [],
|
||||
}
|
||||
},
|
||||
inject: ['reload'],
|
||||
methods: {
|
||||
filterChange(data) {
|
||||
Object.entries(data).forEach(([key, value]) => {
|
||||
@ -176,9 +161,22 @@ export default {
|
||||
const res = await this.$API.sys_log.query.post({
|
||||
filter: { id: row.id },
|
||||
})
|
||||
this.$refs.info.open(tool.sortProperties(res.data[0]), this.$t('日志详情:{id}', { id: row.id }))
|
||||
this.$refs.info.open(this.$TOOL.sortProperties(res.data[0]), this.$t('日志详情:{id}', { id: row.id }))
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
if (this.keywords) {
|
||||
this.$refs.search.form.root.keywords = this.keywords
|
||||
this.$refs.search.keepKeywords = this.keywords
|
||||
}
|
||||
this.$refs.search.form.dy.apiId = 'api/sys/user/login.by.pwd'
|
||||
this.$refs.search.form.dy.createdTime = this.$refs.search.keepCreatedTime = [
|
||||
`${this.$TOOL.dateFormat(new Date(), 'yyyy-MM-dd')} 00:00:00`,
|
||||
`${this.$TOOL.dateFormat(new Date(), 'yyyy-MM-dd')} 00:00:00`,
|
||||
]
|
||||
},
|
||||
props: ['keywords'],
|
||||
watch: {},
|
||||
}
|
||||
</script>
|
||||
|
||||
|
@ -73,8 +73,7 @@
|
||||
remote-sort
|
||||
row-key="id"
|
||||
stripe>
|
||||
<el-table-column :label="$t('日志编号')" prop="id" sortable="custom" width="150" />
|
||||
<el-table-column :label="$t('创建时间')" prop="createdTime" sortable="custom" width="170" />
|
||||
<na-col-id label="日志编号" prop="id" sortable="custom" width="170" />
|
||||
<el-table-column :label="$t('响应码')" align="center" prop="httpStatusCode" sortable="custom" width="150">
|
||||
<template #default="{ row }">
|
||||
<sc-status-indicator :type="row.httpStatusCode >= 200 && row.httpStatusCode < 300 ? 'success' : 'danger'" />
|
||||
@ -83,20 +82,20 @@
|
||||
</el-table-column>
|
||||
<el-table-column :label="$t('请求服务')" align="center">
|
||||
<el-table-column :label="$t('路径')" prop="apiId" show-overflow-tooltip sortable="custom">
|
||||
<template #default="scope">
|
||||
<p>{{ scope.row.apiId }}</p>
|
||||
<p>{{ scope.row.apiSummary }}</p>
|
||||
<template #default="{ row }">
|
||||
<p>{{ row.apiId }}</p>
|
||||
<p>{{ row.apiSummary }}</p>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column :label="$t('方法')" align="center" prop="method" sortable="custom" width="100">
|
||||
<template #default="scope">
|
||||
<template #default="{ row }">
|
||||
<sc-status-indicator
|
||||
:style="`background: #${Math.abs(this.$TOOL.crypto.hashCode(scope.row.method)).toString(16).substring(0, 6)}`" />
|
||||
{{ scope.row.method }}
|
||||
:style="`background: #${Math.abs(this.$TOOL.crypto.hashCode(row.method)).toString(16).substring(0, 6)}`" />
|
||||
{{ row.method }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
:formatter="(row) => `${tool.groupSeparator((row.duration / 1000).toFixed(0))} ms`"
|
||||
:formatter="(row) => `${$TOOL.groupSeparator((row.duration / 1000).toFixed(0))} ms`"
|
||||
:label="$t('耗时')"
|
||||
align="right"
|
||||
prop="duration"
|
||||
@ -114,8 +113,8 @@
|
||||
sortable="custom"
|
||||
width="170"></na-col-user>
|
||||
<el-table-column :label="$t('客户端IP')" prop="createdClientIp" show-overflow-tooltip sortable="custom" width="200">
|
||||
<template #default="scope">
|
||||
<na-ip :ip="scope.row.createdClientIp"></na-ip>
|
||||
<template #default="{ row }">
|
||||
<na-ip :ip="row.createdClientIp"></na-ip>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column :label="$t('操作系统')" align="center" prop="os" width="150" />
|
||||
@ -137,57 +136,39 @@
|
||||
|
||||
<script>
|
||||
import naInfo from '@/components/naInfo/index.vue'
|
||||
import tool from '@/utils/tool'
|
||||
import ScTable from '@/components/scTable/index.vue'
|
||||
import ScStatusIndicator from '@/components/scMini/scStatusIndicator.vue'
|
||||
|
||||
export default {
|
||||
computed: {
|
||||
tool() {
|
||||
return tool
|
||||
},
|
||||
},
|
||||
components: {
|
||||
ScStatusIndicator,
|
||||
ScTable,
|
||||
naInfo,
|
||||
},
|
||||
watch: {},
|
||||
inject: ['reload'],
|
||||
computed: {},
|
||||
created() {
|
||||
if (this.keywords) {
|
||||
this.query.keywords = this.keywords
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
dialog: {
|
||||
info: false,
|
||||
},
|
||||
loading: false,
|
||||
query: {
|
||||
dynamicFilter: {
|
||||
filters: [
|
||||
{
|
||||
field: 'createdTime',
|
||||
operator: 'dateRange',
|
||||
value: [tool.dateFormat(new Date(), 'yyyy-MM-dd'), tool.dateFormat(new Date(), 'yyyy-MM-dd')],
|
||||
value: [this.$TOOL.dateFormat(new Date(), 'yyyy-MM-dd'), this.$TOOL.dateFormat(new Date(), 'yyyy-MM-dd')],
|
||||
},
|
||||
],
|
||||
},
|
||||
filter: {},
|
||||
},
|
||||
dialog: {
|
||||
info: false,
|
||||
},
|
||||
}
|
||||
},
|
||||
async mounted() {
|
||||
if (this.keywords) {
|
||||
this.$refs.search.form.root.keywords = this.keywords
|
||||
this.$refs.search.keepKeywords = this.keywords
|
||||
}
|
||||
this.$refs.search.form.dy.createdTime = this.$refs.search.keepCreatedTime = [
|
||||
`${tool.dateFormat(new Date(), 'yyyy-MM-dd')} 00:00:00`,
|
||||
`${tool.dateFormat(new Date(), 'yyyy-MM-dd')} 00:00:00`,
|
||||
]
|
||||
},
|
||||
created() {
|
||||
if (this.keywords) {
|
||||
this.query.keywords = this.keywords
|
||||
selection: [],
|
||||
}
|
||||
},
|
||||
inject: ['reload'],
|
||||
methods: {
|
||||
filterChange(data) {
|
||||
Object.entries(data).forEach(([key, value]) => {
|
||||
@ -243,9 +224,21 @@ export default {
|
||||
const res = await this.$API.sys_log.query.post({
|
||||
filter: { id: row.id },
|
||||
})
|
||||
this.$refs.info.open(tool.sortProperties(res.data[0]), this.$t('日志详情:{id}', { id: row.id }))
|
||||
this.$refs.info.open(this.$TOOL.sortProperties(res.data[0]), this.$t('日志详情:{id}', { id: row.id }))
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
if (this.keywords) {
|
||||
this.$refs.search.form.root.keywords = this.keywords
|
||||
this.$refs.search.keepKeywords = this.keywords
|
||||
}
|
||||
this.$refs.search.form.dy.createdTime = this.$refs.search.keepCreatedTime = [
|
||||
`${this.$TOOL.dateFormat(new Date(), 'yyyy-MM-dd')} 00:00:00`,
|
||||
`${this.$TOOL.dateFormat(new Date(), 'yyyy-MM-dd')} 00:00:00`,
|
||||
]
|
||||
},
|
||||
props: ['keywords'],
|
||||
watch: {},
|
||||
}
|
||||
</script>
|
||||
|
||||
|
@ -60,10 +60,7 @@
|
||||
import save from './save'
|
||||
|
||||
export default {
|
||||
inject: ['reload'],
|
||||
components: {
|
||||
save,
|
||||
},
|
||||
components: { save },
|
||||
data() {
|
||||
return {
|
||||
loading: false,
|
||||
@ -71,14 +68,7 @@ export default {
|
||||
filterText: '',
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
filterText(val) {
|
||||
this.$refs.tree.filter(val)
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.getTree()
|
||||
},
|
||||
inject: ['reload'],
|
||||
methods: {
|
||||
//加载树数据
|
||||
async getTree() {
|
||||
@ -167,6 +157,14 @@ export default {
|
||||
this.reload()
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.getTree()
|
||||
},
|
||||
watch: {
|
||||
filterText(val) {
|
||||
this.$refs.tree.filter(val)
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
|
@ -78,38 +78,21 @@
|
||||
import scIconSelect from '@/components/scIconSelect'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
scIconSelect,
|
||||
},
|
||||
props: {
|
||||
tree: {
|
||||
type: Object,
|
||||
default: () => {},
|
||||
},
|
||||
},
|
||||
components: { scIconSelect },
|
||||
data() {
|
||||
return {
|
||||
form: {
|
||||
meta: {},
|
||||
},
|
||||
loading: false,
|
||||
treeOptions: [],
|
||||
rules: {
|
||||
meta: {
|
||||
title: [{ required: true, message: '请输入显示名称' }],
|
||||
},
|
||||
},
|
||||
loading: false,
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
tree: {
|
||||
handler() {
|
||||
this.treeOptions = this.treeToMap(this.tree)
|
||||
},
|
||||
deep: true,
|
||||
},
|
||||
},
|
||||
mounted() {},
|
||||
methods: {
|
||||
//简单化菜单
|
||||
treeToMap(tree) {
|
||||
@ -146,6 +129,21 @@ export default {
|
||||
this.form = Object.assign({}, data, { parentId: pid })
|
||||
},
|
||||
},
|
||||
mounted() {},
|
||||
props: {
|
||||
tree: {
|
||||
type: Object,
|
||||
default: () => {},
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
tree: {
|
||||
handler() {
|
||||
this.treeOptions = this.treeToMap(this.tree)
|
||||
},
|
||||
deep: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
|
@ -35,13 +35,12 @@
|
||||
ref="search" />
|
||||
</div>
|
||||
<div class="right-panel">
|
||||
<na-button-add :vue="this" />
|
||||
<el-button @click="this.dialog.save = { mode: 'add' }" icon="el-icon-plus" type="primary"></el-button>
|
||||
<na-button-bulk-del :api="$API.sys_sitemsg.bulkDelete" :vue="this" />
|
||||
</div>
|
||||
</el-header>
|
||||
<el-main class="nopadding">
|
||||
<sc-table
|
||||
v-loading="loading"
|
||||
:apiObj="$API.sys_sitemsg.pagedQuery"
|
||||
:context-menus="['id', 'createdUserName', 'msgType', 'title', 'summary', 'createdTime']"
|
||||
:default-sort="{ prop: 'createdTime', order: 'descending' }"
|
||||
@ -58,7 +57,7 @@
|
||||
row-key="id"
|
||||
stripe>
|
||||
<el-table-column type="selection" />
|
||||
<el-table-column :label="$t('消息编号')" prop="id" sortable="custom" width="150" />
|
||||
<na-col-id :label="$t('消息编号')" prop="id" sortable="custom" width="170" />
|
||||
<na-col-avatar :label="$t('用户名')" prop="createdUserName" />
|
||||
<na-col-indicator
|
||||
:label="$t('消息类型')"
|
||||
@ -73,7 +72,7 @@
|
||||
width="150" />
|
||||
<el-table-column :label="$t('消息主题')" prop="title" show-overflow-tooltip sortable="custom" />
|
||||
<el-table-column :label="$t('消息摘要')" prop="summary" show-overflow-tooltip sortable="custom" />
|
||||
<el-table-column :label="$t('创建时间')" align="right" prop="createdTime" sortable="custom" width="170" />
|
||||
|
||||
<na-col-operation
|
||||
:buttons="
|
||||
naColOperation.buttons.concat({
|
||||
@ -91,37 +90,22 @@
|
||||
|
||||
<save-dialog
|
||||
v-if="dialog.save"
|
||||
@closed="dialog.save = false"
|
||||
@closed="dialog.save = null"
|
||||
@mounted="$refs.saveDialog.open(dialog.save)"
|
||||
@success="(data, mode) => table.handleUpdate($refs.table, data, mode)"
|
||||
ref="saveDialog"></save-dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import saveDialog from './save'
|
||||
import { defineAsyncComponent } from 'vue'
|
||||
import table from '@/config/table'
|
||||
import naColOperation from '@/config/naColOperation'
|
||||
|
||||
const saveDialog = defineAsyncComponent(() => import('./save.vue'))
|
||||
export default {
|
||||
components: {
|
||||
saveDialog,
|
||||
},
|
||||
inject: ['reload'],
|
||||
data() {
|
||||
return {
|
||||
loading: false,
|
||||
query: {
|
||||
dynamicFilter: {
|
||||
filters: [],
|
||||
},
|
||||
filter: {},
|
||||
},
|
||||
dialog: {
|
||||
save: false,
|
||||
},
|
||||
selection: [],
|
||||
}
|
||||
},
|
||||
watch: {},
|
||||
computed: {
|
||||
naColOperation() {
|
||||
return naColOperation
|
||||
@ -130,16 +114,32 @@ export default {
|
||||
return table
|
||||
},
|
||||
},
|
||||
mounted() {},
|
||||
created() {},
|
||||
created() {
|
||||
if (this.keywords) {
|
||||
this.query.keywords = this.keywords
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
dialog: {},
|
||||
loading: false,
|
||||
query: {
|
||||
dynamicFilter: {
|
||||
filters: [],
|
||||
},
|
||||
filter: {},
|
||||
},
|
||||
selection: [],
|
||||
}
|
||||
},
|
||||
inject: ['reload'],
|
||||
methods: {
|
||||
filterChange(data) {
|
||||
Object.entries(data).forEach(([key, value]) => {
|
||||
this.$refs.search.form.dy[key] = value
|
||||
this.$refs.search.form.dy[key] = value === 'true' ? true : value === 'false' ? false : value
|
||||
})
|
||||
this.$refs.search.search()
|
||||
},
|
||||
//删除
|
||||
async rowDel(row) {
|
||||
try {
|
||||
const res = await this.$API.sys_sitemsg.delete.post({ id: row.id })
|
||||
@ -149,8 +149,6 @@ export default {
|
||||
}
|
||||
this.$refs.table.refresh()
|
||||
},
|
||||
|
||||
//搜索
|
||||
onSearch(form) {
|
||||
if (Array.isArray(form.dy.createdTime)) {
|
||||
this.query.dynamicFilter.filters.push({
|
||||
@ -171,6 +169,14 @@ export default {
|
||||
this.$refs.table.upData()
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
if (this.keywords) {
|
||||
this.$refs.search.form.root.keywords = this.keywords
|
||||
this.$refs.search.keepKeywords = this.keywords
|
||||
}
|
||||
},
|
||||
props: ['keywords'],
|
||||
watch: {},
|
||||
}
|
||||
</script>
|
||||
|
||||
|
@ -1,11 +1,5 @@
|
||||
<template>
|
||||
<sc-dialog
|
||||
v-model="visible"
|
||||
:title="`${titleMap[mode]}:${form?.id ?? '...'}`"
|
||||
:width="800"
|
||||
@closed="$emit('closed')"
|
||||
destroy-on-close
|
||||
full-screen>
|
||||
<sc-dialog v-model="visible" :title="`${titleMap[mode]}:${form?.id ?? '...'}`" @closed="$emit('closed')" destroy-on-close full-screen>
|
||||
<el-form
|
||||
v-loading="loading"
|
||||
:disabled="mode === 'view'"
|
||||
@ -29,7 +23,7 @@
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('消息内容')" prop="content">
|
||||
<div
|
||||
:class="this.$TOOL.data.get('APP_DARK') ? 'aie-theme-dark' : 'aie-theme-light'"
|
||||
:class="this.$TOOL.data.get('APP_SET_DARK') || this.$CONFIG.APP_SET_DARK ? 'aie-theme-dark' : 'aie-theme-light'"
|
||||
ref="editor"
|
||||
style="width: 100%; height: 30rem"></div>
|
||||
</el-form-item>
|
||||
@ -62,7 +56,7 @@
|
||||
<el-tab-pane v-if="mode === 'view'" :label="$t('原始数据')">
|
||||
<json-viewer
|
||||
:expand-depth="5"
|
||||
:theme="this.$TOOL.data.get('APP_DARK') ? 'dark' : 'light'"
|
||||
:theme="this.$TOOL.data.get('APP_SET_DARK') || this.$CONFIG.APP_SET_DARK ? 'dark' : 'light'"
|
||||
:value="form"
|
||||
copyable
|
||||
expanded
|
||||
@ -72,7 +66,7 @@
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button @click="visible = false">{{ $t('取消') }}</el-button>
|
||||
<el-button v-if="mode !== 'view'" :loading="loading" @click="submit" type="primary">{{ $t('保存') }}</el-button>
|
||||
<el-button v-if="mode !== 'view'" :disabled="loading" :loading="loading" @click="submit" type="primary">{{ $t('保存') }}</el-button>
|
||||
</template>
|
||||
</sc-dialog>
|
||||
</template>
|
||||
@ -87,20 +81,14 @@ export default {
|
||||
emits: ['success', 'closed'],
|
||||
data() {
|
||||
return {
|
||||
mode: 'add',
|
||||
titleMap: {
|
||||
view: this.$t('查看消息'),
|
||||
add: this.$t('新增消息'),
|
||||
edit: this.$t('编辑消息'),
|
||||
},
|
||||
visible: false,
|
||||
loading: false,
|
||||
//表单数据
|
||||
form: {
|
||||
userIds: [],
|
||||
roleIds: [],
|
||||
deptIds: [],
|
||||
},
|
||||
loading: false,
|
||||
mode: 'add',
|
||||
//验证规则
|
||||
rules: {
|
||||
title: [
|
||||
@ -122,17 +110,23 @@ export default {
|
||||
},
|
||||
],
|
||||
},
|
||||
titleMap: {
|
||||
add: this.$t('新增消息'),
|
||||
edit: this.$t('编辑消息'),
|
||||
view: this.$t('查看消息'),
|
||||
},
|
||||
visible: false,
|
||||
}
|
||||
},
|
||||
mounted() {},
|
||||
emits: ['success', 'closed', 'mounted'],
|
||||
methods: {
|
||||
//显示
|
||||
async open(mode = 'add', data) {
|
||||
async open(data) {
|
||||
this.visible = true
|
||||
this.loading = true
|
||||
this.mode = mode
|
||||
if (data) {
|
||||
const res = await this.$API.sys_sitemsg.get.post({ id: data.id })
|
||||
this.mode = data.mode
|
||||
if (data.row?.id) {
|
||||
const res = await this.$API.sys_sitemsg.get.post({ id: data.row.id })
|
||||
Object.assign(this.form, res.data, {
|
||||
roleIds: res.data.roles?.map((x) => x.id) ?? [],
|
||||
deptIds: res.data.depts?.map((x) => x.id) ?? [],
|
||||
@ -150,7 +144,7 @@ export default {
|
||||
this.form.content = content.getHtml()
|
||||
},
|
||||
})
|
||||
aiEditor.changeLang(this.$TOOL.data.get('APP_LANG') || sysConfig.LANG)
|
||||
aiEditor.changeLang(this.$TOOL.data.get('APP_SET_LANG') || sysConfig.APP_SET_LANG)
|
||||
return this
|
||||
},
|
||||
|
||||
@ -160,20 +154,21 @@ export default {
|
||||
if (!valid) {
|
||||
return false
|
||||
}
|
||||
|
||||
this.loading = true
|
||||
const method = this.mode === 'add' ? this.$API.sys_sitemsg.create : this.$API.sys_sitemsg.edit
|
||||
try {
|
||||
const method = this.mode === 'add' ? this.$API.sys_sitemsg.create : this.$API.sys_sitemsg.edit
|
||||
this.loading = true
|
||||
const res = await method.post(Object.assign({}, this.form, { userIds: this.form.userIds.map((x) => x.id) }))
|
||||
this.loading = false
|
||||
this.$emit('success', res.data, this.mode)
|
||||
this.visible = false
|
||||
this.$message.success(this.$t('操作成功'))
|
||||
} catch {
|
||||
//
|
||||
this.loading = false
|
||||
}
|
||||
} catch {}
|
||||
this.loading = false
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.$emit('mounted')
|
||||
},
|
||||
}
|
||||
</script>
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
@ -12,8 +12,26 @@
|
||||
{ label: $t('禁用'), value: false },
|
||||
],
|
||||
},
|
||||
{
|
||||
title: $t('无限权限'),
|
||||
key: 'ignorePermissionControl',
|
||||
options: [
|
||||
{ label: $t('全部'), value: '' },
|
||||
{ label: $t('是'), value: true },
|
||||
{ label: $t('否'), value: false },
|
||||
],
|
||||
},
|
||||
{
|
||||
title: $t('显示仪表板'),
|
||||
key: 'displayDashboard',
|
||||
options: [
|
||||
{ label: $t('全部'), value: '' },
|
||||
{ label: $t('是'), value: true },
|
||||
{ label: $t('否'), value: false },
|
||||
],
|
||||
},
|
||||
]"
|
||||
:label-width="10"
|
||||
:label-width="15"
|
||||
@on-change="filterChange"
|
||||
ref="selectFilter"></sc-select-filter>
|
||||
</el-header>
|
||||
@ -27,26 +45,6 @@
|
||||
placeholder: $t('角色编号 / 角色名称 / 备注'),
|
||||
style: 'width:20rem',
|
||||
},
|
||||
{
|
||||
type: 'select',
|
||||
field: ['dy', 'ignorePermissionControl'],
|
||||
options: [
|
||||
{ label: '是', value: true },
|
||||
{ label: '否', value: false },
|
||||
],
|
||||
placeholder: $t('无限权限'),
|
||||
style: 'width:15rem',
|
||||
},
|
||||
{
|
||||
type: 'select',
|
||||
field: ['dy', 'displayDashboard'],
|
||||
options: [
|
||||
{ label: '是', value: true },
|
||||
{ label: '否', value: false },
|
||||
],
|
||||
placeholder: $t('显示仪表板'),
|
||||
style: 'width:15rem',
|
||||
},
|
||||
]"
|
||||
:vue="this"
|
||||
@reset="Object.entries(this.$refs.selectFilter.selected).forEach(([key, _]) => (this.$refs.selectFilter.selected[key] = ['']))"
|
||||
@ -54,13 +52,26 @@
|
||||
ref="search" />
|
||||
</div>
|
||||
<div class="right-panel">
|
||||
<na-button-add :vue="this" />
|
||||
<el-button @click="this.dialog.save = { mode: 'add' }" icon="el-icon-plus" type="primary"></el-button>
|
||||
<na-button-bulk-del :api="$API.sys_role.bulkDelete" :vue="this" />
|
||||
<el-dropdown v-show="this.selection.length > 0">
|
||||
<el-button type="primary">
|
||||
{{ $t('批量操作') }}
|
||||
<el-icon>
|
||||
<el-icon-arrow-down />
|
||||
</el-icon>
|
||||
</el-button>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item @click="setEnabled(true)">{{ $t('启用角色') }}</el-dropdown-item>
|
||||
<el-dropdown-item @click="setEnabled(false)">{{ $t('禁用角色') }}</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
</div>
|
||||
</el-header>
|
||||
<el-main class="nopadding">
|
||||
<sc-table
|
||||
v-loading="loading"
|
||||
:apiObj="$API.sys_role.pagedQuery"
|
||||
:context-menus="['id', 'name', 'sort', 'enabled', 'ignorePermissionControl', 'dataScope', 'displayDashboard', 'createdTime']"
|
||||
:default-sort="{ prop: 'sort', order: 'descending' }"
|
||||
@ -77,23 +88,14 @@
|
||||
row-key="id"
|
||||
stripe>
|
||||
<el-table-column type="selection" />
|
||||
<el-table-column :label="$t('角色编号')" prop="id" sortable="custom" />
|
||||
<na-col-id :label="$t('角色编号')" prop="id" sortable="custom" width="170" />
|
||||
<el-table-column :label="$t('角色名称')" prop="name" sortable="custom" />
|
||||
<el-table-column :label="$t('排序')" align="right" prop="sort" sortable="custom" />
|
||||
<el-table-column :label="$t('启用')" align="center" prop="enabled" sortable="custom" width="100">
|
||||
<template #default="scope">
|
||||
<el-switch v-model="scope.row.enabled" @change="changeSwitch($event, scope.row)"></el-switch>
|
||||
<el-table-column :label="$t('无限权限')" align="center" prop="ignorePermissionControl" sortable="custom">
|
||||
<template #default="{ row }">
|
||||
<el-switch v-model="row.ignorePermissionControl" @change="changeIgnorePermissionControl($event, row)"></el-switch>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<na-col-indicator
|
||||
:label="$t('无限权限')"
|
||||
:options="[
|
||||
{ text: '是', type: 'success', value: true, pulse: true },
|
||||
{ text: '否', type: 'danger', value: false },
|
||||
]"
|
||||
align="center"
|
||||
prop="ignorePermissionControl"
|
||||
sortable="custom"></na-col-indicator>
|
||||
<na-col-indicator
|
||||
:label="$t('数据范围')"
|
||||
:options="
|
||||
@ -107,26 +109,33 @@
|
||||
width="120">
|
||||
</na-col-indicator>
|
||||
|
||||
<na-col-indicator
|
||||
:label="$t('显示仪表板')"
|
||||
:options="[
|
||||
{ text: '是', type: 'success', value: true },
|
||||
{ text: '否', type: 'danger', value: false },
|
||||
]"
|
||||
align="center"
|
||||
prop="displayDashboard"
|
||||
sortable="custom" />
|
||||
|
||||
<el-table-column :label="$t('创建时间')" align="right" prop="createdTime" sortable="custom" />
|
||||
<el-table-column :label="$t('显示仪表板')" align="center" prop="displayDashboard" sortable="custom">
|
||||
<template #default="{ row }">
|
||||
<el-switch v-model="row.displayDashboard" @change="changeDisplayDashboard($event, row)"></el-switch>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column :label="$t('启用')" align="center" prop="enabled" sortable="custom" width="100">
|
||||
<template #default="{ row }">
|
||||
<el-switch v-model="row.enabled" @change="changeEnabled($event, row)"></el-switch>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<na-col-operation
|
||||
:buttons="
|
||||
naColOperation.buttons.concat({
|
||||
icon: 'el-icon-delete',
|
||||
confirm: true,
|
||||
title: '删除角色',
|
||||
click: rowDel,
|
||||
type: 'danger',
|
||||
})
|
||||
naColOperation.buttons.concat(
|
||||
{
|
||||
icon: 'el-icon-document-copy',
|
||||
confirm: true,
|
||||
title: '复制角色',
|
||||
click: copyRole,
|
||||
},
|
||||
{
|
||||
icon: 'el-icon-delete',
|
||||
confirm: true,
|
||||
title: '删除角色',
|
||||
click: rowDel,
|
||||
type: 'danger',
|
||||
},
|
||||
)
|
||||
"
|
||||
:vue="this" />
|
||||
</sc-table>
|
||||
@ -135,16 +144,18 @@
|
||||
|
||||
<save-dialog
|
||||
v-if="dialog.save"
|
||||
@closed="dialog.save = false"
|
||||
@closed="dialog.save = null"
|
||||
@mounted="$refs.saveDialog.open(dialog.save)"
|
||||
@success="(data, mode) => table.handleUpdate($refs.table, data, mode)"
|
||||
ref="saveDialog"></save-dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import saveDialog from './save'
|
||||
import naColOperation from '@/config/naColOperation'
|
||||
import { defineAsyncComponent } from 'vue'
|
||||
import table from '@/config/table'
|
||||
import naColOperation from '@/config/naColOperation'
|
||||
|
||||
const saveDialog = defineAsyncComponent(() => import('./save.vue'))
|
||||
export default {
|
||||
components: {
|
||||
saveDialog,
|
||||
@ -157,12 +168,14 @@ export default {
|
||||
return table
|
||||
},
|
||||
},
|
||||
created() {},
|
||||
created() {
|
||||
if (this.keywords) {
|
||||
this.query.keywords = this.keywords
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
dialog: {
|
||||
save: false,
|
||||
},
|
||||
dialog: {},
|
||||
loading: false,
|
||||
query: {
|
||||
dynamicFilter: {
|
||||
@ -175,7 +188,58 @@ export default {
|
||||
},
|
||||
inject: ['reload'],
|
||||
methods: {
|
||||
async changeSwitch(event, row) {
|
||||
async copyRole(row) {
|
||||
const loading = this.$loading()
|
||||
await this.$API.sys_role.create.post(Object.assign({}, row, { id: null, name: row.name + '-copy' }))
|
||||
this.$refs.table.refresh()
|
||||
loading.close()
|
||||
},
|
||||
async setEnabled(enabled) {
|
||||
let loading
|
||||
try {
|
||||
await this.$confirm(
|
||||
this.$t('确定要 {operator} 选中的 {count} 项吗?', {
|
||||
operator: enabled ? this.$t('启用') : this.$t('禁用'),
|
||||
count: this.selection.length,
|
||||
}),
|
||||
this.$t('提示'),
|
||||
{
|
||||
type: 'warning',
|
||||
},
|
||||
)
|
||||
loading = this.$loading()
|
||||
const res = await Promise.all(this.selection.map((x) => this.$API.sys_role.setEnabled.post(Object.assign(x, { enabled: enabled }))))
|
||||
this.$message.success(
|
||||
this.$t('操作成功 {count}/{total} 项', {
|
||||
count: res.map((x) => x.data ?? 0).reduce((a, b) => a + b, 0),
|
||||
total: this.selection.length,
|
||||
}),
|
||||
)
|
||||
} catch {
|
||||
//
|
||||
}
|
||||
this.$refs.table.refresh()
|
||||
loading?.close()
|
||||
},
|
||||
async changeIgnorePermissionControl(event, row) {
|
||||
try {
|
||||
await this.$API.sys_role.setIgnorePermissionControl.post(row)
|
||||
this.$message.success(this.$t('操作成功'))
|
||||
} catch {
|
||||
//
|
||||
}
|
||||
this.$refs.table.refresh()
|
||||
},
|
||||
async changeDisplayDashboard(event, row) {
|
||||
try {
|
||||
await this.$API.sys_role.setDisplayDashboard.post(row)
|
||||
this.$message.success(this.$t('操作成功'))
|
||||
} catch {
|
||||
//
|
||||
}
|
||||
this.$refs.table.refresh()
|
||||
},
|
||||
async changeEnabled(event, row) {
|
||||
try {
|
||||
await this.$API.sys_role.setEnabled.post(row)
|
||||
this.$message.success(this.$t('操作成功'))
|
||||
@ -187,8 +251,8 @@ export default {
|
||||
filterChange(data) {
|
||||
Object.entries(data).forEach(([key, value]) => {
|
||||
this.$refs.search.form.dy[key] = value === 'true' ? true : value === 'false' ? false : value
|
||||
this.$refs.search.search()
|
||||
})
|
||||
this.$refs.search.search()
|
||||
},
|
||||
async rowDel(row) {
|
||||
try {
|
||||
@ -234,7 +298,13 @@ export default {
|
||||
this.$refs.table.upData()
|
||||
},
|
||||
},
|
||||
mounted() {},
|
||||
mounted() {
|
||||
if (this.keywords) {
|
||||
this.$refs.search.form.root.keywords = this.keywords
|
||||
this.$refs.search.keepKeywords = this.keywords
|
||||
}
|
||||
},
|
||||
props: ['keywords'],
|
||||
watch: {},
|
||||
}
|
||||
</script>
|
||||
|
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<sc-dialog v-model="visible" :title="`${titleMap[mode]}:${form?.id ?? '...'}`" @closed="$emit('closed')" destroy-on-close full-screen>
|
||||
<div v-loading="loading">
|
||||
<el-tabs tab-position="top">
|
||||
<el-tabs v-model="tabId" tab-position="top">
|
||||
<el-tab-pane :label="$t('基本信息')">
|
||||
<el-form :disabled="mode === 'view'" :model="form" :rules="rules" label-width="15rem" ref="dialogForm">
|
||||
<el-form-item :label="$t('角色名称')" prop="name">
|
||||
@ -76,10 +76,13 @@
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane v-if="mode === 'view'" :label="$t('用户列表')" name="user">
|
||||
<user v-if="tabId === 'user'" :role-id="form.id"></user>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane v-if="mode === 'view'" :label="$t('原始数据')">
|
||||
<json-viewer
|
||||
:expand-depth="5"
|
||||
:theme="this.$TOOL.data.get('APP_DARK') ? 'dark' : 'light'"
|
||||
:theme="this.$TOOL.data.get('APP_SET_DARK') || this.$CONFIG.APP_SET_DARK ? 'dark' : 'light'"
|
||||
:value="form"
|
||||
copyable
|
||||
expanded
|
||||
@ -89,32 +92,23 @@
|
||||
</div>
|
||||
<template #footer>
|
||||
<el-button @click="visible = false">{{ $t('取消') }}</el-button>
|
||||
<el-button v-if="mode !== 'view'" :loading="loading" @click="submit" type="primary">{{ $t('保存') }}</el-button>
|
||||
<el-button v-if="mode !== 'view'" :disabled="loading" :loading="loading" @click="submit" type="primary">{{ $t('保存') }}</el-button>
|
||||
</template>
|
||||
</sc-dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { defineAsyncComponent } from 'vue'
|
||||
|
||||
const User = defineAsyncComponent(() => import('@/views/sys/user/index.vue'))
|
||||
export default {
|
||||
components: {},
|
||||
emits: ['success', 'closed'],
|
||||
components: { User },
|
||||
data() {
|
||||
return {
|
||||
mode: 'add',
|
||||
titleMap: {
|
||||
add: this.$t('新增角色'),
|
||||
edit: this.$t('编辑角色'),
|
||||
view: this.$t('查看角色'),
|
||||
},
|
||||
visible: false,
|
||||
loading: false,
|
||||
trees: {
|
||||
menu: [],
|
||||
api: [],
|
||||
dept: [],
|
||||
},
|
||||
//表单数据
|
||||
form: { displayDashboard: false, sort: 100, enabled: true },
|
||||
loading: false,
|
||||
mode: 'add',
|
||||
//验证规则
|
||||
rules: {
|
||||
sort: [
|
||||
@ -126,12 +120,25 @@ export default {
|
||||
],
|
||||
name: [{ required: true, message: '请输入角色名称' }],
|
||||
},
|
||||
tabId: '0',
|
||||
titleMap: {
|
||||
add: this.$t('新增角色'),
|
||||
edit: this.$t('编辑角色'),
|
||||
view: this.$t('查看角色'),
|
||||
},
|
||||
trees: {
|
||||
menu: [],
|
||||
api: [],
|
||||
dept: [],
|
||||
},
|
||||
visible: false,
|
||||
}
|
||||
},
|
||||
mounted() {},
|
||||
emits: ['success', 'closed', 'mounted'],
|
||||
methods: {
|
||||
async getTrees(name) {
|
||||
this.trees[name] = (await this.$API[`sys_${name}`].query.post()).data
|
||||
const res = await this.$API[`sys_${name}`].query.post()
|
||||
this.trees[name] = res.data
|
||||
await this.$nextTick()
|
||||
await this.$refs[name].setCheckedKeys(
|
||||
(this.form[`${name}Ids`] || []).filter((key) => this.$refs[name].getNode(key).isLeaf),
|
||||
@ -139,12 +146,13 @@ export default {
|
||||
)
|
||||
},
|
||||
//显示
|
||||
async open(mode = 'add', data) {
|
||||
async open(data) {
|
||||
this.visible = true
|
||||
this.loading = true
|
||||
this.mode = mode
|
||||
if (data) {
|
||||
Object.assign(this.form, (await this.$API.sys_role.get.post({ id: data.id })).data)
|
||||
this.mode = data.mode
|
||||
if (data.row?.id) {
|
||||
const res = await this.$API.sys_role.get.post({ id: data.row.id })
|
||||
Object.assign(this.form, res.data)
|
||||
}
|
||||
await this.getTrees('menu')
|
||||
await this.getTrees('api')
|
||||
@ -159,26 +167,26 @@ export default {
|
||||
if (!valid) {
|
||||
return false
|
||||
}
|
||||
|
||||
this.loading = true
|
||||
const method = this.mode === 'add' ? this.$API.sys_role.create : this.$API.sys_role.edit
|
||||
const postData = Object.assign({}, this.form, {
|
||||
deptIds: this.$refs.dept.getCheckedKeys().concat(this.$refs.dept.getHalfCheckedKeys()),
|
||||
menuIds: this.$refs.menu.getCheckedKeys().concat(this.$refs.menu.getHalfCheckedKeys()),
|
||||
apiIds: this.$refs.api.getCheckedKeys().concat(this.$refs.api.getHalfCheckedKeys()),
|
||||
})
|
||||
const method = this.mode === 'add' ? this.$API.sys_role.create : this.$API.sys_role.edit
|
||||
try {
|
||||
const res = await method.post(postData)
|
||||
this.$emit('success', res.data, this.mode)
|
||||
this.visible = false
|
||||
this.$message.success(this.$t('操作成功'))
|
||||
} catch {
|
||||
//
|
||||
}
|
||||
} catch {}
|
||||
this.loading = false
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.$emit('mounted')
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style></style>
|
||||
<style scoped></style>
|
@ -50,12 +50,25 @@
|
||||
ref="search" />
|
||||
</div>
|
||||
<div class="right-panel">
|
||||
<na-button-add :vue="this" />
|
||||
<el-button @click="this.dialog.save = { mode: 'add' }" icon="el-icon-plus" type="primary"></el-button>
|
||||
<el-dropdown v-show="this.selection.length > 0">
|
||||
<el-button type="primary">
|
||||
{{ $t('批量操作') }}
|
||||
<el-icon>
|
||||
<el-icon-arrow-down />
|
||||
</el-icon>
|
||||
</el-button>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item @click="setEnabled(true)">{{ $t('启用用户') }}</el-dropdown-item>
|
||||
<el-dropdown-item @click="setEnabled(false)">{{ $t('禁用用户') }}</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
</div>
|
||||
</el-header>
|
||||
<el-main class="nopadding">
|
||||
<sc-table
|
||||
v-loading="loading"
|
||||
:apiObj="$API.sys_user.pagedQuery"
|
||||
:context-menus="['id', 'userName', 'mobile', 'email', 'enabled', 'createdTime']"
|
||||
:context-opers="['view', 'edit']"
|
||||
@ -73,38 +86,56 @@
|
||||
row-key="id"
|
||||
stripe>
|
||||
<el-table-column type="selection" />
|
||||
<el-table-column :label="$t('用户编号')" prop="id" sortable="custom" width="150" />
|
||||
<na-col-avatar :label="$t('用户名')" prop="userName" />
|
||||
<na-col-id :label="$t('用户编号')" prop="id" sortable="custom" width="170" />
|
||||
<na-col-avatar :label="$t('用户名')" prop="userName" width="170" />
|
||||
<el-table-column :label="$t('手机号')" align="center" prop="mobile" sortable="custom" width="120" />
|
||||
<el-table-column :label="$t('邮箱')" prop="email" sortable="custom" />
|
||||
<na-col-tags :label="$t('所属角色')" @click="(item) => openDialog('sys_role', item.id, 'roleSave')" field="name" prop="roles" />
|
||||
<na-col-tags :label="$t('所属部门')" @click="(item) => openDialog('sys_dept', item.id, 'deptSave')" field="name" prop="dept" />
|
||||
<el-table-column :label="$t('邮箱')" align="right" prop="email" sortable="custom" />
|
||||
<na-col-tags
|
||||
:label="$t('所属角色')"
|
||||
@click="(item) => (this.dialog.roleSave = { row: item, mode: 'view' })"
|
||||
field="name"
|
||||
prop="roles" />
|
||||
<na-col-tags
|
||||
:label="$t('所属部门')"
|
||||
@click="(item) => (this.dialog.deptSave = { row: item, mode: 'view' })"
|
||||
field="name"
|
||||
prop="dept"
|
||||
width="200" />
|
||||
<el-table-column :label="$t('启用')" align="center" prop="enabled" sortable="custom" width="100">
|
||||
<template #default="scope">
|
||||
<el-switch v-model="scope.row.enabled" @change="changeSwitch($event, scope.row)"></el-switch>
|
||||
<template #default="{ row }">
|
||||
<el-switch v-model="row.enabled" @change="changeSwitch($event, row)"></el-switch>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column :label="$t('创建时间')" align="right" prop="createdTime" sortable="custom" />
|
||||
<na-col-operation :vue="this" />
|
||||
<na-col-operation :vue="this" width="120" />
|
||||
</sc-table>
|
||||
</el-main>
|
||||
</el-container>
|
||||
|
||||
<save-dialog
|
||||
v-if="dialog.save"
|
||||
@closed="dialog.save = false"
|
||||
@closed="dialog.save = null"
|
||||
@mounted="$refs.saveDialog.open(dialog.save)"
|
||||
@success="(data, mode) => table.handleUpdate($refs.table, data, mode)"
|
||||
ref="saveDialog"></save-dialog>
|
||||
<role-save-dialog v-if="dialog.roleSave" @closed="dialog.roleSave = false" ref="roleSaveDialog"></role-save-dialog>
|
||||
<dept-save-dialog v-if="dialog.deptSave" @closed="dialog.deptSave = false" ref="deptSaveDialog"></dept-save-dialog>
|
||||
<role-save-dialog
|
||||
v-if="dialog.roleSave"
|
||||
@closed="dialog.roleSave = null"
|
||||
@mounted="$refs.roleSaveDialog.open(dialog.roleSave)"
|
||||
ref="roleSaveDialog"></role-save-dialog>
|
||||
<dept-save-dialog
|
||||
v-if="dialog.deptSave"
|
||||
@closed="dialog.deptSave = null"
|
||||
@mounted="$refs.deptSaveDialog.open(dialog.deptSave)"
|
||||
ref="deptSaveDialog"></dept-save-dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import saveDialog from './save'
|
||||
import roleSaveDialog from '@/views/sys/role/save.vue'
|
||||
import deptSaveDialog from '@/views/sys/dept/save.vue'
|
||||
import { defineAsyncComponent } from 'vue'
|
||||
import table from '@/config/table'
|
||||
|
||||
const roleSaveDialog = defineAsyncComponent(() => import('@/views/sys/role/save.vue'))
|
||||
const deptSaveDialog = defineAsyncComponent(() => import('@/views/sys/dept/save.vue'))
|
||||
const saveDialog = defineAsyncComponent(() => import('./save.vue'))
|
||||
export default {
|
||||
components: {
|
||||
deptSaveDialog,
|
||||
@ -116,14 +147,20 @@ export default {
|
||||
return table
|
||||
},
|
||||
},
|
||||
created() {},
|
||||
created() {
|
||||
if (this.keywords) {
|
||||
this.query.keywords = this.keywords
|
||||
}
|
||||
if (this.roleId) {
|
||||
this.query.filter.roleId = this.roleId
|
||||
}
|
||||
if (this.deptId) {
|
||||
this.query.filter.deptId = this.deptId
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
dialog: {
|
||||
deptSave: false,
|
||||
roleSave: false,
|
||||
save: false,
|
||||
},
|
||||
dialog: {},
|
||||
loading: false,
|
||||
query: {
|
||||
dynamicFilter: {
|
||||
@ -136,6 +173,33 @@ export default {
|
||||
},
|
||||
inject: ['reload'],
|
||||
methods: {
|
||||
async setEnabled(enabled) {
|
||||
let loading
|
||||
try {
|
||||
await this.$confirm(
|
||||
this.$t('确定要 {operator} 选中的 {count} 项吗?', {
|
||||
operator: enabled ? this.$t('启用') : this.$t('禁用'),
|
||||
count: this.selection.length,
|
||||
}),
|
||||
this.$t('提示'),
|
||||
{
|
||||
type: 'warning',
|
||||
},
|
||||
)
|
||||
loading = this.$loading()
|
||||
const res = await Promise.all(this.selection.map((x) => this.$API.sys_user.setEnabled.post(Object.assign(x, { enabled: enabled }))))
|
||||
this.$message.success(
|
||||
this.$t('操作成功 {count}/{total} 项', {
|
||||
count: res.map((x) => x.data ?? 0).reduce((a, b) => a + b, 0),
|
||||
total: this.selection.length,
|
||||
}),
|
||||
)
|
||||
} catch {
|
||||
//
|
||||
}
|
||||
this.$refs.table.refresh()
|
||||
loading?.close()
|
||||
},
|
||||
async changeSwitch(event, row) {
|
||||
try {
|
||||
await this.$API.sys_user.setEnabled.post(row)
|
||||
@ -148,18 +212,8 @@ export default {
|
||||
filterChange(data) {
|
||||
Object.entries(data).forEach(([key, value]) => {
|
||||
this.$refs.search.form.dy[key] = value === 'true' ? true : value === 'false' ? false : value
|
||||
this.$refs.search.search()
|
||||
})
|
||||
},
|
||||
async openDialog(api, id, dialog) {
|
||||
this.loading = true
|
||||
const res = await this.$API[api].query.post({
|
||||
filter: { id: id },
|
||||
})
|
||||
this.loading = false
|
||||
this.dialog[dialog] = true
|
||||
await this.$nextTick()
|
||||
this.$refs[`${dialog}Dialog`].open('view', res.data[0])
|
||||
this.$refs.search.search()
|
||||
},
|
||||
onSearch(form) {
|
||||
if (Array.isArray(form.dy.createdTime)) {
|
||||
@ -181,7 +235,13 @@ export default {
|
||||
this.$refs.table.upData()
|
||||
},
|
||||
},
|
||||
mounted() {},
|
||||
mounted() {
|
||||
if (this.keywords) {
|
||||
this.$refs.search.form.root.keywords = this.keywords
|
||||
this.$refs.search.keepKeywords = this.keywords
|
||||
}
|
||||
},
|
||||
props: ['keywords', 'roleId', 'deptId'],
|
||||
watch: {},
|
||||
}
|
||||
</script>
|
||||
|
@ -2,10 +2,10 @@
|
||||
<sc-dialog
|
||||
v-model="visible"
|
||||
:title="`${titleMap[mode]}:${form?.id ?? '...'}`"
|
||||
:width="800"
|
||||
@closed="$emit('closed')"
|
||||
append-to-body
|
||||
destroy-on-close>
|
||||
destroy-on-close
|
||||
full-screen>
|
||||
<el-form
|
||||
v-loading="loading"
|
||||
:disabled="mode === 'view'"
|
||||
@ -225,7 +225,7 @@
|
||||
<el-tab-pane v-if="mode === 'view'" :label="$t('原始数据')">
|
||||
<json-viewer
|
||||
:expand-depth="5"
|
||||
:theme="this.$TOOL.data.get('APP_DARK') ? 'dark' : 'light'"
|
||||
:theme="this.$TOOL.data.get('APP_SET_DARK') || this.$CONFIG.APP_SET_DARK ? 'dark' : 'light'"
|
||||
:value="form"
|
||||
copyable
|
||||
expanded
|
||||
@ -235,7 +235,7 @@
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button @click="visible = false">{{ $t('取消') }}</el-button>
|
||||
<el-button v-if="mode !== 'view'" :loading="loading" @click="submit" type="primary">{{ $t('保存') }}</el-button>
|
||||
<el-button v-if="mode !== 'view'" :disabled="loading" :loading="loading" @click="submit" type="primary">{{ $t('保存') }}</el-button>
|
||||
</template>
|
||||
</sc-dialog>
|
||||
</template>
|
||||
@ -243,17 +243,8 @@
|
||||
<script>
|
||||
export default {
|
||||
components: {},
|
||||
emits: ['success', 'closed'],
|
||||
data() {
|
||||
return {
|
||||
mode: 'add',
|
||||
titleMap: {
|
||||
view: this.$t('查看用户'),
|
||||
add: this.$t('新增用户'),
|
||||
edit: this.$t('编辑用户'),
|
||||
},
|
||||
visible: false,
|
||||
loading: false,
|
||||
//表单数据
|
||||
form: {
|
||||
profile: {
|
||||
@ -263,6 +254,8 @@ export default {
|
||||
emergencyContactArea: '',
|
||||
},
|
||||
},
|
||||
loading: false,
|
||||
mode: 'add',
|
||||
//验证规则
|
||||
rules: {
|
||||
userName: [
|
||||
@ -300,23 +293,29 @@ export default {
|
||||
},
|
||||
],
|
||||
},
|
||||
titleMap: {
|
||||
add: this.$t('新增用户'),
|
||||
edit: this.$t('编辑用户'),
|
||||
view: this.$t('查看用户'),
|
||||
},
|
||||
visible: false,
|
||||
}
|
||||
},
|
||||
mounted() {},
|
||||
emits: ['success', 'closed', 'mounted'],
|
||||
methods: {
|
||||
//显示
|
||||
async open(mode = 'add', data) {
|
||||
async open(data) {
|
||||
this.visible = true
|
||||
this.loading = true
|
||||
this.mode = mode
|
||||
if (mode === 'add') {
|
||||
this.mode = data.mode
|
||||
if (this.mode === 'add') {
|
||||
this.rules.passwordText[0].required = true
|
||||
}
|
||||
if (data) {
|
||||
const user = (await this.$API.sys_user.get.post({ id: data.id })).data
|
||||
Object.assign(this.form, user, {
|
||||
roleIds: user.roles.map((x) => x.id),
|
||||
deptId: user.dept.id,
|
||||
if (data.row?.id) {
|
||||
const res = await this.$API.sys_user.get.post({ id: data.row.id })
|
||||
Object.assign(this.form, res.data, {
|
||||
roleIds: res.data.roles.map((x) => x.id),
|
||||
deptId: res.data.dept.id,
|
||||
})
|
||||
await this.getProfile()
|
||||
}
|
||||
@ -341,20 +340,20 @@ export default {
|
||||
if (!valid) {
|
||||
return false
|
||||
}
|
||||
|
||||
this.loading = true
|
||||
const method = this.mode === 'add' ? this.$API.sys_user.create : this.$API.sys_user.edit
|
||||
try {
|
||||
const method = this.mode === 'add' ? this.$API.sys_user.create : this.$API.sys_user.edit
|
||||
this.loading = true
|
||||
const res = await method.post(Object.assign({}, this.form))
|
||||
this.loading = false
|
||||
const res = await method.post(this.form)
|
||||
this.$emit('success', res.data, this.mode)
|
||||
this.visible = false
|
||||
this.$message.success(this.$t('操作成功'))
|
||||
} catch {
|
||||
this.loading = false
|
||||
}
|
||||
} catch {}
|
||||
this.loading = false
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.$emit('mounted')
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
|
Reference in New Issue
Block a user