fix
This commit is contained in:
@@ -48,7 +48,7 @@
|
||||
:data="state.dataList"
|
||||
v-loading="state.loading"
|
||||
style="width: 100%"
|
||||
row-key="id"
|
||||
row-key="id"
|
||||
@selection-change="handleSelectionChange"
|
||||
@sort-change="sortChangeHandle"
|
||||
border
|
||||
@@ -109,7 +109,7 @@ const resetQuery = () => {
|
||||
|
||||
// 导出excel
|
||||
const exportExcel = () => {
|
||||
downBlobFile('/admin/audit/export', Object.assign(state.queryForm,{ids:selectObjs}), 'audit.xlsx');
|
||||
downBlobFile('/admin/audit/export', Object.assign(state.queryForm, { ids: selectObjs }), 'audit.xlsx');
|
||||
};
|
||||
|
||||
// 多选事件
|
||||
|
||||
@@ -164,7 +164,7 @@ const collapseActive = ref('1');
|
||||
// 定义校验规则
|
||||
const dataRules = ref({
|
||||
clientId: [
|
||||
{ validator: rule.overLength, trigger: 'blur' },
|
||||
{ validator: rule.overLength, trigger: 'blur' },
|
||||
{ required: true, message: '编号不能为空', trigger: 'blur' },
|
||||
{ validator: rule.validatorLowercase, trigger: 'blur' },
|
||||
{
|
||||
@@ -175,11 +175,14 @@ const dataRules = ref({
|
||||
},
|
||||
],
|
||||
clientSecret: [
|
||||
{ validator: rule.overLength, trigger: 'blur' },
|
||||
{ validator: rule.overLength, trigger: 'blur' },
|
||||
{ required: true, message: '密钥不能为空', trigger: 'blur' },
|
||||
{ validator: rule.validatorLower, trigger: 'blur' },
|
||||
],
|
||||
scope: [{ validator: rule.overLength, trigger: 'blur' },{ required: true, message: '域不能为空', trigger: 'blur' }],
|
||||
scope: [
|
||||
{ validator: rule.overLength, trigger: 'blur' },
|
||||
{ required: true, message: '域不能为空', trigger: 'blur' },
|
||||
],
|
||||
authorizedGrantTypes: [{ required: true, message: '授权模式不能为空', trigger: 'blur' }],
|
||||
accessTokenValidity: [
|
||||
{ required: true, message: '令牌时效不能为空', trigger: 'blur' },
|
||||
@@ -193,7 +196,10 @@ const dataRules = ref({
|
||||
encFlag: [{ required: true, message: '是否开启密码加密传输', trigger: 'blur' }],
|
||||
onlineQuantity: [{ required: true, message: '是否允许同时在线', trigger: 'blur' }],
|
||||
autoapprove: [{ required: true, message: '自动放行不能为空', trigger: 'blur' }],
|
||||
webServerRedirectUri: [{ validator: rule.overLength, trigger: 'blur' },{ required: true, message: '回调地址不能为空', trigger: 'blur' }],
|
||||
webServerRedirectUri: [
|
||||
{ validator: rule.overLength, trigger: 'blur' },
|
||||
{ required: true, message: '回调地址不能为空', trigger: 'blur' },
|
||||
],
|
||||
});
|
||||
|
||||
// 打开弹窗
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
:data="state.dataList"
|
||||
@selection-change="handleSelectionChange"
|
||||
style="width: 100%"
|
||||
row-key="id"
|
||||
row-key="id"
|
||||
v-loading="state.loading"
|
||||
border
|
||||
:cell-style="tableStyle.cellStyle"
|
||||
@@ -127,7 +127,7 @@ const resetQuery = () => {
|
||||
|
||||
// 导出excel
|
||||
const exportExcel = () => {
|
||||
downBlobFile('/admin/client/export', Object.assign(state.queryForm,{ids:selectObjs}), 'client.xlsx');
|
||||
downBlobFile('/admin/client/export', Object.assign(state.queryForm, { ids: selectObjs }), 'client.xlsx');
|
||||
};
|
||||
|
||||
// 多选事件
|
||||
|
||||
@@ -1,50 +1,46 @@
|
||||
<template>
|
||||
<el-dialog v-model="visible" :title="dataForm.id ? $t('common.editBtn') : $t('common.addBtn')" width="600">
|
||||
<el-form ref="dicDialogFormRef" :model="dataForm" label-width="120px" :rules="dataRules" v-loading="loading">
|
||||
<el-form-item :label="$t('dictItem.dictType')" prop="dictType">
|
||||
<el-input v-model="dataForm.dictType" clearable disabled
|
||||
:placeholder="$t('dictItem.inputDictTypeTip')"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('dictItem.label')" prop="label">
|
||||
<el-input v-model="dataForm.label" :placeholder="$t('dictItem.inputLabelTip')" clearable></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('dictItem.itemValue')" prop="value">
|
||||
<el-input v-model="dataForm.value" :placeholder="$t('dictItem.inputItemValueTip')" clearable></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('dictItem.description')" prop="description">
|
||||
<el-input v-model="dataForm.description" :placeholder="$t('dictItem.inputDescriptionTip')" clearable></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('dictItem.sortOrder')" prop="sortOrder">
|
||||
<el-input-number v-model="dataForm.sortOrder" :placeholder="$t('dictItem.inputSortOrderTip')"
|
||||
clearable></el-input-number>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('dictItem.remarks')" prop="remarks">
|
||||
<el-input type="textarea" maxlength="100" :rows="3" v-model="dataForm.remarks"
|
||||
:placeholder="$t('dictItem.inputRemarksTip')"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="状态颜色" prop="fontCss">
|
||||
<el-input maxlength="100" v-model="dataForm.fontCss"
|
||||
placeholder="状态颜色"></el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-dialog v-model="visible" :title="dataForm.id ? $t('common.editBtn') : $t('common.addBtn')" width="600">
|
||||
<el-form ref="dicDialogFormRef" :model="dataForm" label-width="120px" :rules="dataRules" v-loading="loading">
|
||||
<el-form-item :label="$t('dictItem.dictType')" prop="dictType">
|
||||
<el-input v-model="dataForm.dictType" clearable disabled :placeholder="$t('dictItem.inputDictTypeTip')"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('dictItem.label')" prop="label">
|
||||
<el-input v-model="dataForm.label" :placeholder="$t('dictItem.inputLabelTip')" clearable></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('dictItem.itemValue')" prop="value">
|
||||
<el-input v-model="dataForm.value" :placeholder="$t('dictItem.inputItemValueTip')" clearable></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('dictItem.description')" prop="description">
|
||||
<el-input v-model="dataForm.description" :placeholder="$t('dictItem.inputDescriptionTip')" clearable></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('dictItem.sortOrder')" prop="sortOrder">
|
||||
<el-input-number v-model="dataForm.sortOrder" :placeholder="$t('dictItem.inputSortOrderTip')" clearable></el-input-number>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('dictItem.remarks')" prop="remarks">
|
||||
<el-input type="textarea" maxlength="100" :rows="3" v-model="dataForm.remarks" :placeholder="$t('dictItem.inputRemarksTip')"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="状态颜色" prop="fontCss">
|
||||
<el-input maxlength="100" v-model="dataForm.fontCss" placeholder="状态颜色"></el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="visible = false">{{ $t('common.cancelButtonText') }}</el-button>
|
||||
<el-button type="primary" @click="onSubmit" :disabled="loading">{{ $t('common.confirmButtonText') }}</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="dict-item-form">
|
||||
import {useI18n} from 'vue-i18n';
|
||||
import {getItemObj, addItemObj, putItemObj, validateDictItemLabel} from '/@/api/admin/dict';
|
||||
import {useMessage} from '/@/hooks/message';
|
||||
import {rule} from "/@/utils/validate";
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { getItemObj, addItemObj, putItemObj, validateDictItemLabel } from '/@/api/admin/dict';
|
||||
import { useMessage } from '/@/hooks/message';
|
||||
import { rule } from '/@/utils/validate';
|
||||
|
||||
// 定义子组件向父组件传值/事件
|
||||
const emit = defineEmits(['refresh']);
|
||||
const {t} = useI18n();
|
||||
const { t } = useI18n();
|
||||
|
||||
// 定义变量内容
|
||||
const dicDialogFormRef = ref();
|
||||
@@ -53,86 +49,97 @@ const visible = ref(false);
|
||||
const loading = ref(false);
|
||||
|
||||
const dataForm = reactive({
|
||||
id: '',
|
||||
dictId: '',
|
||||
dictType: '',
|
||||
value: '',
|
||||
label: '',
|
||||
description: '',
|
||||
sortOrder: 0,
|
||||
remarks: '',
|
||||
fontCss: '',
|
||||
id: '',
|
||||
dictId: '',
|
||||
dictType: '',
|
||||
value: '',
|
||||
label: '',
|
||||
description: '',
|
||||
sortOrder: 0,
|
||||
remarks: '',
|
||||
fontCss: '',
|
||||
});
|
||||
|
||||
const dataRules = reactive({
|
||||
dictType: [{validator: rule.overLength, trigger: 'blur'}, {
|
||||
required: true,
|
||||
message: '请点选左侧字典项',
|
||||
trigger: 'blur'
|
||||
}],
|
||||
value: [{validator: rule.overLength, trigger: 'blur'}, {required: true, message: '数据值不能为空', trigger: 'blur'}],
|
||||
label: [
|
||||
{validator: rule.overLength, trigger: 'blur'},
|
||||
{required: true, message: '标签不能为空', trigger: 'blur'},
|
||||
{
|
||||
validator: (rule: any, value: any, callback: any) => {
|
||||
validateDictItemLabel(rule, value, callback, dataForm.dictType, dataForm.id !== '');
|
||||
},
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
description: [{validator: rule.overLength, trigger: 'blur'}, {
|
||||
required: true,
|
||||
message: '描述不能为空',
|
||||
trigger: 'blur'
|
||||
}],
|
||||
sortOrder: [{validator: rule.overLength, trigger: 'blur'}, {
|
||||
required: true,
|
||||
message: '排序不能为空',
|
||||
trigger: 'blur'
|
||||
}],
|
||||
dictType: [
|
||||
{ validator: rule.overLength, trigger: 'blur' },
|
||||
{
|
||||
required: true,
|
||||
message: '请点选左侧字典项',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
value: [
|
||||
{ validator: rule.overLength, trigger: 'blur' },
|
||||
{ required: true, message: '数据值不能为空', trigger: 'blur' },
|
||||
],
|
||||
label: [
|
||||
{ validator: rule.overLength, trigger: 'blur' },
|
||||
{ required: true, message: '标签不能为空', trigger: 'blur' },
|
||||
{
|
||||
validator: (rule: any, value: any, callback: any) => {
|
||||
validateDictItemLabel(rule, value, callback, dataForm.dictType, dataForm.id !== '');
|
||||
},
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
description: [
|
||||
{ validator: rule.overLength, trigger: 'blur' },
|
||||
{
|
||||
required: true,
|
||||
message: '描述不能为空',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
sortOrder: [
|
||||
{ validator: rule.overLength, trigger: 'blur' },
|
||||
{
|
||||
required: true,
|
||||
message: '排序不能为空',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
// 打开弹窗
|
||||
const openDialog = (row: any, dictForm: any) => {
|
||||
visible.value = true;
|
||||
dataForm.id = '';
|
||||
visible.value = true;
|
||||
dataForm.id = '';
|
||||
|
||||
nextTick(() => {
|
||||
dicDialogFormRef.value?.resetFields();
|
||||
if (dictForm) {
|
||||
dataForm.dictId = dictForm.dictId;
|
||||
dataForm.dictType = dictForm.dictType;
|
||||
}
|
||||
});
|
||||
if (row?.id) {
|
||||
getItemObj(row.id).then((res) => {
|
||||
Object.assign(dataForm, res.data);
|
||||
});
|
||||
}
|
||||
nextTick(() => {
|
||||
dicDialogFormRef.value?.resetFields();
|
||||
if (dictForm) {
|
||||
dataForm.dictId = dictForm.dictId;
|
||||
dataForm.dictType = dictForm.dictType;
|
||||
}
|
||||
});
|
||||
if (row?.id) {
|
||||
getItemObj(row.id).then((res) => {
|
||||
Object.assign(dataForm, res.data);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// 提交
|
||||
const onSubmit = async () => {
|
||||
const valid = await dicDialogFormRef.value.validate().catch(() => {
|
||||
});
|
||||
if (!valid) return false;
|
||||
const valid = await dicDialogFormRef.value.validate().catch(() => {});
|
||||
if (!valid) return false;
|
||||
|
||||
try {
|
||||
loading.value = true;
|
||||
dataForm.id ? await putItemObj(dataForm) : await addItemObj(dataForm);
|
||||
useMessage().success(t(dataForm.id ? 'common.editSuccessText' : 'common.addSuccessText'));
|
||||
visible.value = false;
|
||||
emit('refresh');
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg);
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
try {
|
||||
loading.value = true;
|
||||
dataForm.id ? await putItemObj(dataForm) : await addItemObj(dataForm);
|
||||
useMessage().success(t(dataForm.id ? 'common.editSuccessText' : 'common.addSuccessText'));
|
||||
visible.value = false;
|
||||
emit('refresh');
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg);
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
// 暴露变量
|
||||
defineExpose({
|
||||
openDialog,
|
||||
openDialog,
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -54,7 +54,7 @@ const dataForm = reactive({
|
||||
|
||||
const dataRules = reactive({
|
||||
dictType: [
|
||||
{ validator: rule.overLength, trigger: 'blur' },
|
||||
{ validator: rule.overLength, trigger: 'blur' },
|
||||
{ required: true, message: '类型不能为空', trigger: 'blur' },
|
||||
{ validator: rule.validatorNameCn, trigger: 'blur' },
|
||||
{
|
||||
@@ -65,7 +65,10 @@ const dataRules = reactive({
|
||||
},
|
||||
],
|
||||
systemFlag: [{ required: true, message: '字典类型不能为空', trigger: 'blur' }],
|
||||
description: [{ validator: rule.overLength, trigger: 'blur' },{ required: true, message: '描述不能为空', trigger: 'blur' }],
|
||||
description: [
|
||||
{ validator: rule.overLength, trigger: 'blur' },
|
||||
{ required: true, message: '描述不能为空', trigger: 'blur' },
|
||||
],
|
||||
});
|
||||
|
||||
// 打开弹窗
|
||||
|
||||
@@ -46,7 +46,7 @@ const form = reactive({
|
||||
// 定义校验规则
|
||||
const dataRules = ref({
|
||||
name: [
|
||||
{ validator: rule.overLength, trigger: 'blur' },
|
||||
{ validator: rule.overLength, trigger: 'blur' },
|
||||
{ required: true, message: 'name不能为空', trigger: 'blur' },
|
||||
{ validator: rule.noChinese, trigger: 'blur' },
|
||||
{
|
||||
@@ -57,7 +57,7 @@ const dataRules = ref({
|
||||
},
|
||||
],
|
||||
zhCn: [
|
||||
{ validator: rule.overLength, trigger: 'blur' },
|
||||
{ validator: rule.overLength, trigger: 'blur' },
|
||||
{ required: true, message: '中文不能为空', trigger: 'blur' },
|
||||
{
|
||||
validator: (rule: any, value: any, callback: any) => {
|
||||
@@ -67,7 +67,7 @@ const dataRules = ref({
|
||||
},
|
||||
],
|
||||
en: [
|
||||
{ validator: rule.overLength, trigger: 'blur' },
|
||||
{ validator: rule.overLength, trigger: 'blur' },
|
||||
{ required: true, message: '英文不能为空', trigger: 'blur' },
|
||||
{ validator: rule.letter, trigger: 'blur' },
|
||||
{
|
||||
|
||||
@@ -55,7 +55,7 @@
|
||||
@selection-change="handleSelectionChange"
|
||||
@sort-change="sortChangeHandle"
|
||||
style="width: 100%"
|
||||
row-key="id"
|
||||
row-key="id"
|
||||
v-loading="state.loading"
|
||||
border
|
||||
:cell-style="tableStyle.cellStyle"
|
||||
@@ -139,7 +139,7 @@ const handleRefreshCache = () => {
|
||||
|
||||
// 导出excel
|
||||
const exportExcel = () => {
|
||||
downBlobFile('/admin/i18n/export', Object.assign(state.queryForm,{ids:selectObjs}), 'i18n.xlsx');
|
||||
downBlobFile('/admin/i18n/export', Object.assign(state.queryForm, { ids: selectObjs }), 'i18n.xlsx');
|
||||
};
|
||||
|
||||
// 多选事件
|
||||
|
||||
@@ -1,86 +1,87 @@
|
||||
<template>
|
||||
<el-drawer v-model="visible" :title="data.title" size="30%">
|
||||
<div class="w-full">
|
||||
<div class="coding inverse-toggle px-5 pt-4 shadow-lg text-gray-100 text-sm font-mono subpixel-antialiased
|
||||
bg-gray-800 pb-6 pt-4 rounded-lg leading-normal overflow-hidden">
|
||||
<div class="top mb-2 flex">
|
||||
<div class="h-3 w-3 bg-red-500 rounded-full"></div>
|
||||
<div class="ml-2 h-3 w-3 bg-orange-300 rounded-full"></div>
|
||||
<div class="ml-2 h-3 w-3 bg-green-500 rounded-full"></div>
|
||||
</div>
|
||||
<div class="mt-4 flex">
|
||||
<span class="text-green-400">{{ $t('syslog.createTime') }}: </span>
|
||||
<p class="flex-1 typing items-center pl-2 whitespace-normal overflow-hidden break-all">
|
||||
{{ data.createTime }}
|
||||
<br>
|
||||
</p>
|
||||
</div>
|
||||
<div class="mt-4 flex">
|
||||
<span class="text-green-400">{{ $t('syslog.createBy') }}: </span>
|
||||
<p class="flex-1 typing items-center pl-2 whitespace-normal overflow-hidden break-all">
|
||||
{{ data.createBy }}
|
||||
<br>
|
||||
</p>
|
||||
</div>
|
||||
<div class="mt-4 flex">
|
||||
<span class="text-green-400">{{ $t('syslog.requestUri') }}: </span>
|
||||
<p class="flex-1 typing items-center pl-2 whitespace-normal overflow-hidden break-all">
|
||||
{{ data.requestUri }}
|
||||
<br>
|
||||
</p>
|
||||
</div>
|
||||
<div class="mt-4 flex">
|
||||
<span class="text-green-400">{{ $t('syslog.remoteAddr') }}: </span>
|
||||
<p class="flex-1 typing items-center pl-2 whitespace-normal overflow-hidden break-all">
|
||||
{{ data.remoteAddr }}
|
||||
<br>
|
||||
</p>
|
||||
</div>
|
||||
<div class="mt-4 flex">
|
||||
<span class="text-green-400">{{ $t('syslog.method') }}: </span>
|
||||
<p class="flex-1 typing items-center pl-2 whitespace-normal overflow-hidden break-all">
|
||||
{{ data.method }}
|
||||
<br>
|
||||
</p>
|
||||
</div>
|
||||
<div class="mt-4 flex">
|
||||
<span class="text-green-400">{{ $t('syslog.serviceId') }}: </span>
|
||||
<p class="flex-1 typing items-center pl-2 whitespace-normal overflow-hidden break-all">
|
||||
{{ data.serviceId }}
|
||||
<br>
|
||||
</p>
|
||||
</div>
|
||||
<div class="mt-4 flex">
|
||||
<span class="text-green-400">{{ $t('syslog.time') }}: </span>
|
||||
<p class="flex-1 typing items-center pl-2 whitespace-normal overflow-hidden break-all">
|
||||
{{ data.time }}/ms
|
||||
<br>
|
||||
</p>
|
||||
</div>
|
||||
<div class="mt-4 flex">
|
||||
<span class="text-green-400">{{ $t('syslog.ua') }}: </span>
|
||||
<p class="flex-1 typing items-center pl-2 whitespace-normal overflow-hidden break-all">
|
||||
{{ data.userAgent }}
|
||||
<br>
|
||||
</p>
|
||||
</div>
|
||||
<div class="mt-4 flex" v-if="data.params">
|
||||
<span class="text-green-400">{{ $t('syslog.params') }}: </span>
|
||||
<p class="flex-1 typing items-center pl-2 whitespace-normal overflow-hidden break-all">
|
||||
{{ data.params }}
|
||||
<br>
|
||||
</p>
|
||||
</div>
|
||||
<div class="mt-4 flex" v-if="data.exception">
|
||||
<span class="text-green-400">{{ data.logType === '0' ? $t('syslog.result') : $t('syslog.exception') }}: </span>
|
||||
<p class="flex-1 typing items-center pl-2 whitespace-normal overflow-hidden break-all">
|
||||
{{ data.exception }}
|
||||
<br>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-drawer>
|
||||
<el-drawer v-model="visible" :title="data.title" size="30%">
|
||||
<div class="w-full">
|
||||
<div
|
||||
class="coding inverse-toggle px-5 pt-4 shadow-lg text-gray-100 text-sm font-mono subpixel-antialiased bg-gray-800 pb-6 pt-4 rounded-lg leading-normal overflow-hidden"
|
||||
>
|
||||
<div class="top mb-2 flex">
|
||||
<div class="h-3 w-3 bg-red-500 rounded-full"></div>
|
||||
<div class="ml-2 h-3 w-3 bg-orange-300 rounded-full"></div>
|
||||
<div class="ml-2 h-3 w-3 bg-green-500 rounded-full"></div>
|
||||
</div>
|
||||
<div class="mt-4 flex">
|
||||
<span class="text-green-400">{{ $t('syslog.createTime') }}: </span>
|
||||
<p class="flex-1 typing items-center pl-2 whitespace-normal overflow-hidden break-all">
|
||||
{{ data.createTime }}
|
||||
<br />
|
||||
</p>
|
||||
</div>
|
||||
<div class="mt-4 flex">
|
||||
<span class="text-green-400">{{ $t('syslog.createBy') }}: </span>
|
||||
<p class="flex-1 typing items-center pl-2 whitespace-normal overflow-hidden break-all">
|
||||
{{ data.createBy }}
|
||||
<br />
|
||||
</p>
|
||||
</div>
|
||||
<div class="mt-4 flex">
|
||||
<span class="text-green-400">{{ $t('syslog.requestUri') }}: </span>
|
||||
<p class="flex-1 typing items-center pl-2 whitespace-normal overflow-hidden break-all">
|
||||
{{ data.requestUri }}
|
||||
<br />
|
||||
</p>
|
||||
</div>
|
||||
<div class="mt-4 flex">
|
||||
<span class="text-green-400">{{ $t('syslog.remoteAddr') }}: </span>
|
||||
<p class="flex-1 typing items-center pl-2 whitespace-normal overflow-hidden break-all">
|
||||
{{ data.remoteAddr }}
|
||||
<br />
|
||||
</p>
|
||||
</div>
|
||||
<div class="mt-4 flex">
|
||||
<span class="text-green-400">{{ $t('syslog.method') }}: </span>
|
||||
<p class="flex-1 typing items-center pl-2 whitespace-normal overflow-hidden break-all">
|
||||
{{ data.method }}
|
||||
<br />
|
||||
</p>
|
||||
</div>
|
||||
<div class="mt-4 flex">
|
||||
<span class="text-green-400">{{ $t('syslog.serviceId') }}: </span>
|
||||
<p class="flex-1 typing items-center pl-2 whitespace-normal overflow-hidden break-all">
|
||||
{{ data.serviceId }}
|
||||
<br />
|
||||
</p>
|
||||
</div>
|
||||
<div class="mt-4 flex">
|
||||
<span class="text-green-400">{{ $t('syslog.time') }}: </span>
|
||||
<p class="flex-1 typing items-center pl-2 whitespace-normal overflow-hidden break-all">
|
||||
{{ data.time }}/ms
|
||||
<br />
|
||||
</p>
|
||||
</div>
|
||||
<div class="mt-4 flex">
|
||||
<span class="text-green-400">{{ $t('syslog.ua') }}: </span>
|
||||
<p class="flex-1 typing items-center pl-2 whitespace-normal overflow-hidden break-all">
|
||||
{{ data.userAgent }}
|
||||
<br />
|
||||
</p>
|
||||
</div>
|
||||
<div class="mt-4 flex" v-if="data.params">
|
||||
<span class="text-green-400">{{ $t('syslog.params') }}: </span>
|
||||
<p class="flex-1 typing items-center pl-2 whitespace-normal overflow-hidden break-all">
|
||||
{{ data.params }}
|
||||
<br />
|
||||
</p>
|
||||
</div>
|
||||
<div class="mt-4 flex" v-if="data.exception">
|
||||
<span class="text-green-400">{{ data.logType === '0' ? $t('syslog.result') : $t('syslog.exception') }}: </span>
|
||||
<p class="flex-1 typing items-center pl-2 whitespace-normal overflow-hidden break-all">
|
||||
{{ data.exception }}
|
||||
<br />
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-drawer>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="log-detail">
|
||||
@@ -89,12 +90,12 @@ const visible = ref(false);
|
||||
const data = reactive({} as any);
|
||||
|
||||
const openDialog = (row: any) => {
|
||||
visible.value = true;
|
||||
Object.assign(data, row);
|
||||
visible.value = true;
|
||||
Object.assign(data, row);
|
||||
};
|
||||
|
||||
// 暴露变量
|
||||
defineExpose({
|
||||
openDialog,
|
||||
openDialog,
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -1,22 +1,22 @@
|
||||
export default {
|
||||
syslog: {
|
||||
index: '#',
|
||||
logType: 'logType',
|
||||
title: 'title',
|
||||
remoteAddr: 'remoteAddr',
|
||||
method: 'method',
|
||||
ua: 'browser',
|
||||
serviceId: 'serviceId',
|
||||
time: 'time',
|
||||
params: 'params',
|
||||
createTime: 'createTime',
|
||||
requestUri: 'requestUri',
|
||||
exception: 'exception',
|
||||
createBy: 'createBy',
|
||||
action: 'action',
|
||||
inputLogTypeTip: 'select logType',
|
||||
inputStartPlaceholderTip: 'Start Time',
|
||||
inputEndPlaceholderTip: 'End TIme',
|
||||
result: 'result'
|
||||
},
|
||||
syslog: {
|
||||
index: '#',
|
||||
logType: 'logType',
|
||||
title: 'title',
|
||||
remoteAddr: 'remoteAddr',
|
||||
method: 'method',
|
||||
ua: 'browser',
|
||||
serviceId: 'serviceId',
|
||||
time: 'time',
|
||||
params: 'params',
|
||||
createTime: 'createTime',
|
||||
requestUri: 'requestUri',
|
||||
exception: 'exception',
|
||||
createBy: 'createBy',
|
||||
action: 'action',
|
||||
inputLogTypeTip: 'select logType',
|
||||
inputStartPlaceholderTip: 'Start Time',
|
||||
inputEndPlaceholderTip: 'End TIme',
|
||||
result: 'result',
|
||||
},
|
||||
};
|
||||
|
||||
@@ -1,22 +1,22 @@
|
||||
export default {
|
||||
syslog: {
|
||||
index: '#',
|
||||
logType: '类型',
|
||||
title: '标题',
|
||||
remoteAddr: 'IP地址',
|
||||
method: '请求方式',
|
||||
ua: '浏览器',
|
||||
serviceId: '客户端',
|
||||
time: '耗时',
|
||||
params: '请求参数',
|
||||
createTime: '请求时间',
|
||||
requestUri: '请求地址',
|
||||
exception: '异常信息',
|
||||
createBy: '操作人',
|
||||
action: '操作',
|
||||
inputLogTypeTip: '请选择类型',
|
||||
inputStartPlaceholderTip: '开始时间',
|
||||
inputEndPlaceholderTip: '结束时间',
|
||||
result: '结果',
|
||||
},
|
||||
syslog: {
|
||||
index: '#',
|
||||
logType: '类型',
|
||||
title: '标题',
|
||||
remoteAddr: 'IP地址',
|
||||
method: '请求方式',
|
||||
ua: '浏览器',
|
||||
serviceId: '客户端',
|
||||
time: '耗时',
|
||||
params: '请求参数',
|
||||
createTime: '请求时间',
|
||||
requestUri: '请求地址',
|
||||
exception: '异常信息',
|
||||
createBy: '操作人',
|
||||
action: '操作',
|
||||
inputLogTypeTip: '请选择类型',
|
||||
inputStartPlaceholderTip: '开始时间',
|
||||
inputEndPlaceholderTip: '结束时间',
|
||||
result: '结果',
|
||||
},
|
||||
};
|
||||
|
||||
@@ -1,114 +1,108 @@
|
||||
<template>
|
||||
<div class="layout-padding">
|
||||
<div class="layout-padding-auto layout-padding-view">
|
||||
<!-- 顶部折线图-->
|
||||
<log-line-chart/>
|
||||
<div class="layout-padding">
|
||||
<div class="layout-padding-auto layout-padding-view">
|
||||
<!-- 顶部折线图-->
|
||||
<log-line-chart />
|
||||
|
||||
<el-row class="mt-4 ml10" v-show="showSearch">
|
||||
<el-form :inline="true" :model="state.queryForm" @keyup.enter="getDataList" ref="queryRef">
|
||||
<el-form-item :label="$t('syslog.logType')" prop="logType">
|
||||
<el-select :placeholder="$t('syslog.inputLogTypeTip')" clearable
|
||||
v-model="state.queryForm.logType">
|
||||
<el-option :key="item.value" :label="item.label" :value="item.value" v-for="item in log_type"/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('syslog.createTime')" prop="createTime">
|
||||
<el-date-picker
|
||||
:end-placeholder="$t('syslog.inputEndPlaceholderTip')"
|
||||
:start-placeholder="$t('syslog.inputStartPlaceholderTip')"
|
||||
range-separator="To"
|
||||
type="datetimerange"
|
||||
v-model="state.queryForm.createTime"
|
||||
value-format="YYYY-MM-DD HH:mm:ss"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button @click="getDataList" icon="Search" type="primary">{{ $t('common.queryBtn') }}</el-button>
|
||||
<el-button @click="resetQuery" icon="Refresh">{{ $t('common.resetBtn') }}</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-row>
|
||||
<el-row class="mt-4 ml10" v-show="showSearch">
|
||||
<el-form :inline="true" :model="state.queryForm" @keyup.enter="getDataList" ref="queryRef">
|
||||
<el-form-item :label="$t('syslog.logType')" prop="logType">
|
||||
<el-select :placeholder="$t('syslog.inputLogTypeTip')" clearable v-model="state.queryForm.logType">
|
||||
<el-option :key="item.value" :label="item.label" :value="item.value" v-for="item in log_type" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('syslog.createTime')" prop="createTime">
|
||||
<el-date-picker
|
||||
:end-placeholder="$t('syslog.inputEndPlaceholderTip')"
|
||||
:start-placeholder="$t('syslog.inputStartPlaceholderTip')"
|
||||
range-separator="To"
|
||||
type="datetimerange"
|
||||
v-model="state.queryForm.createTime"
|
||||
value-format="YYYY-MM-DD HH:mm:ss"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button @click="getDataList" icon="Search" type="primary">{{ $t('common.queryBtn') }}</el-button>
|
||||
<el-button @click="resetQuery" icon="Refresh">{{ $t('common.resetBtn') }}</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-row>
|
||||
|
||||
<el-row>
|
||||
<div class="mb-2" style="width: 100%">
|
||||
<el-button :disabled="multiple" v-auth="'sys_log_del'" @click="handleDelete(selectObjs)" class="ml10"
|
||||
icon="Delete" type="primary">
|
||||
{{ $t('common.delBtn') }}
|
||||
</el-button>
|
||||
<right-toolbar
|
||||
:export="'sys_log_export'"
|
||||
@exportExcel="exportExcel"
|
||||
@queryTable="getDataList"
|
||||
class="ml10"
|
||||
style="float: right; margin-right: 20px"
|
||||
v-model:showSearch="showSearch"
|
||||
></right-toolbar>
|
||||
</div>
|
||||
</el-row>
|
||||
<el-table
|
||||
ref="tableRef"
|
||||
:data="state.dataList"
|
||||
@selection-change="handleSelectionChange"
|
||||
@sort-change="sortChangeHandle"
|
||||
v-loading="state.loading"
|
||||
border
|
||||
:cell-style="tableStyle.cellStyle"
|
||||
:header-cell-style="tableStyle.headerCellStyle"
|
||||
>
|
||||
<el-table-column align="center" type="selection" width="40"/>
|
||||
<el-table-column :label="$t('syslog.index')" type="index" width="60"/>
|
||||
<el-table-column :label="$t('syslog.logType')" show-overflow-tooltip>
|
||||
<template #default="scope">
|
||||
<dict-tag :options="log_type" :value="scope.row.logType"></dict-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column :label="$t('syslog.title')" prop="title" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column :label="$t('syslog.remoteAddr')" prop="remoteAddr" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column :label="$t('syslog.method')" prop="method" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column :label="$t('syslog.time')" prop="time" show-overflow-tooltip>
|
||||
<template #default="scope">
|
||||
<span v-if="scope.row.time">{{ scope.row.time }}/ms</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column :label="$t('syslog.createTime')" prop="createTime" show-overflow-tooltip sortable="custom"
|
||||
width="200"></el-table-column>
|
||||
<el-table-column :label="$t('syslog.createBy')" prop="createBy" show-overflow-tooltip sortable="custom"
|
||||
width="200"></el-table-column>
|
||||
<el-table-column :label="$t('common.action')" width="150">
|
||||
<template #default="scope">
|
||||
<el-button icon="view" @click="LogDetailRef.openDialog(scope.row)" size="small" text type="primary">
|
||||
{{ $t('common.detailBtn') }}
|
||||
</el-button>
|
||||
<el-button v-auth="'sys_log_del'" icon="delete" @click="handleDelete([scope.row.id])" size="small" text
|
||||
type="primary">
|
||||
{{ $t('common.delBtn') }}
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<el-row>
|
||||
<div class="mb-2" style="width: 100%">
|
||||
<el-button :disabled="multiple" v-auth="'sys_log_del'" @click="handleDelete(selectObjs)" class="ml10" icon="Delete" type="primary">
|
||||
{{ $t('common.delBtn') }}
|
||||
</el-button>
|
||||
<right-toolbar
|
||||
:export="'sys_log_export'"
|
||||
@exportExcel="exportExcel"
|
||||
@queryTable="getDataList"
|
||||
class="ml10"
|
||||
style="float: right; margin-right: 20px"
|
||||
v-model:showSearch="showSearch"
|
||||
></right-toolbar>
|
||||
</div>
|
||||
</el-row>
|
||||
<el-table
|
||||
ref="tableRef"
|
||||
:data="state.dataList"
|
||||
@selection-change="handleSelectionChange"
|
||||
@sort-change="sortChangeHandle"
|
||||
v-loading="state.loading"
|
||||
border
|
||||
:cell-style="tableStyle.cellStyle"
|
||||
:header-cell-style="tableStyle.headerCellStyle"
|
||||
>
|
||||
<el-table-column align="center" type="selection" width="40" />
|
||||
<el-table-column :label="$t('syslog.index')" type="index" width="60" />
|
||||
<el-table-column :label="$t('syslog.logType')" show-overflow-tooltip>
|
||||
<template #default="scope">
|
||||
<dict-tag :options="log_type" :value="scope.row.logType"></dict-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column :label="$t('syslog.title')" prop="title" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column :label="$t('syslog.remoteAddr')" prop="remoteAddr" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column :label="$t('syslog.method')" prop="method" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column :label="$t('syslog.time')" prop="time" show-overflow-tooltip>
|
||||
<template #default="scope">
|
||||
<span v-if="scope.row.time">{{ scope.row.time }}/ms</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column :label="$t('syslog.createTime')" prop="createTime" show-overflow-tooltip sortable="custom" width="200"></el-table-column>
|
||||
<el-table-column :label="$t('syslog.createBy')" prop="createBy" show-overflow-tooltip sortable="custom" width="200"></el-table-column>
|
||||
<el-table-column :label="$t('common.action')" width="150">
|
||||
<template #default="scope">
|
||||
<el-button icon="view" @click="LogDetailRef.openDialog(scope.row)" size="small" text type="primary">
|
||||
{{ $t('common.detailBtn') }}
|
||||
</el-button>
|
||||
<el-button v-auth="'sys_log_del'" icon="delete" @click="handleDelete([scope.row.id])" size="small" text type="primary">
|
||||
{{ $t('common.delBtn') }}
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<pagination @current-change="currentChangeHandle" @size-change="sizeChangeHandle"
|
||||
v-bind="state.pagination"></pagination>
|
||||
<log-detail ref="LogDetailRef"></log-detail>
|
||||
</div>
|
||||
</div>
|
||||
<pagination @current-change="currentChangeHandle" @size-change="sizeChangeHandle" v-bind="state.pagination"></pagination>
|
||||
<log-detail ref="LogDetailRef"></log-detail>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import {BasicTableProps, useTable} from '/@/hooks/table';
|
||||
import {delObj, pageList} from '/@/api/admin/log';
|
||||
import {useI18n} from 'vue-i18n';
|
||||
import {useMessage, useMessageBox} from '/@/hooks/message';
|
||||
import {useDict} from '/@/hooks/dict';
|
||||
import { BasicTableProps, useTable } from '/@/hooks/table';
|
||||
import { delObj, pageList } from '/@/api/admin/log';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { useMessage, useMessageBox } from '/@/hooks/message';
|
||||
import { useDict } from '/@/hooks/dict';
|
||||
|
||||
const LogDetail = defineAsyncComponent(() => import('./detail.vue'));
|
||||
const LogLineChart = defineAsyncComponent(() => import('./line-chart.vue'));
|
||||
|
||||
const LogDetailRef = ref();
|
||||
|
||||
const {log_type} = useDict('log_type');
|
||||
const { log_type } = useDict('log_type');
|
||||
|
||||
const {t} = useI18n();
|
||||
const { t } = useI18n();
|
||||
|
||||
// 定义变量内容
|
||||
const queryRef = ref();
|
||||
@@ -121,82 +115,75 @@ const multiple = ref(true);
|
||||
let tableRef = ref(null);
|
||||
|
||||
const state: BasicTableProps = reactive<BasicTableProps>({
|
||||
queryForm: {
|
||||
logType: '',
|
||||
createTime: '',
|
||||
serviceId: '',
|
||||
},
|
||||
selectObjs: [],
|
||||
pageList: pageList,
|
||||
descs: ['create_time'],
|
||||
createdIsNeed: false,
|
||||
queryForm: {
|
||||
logType: '',
|
||||
createTime: '',
|
||||
serviceId: '',
|
||||
},
|
||||
selectObjs: [],
|
||||
pageList: pageList,
|
||||
descs: ['create_time'],
|
||||
createdIsNeed: false,
|
||||
});
|
||||
|
||||
// table hook
|
||||
const {
|
||||
downBlobFile,
|
||||
getDataList,
|
||||
currentChangeHandle: baseCurrentChangeHandle,
|
||||
sortChangeHandle,
|
||||
sizeChangeHandle,
|
||||
tableStyle
|
||||
} = useTable(state);
|
||||
const { downBlobFile, getDataList, currentChangeHandle: baseCurrentChangeHandle, sortChangeHandle, sizeChangeHandle, tableStyle } = useTable(state);
|
||||
|
||||
// 分页事件
|
||||
const currentChangeHandle = (page: number) => {
|
||||
// Reset table scroll position to top
|
||||
tableRef.value?.setScrollTop(0);
|
||||
// Call the original handler
|
||||
baseCurrentChangeHandle(page);
|
||||
// Reset table scroll position to top
|
||||
tableRef.value?.setScrollTop(0);
|
||||
// Call the original handler
|
||||
baseCurrentChangeHandle(page);
|
||||
};
|
||||
|
||||
// 清空搜索条件
|
||||
const resetQuery = () => {
|
||||
queryRef.value?.resetFields();
|
||||
getDataList();
|
||||
queryRef.value?.resetFields();
|
||||
getDataList();
|
||||
};
|
||||
|
||||
// 导出excel
|
||||
const exportExcel = () => {
|
||||
downBlobFile('/admin/log/export', state.queryForm, 'log.xlsx');
|
||||
downBlobFile('/admin/log/export', state.queryForm, 'log.xlsx');
|
||||
};
|
||||
|
||||
// 多选事件
|
||||
const handleSelectionChange = (objs: { id: string }[]) => {
|
||||
selectObjs.value = objs.map(({id}) => id);
|
||||
multiple.value = !objs.length;
|
||||
selectObjs.value = objs.map(({ id }) => id);
|
||||
multiple.value = !objs.length;
|
||||
};
|
||||
|
||||
// 删除操作
|
||||
const handleDelete = async (ids: string[]) => {
|
||||
try {
|
||||
await useMessageBox().confirm(t('common.delConfirmText'));
|
||||
} catch {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
await useMessageBox().confirm(t('common.delConfirmText'));
|
||||
} catch {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await delObj(ids);
|
||||
getDataList();
|
||||
useMessage().success(t('common.delSuccessText'));
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg);
|
||||
}
|
||||
try {
|
||||
await delObj(ids);
|
||||
getDataList();
|
||||
useMessage().success(t('common.delSuccessText'));
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg);
|
||||
}
|
||||
};
|
||||
|
||||
// onMounted 通过路由参数给 serviceId 赋值
|
||||
const route = useRoute();
|
||||
onMounted(() => {
|
||||
const {serviceId} = route.query;
|
||||
if (serviceId) {
|
||||
state.queryForm.serviceId = serviceId;
|
||||
}
|
||||
getDataList();
|
||||
const { serviceId } = route.query;
|
||||
if (serviceId) {
|
||||
state.queryForm.serviceId = serviceId;
|
||||
}
|
||||
getDataList();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
pre code.hljs {
|
||||
width: 65%;
|
||||
width: 65%;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -95,7 +95,7 @@ const form = reactive({
|
||||
// 定义校验规则
|
||||
const dataRules = reactive({
|
||||
publicName: [
|
||||
{ validator: rule.overLength, trigger: 'blur' },
|
||||
{ validator: rule.overLength, trigger: 'blur' },
|
||||
{ required: true, message: '名称不能为空', trigger: 'blur' },
|
||||
{
|
||||
validator: (rule: any, value: any, callback: any) => {
|
||||
@@ -105,7 +105,7 @@ const dataRules = reactive({
|
||||
},
|
||||
],
|
||||
publicKey: [
|
||||
{ validator: rule.overLength, trigger: 'blur' },
|
||||
{ validator: rule.overLength, trigger: 'blur' },
|
||||
{ required: true, message: '参数键不能为空', trigger: 'blur' },
|
||||
{ validator: rule.validatorCapital, trigger: 'blur' },
|
||||
{
|
||||
@@ -115,7 +115,10 @@ const dataRules = reactive({
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
publicValue: [{ validator: rule.overLength, trigger: 'blur' },{ required: true, message: '参数值不能为空', trigger: 'blur' }],
|
||||
publicValue: [
|
||||
{ validator: rule.overLength, trigger: 'blur' },
|
||||
{ required: true, message: '参数值不能为空', trigger: 'blur' },
|
||||
],
|
||||
status: [{ required: true, message: '状态不能为空', trigger: 'blur' }],
|
||||
publicType: [{ required: true, message: '类型不能为空', trigger: 'blur' }],
|
||||
systemFlag: [{ required: true, message: '类型不能为空', trigger: 'blur' }],
|
||||
|
||||
@@ -58,7 +58,7 @@
|
||||
:data="state.dataList"
|
||||
@selection-change="handleSelectionChange"
|
||||
style="width: 100%"
|
||||
row-key="publicId"
|
||||
row-key="publicId"
|
||||
v-loading="state.loading"
|
||||
border
|
||||
:cell-style="tableStyle.cellStyle"
|
||||
@@ -158,7 +158,7 @@ const handleSelectable = (row: any) => {
|
||||
|
||||
// 导出excel
|
||||
const exportExcel = () => {
|
||||
downBlobFile('/admin/param/export', Object.assign(state.queryForm,{ids:selectObjs}), 'param.xlsx');
|
||||
downBlobFile('/admin/param/export', Object.assign(state.queryForm, { ids: selectObjs }), 'param.xlsx');
|
||||
};
|
||||
|
||||
const handleRefreshCache = () => {
|
||||
|
||||
@@ -1,137 +1,136 @@
|
||||
<template>
|
||||
<el-dialog :title="form.sensitiveId ? '编辑' : '新增'" v-model="visible"
|
||||
:close-on-click-modal="false" draggable>
|
||||
<el-form ref="dataFormRef" :model="form" :rules="dataRules" formDialogRef label-width="90px" v-loading="loading">
|
||||
<el-row :gutter="24">
|
||||
<el-col :span="24" class="mb20">
|
||||
<el-form-item label="敏感词" prop="sensitiveWord">
|
||||
<el-input v-model="form.sensitiveWord" placeholder="请输入敏感词"/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-dialog :title="form.sensitiveId ? '编辑' : '新增'" v-model="visible" :close-on-click-modal="false" draggable>
|
||||
<el-form ref="dataFormRef" :model="form" :rules="dataRules" formDialogRef label-width="90px" v-loading="loading">
|
||||
<el-row :gutter="24">
|
||||
<el-col :span="24" class="mb20">
|
||||
<el-form-item label="敏感词" prop="sensitiveWord">
|
||||
<el-input v-model="form.sensitiveWord" placeholder="请输入敏感词" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="24" class="mb20">
|
||||
<el-form-item label="类型" prop="sensitiveType">
|
||||
<el-radio-group v-model="form.sensitiveType">
|
||||
<el-radio :label="item.value" v-for="(item, index) in sensitive_type" border :key="index">{{ item.label }}
|
||||
</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24" class="mb20">
|
||||
<el-form-item label="类型" prop="sensitiveType">
|
||||
<el-radio-group v-model="form.sensitiveType">
|
||||
<el-radio :label="item.value" v-for="(item, index) in sensitive_type" border :key="index">{{ item.label }} </el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="24" class="mb20">
|
||||
<el-form-item label="备注" prop="remark">
|
||||
<el-input v-model="form.remark" placeholder="请输入备注"/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="visible = false">取消</el-button>
|
||||
<el-button type="primary" @click="onSubmit" :disabled="loading">确认</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
<el-col :span="24" class="mb20">
|
||||
<el-form-item label="备注" prop="remark">
|
||||
<el-input v-model="form.remark" placeholder="请输入备注" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="visible = false">取消</el-button>
|
||||
<el-button type="primary" @click="onSubmit" :disabled="loading">确认</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="SysSensitiveWordDialog">
|
||||
import {useDict} from '/@/hooks/dict';
|
||||
import {useMessage} from "/@/hooks/message";
|
||||
import {getObj, addObj, putObj, validateWord} from '/@/api/admin/sensitive'
|
||||
import {rule} from '/@/utils/validate';
|
||||
import { useDict } from '/@/hooks/dict';
|
||||
import { useMessage } from '/@/hooks/message';
|
||||
import { getObj, addObj, putObj, validateWord } from '/@/api/admin/sensitive';
|
||||
import { rule } from '/@/utils/validate';
|
||||
|
||||
const emit = defineEmits(['refresh']);
|
||||
|
||||
// 定义变量内容
|
||||
const dataFormRef = ref();
|
||||
const visible = ref(false)
|
||||
const loading = ref(false)
|
||||
const visible = ref(false);
|
||||
const loading = ref(false);
|
||||
// 定义字典
|
||||
const {sensitive_type} = useDict('sensitive_type')
|
||||
const { sensitive_type } = useDict('sensitive_type');
|
||||
|
||||
// 提交表单数据
|
||||
const form = reactive({
|
||||
sensitiveId: '',
|
||||
sensitiveWord: '',
|
||||
sensitiveType: '0',
|
||||
remark: '',
|
||||
sensitiveId: '',
|
||||
sensitiveWord: '',
|
||||
sensitiveType: '0',
|
||||
remark: '',
|
||||
});
|
||||
|
||||
// 定义校验规则
|
||||
const dataRules = ref({
|
||||
sensitiveWord: [{validator: rule.overLength, trigger: 'blur'}
|
||||
, {
|
||||
validator: (rule: any, value: any, callback: any) => {
|
||||
validateWord(rule, value, callback, form.sensitiveId !== '');
|
||||
}
|
||||
, trigger: 'blur'
|
||||
}
|
||||
, {
|
||||
required: true,
|
||||
message: '敏感词不能为空',
|
||||
trigger: 'blur'
|
||||
}],
|
||||
sensitiveType: [{required: true, message: '类型不能为空', trigger: 'blur'}],
|
||||
remark: [{validator: rule.overLength, trigger: 'blur'}],
|
||||
})
|
||||
sensitiveWord: [
|
||||
{ validator: rule.overLength, trigger: 'blur' },
|
||||
{
|
||||
validator: (rule: any, value: any, callback: any) => {
|
||||
validateWord(rule, value, callback, form.sensitiveId !== '');
|
||||
},
|
||||
trigger: 'blur',
|
||||
},
|
||||
{
|
||||
required: true,
|
||||
message: '敏感词不能为空',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
sensitiveType: [{ required: true, message: '类型不能为空', trigger: 'blur' }],
|
||||
remark: [{ validator: rule.overLength, trigger: 'blur' }],
|
||||
});
|
||||
|
||||
// 打开弹窗
|
||||
const openDialog = (sensitiveId: string) => {
|
||||
visible.value = true
|
||||
form.sensitiveId = ''
|
||||
visible.value = true;
|
||||
form.sensitiveId = '';
|
||||
|
||||
// 重置表单数据
|
||||
nextTick(() => {
|
||||
dataFormRef.value?.resetFields();
|
||||
});
|
||||
// 重置表单数据
|
||||
nextTick(() => {
|
||||
dataFormRef.value?.resetFields();
|
||||
});
|
||||
|
||||
// 获取sysSensitiveWord信息
|
||||
if (sensitiveId) {
|
||||
form.sensitiveId = sensitiveId
|
||||
getsysSensitiveWordData(sensitiveId)
|
||||
}
|
||||
// 获取sysSensitiveWord信息
|
||||
if (sensitiveId) {
|
||||
form.sensitiveId = sensitiveId;
|
||||
getsysSensitiveWordData(sensitiveId);
|
||||
}
|
||||
};
|
||||
|
||||
// 提交
|
||||
const onSubmit = async () => {
|
||||
// 立即设置 loading,防止重复点击
|
||||
if (loading.value) return;
|
||||
loading.value = true;
|
||||
// 立即设置 loading,防止重复点击
|
||||
if (loading.value) return;
|
||||
loading.value = true;
|
||||
|
||||
try {
|
||||
const valid = await dataFormRef.value.validate().catch(() => {
|
||||
});
|
||||
if (!valid) {
|
||||
loading.value = false;
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
const valid = await dataFormRef.value.validate().catch(() => {});
|
||||
if (!valid) {
|
||||
loading.value = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
form.sensitiveId ? await putObj(form) : await addObj(form);
|
||||
useMessage().success(form.sensitiveId ? '修改成功' : '添加成功');
|
||||
visible.value = false;
|
||||
emit('refresh');
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg);
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
form.sensitiveId ? await putObj(form) : await addObj(form);
|
||||
useMessage().success(form.sensitiveId ? '修改成功' : '添加成功');
|
||||
visible.value = false;
|
||||
emit('refresh');
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg);
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// 初始化表单数据
|
||||
const getsysSensitiveWordData = (sensitiveId: string) => {
|
||||
// 获取数据
|
||||
loading.value = true
|
||||
getObj({sensitiveId}).then((res: any) => {
|
||||
|
||||
Object.assign(form, res.data)
|
||||
}).finally(() => {
|
||||
loading.value = false
|
||||
})
|
||||
// 获取数据
|
||||
loading.value = true;
|
||||
getObj({ sensitiveId })
|
||||
.then((res: any) => {
|
||||
Object.assign(form, res.data);
|
||||
})
|
||||
.finally(() => {
|
||||
loading.value = false;
|
||||
});
|
||||
};
|
||||
|
||||
// 暴露变量
|
||||
defineExpose({
|
||||
openDialog
|
||||
openDialog,
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -1,165 +1,167 @@
|
||||
<template>
|
||||
<div class="layout-padding">
|
||||
<div class="layout-padding-auto layout-padding-view">
|
||||
<el-row v-show="showSearch">
|
||||
<el-form :model="state.queryForm" ref="queryRef" :inline="true" @keyup.enter="getDataList">
|
||||
<el-form-item label="敏感词" prop="sensitiveWord">
|
||||
<el-input placeholder="请输入敏感词" v-model="state.queryForm.sensitiveWord"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="类型" prop="sensitiveType">
|
||||
<el-radio-group v-model="state.queryForm.sensitiveType">
|
||||
<el-radio :label="item.value" v-for="(item, index) in sensitive_type" border :key="index">{{ item.label }}
|
||||
</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button icon="search" type="primary" @click="getDataList">
|
||||
查询
|
||||
</el-button>
|
||||
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<div class="mb8" style="width: 100%">
|
||||
<el-button icon="folder-add" type="primary" class="ml10" @click="formDialogRef.openDialog()"
|
||||
v-auth="'admin_sysSensitiveWord_add'">
|
||||
新 增
|
||||
</el-button>
|
||||
<el-button plain :disabled="multiple" icon="Delete" type="primary"
|
||||
v-auth="'admin_sysSensitiveWord_del'" @click="handleDelete(selectObjs)">
|
||||
删 除
|
||||
</el-button>
|
||||
<el-button plain icon="Check" type="primary"
|
||||
v-auth="'admin_sysSensitiveWord_del'" @click="matchDialogRef.openDialog()">
|
||||
匹配测试
|
||||
</el-button>
|
||||
<el-button plain @click="handleRefreshCache()" class="ml10" icon="refresh-left" type="primary">
|
||||
{{ $t('common.refreshCacheBtn') }}
|
||||
</el-button>
|
||||
<div class="layout-padding">
|
||||
<div class="layout-padding-auto layout-padding-view">
|
||||
<el-row v-show="showSearch">
|
||||
<el-form :model="state.queryForm" ref="queryRef" :inline="true" @keyup.enter="getDataList">
|
||||
<el-form-item label="敏感词" prop="sensitiveWord">
|
||||
<el-input placeholder="请输入敏感词" v-model="state.queryForm.sensitiveWord" />
|
||||
</el-form-item>
|
||||
<el-form-item label="类型" prop="sensitiveType">
|
||||
<el-radio-group v-model="state.queryForm.sensitiveType">
|
||||
<el-radio :label="item.value" v-for="(item, index) in sensitive_type" border :key="index">{{ item.label }} </el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button icon="search" type="primary" @click="getDataList"> 查询 </el-button>
|
||||
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<div class="mb8" style="width: 100%">
|
||||
<el-button icon="folder-add" type="primary" class="ml10" @click="formDialogRef.openDialog()" v-auth="'admin_sysSensitiveWord_add'">
|
||||
新 增
|
||||
</el-button>
|
||||
<el-button plain :disabled="multiple" icon="Delete" type="primary" v-auth="'admin_sysSensitiveWord_del'" @click="handleDelete(selectObjs)">
|
||||
删 除
|
||||
</el-button>
|
||||
<el-button plain icon="Check" type="primary" v-auth="'admin_sysSensitiveWord_del'" @click="matchDialogRef.openDialog()">
|
||||
匹配测试
|
||||
</el-button>
|
||||
<el-button plain @click="handleRefreshCache()" class="ml10" icon="refresh-left" type="primary">
|
||||
{{ $t('common.refreshCacheBtn') }}
|
||||
</el-button>
|
||||
|
||||
<right-toolbar v-model:showSearch="showSearch" :export="'admin_sysSensitiveWord_export'"
|
||||
@exportExcel="exportExcel" class="ml10 mr20" style="float: right;"
|
||||
@queryTable="getDataList"></right-toolbar>
|
||||
</div>
|
||||
</el-row>
|
||||
<el-table :data="state.dataList" v-loading="state.loading" border
|
||||
:cell-style="tableStyle.cellStyle" :header-cell-style="tableStyle.headerCellStyle"
|
||||
@selection-change="selectionChangHandle"
|
||||
@sort-change="sortChangeHandle">
|
||||
<el-table-column type="selection" width="40" align="center"/>
|
||||
<el-table-column type="index" label="#" width="40"/>
|
||||
<el-table-column prop="sensitiveWord" label="敏感词" show-overflow-tooltip/>
|
||||
<el-table-column prop="sensitiveType" label="类型" show-overflow-tooltip>
|
||||
<template #default="scope">
|
||||
<dict-tag :options="sensitive_type" :value="scope.row.sensitiveType"></dict-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="remark" label="备注" width="200" show-overflow-tooltip/>
|
||||
<el-table-column label="操作" width="150">
|
||||
<template #default="scope">
|
||||
<el-button icon="edit-pen" text type="primary" v-auth="'admin_sysSensitiveWord_edit'"
|
||||
@click="formDialogRef.openDialog(scope.row.sensitiveId)">编辑
|
||||
</el-button>
|
||||
<el-button icon="delete" text type="primary" v-auth="'admin_sysSensitiveWord_del'"
|
||||
@click="handleDelete([scope.row.sensitiveId])">删除
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<pagination @size-change="sizeChangeHandle" @current-change="currentChangeHandle" v-bind="state.pagination"/>
|
||||
</div>
|
||||
<right-toolbar
|
||||
v-model:showSearch="showSearch"
|
||||
:export="'admin_sysSensitiveWord_export'"
|
||||
@exportExcel="exportExcel"
|
||||
class="ml10 mr20"
|
||||
style="float: right"
|
||||
@queryTable="getDataList"
|
||||
></right-toolbar>
|
||||
</div>
|
||||
</el-row>
|
||||
<el-table
|
||||
:data="state.dataList"
|
||||
v-loading="state.loading"
|
||||
border
|
||||
:cell-style="tableStyle.cellStyle"
|
||||
:header-cell-style="tableStyle.headerCellStyle"
|
||||
@selection-change="selectionChangHandle"
|
||||
@sort-change="sortChangeHandle"
|
||||
>
|
||||
<el-table-column type="selection" width="40" align="center" />
|
||||
<el-table-column type="index" label="#" width="40" />
|
||||
<el-table-column prop="sensitiveWord" label="敏感词" show-overflow-tooltip />
|
||||
<el-table-column prop="sensitiveType" label="类型" show-overflow-tooltip>
|
||||
<template #default="scope">
|
||||
<dict-tag :options="sensitive_type" :value="scope.row.sensitiveType"></dict-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="remark" label="备注" width="200" show-overflow-tooltip />
|
||||
<el-table-column label="操作" width="150">
|
||||
<template #default="scope">
|
||||
<el-button
|
||||
icon="edit-pen"
|
||||
text
|
||||
type="primary"
|
||||
v-auth="'admin_sysSensitiveWord_edit'"
|
||||
@click="formDialogRef.openDialog(scope.row.sensitiveId)"
|
||||
>编辑
|
||||
</el-button>
|
||||
<el-button icon="delete" text type="primary" v-auth="'admin_sysSensitiveWord_del'" @click="handleDelete([scope.row.sensitiveId])"
|
||||
>删除
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<pagination @size-change="sizeChangeHandle" @current-change="currentChangeHandle" v-bind="state.pagination" />
|
||||
</div>
|
||||
|
||||
<!-- 编辑、新增 -->
|
||||
<form-dialog ref="formDialogRef" @refresh="getDataList(false)"/>
|
||||
<!-- 编辑、新增 -->
|
||||
<form-dialog ref="formDialogRef" @refresh="getDataList(false)" />
|
||||
|
||||
<!-- 匹配测试 -->
|
||||
<match-dialog ref="matchDialogRef" @refresh="getDataList(false)"/>
|
||||
</div>
|
||||
<!-- 匹配测试 -->
|
||||
<match-dialog ref="matchDialogRef" @refresh="getDataList(false)" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="systemSysSensitiveWord">
|
||||
import {BasicTableProps, useTable} from "/@/hooks/table";
|
||||
import {fetchList, delObjs, refreshObj} from "/@/api/admin/sensitive";
|
||||
import {useMessage, useMessageBox} from "/@/hooks/message";
|
||||
import {useDict} from '/@/hooks/dict';
|
||||
import { BasicTableProps, useTable } from '/@/hooks/table';
|
||||
import { fetchList, delObjs, refreshObj } from '/@/api/admin/sensitive';
|
||||
import { useMessage, useMessageBox } from '/@/hooks/message';
|
||||
import { useDict } from '/@/hooks/dict';
|
||||
|
||||
// 引入组件
|
||||
const FormDialog = defineAsyncComponent(() => import('./form.vue'));
|
||||
const MatchDialog = defineAsyncComponent(() => import('./match.vue'));
|
||||
// 定义查询字典
|
||||
|
||||
const {sensitive_type} = useDict('sensitive_type')
|
||||
const { sensitive_type } = useDict('sensitive_type');
|
||||
// 定义变量内容
|
||||
const formDialogRef = ref()
|
||||
const matchDialogRef = ref()
|
||||
const formDialogRef = ref();
|
||||
const matchDialogRef = ref();
|
||||
// 搜索变量
|
||||
const queryRef = ref()
|
||||
const showSearch = ref(true)
|
||||
const queryRef = ref();
|
||||
const showSearch = ref(true);
|
||||
// 多选变量
|
||||
const selectObjs = ref([]) as any
|
||||
const multiple = ref(true)
|
||||
const selectObjs = ref([]) as any;
|
||||
const multiple = ref(true);
|
||||
|
||||
const state: BasicTableProps = reactive<BasicTableProps>({
|
||||
queryForm: {},
|
||||
pageList: fetchList
|
||||
})
|
||||
queryForm: {},
|
||||
pageList: fetchList,
|
||||
});
|
||||
|
||||
// table hook
|
||||
const {
|
||||
getDataList,
|
||||
currentChangeHandle,
|
||||
sizeChangeHandle,
|
||||
sortChangeHandle,
|
||||
downBlobFile,
|
||||
tableStyle
|
||||
} = useTable(state)
|
||||
const { getDataList, currentChangeHandle, sizeChangeHandle, sortChangeHandle, downBlobFile, tableStyle } = useTable(state);
|
||||
|
||||
// 清空搜索条件
|
||||
const resetQuery = () => {
|
||||
// 清空搜索条件
|
||||
queryRef.value?.resetFields()
|
||||
// 清空多选
|
||||
selectObjs.value = []
|
||||
getDataList()
|
||||
}
|
||||
// 清空搜索条件
|
||||
queryRef.value?.resetFields();
|
||||
// 清空多选
|
||||
selectObjs.value = [];
|
||||
getDataList();
|
||||
};
|
||||
|
||||
// 导出excel
|
||||
const exportExcel = () => {
|
||||
downBlobFile('/admin/sysSensitiveWord/export', Object.assign(state.queryForm, {ids: selectObjs}), 'sysSensitiveWord.xlsx')
|
||||
}
|
||||
downBlobFile('/admin/sysSensitiveWord/export', Object.assign(state.queryForm, { ids: selectObjs }), 'sysSensitiveWord.xlsx');
|
||||
};
|
||||
|
||||
// 多选事件
|
||||
const selectionChangHandle = (objs: { sensitiveId: string }[]) => {
|
||||
selectObjs.value = objs.map(({sensitiveId}) => sensitiveId);
|
||||
multiple.value = !objs.length;
|
||||
selectObjs.value = objs.map(({ sensitiveId }) => sensitiveId);
|
||||
multiple.value = !objs.length;
|
||||
};
|
||||
|
||||
// 删除操作
|
||||
const handleDelete = async (ids: string[]) => {
|
||||
try {
|
||||
await useMessageBox().confirm('此操作将永久删除');
|
||||
} catch {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
await useMessageBox().confirm('此操作将永久删除');
|
||||
} catch {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await delObjs(ids);
|
||||
getDataList();
|
||||
useMessage().success('删除成功');
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg);
|
||||
}
|
||||
try {
|
||||
await delObjs(ids);
|
||||
getDataList();
|
||||
useMessage().success('删除成功');
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg);
|
||||
}
|
||||
};
|
||||
|
||||
// 刷新缓存
|
||||
const handleRefreshCache = async () => {
|
||||
try {
|
||||
await refreshObj();
|
||||
getDataList();
|
||||
useMessage().success('刷新成功');
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg);
|
||||
}
|
||||
}
|
||||
try {
|
||||
await refreshObj();
|
||||
getDataList();
|
||||
useMessage().success('刷新成功');
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg);
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -1,127 +1,128 @@
|
||||
<template>
|
||||
<el-dialog title="匹配测试" v-model="visible"
|
||||
:close-on-click-modal="false" draggable>
|
||||
<el-form ref="dataFormRef" :model="form" :rules="dataRules" formDialogRef label-width="90px" v-loading="loading">
|
||||
<el-row :gutter="24">
|
||||
<el-col :span="24" class="mb20">
|
||||
<el-form-item label="敏感词" prop="sensitiveWord">
|
||||
<el-input type="textarea" rows="3" v-model="form.sensitiveWord" placeholder="请输入敏感词"
|
||||
@blur="onSubmit"/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24" class="mb20">
|
||||
<el-form-item prop="result">
|
||||
<template #label>
|
||||
匹配结果
|
||||
<tip content="可点击敏感词加入白名单"/>
|
||||
</template>
|
||||
<div v-html="matchResult" @click="handleChildClick"/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="visible = false">取消</el-button>
|
||||
<el-button type="primary" @click="onSubmit" :disabled="loading">确认</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
<el-dialog title="匹配测试" v-model="visible" :close-on-click-modal="false" draggable>
|
||||
<el-form ref="dataFormRef" :model="form" :rules="dataRules" formDialogRef label-width="90px" v-loading="loading">
|
||||
<el-row :gutter="24">
|
||||
<el-col :span="24" class="mb20">
|
||||
<el-form-item label="敏感词" prop="sensitiveWord">
|
||||
<el-input type="textarea" rows="3" v-model="form.sensitiveWord" placeholder="请输入敏感词" @blur="onSubmit" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24" class="mb20">
|
||||
<el-form-item prop="result">
|
||||
<template #label>
|
||||
匹配结果
|
||||
<tip content="可点击敏感词加入白名单" />
|
||||
</template>
|
||||
<div v-html="matchResult" @click="handleChildClick" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="visible = false">取消</el-button>
|
||||
<el-button type="primary" @click="onSubmit" :disabled="loading">确认</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="SysSensitiveWordDialog">
|
||||
import {useMessage} from "/@/hooks/message";
|
||||
import {testObj, addObj, getObj} from '/@/api/admin/sensitive'
|
||||
import {rule} from '/@/utils/validate';
|
||||
import { useMessage } from '/@/hooks/message';
|
||||
import { testObj, addObj, getObj } from '/@/api/admin/sensitive';
|
||||
import { rule } from '/@/utils/validate';
|
||||
|
||||
const emit = defineEmits(['refresh']);
|
||||
|
||||
// 定义变量内容
|
||||
const dataFormRef = ref();
|
||||
const visible = ref(false)
|
||||
const loading = ref(false)
|
||||
const matchResult = ref('')
|
||||
const visible = ref(false);
|
||||
const loading = ref(false);
|
||||
const matchResult = ref('');
|
||||
|
||||
// 提交表单数据
|
||||
const form = reactive({
|
||||
sensitiveId: '',
|
||||
sensitiveWord: '',
|
||||
sensitiveId: '',
|
||||
sensitiveWord: '',
|
||||
});
|
||||
|
||||
// 定义校验规则
|
||||
const dataRules = ref({
|
||||
sensitiveWord: [{validator: rule.overLength, trigger: 'blur'}, {
|
||||
required: true,
|
||||
message: '敏感词不能为空',
|
||||
trigger: 'blur'
|
||||
}]
|
||||
})
|
||||
sensitiveWord: [
|
||||
{ validator: rule.overLength, trigger: 'blur' },
|
||||
{
|
||||
required: true,
|
||||
message: '敏感词不能为空',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
// 打开弹窗
|
||||
const openDialog = (id: string) => {
|
||||
visible.value = true
|
||||
form.sensitiveId = ''
|
||||
visible.value = true;
|
||||
form.sensitiveId = '';
|
||||
|
||||
// 重置表单数据
|
||||
nextTick(() => {
|
||||
dataFormRef.value?.resetFields();
|
||||
});
|
||||
// 重置表单数据
|
||||
nextTick(() => {
|
||||
dataFormRef.value?.resetFields();
|
||||
});
|
||||
};
|
||||
|
||||
const handleChildClick = async (event: any) => {
|
||||
try {
|
||||
if (event.target.tagName.toLowerCase() === 'a' && event.target.classList.contains('link-error')) {
|
||||
const {data} = await getObj({sensitiveWord: event.target.innerText, sensitiveType: '1'})
|
||||
if (data) {
|
||||
useMessage().error('数据已存在,请勿重新添加');
|
||||
return
|
||||
}
|
||||
await addObj({sensitiveWord: event.target.innerText, sensitiveType: '1'})
|
||||
useMessage().success('白名单添加成功');
|
||||
emit('refresh');
|
||||
}
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
if (event.target.tagName.toLowerCase() === 'a' && event.target.classList.contains('link-error')) {
|
||||
const { data } = await getObj({ sensitiveWord: event.target.innerText, sensitiveType: '1' });
|
||||
if (data) {
|
||||
useMessage().error('数据已存在,请勿重新添加');
|
||||
return;
|
||||
}
|
||||
await addObj({ sensitiveWord: event.target.innerText, sensitiveType: '1' });
|
||||
useMessage().success('白名单添加成功');
|
||||
emit('refresh');
|
||||
}
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg);
|
||||
}
|
||||
};
|
||||
|
||||
// 提交
|
||||
const onSubmit = async () => {
|
||||
const valid = await dataFormRef.value.validate().catch(() => {
|
||||
});
|
||||
if (!valid) return false;
|
||||
const valid = await dataFormRef.value.validate().catch(() => {});
|
||||
if (!valid) return false;
|
||||
|
||||
try {
|
||||
loading.value = true;
|
||||
const {data} = await testObj(form);
|
||||
// 要处理的字符串
|
||||
matchResult.value = data;
|
||||
// 遍历关键词数组,并进行替换
|
||||
matchResult.value = matchResult.value.map((item: string) => {
|
||||
let modifiedItem = item;
|
||||
data.forEach((word: string) => {
|
||||
let regex = new RegExp(word, 'g');
|
||||
modifiedItem = modifiedItem.replace(regex, `
|
||||
try {
|
||||
loading.value = true;
|
||||
const { data } = await testObj(form);
|
||||
// 要处理的字符串
|
||||
matchResult.value = data;
|
||||
// 遍历关键词数组,并进行替换
|
||||
matchResult.value = matchResult.value.map((item: string) => {
|
||||
let modifiedItem = item;
|
||||
data.forEach((word: string) => {
|
||||
let regex = new RegExp(word, 'g');
|
||||
modifiedItem = modifiedItem.replace(
|
||||
regex,
|
||||
`
|
||||
<div class="tooltip tooltip-open tooltip-bottom" data-tip="触发敏感词">
|
||||
<a class="link link-error" @click="$emit('click-child','${word}')">${word}</a>
|
||||
</div>
|
||||
`);
|
||||
});
|
||||
return modifiedItem;
|
||||
});
|
||||
useMessage().success('操作成功');
|
||||
emit('refresh');
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg);
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
`
|
||||
);
|
||||
});
|
||||
return modifiedItem;
|
||||
});
|
||||
useMessage().success('操作成功');
|
||||
emit('refresh');
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg);
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// 暴露变量
|
||||
defineExpose({
|
||||
openDialog
|
||||
openDialog,
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -81,14 +81,23 @@ const form = reactive({
|
||||
// 定义校验规则
|
||||
const dataRules = ref({
|
||||
type: [{ required: true, message: '类型不能为空', trigger: 'blur' }],
|
||||
appId: [{ validator: rule.overLength, trigger: 'blur' },{ required: true, message: 'appId不能为空', trigger: 'blur' }],
|
||||
remark: [{ validator: rule.overLength, trigger: 'blur' },{ required: true, message: '描述不能为空', trigger: 'blur' }],
|
||||
appId: [
|
||||
{ validator: rule.overLength, trigger: 'blur' },
|
||||
{ required: true, message: 'appId不能为空', trigger: 'blur' },
|
||||
],
|
||||
remark: [
|
||||
{ validator: rule.overLength, trigger: 'blur' },
|
||||
{ required: true, message: '描述不能为空', trigger: 'blur' },
|
||||
],
|
||||
redirectUrl: [
|
||||
{ validator: rule.overLength, trigger: 'blur' },
|
||||
{ validator: rule.overLength, trigger: 'blur' },
|
||||
{ required: true, message: '回调地址不能为空', trigger: 'blur' },
|
||||
{ validator: rule.url, trigger: 'blur' },
|
||||
],
|
||||
appSecret: [{ validator: rule.overLength, trigger: 'blur' },{ required: true, message: 'appSecret不能为空', trigger: 'blur' }],
|
||||
appSecret: [
|
||||
{ validator: rule.overLength, trigger: 'blur' },
|
||||
{ required: true, message: 'appSecret不能为空', trigger: 'blur' },
|
||||
],
|
||||
});
|
||||
|
||||
// 打开弹窗
|
||||
|
||||
@@ -45,7 +45,7 @@
|
||||
v-loading="state.loading"
|
||||
:data="state.dataList"
|
||||
style="width: 100%"
|
||||
row-key="id"
|
||||
row-key="id"
|
||||
@selection-change="handleSelectionChange"
|
||||
border
|
||||
:cell-style="tableStyle.cellStyle"
|
||||
@@ -120,7 +120,7 @@ const resetQuery = () => {
|
||||
|
||||
// 导出excel
|
||||
const exportExcel = () => {
|
||||
downBlobFile('/admin/social/export', Object.assign(state.queryForm,{ids:selectObjs}), 'social.xlsx');
|
||||
downBlobFile('/admin/social/export', Object.assign(state.queryForm, { ids: selectObjs }), 'social.xlsx');
|
||||
};
|
||||
|
||||
// 多选事件
|
||||
|
||||
@@ -1,200 +1,191 @@
|
||||
<template>
|
||||
<el-dialog :title="form.id ? $t('common.editBtn') : $t('common.addBtn')" v-model="visible"
|
||||
:close-on-click-modal="false" draggable width="600">
|
||||
<el-form ref="dataFormRef" :model="form" :rules="dataRules" formDialogRef label-width="90px" v-loading="loading">
|
||||
<el-row>
|
||||
<el-col :span="24" class="mb20" v-if="!form.id">
|
||||
<el-form-item :label="t('area.pid')" prop="pid">
|
||||
<china-area class="w-full" :placeholder="t('area.inputPidByTip')" :plus="true" @change="handleChange"/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-dialog :title="form.id ? $t('common.editBtn') : $t('common.addBtn')" v-model="visible" :close-on-click-modal="false" draggable width="600">
|
||||
<el-form ref="dataFormRef" :model="form" :rules="dataRules" formDialogRef label-width="90px" v-loading="loading">
|
||||
<el-row>
|
||||
<el-col :span="24" class="mb20" v-if="!form.id">
|
||||
<el-form-item :label="t('area.pid')" prop="pid">
|
||||
<china-area class="w-full" :placeholder="t('area.inputPidByTip')" :plus="true" @change="handleChange" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="24" class="mb20">
|
||||
<el-form-item :label="t('area.name')" prop="name">
|
||||
<el-input v-model="form.name" :placeholder="t('area.inputNameByTip')"/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24" class="mb20">
|
||||
<el-form-item :label="t('area.name')" prop="name">
|
||||
<el-input v-model="form.name" :placeholder="t('area.inputNameByTip')" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="24" class="mb20">
|
||||
<el-form-item :label="t('area.adcode')" prop="adcode">
|
||||
<el-input-number v-model="form.adcode" :placeholder="t('area.inputAdCodeByTip')" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="24" class="mb20">
|
||||
<el-form-item :label="t('area.adcode')" prop="adcode">
|
||||
<el-input-number v-model="form.adcode" :placeholder="t('area.inputAdCodeByTip')"/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24" class="mb20">
|
||||
<el-form-item :label="t('area.areaType')" prop="areaType">
|
||||
<el-select v-model="form.areaType">
|
||||
<el-option :key="item.value" :label="item.label" :value="item.value" v-for="item in area_type_dict"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="24" class="mb20">
|
||||
<el-form-item :label="t('area.areaType')" prop="areaType">
|
||||
<el-select v-model="form.areaType">
|
||||
<el-option :key="item.value" :label="item.label" :value="item.value"
|
||||
v-for="item in area_type_dict"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24" class="mb20">
|
||||
<el-form-item :label="t('area.areaSort')" prop="areaSort">
|
||||
<el-input-number v-model="form.areaSort" :placeholder="t('area.inputAreaSortByTip')" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="24" class="mb20">
|
||||
<el-form-item :label="t('area.areaSort')" prop="areaSort">
|
||||
<el-input-number v-model="form.areaSort" :placeholder="t('area.inputAreaSortByTip')"/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24" class="mb20">
|
||||
<el-form-item :label="t('area.hot')" prop="hot">
|
||||
<el-radio-group v-model="form.hot">
|
||||
<el-radio :key="index" :label="item.value" border v-for="(item, index) in yes_no_type">{{ item.label }} </el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="24" class="mb20">
|
||||
<el-form-item :label="t('area.hot')" prop="hot">
|
||||
<el-radio-group v-model="form.hot">
|
||||
<el-radio :key="index" :label="item.value" border v-for="(item, index) in yes_no_type">{{
|
||||
item.label
|
||||
}}
|
||||
</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="24" class="mb20">
|
||||
<el-form-item :label="t('area.areaStatus')" prop="areaStatus">
|
||||
<el-radio-group v-model="form.areaStatus">
|
||||
<el-radio :key="index" :label="item.value" border v-for="(item, index) in yes_no_type">{{
|
||||
item.label
|
||||
}}
|
||||
</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="visible = false">{{ $t('common.cancelButtonText') }}</el-button>
|
||||
<el-button @click="onSubmit" type="primary" :disabled="loading">{{ $t('common.confirmButtonText') }}</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
<el-col :span="24" class="mb20">
|
||||
<el-form-item :label="t('area.areaStatus')" prop="areaStatus">
|
||||
<el-radio-group v-model="form.areaStatus">
|
||||
<el-radio :key="index" :label="item.value" border v-for="(item, index) in yes_no_type">{{ item.label }} </el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="visible = false">{{ $t('common.cancelButtonText') }}</el-button>
|
||||
<el-button @click="onSubmit" type="primary" :disabled="loading">{{ $t('common.confirmButtonText') }}</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="SysAreaDialog">
|
||||
import {useMessage} from "/@/hooks/message";
|
||||
import {getObj, addObj, putObj, validateExist} from '/@/api/admin/sysArea'
|
||||
import {useDict} from "/@/hooks/dict";
|
||||
import {useI18n} from "vue-i18n";
|
||||
import {rule} from "/@/utils/validate";
|
||||
import { useMessage } from '/@/hooks/message';
|
||||
import { getObj, addObj, putObj, validateExist } from '/@/api/admin/sysArea';
|
||||
import { useDict } from '/@/hooks/dict';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { rule } from '/@/utils/validate';
|
||||
|
||||
const ChinaArea = defineAsyncComponent(() => import("/@/components/ChinaArea/index.vue"));
|
||||
const ChinaArea = defineAsyncComponent(() => import('/@/components/ChinaArea/index.vue'));
|
||||
const emit = defineEmits(['refresh']);
|
||||
const { t } = useI18n();
|
||||
|
||||
// 定义变量内容
|
||||
const dataFormRef = ref();
|
||||
const visible = ref(false)
|
||||
const loading = ref(false)
|
||||
const visible = ref(false);
|
||||
const loading = ref(false);
|
||||
// 定义字典
|
||||
const {yes_no_type} = useDict('yes_no_type')
|
||||
const { yes_no_type } = useDict('yes_no_type');
|
||||
const area_type_dict = [
|
||||
{value: '0', label: '国家'},
|
||||
{value: '1', label: '省份'},
|
||||
{value: '2', label: '城市'},
|
||||
{value: '3', label: '县区'},
|
||||
{value: '4', label: '街道'}
|
||||
]
|
||||
{ value: '0', label: '国家' },
|
||||
{ value: '1', label: '省份' },
|
||||
{ value: '2', label: '城市' },
|
||||
{ value: '3', label: '县区' },
|
||||
{ value: '4', label: '街道' },
|
||||
];
|
||||
|
||||
// 提交表单数据
|
||||
const form = reactive({
|
||||
id: '',
|
||||
pid: 100000,
|
||||
name: '',
|
||||
letter: '',
|
||||
adcode: 0,
|
||||
location: '',
|
||||
areaSort: 0,
|
||||
areaStatus: '1',
|
||||
areaType: '2',
|
||||
hot: '0',
|
||||
cityCode: '',
|
||||
id: '',
|
||||
pid: 100000,
|
||||
name: '',
|
||||
letter: '',
|
||||
adcode: 0,
|
||||
location: '',
|
||||
areaSort: 0,
|
||||
areaStatus: '1',
|
||||
areaType: '2',
|
||||
hot: '0',
|
||||
cityCode: '',
|
||||
});
|
||||
|
||||
// 定义校验规则
|
||||
const dataRules = ref({
|
||||
name: [
|
||||
{required: true, message: '地区名称不能为空', trigger: 'blur'},
|
||||
{min: 2, max: 20, message: '长度在 3 到 30 个字符', trigger: 'blur'},
|
||||
{
|
||||
validator: (rule: any, value: any, callback: any) => {
|
||||
validateExist(rule, value, callback, form.id !== '');
|
||||
},
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
adcode: [
|
||||
{ validator: rule.overLength, trigger: 'blur' },
|
||||
{required: true, message: '编码不能为空', trigger: 'blur'},
|
||||
{
|
||||
validator: (rule: any, value: any, callback: any) => {
|
||||
validateExist(rule, value, callback, form.id !== '');
|
||||
},
|
||||
trigger: 'blur',
|
||||
},
|
||||
]
|
||||
name: [
|
||||
{ required: true, message: '地区名称不能为空', trigger: 'blur' },
|
||||
{ min: 2, max: 20, message: '长度在 3 到 30 个字符', trigger: 'blur' },
|
||||
{
|
||||
validator: (rule: any, value: any, callback: any) => {
|
||||
validateExist(rule, value, callback, form.id !== '');
|
||||
},
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
adcode: [
|
||||
{ validator: rule.overLength, trigger: 'blur' },
|
||||
{ required: true, message: '编码不能为空', trigger: 'blur' },
|
||||
{
|
||||
validator: (rule: any, value: any, callback: any) => {
|
||||
validateExist(rule, value, callback, form.id !== '');
|
||||
},
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
// 打开弹窗
|
||||
const openDialog = (id: string) => {
|
||||
visible.value = true
|
||||
form.id = ''
|
||||
visible.value = true;
|
||||
form.id = '';
|
||||
|
||||
// 重置表单数据
|
||||
nextTick(() => {
|
||||
dataFormRef.value?.resetFields();
|
||||
});
|
||||
// 重置表单数据
|
||||
nextTick(() => {
|
||||
dataFormRef.value?.resetFields();
|
||||
});
|
||||
|
||||
// 获取sysArea信息
|
||||
if (id) {
|
||||
form.id = id
|
||||
getsysAreaData(id)
|
||||
}
|
||||
// 获取sysArea信息
|
||||
if (id) {
|
||||
form.id = id;
|
||||
getsysAreaData(id);
|
||||
}
|
||||
};
|
||||
|
||||
// 提交
|
||||
const onSubmit = async () => {
|
||||
// 立即设置 loading,防止重复点击
|
||||
if (loading.value) return;
|
||||
loading.value = true;
|
||||
// 立即设置 loading,防止重复点击
|
||||
if (loading.value) return;
|
||||
loading.value = true;
|
||||
|
||||
try {
|
||||
const valid = await dataFormRef.value.validate().catch(() => {
|
||||
});
|
||||
if (!valid) {
|
||||
loading.value = false;
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
const valid = await dataFormRef.value.validate().catch(() => {});
|
||||
if (!valid) {
|
||||
loading.value = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
form.id ? await putObj(form) : await addObj(form);
|
||||
useMessage().success(form.id ? t('common.editSuccessText') : t('common.addSuccessText'));
|
||||
visible.value = false;
|
||||
emit('refresh');
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg);
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
form.id ? await putObj(form) : await addObj(form);
|
||||
useMessage().success(form.id ? t('common.editSuccessText') : t('common.addSuccessText'));
|
||||
visible.value = false;
|
||||
emit('refresh');
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg);
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// 初始化表单数据
|
||||
const getsysAreaData = (id: string) => {
|
||||
// 获取数据
|
||||
loading.value = true
|
||||
getObj({id: id}).then((res: any) => {
|
||||
Object.assign(form, res.data)
|
||||
}).finally(() => {
|
||||
loading.value = false
|
||||
})
|
||||
// 获取数据
|
||||
loading.value = true;
|
||||
getObj({ id: id })
|
||||
.then((res: any) => {
|
||||
Object.assign(form, res.data);
|
||||
})
|
||||
.finally(() => {
|
||||
loading.value = false;
|
||||
});
|
||||
};
|
||||
|
||||
// 地区选择
|
||||
const handleChange = (data: string) => {
|
||||
let dataArray = data.split(",");
|
||||
form.pid = dataArray[dataArray.length - 1];
|
||||
}
|
||||
let dataArray = data.split(',');
|
||||
form.pid = dataArray[dataArray.length - 1];
|
||||
};
|
||||
|
||||
// 暴露变量
|
||||
defineExpose({
|
||||
openDialog
|
||||
openDialog,
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -4,11 +4,11 @@ export default {
|
||||
id: 'id',
|
||||
pid: 'pid',
|
||||
name: 'name',
|
||||
adcode:'adcode',
|
||||
areaType:'areaType',
|
||||
areaSort:'areaSort',
|
||||
hot:'hot',
|
||||
areaStatus:'areaStatus',
|
||||
adcode: 'adcode',
|
||||
areaType: 'areaType',
|
||||
areaSort: 'areaSort',
|
||||
hot: 'hot',
|
||||
areaStatus: 'areaStatus',
|
||||
inputAdCodeByTip: 'input adcode',
|
||||
inputPidByTip: 'input pid',
|
||||
inputNameByTip: 'input name',
|
||||
|
||||
@@ -4,11 +4,11 @@ export default {
|
||||
id: '主键',
|
||||
pid: '父级地区',
|
||||
name: '名称',
|
||||
adcode:'编码',
|
||||
areaType:'类型',
|
||||
areaSort:'排序值',
|
||||
hot:'热门',
|
||||
areaStatus:'有效',
|
||||
adcode: '编码',
|
||||
areaType: '类型',
|
||||
areaSort: '排序值',
|
||||
hot: '热门',
|
||||
areaStatus: '有效',
|
||||
inputAdCodeByTip: '请选择编码',
|
||||
inputPidByTip: '请选择父级地区',
|
||||
inputNameByTip: '请输入地区名称',
|
||||
|
||||
@@ -1,174 +1,173 @@
|
||||
<template>
|
||||
<div class="layout-padding">
|
||||
<div class="layout-padding-auto layout-padding-view">
|
||||
<el-row v-show="showSearch">
|
||||
<el-form :model="state.queryForm" ref="queryRef" :inline="true" @keyup.enter="getDataList">
|
||||
<el-form-item :label="t('area.pid')" prop="adcode">
|
||||
<china-area :type="3" :placeholder="t('area.inputPidByTip')" v-model="pid" :plus="true" @change="handleChange"/>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('area.name')" prop="name">
|
||||
<el-input :placeholder="t('area.inputNameByTip')" v-model="state.queryForm.name"/>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button icon="search" type="primary" @click="getDataList">
|
||||
{{ $t('common.queryBtn') }}
|
||||
</el-button>
|
||||
<el-button icon="Refresh" @click="resetQuery">{{ $t('common.resetBtn') }}</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<div class="mb8" style="width: 100%">
|
||||
<el-button icon="folder-add" type="primary" class="ml10" @click="formDialogRef.openDialog()"
|
||||
v-auth="'sys_sysArea_add'">
|
||||
{{ $t('common.addBtn') }}
|
||||
</el-button>
|
||||
<el-button plain :disabled="multiple" icon="Delete" type="primary"
|
||||
v-auth="'sys_sysArea_del'" @click="handleDelete(selectObjs)">
|
||||
{{ $t('common.delBtn') }}
|
||||
</el-button>
|
||||
<right-toolbar v-model:showSearch="showSearch" :export="'sys_sysArea_export'"
|
||||
@exportExcel="exportExcel" class="ml10 mr20" style="float: right;"
|
||||
@queryTable="getDataList"></right-toolbar>
|
||||
</div>
|
||||
</el-row>
|
||||
<el-table :data="state.dataList" v-loading="state.loading" border
|
||||
:cell-style="tableStyle.cellStyle" :header-cell-style="tableStyle.headerCellStyle"
|
||||
@selection-change="selectionChangHandle"
|
||||
@sort-change="sortChangeHandle">
|
||||
<el-table-column type="selection" width="40" align="center"/>
|
||||
<el-table-column type="index" label="#" width="40"/>
|
||||
<el-table-column prop="name" :label="t('area.name')" show-overflow-tooltip/>
|
||||
<el-table-column prop="adcode" :label="t('area.adcode')" show-overflow-tooltip/>
|
||||
<el-table-column prop="areaType" :label="t('area.areaType')" show-overflow-tooltip>
|
||||
<template #default="scope">
|
||||
<dict-tag :options="area_type_dict" :value="scope.row.areaType"></dict-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="hot" :label="t('area.hot')" show-overflow-tooltip>
|
||||
<template #default="scope">
|
||||
<dict-tag :options="yes_no_type" :value="scope.row.hot"></dict-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="areaStatus" :label="t('area.areaStatus')" show-overflow-tooltip>
|
||||
<template #default="scope">
|
||||
<dict-tag :options="yes_no_type" :value="scope.row.areaStatus"></dict-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="areaSort" :label="t('area.areaSort')" width="100" sortable="custom"
|
||||
show-overflow-tooltip/>
|
||||
<el-table-column :label="$t('common.action')" width="150">
|
||||
<template #default="scope">
|
||||
<el-button icon="edit-pen" text type="primary" v-auth="'sys_sysArea_edit'"
|
||||
@click="formDialogRef.openDialog(scope.row.id)">{{ $t('common.editBtn') }}
|
||||
</el-button>
|
||||
<el-button icon="delete" text type="primary" v-auth="'sys_sysArea_del'"
|
||||
@click="handleDelete([scope.row.id])">{{ $t('common.delBtn') }}
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<pagination @size-change="sizeChangeHandle" @current-change="currentChangeHandle" v-bind="state.pagination"/>
|
||||
</div>
|
||||
<div class="layout-padding">
|
||||
<div class="layout-padding-auto layout-padding-view">
|
||||
<el-row v-show="showSearch">
|
||||
<el-form :model="state.queryForm" ref="queryRef" :inline="true" @keyup.enter="getDataList">
|
||||
<el-form-item :label="t('area.pid')" prop="adcode">
|
||||
<china-area :type="3" :placeholder="t('area.inputPidByTip')" v-model="pid" :plus="true" @change="handleChange" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('area.name')" prop="name">
|
||||
<el-input :placeholder="t('area.inputNameByTip')" v-model="state.queryForm.name" />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button icon="search" type="primary" @click="getDataList">
|
||||
{{ $t('common.queryBtn') }}
|
||||
</el-button>
|
||||
<el-button icon="Refresh" @click="resetQuery">{{ $t('common.resetBtn') }}</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<div class="mb8" style="width: 100%">
|
||||
<el-button icon="folder-add" type="primary" class="ml10" @click="formDialogRef.openDialog()" v-auth="'sys_sysArea_add'">
|
||||
{{ $t('common.addBtn') }}
|
||||
</el-button>
|
||||
<el-button plain :disabled="multiple" icon="Delete" type="primary" v-auth="'sys_sysArea_del'" @click="handleDelete(selectObjs)">
|
||||
{{ $t('common.delBtn') }}
|
||||
</el-button>
|
||||
<right-toolbar
|
||||
v-model:showSearch="showSearch"
|
||||
:export="'sys_sysArea_export'"
|
||||
@exportExcel="exportExcel"
|
||||
class="ml10 mr20"
|
||||
style="float: right"
|
||||
@queryTable="getDataList"
|
||||
></right-toolbar>
|
||||
</div>
|
||||
</el-row>
|
||||
<el-table
|
||||
:data="state.dataList"
|
||||
v-loading="state.loading"
|
||||
border
|
||||
:cell-style="tableStyle.cellStyle"
|
||||
:header-cell-style="tableStyle.headerCellStyle"
|
||||
@selection-change="selectionChangHandle"
|
||||
@sort-change="sortChangeHandle"
|
||||
>
|
||||
<el-table-column type="selection" width="40" align="center" />
|
||||
<el-table-column type="index" label="#" width="40" />
|
||||
<el-table-column prop="name" :label="t('area.name')" show-overflow-tooltip />
|
||||
<el-table-column prop="adcode" :label="t('area.adcode')" show-overflow-tooltip />
|
||||
<el-table-column prop="areaType" :label="t('area.areaType')" show-overflow-tooltip>
|
||||
<template #default="scope">
|
||||
<dict-tag :options="area_type_dict" :value="scope.row.areaType"></dict-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="hot" :label="t('area.hot')" show-overflow-tooltip>
|
||||
<template #default="scope">
|
||||
<dict-tag :options="yes_no_type" :value="scope.row.hot"></dict-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="areaStatus" :label="t('area.areaStatus')" show-overflow-tooltip>
|
||||
<template #default="scope">
|
||||
<dict-tag :options="yes_no_type" :value="scope.row.areaStatus"></dict-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="areaSort" :label="t('area.areaSort')" width="100" sortable="custom" show-overflow-tooltip />
|
||||
<el-table-column :label="$t('common.action')" width="150">
|
||||
<template #default="scope">
|
||||
<el-button icon="edit-pen" text type="primary" v-auth="'sys_sysArea_edit'" @click="formDialogRef.openDialog(scope.row.id)"
|
||||
>{{ $t('common.editBtn') }}
|
||||
</el-button>
|
||||
<el-button icon="delete" text type="primary" v-auth="'sys_sysArea_del'" @click="handleDelete([scope.row.id])"
|
||||
>{{ $t('common.delBtn') }}
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<pagination @size-change="sizeChangeHandle" @current-change="currentChangeHandle" v-bind="state.pagination" />
|
||||
</div>
|
||||
|
||||
<!-- 编辑、新增 -->
|
||||
<form-dialog ref="formDialogRef" @refresh="getDataList(false)"/>
|
||||
|
||||
</div>
|
||||
<!-- 编辑、新增 -->
|
||||
<form-dialog ref="formDialogRef" @refresh="getDataList(false)" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="systemSysArea">
|
||||
import {BasicTableProps, useTable} from "/@/hooks/table";
|
||||
import {delObjs, fetchList} from "/@/api/admin/sysArea";
|
||||
import {useMessage, useMessageBox} from "/@/hooks/message";
|
||||
import {useDict} from '/@/hooks/dict';
|
||||
import {useI18n} from "vue-i18n";
|
||||
import { BasicTableProps, useTable } from '/@/hooks/table';
|
||||
import { delObjs, fetchList } from '/@/api/admin/sysArea';
|
||||
import { useMessage, useMessageBox } from '/@/hooks/message';
|
||||
import { useDict } from '/@/hooks/dict';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
const {t} = useI18n();
|
||||
const { t } = useI18n();
|
||||
|
||||
// 省市区查询组件
|
||||
const ChinaArea = defineAsyncComponent(() => import("/@/components/ChinaArea/index.vue"));
|
||||
const ChinaArea = defineAsyncComponent(() => import('/@/components/ChinaArea/index.vue'));
|
||||
// 引入组件
|
||||
const FormDialog = defineAsyncComponent(() => import('./form.vue'));
|
||||
// 定义查询字典
|
||||
const {yes_no_type} = useDict('yes_no_type');
|
||||
const { yes_no_type } = useDict('yes_no_type');
|
||||
const area_type_dict = [
|
||||
{value: '0', label: '国家'},
|
||||
{value: '1', label: '省份'},
|
||||
{value: '2', label: '城市'},
|
||||
{value: '3', label: '县区'},
|
||||
{value: '4', label: '街道'}
|
||||
]
|
||||
{ value: '0', label: '国家' },
|
||||
{ value: '1', label: '省份' },
|
||||
{ value: '2', label: '城市' },
|
||||
{ value: '3', label: '县区' },
|
||||
{ value: '4', label: '街道' },
|
||||
];
|
||||
// 定义变量内容
|
||||
const formDialogRef = ref()
|
||||
const formDialogRef = ref();
|
||||
// 搜索变量
|
||||
const queryRef = ref()
|
||||
const showSearch = ref(true)
|
||||
const queryRef = ref();
|
||||
const showSearch = ref(true);
|
||||
// 多选变量
|
||||
const selectObjs = ref([]) as any
|
||||
const multiple = ref(true)
|
||||
const pid = ref()
|
||||
const selectObjs = ref([]) as any;
|
||||
const multiple = ref(true);
|
||||
const pid = ref();
|
||||
|
||||
const state: BasicTableProps = reactive<BasicTableProps>({
|
||||
queryForm: {
|
||||
adcode: '',
|
||||
name: ''
|
||||
},
|
||||
ascs: ['adcode'],
|
||||
pageList: fetchList
|
||||
})
|
||||
queryForm: {
|
||||
adcode: '',
|
||||
name: '',
|
||||
},
|
||||
ascs: ['adcode'],
|
||||
pageList: fetchList,
|
||||
});
|
||||
|
||||
// table hook
|
||||
const {
|
||||
getDataList,
|
||||
currentChangeHandle,
|
||||
sizeChangeHandle,
|
||||
sortChangeHandle,
|
||||
downBlobFile,
|
||||
tableStyle
|
||||
} = useTable(state)
|
||||
const { getDataList, currentChangeHandle, sizeChangeHandle, sortChangeHandle, downBlobFile, tableStyle } = useTable(state);
|
||||
|
||||
// 清空搜索条件
|
||||
const resetQuery = () => {
|
||||
// 清空搜索条件
|
||||
queryRef.value?.resetFields()
|
||||
pid.value = ''
|
||||
// 清空多选
|
||||
selectObjs.value = []
|
||||
getDataList()
|
||||
}
|
||||
// 清空搜索条件
|
||||
queryRef.value?.resetFields();
|
||||
pid.value = '';
|
||||
// 清空多选
|
||||
selectObjs.value = [];
|
||||
getDataList();
|
||||
};
|
||||
|
||||
// 导出excel
|
||||
const exportExcel = () => {
|
||||
downBlobFile('/admin/sysArea/export', Object.assign(state.queryForm, {ids: selectObjs}), 'sysArea.xlsx')
|
||||
}
|
||||
downBlobFile('/admin/sysArea/export', Object.assign(state.queryForm, { ids: selectObjs }), 'sysArea.xlsx');
|
||||
};
|
||||
|
||||
// 多选事件
|
||||
const selectionChangHandle = (objs: { id: string }[]) => {
|
||||
selectObjs.value = objs.map(({id}) => id);
|
||||
multiple.value = !objs.length;
|
||||
selectObjs.value = objs.map(({ id }) => id);
|
||||
multiple.value = !objs.length;
|
||||
};
|
||||
|
||||
// 删除操作
|
||||
const handleDelete = async (ids: string[]) => {
|
||||
try {
|
||||
await useMessageBox().confirm(t('common.delConfirmText'));
|
||||
} catch {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
await useMessageBox().confirm(t('common.delConfirmText'));
|
||||
} catch {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await delObjs(ids);
|
||||
getDataList();
|
||||
useMessage().success(t('common.delSuccessText'));
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg);
|
||||
}
|
||||
try {
|
||||
await delObjs(ids);
|
||||
getDataList();
|
||||
useMessage().success(t('common.delSuccessText'));
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg);
|
||||
}
|
||||
};
|
||||
|
||||
// 地区查询
|
||||
const handleChange = (data: string) => {
|
||||
let dataArray = data.split(",");
|
||||
state.queryForm.adcode = dataArray[dataArray.length - 1];
|
||||
}
|
||||
let dataArray = data.split(',');
|
||||
state.queryForm.adcode = dataArray[dataArray.length - 1];
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { getObj, deptTree, addObj, putObj } from '/@/api/admin/dept';
|
||||
import { useMessage } from '/@/hooks/message';
|
||||
import {rule} from "/@/utils/validate";
|
||||
import { rule } from '/@/utils/validate';
|
||||
|
||||
// 定义子组件向父组件传值/事件
|
||||
const emit = defineEmits(['refresh']);
|
||||
@@ -52,7 +52,10 @@ const loading = ref(false);
|
||||
|
||||
const dataRules = ref({
|
||||
parentId: [{ required: true, message: '上级部门不能为空', trigger: 'blur' }],
|
||||
name: [{ validator: rule.overLength, trigger: 'blur' },{ required: true, message: '部门名称不能为空', trigger: 'blur' }],
|
||||
name: [
|
||||
{ validator: rule.overLength, trigger: 'blur' },
|
||||
{ required: true, message: '部门名称不能为空', trigger: 'blur' },
|
||||
],
|
||||
sortOrder: [{ required: true, message: '排序不能为空', trigger: 'blur' }],
|
||||
});
|
||||
|
||||
|
||||
@@ -12,9 +12,9 @@ export default {
|
||||
inputLeaderIdTip: 'input leader',
|
||||
inputsortOrderTip: 'input sortOrder',
|
||||
importTip: 'import dept',
|
||||
addNodeText:'add dept',
|
||||
editNodeText:'edit dept',
|
||||
delNodeText:'delete dept',
|
||||
addNodeText: 'add dept',
|
||||
editNodeText: 'edit dept',
|
||||
delNodeText: 'delete dept',
|
||||
view: 'tree/table view',
|
||||
tenantNodeErrorText: 'The current node cannot be operated. You need to maintain it in tenant management',
|
||||
},
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
export default {
|
||||
sysdept: {
|
||||
name: '部门名称',
|
||||
parentId: '上级部门',
|
||||
createTime: '创建时间',
|
||||
weight: '排序',
|
||||
sortOrder: '排序',
|
||||
leaderId: '部门负责人',
|
||||
inputdeptNameTip: '请输入部门名称',
|
||||
inputnameTip: '请输入部门名称',
|
||||
inputLeaderIdTip: '请输入部门领导',
|
||||
inputparentIdTip: '请选择上级部门',
|
||||
inputsortOrderTip: '请输入排序',
|
||||
importTip: '导入部门',
|
||||
addNodeText: '添加部门',
|
||||
editNodeText: '编辑部门',
|
||||
delNodeText: '删除部门',
|
||||
tenantNodeErrorText: '当前节点不可操作,请在租户管理功能中维护',
|
||||
view: '树/表视图'
|
||||
},
|
||||
sysdept: {
|
||||
name: '部门名称',
|
||||
parentId: '上级部门',
|
||||
createTime: '创建时间',
|
||||
weight: '排序',
|
||||
sortOrder: '排序',
|
||||
leaderId: '部门负责人',
|
||||
inputdeptNameTip: '请输入部门名称',
|
||||
inputnameTip: '请输入部门名称',
|
||||
inputLeaderIdTip: '请输入部门领导',
|
||||
inputparentIdTip: '请选择上级部门',
|
||||
inputsortOrderTip: '请输入排序',
|
||||
importTip: '导入部门',
|
||||
addNodeText: '添加部门',
|
||||
editNodeText: '编辑部门',
|
||||
delNodeText: '删除部门',
|
||||
tenantNodeErrorText: '当前节点不可操作,请在租户管理功能中维护',
|
||||
view: '树/表视图',
|
||||
},
|
||||
};
|
||||
|
||||
@@ -130,6 +130,6 @@ const resetQuery = () => {
|
||||
</script>
|
||||
<style scoped>
|
||||
:deep(.el-table__body tr td) {
|
||||
text-align: left !important;
|
||||
text-align: left !important;
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
||||
@@ -1,50 +1,45 @@
|
||||
<template>
|
||||
<el-table
|
||||
ref="tableRef"
|
||||
:data="state.dataList"
|
||||
v-loading="state.loading"
|
||||
style="width: 100%"
|
||||
row-key="id"
|
||||
default-expand-all
|
||||
:tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
|
||||
border
|
||||
:cell-style="tableStyle.cellStyle"
|
||||
:header-cell-style="tableStyle?.headerCellStyle"
|
||||
>
|
||||
<el-table-column :label="$t('sysdept.name')" prop="name" width="400" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column :label="$t('sysdept.weight')" prop="weight" show-overflow-tooltip width="80"></el-table-column>
|
||||
<el-table-column prop="createTime" :label="$t('sysdept.createTime')" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column :label="$t('common.action')" show-overflow-tooltip width="250">
|
||||
<template #default="scope">
|
||||
<el-button text type="primary" icon="folder-add" @click="deptDialogRef.openDialog('add', scope.row?.id)"
|
||||
v-auth="'sys_dept_add'">
|
||||
{{ $t('common.addBtn') }}
|
||||
</el-button
|
||||
>
|
||||
<el-button text type="primary" icon="edit-pen" @click="deptDialogRef.openDialog('edit', scope.row?.id)"
|
||||
v-auth="'sys_dept_edit'">{{
|
||||
$t('common.editBtn')
|
||||
}}
|
||||
</el-button>
|
||||
<el-button text type="primary" icon="delete" @click="handleDelete(scope.row)" v-auth="'sys_dept_del'">
|
||||
{{ $t('common.delBtn') }}
|
||||
</el-button
|
||||
>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<dept-form ref="deptDialogRef" @refresh="getDataList()"/>
|
||||
<el-table
|
||||
ref="tableRef"
|
||||
:data="state.dataList"
|
||||
v-loading="state.loading"
|
||||
style="width: 100%"
|
||||
row-key="id"
|
||||
default-expand-all
|
||||
:tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
|
||||
border
|
||||
:cell-style="tableStyle.cellStyle"
|
||||
:header-cell-style="tableStyle?.headerCellStyle"
|
||||
>
|
||||
<el-table-column :label="$t('sysdept.name')" prop="name" width="400" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column :label="$t('sysdept.weight')" prop="weight" show-overflow-tooltip width="80"></el-table-column>
|
||||
<el-table-column prop="createTime" :label="$t('sysdept.createTime')" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column :label="$t('common.action')" show-overflow-tooltip width="250">
|
||||
<template #default="scope">
|
||||
<el-button text type="primary" icon="folder-add" @click="deptDialogRef.openDialog('add', scope.row?.id)" v-auth="'sys_dept_add'">
|
||||
{{ $t('common.addBtn') }}
|
||||
</el-button>
|
||||
<el-button text type="primary" icon="edit-pen" @click="deptDialogRef.openDialog('edit', scope.row?.id)" v-auth="'sys_dept_edit'"
|
||||
>{{ $t('common.editBtn') }}
|
||||
</el-button>
|
||||
<el-button text type="primary" icon="delete" @click="handleDelete(scope.row)" v-auth="'sys_dept_del'">
|
||||
{{ $t('common.delBtn') }}
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<dept-form ref="deptDialogRef" @refresh="getDataList()" />
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="systemDept">
|
||||
import {BasicTableProps, useTable} from '/@/hooks/table';
|
||||
import {deptTree, delObj} from '/@/api/admin/dept';
|
||||
import {useMessage, useMessageBox} from '/@/hooks/message';
|
||||
import {useI18n} from 'vue-i18n';
|
||||
import { BasicTableProps, useTable } from '/@/hooks/table';
|
||||
import { deptTree, delObj } from '/@/api/admin/dept';
|
||||
import { useMessage, useMessageBox } from '/@/hooks/message';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
// 引入组件
|
||||
const DeptForm = defineAsyncComponent(() => import('./form.vue'));
|
||||
const {t} = useI18n();
|
||||
const { t } = useI18n();
|
||||
// 定义变量内容
|
||||
const tableRef = ref(); // 表格引用
|
||||
const deptDialogRef = ref(); // 部门对话框引用
|
||||
@@ -58,33 +53,33 @@ const isExpand = ref(false); // 是否展开
|
||||
* @returns Promise<any>
|
||||
*/
|
||||
const queryDeptTree = (params?: any) => {
|
||||
return deptTree(params);
|
||||
return deptTree(params);
|
||||
};
|
||||
|
||||
/**
|
||||
* 定义响应式表格数据
|
||||
*/
|
||||
const state: BasicTableProps = reactive<BasicTableProps>({
|
||||
pageList: queryDeptTree, // 页面列表数据
|
||||
queryForm: {
|
||||
deptName: '', // 部门名称
|
||||
},
|
||||
isPage: false, // 是否分页
|
||||
descs: ['create_time'], // 排序字段
|
||||
pageList: queryDeptTree, // 页面列表数据
|
||||
queryForm: {
|
||||
deptName: '', // 部门名称
|
||||
},
|
||||
isPage: false, // 是否分页
|
||||
descs: ['create_time'], // 排序字段
|
||||
});
|
||||
|
||||
/**
|
||||
* 使用 useTable 定义表格相关操作
|
||||
*/
|
||||
const {getDataList, tableStyle} = useTable(state);
|
||||
const { getDataList, tableStyle } = useTable(state);
|
||||
|
||||
/**
|
||||
* 展开/折叠部门树方法
|
||||
*/
|
||||
const handleExpand = async () => {
|
||||
isExpand.value = !isExpand.value;
|
||||
const dataList = await deptTree();
|
||||
toggleExpand(dataList.data, isExpand.value);
|
||||
isExpand.value = !isExpand.value;
|
||||
const dataList = await deptTree();
|
||||
toggleExpand(dataList.data, isExpand.value);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -93,12 +88,12 @@ const handleExpand = async () => {
|
||||
* @param unfold - 是否展开
|
||||
*/
|
||||
const toggleExpand = (children: any[], unfold = true) => {
|
||||
for (const key in children) {
|
||||
tableRef.value?.toggleRowExpansion(children[key], unfold);
|
||||
if (children[key].children) {
|
||||
toggleExpand(children[key].children!, unfold);
|
||||
}
|
||||
}
|
||||
for (const key in children) {
|
||||
tableRef.value?.toggleRowExpansion(children[key], unfold);
|
||||
if (children[key].children) {
|
||||
toggleExpand(children[key].children!, unfold);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -106,32 +101,32 @@ const toggleExpand = (children: any[], unfold = true) => {
|
||||
* @param row - 当前行数据
|
||||
*/
|
||||
const handleDelete = async (row: any) => {
|
||||
try {
|
||||
await useMessageBox().confirm(t('common.delConfirmText'));
|
||||
} catch {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
await useMessageBox().confirm(t('common.delConfirmText'));
|
||||
} catch {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await delObj(row.id);
|
||||
getDataList();
|
||||
useMessage().success(t('common.delSuccessText'));
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg);
|
||||
}
|
||||
try {
|
||||
await delObj(row.id);
|
||||
getDataList();
|
||||
useMessage().success(t('common.delSuccessText'));
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg);
|
||||
}
|
||||
};
|
||||
|
||||
const handleAdd = ()=>{
|
||||
deptDialogRef.value.openDialog('add')
|
||||
}
|
||||
const handleAdd = () => {
|
||||
deptDialogRef.value.openDialog('add');
|
||||
};
|
||||
|
||||
/**
|
||||
* 暴露组件中的一些方法和变量
|
||||
*/
|
||||
defineExpose({
|
||||
handleAdd, // 新增时间
|
||||
state, // 响应式表格数据
|
||||
getDataList, // 获取列表数据方法
|
||||
handleExpand // 展开/折叠部门树方法
|
||||
handleAdd, // 新增时间
|
||||
state, // 响应式表格数据
|
||||
getDataList, // 获取列表数据方法
|
||||
handleExpand, // 展开/折叠部门树方法
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -1,127 +1,134 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
:title="state.ruleForm.menuId ? $t('common.editBtn') : $t('common.addBtn')"
|
||||
v-model="visible"
|
||||
width="600"
|
||||
:close-on-click-modal="false"
|
||||
draggable
|
||||
>
|
||||
<el-form ref="menuDialogFormRef" :model="state.ruleForm" :rules="dataRules" label-width="100px" v-loading="loading">
|
||||
<el-form-item :label="$t('sysmenu.menuType')" prop="menuType">
|
||||
<el-radio-group v-model="state.ruleForm.menuType">
|
||||
<el-radio border label="0">菜单</el-radio>
|
||||
<el-radio border label="1">按钮</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('sysmenu.parentId')" prop="parentId">
|
||||
<el-tree-select
|
||||
v-model="state.ruleForm.parentId"
|
||||
:data="state.parentData"
|
||||
:render-after-expand="false"
|
||||
:props="{ value: 'id', label: 'name', children: 'children' }"
|
||||
class="w100"
|
||||
clearable
|
||||
check-strictly
|
||||
:placeholder="$t('sysmenu.inputParentIdTip')"
|
||||
>
|
||||
</el-tree-select>
|
||||
</el-form-item>
|
||||
<el-form-item prop="name">
|
||||
<template #label>
|
||||
{{ state.ruleForm.menuType === '0' ? t('sysmenu.name') : t('sysmenu.buttonName') }}
|
||||
</template>
|
||||
<el-input v-model="state.ruleForm.name" clearable :placeholder="$t('sysmenu.inputNameTip')"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('sysmenu.path')" prop="path" v-if="state.ruleForm.menuType === '0'">
|
||||
<el-input v-model="state.ruleForm.path" :placeholder="$t('sysmenu.inputPathTip')"/>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('sysmenu.permission')" prop="permission" v-if="state.ruleForm.menuType === '1'">
|
||||
<template #label>
|
||||
{{ t('sysmenu.permission') }}
|
||||
<tip content="对应后台接口@PreAuthorize注解入参字符串"></tip>
|
||||
</template>
|
||||
<el-input v-model="state.ruleForm.permission" maxlength="100" :placeholder="$t('sysmenu.inputPermissionTip')"/>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('sysmenu.sortOrder')" prop="sortOrder">
|
||||
<el-input-number v-model="state.ruleForm.sortOrder" :min="0" controls-position="right"/>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('sysmenu.icon')" prop="icon" v-if="state.ruleForm.menuType === '0'">
|
||||
<IconSelector :placeholder="$t('sysmenu.inputIconTip')" v-model="state.ruleForm.icon"/>
|
||||
</el-form-item>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item prop="keepAlive" v-if="state.ruleForm.menuType === '0'">
|
||||
<template #label> {{ $t('sysmenu.keepAlive') }}
|
||||
<tip content="组件保留状态,避免重新渲染"/>
|
||||
</template>
|
||||
<el-radio-group v-model="state.ruleForm.keepAlive">
|
||||
<el-radio border label="0">否</el-radio>
|
||||
<el-radio border label="1">是</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item prop="visible" v-if="state.ruleForm.menuType === '0'">
|
||||
<template #label> {{ $t('sysmenu.visible') }}
|
||||
<tip content="左侧菜单树是否显示"/>
|
||||
</template>
|
||||
<el-radio-group v-model="state.ruleForm.visible">
|
||||
<el-radio border label="0">否</el-radio>
|
||||
<el-radio border label="1">是</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row class="mt-4">
|
||||
<el-col :span="12">
|
||||
<el-form-item prop="param" v-if="state.ruleForm.menuType === '0'">
|
||||
<template #label> {{ $t('sysmenu.param') }}
|
||||
<tip content="多个路径指向同一个组件"/>
|
||||
</template>
|
||||
<el-radio-group v-model="state.ruleForm.param">
|
||||
<el-radio border label="0">否</el-radio>
|
||||
<el-radio border label="1">是</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item prop="embedded"
|
||||
v-if="state.ruleForm.menuType === '0' && state.ruleForm.path?.startsWith('http')">
|
||||
<template #label> {{ $t('sysmenu.embedded') }}
|
||||
<tip content="iframe嵌套还是打开独立的Tab"/>
|
||||
</template>
|
||||
<el-radio-group v-model="state.ruleForm.embedded">
|
||||
<el-radio border label="0">否</el-radio>
|
||||
<el-radio border label="1">是</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-dialog
|
||||
:title="state.ruleForm.menuId ? $t('common.editBtn') : $t('common.addBtn')"
|
||||
v-model="visible"
|
||||
width="600"
|
||||
:close-on-click-modal="false"
|
||||
draggable
|
||||
>
|
||||
<el-form ref="menuDialogFormRef" :model="state.ruleForm" :rules="dataRules" label-width="100px" v-loading="loading">
|
||||
<el-form-item :label="$t('sysmenu.menuType')" prop="menuType">
|
||||
<el-radio-group v-model="state.ruleForm.menuType">
|
||||
<el-radio border label="0">菜单</el-radio>
|
||||
<el-radio border label="1">按钮</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('sysmenu.parentId')" prop="parentId">
|
||||
<el-tree-select
|
||||
v-model="state.ruleForm.parentId"
|
||||
:data="state.parentData"
|
||||
:render-after-expand="false"
|
||||
:props="{ value: 'id', label: 'name', children: 'children' }"
|
||||
class="w100"
|
||||
clearable
|
||||
check-strictly
|
||||
:placeholder="$t('sysmenu.inputParentIdTip')"
|
||||
>
|
||||
</el-tree-select>
|
||||
</el-form-item>
|
||||
<el-form-item prop="name">
|
||||
<template #label>
|
||||
{{ state.ruleForm.menuType === '0' ? t('sysmenu.name') : t('sysmenu.buttonName') }}
|
||||
</template>
|
||||
<el-input v-model="state.ruleForm.name" clearable :placeholder="$t('sysmenu.inputNameTip')"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('sysmenu.path')" prop="path" v-if="state.ruleForm.menuType === '0'">
|
||||
<el-input v-model="state.ruleForm.path" :placeholder="$t('sysmenu.inputPathTip')" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('sysmenu.permission')" prop="permission" v-if="state.ruleForm.menuType === '1'">
|
||||
<template #label>
|
||||
{{ t('sysmenu.permission') }}
|
||||
<tip content="对应后台接口@PreAuthorize注解入参字符串"></tip>
|
||||
</template>
|
||||
<el-input v-model="state.ruleForm.permission" maxlength="100" :placeholder="$t('sysmenu.inputPermissionTip')" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('sysmenu.sortOrder')" prop="sortOrder">
|
||||
<el-input-number v-model="state.ruleForm.sortOrder" :min="0" controls-position="right" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('sysmenu.icon')" prop="icon" v-if="state.ruleForm.menuType === '0'">
|
||||
<IconSelector :placeholder="$t('sysmenu.inputIconTip')" v-model="state.ruleForm.icon" />
|
||||
</el-form-item>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item prop="keepAlive" v-if="state.ruleForm.menuType === '0'">
|
||||
<template #label>
|
||||
{{ $t('sysmenu.keepAlive') }}
|
||||
<tip content="组件保留状态,避免重新渲染" />
|
||||
</template>
|
||||
<el-radio-group v-model="state.ruleForm.keepAlive">
|
||||
<el-radio border label="0">否</el-radio>
|
||||
<el-radio border label="1">是</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item prop="visible" v-if="state.ruleForm.menuType === '0'">
|
||||
<template #label>
|
||||
{{ $t('sysmenu.visible') }}
|
||||
<tip content="左侧菜单树是否显示" />
|
||||
</template>
|
||||
<el-radio-group v-model="state.ruleForm.visible">
|
||||
<el-radio border label="0">否</el-radio>
|
||||
<el-radio border label="1">是</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row class="mt-4">
|
||||
<el-col :span="12">
|
||||
<el-form-item prop="param" v-if="state.ruleForm.menuType === '0'">
|
||||
<template #label>
|
||||
{{ $t('sysmenu.param') }}
|
||||
<tip content="多个路径指向同一个组件" />
|
||||
</template>
|
||||
<el-radio-group v-model="state.ruleForm.param">
|
||||
<el-radio border label="0">否</el-radio>
|
||||
<el-radio border label="1">是</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item prop="embedded" v-if="state.ruleForm.menuType === '0' && state.ruleForm.path?.startsWith('http')">
|
||||
<template #label>
|
||||
{{ $t('sysmenu.embedded') }}
|
||||
<tip content="iframe嵌套还是打开独立的Tab" />
|
||||
</template>
|
||||
<el-radio-group v-model="state.ruleForm.embedded">
|
||||
<el-radio border label="0">否</el-radio>
|
||||
<el-radio border label="1">是</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-form-item class="mt-4" :label="$t('sysmenu.component')" prop="component" v-if="state.ruleForm.menuType === '0'
|
||||
&& state.ruleForm.param === '1'">
|
||||
<el-input v-model="state.ruleForm.component" :placeholder="$t('sysmenu.inputComponentTip')"/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-form-item
|
||||
class="mt-4"
|
||||
:label="$t('sysmenu.component')"
|
||||
prop="component"
|
||||
v-if="state.ruleForm.menuType === '0' && state.ruleForm.param === '1'"
|
||||
>
|
||||
<el-input v-model="state.ruleForm.component" :placeholder="$t('sysmenu.inputComponentTip')" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="visible = false">{{ $t('common.cancelButtonText') }}</el-button>
|
||||
<el-button type="primary" @click="onSubmit" :disabled="loading">{{ $t('common.confirmButtonText') }}</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="systemMenuDialog">
|
||||
import {useI18n} from 'vue-i18n';
|
||||
import {getObj, pageList, putObj, addObj, validateExist} from '/@/api/admin/menu';
|
||||
import {useMessage} from '/@/hooks/message';
|
||||
import {rule, validateNull} from "/@/utils/validate";
|
||||
import Tip from "/@/components/Tip/index.vue";
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { getObj, pageList, putObj, addObj, validateExist } from '/@/api/admin/menu';
|
||||
import { useMessage } from '/@/hooks/message';
|
||||
import { rule, validateNull } from '/@/utils/validate';
|
||||
import Tip from '/@/components/Tip/index.vue';
|
||||
|
||||
// 定义子组件向父组件传值/事件
|
||||
const emit = defineEmits(['refresh']);
|
||||
const {t} = useI18n();
|
||||
const { t } = useI18n();
|
||||
// 引入组件
|
||||
const IconSelector = defineAsyncComponent(() => import('/@/components/IconSelector/index.vue'));
|
||||
|
||||
@@ -132,148 +139,160 @@ const menuDialogFormRef = ref();
|
||||
const originalName = ref(''); // To store the original menu name for comparison during edits
|
||||
// 定义需要的数据
|
||||
const state = reactive({
|
||||
ruleForm: {
|
||||
menuId: '',
|
||||
name: '',
|
||||
permission: '',
|
||||
parentId: '',
|
||||
icon: '',
|
||||
path: '',
|
||||
param: '0',
|
||||
component: '',
|
||||
sortOrder: 0,
|
||||
menuType: '1',
|
||||
keepAlive: '0',
|
||||
visible: '1',
|
||||
embedded: '0',
|
||||
},
|
||||
parentData: [] as any[], // 上级菜单数据
|
||||
ruleForm: {
|
||||
menuId: '',
|
||||
name: '',
|
||||
permission: '',
|
||||
parentId: '',
|
||||
icon: '',
|
||||
path: '',
|
||||
param: '0',
|
||||
component: '',
|
||||
sortOrder: 0,
|
||||
menuType: '1',
|
||||
keepAlive: '0',
|
||||
visible: '1',
|
||||
embedded: '0',
|
||||
},
|
||||
parentData: [] as any[], // 上级菜单数据
|
||||
});
|
||||
|
||||
// 表单校验规则
|
||||
const dataRules = reactive({
|
||||
menuType: [{required: true, message: '菜单类型不能为空', trigger: 'blur'}],
|
||||
parentId: [{required: true, message: '上级菜单不能为空', trigger: 'blur'}],
|
||||
name: [{validator: rule.overLength, trigger: 'blur'}, {
|
||||
required: true,
|
||||
message: '菜单不能为空',
|
||||
trigger: 'blur'
|
||||
}, {
|
||||
validator: (rule: any, value: any, callback: any) => {
|
||||
// 如果是按钮类型菜单,跳过名称唯一性校验
|
||||
if (state.ruleForm.menuType === '1') {
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
// 如果是编辑状态且菜单名称未改变,跳过校验
|
||||
if (state.ruleForm.menuId !== '' && value === originalName.value) {
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
// 其他情况下,验证菜单名称唯一性
|
||||
validateExist(rule, value, callback, false);
|
||||
},
|
||||
trigger: 'blur',
|
||||
}],
|
||||
path: [{validator: rule.overLength, trigger: 'blur'}, {required: true, message: '路径不能为空', trigger: 'blur'}],
|
||||
permission: [{validator: rule.overLength, trigger: 'blur'}, {
|
||||
required: true,
|
||||
message: '权限代码不能为空',
|
||||
trigger: 'blur'
|
||||
}, {
|
||||
validator: (rule: any, value: any, callback: any) => {
|
||||
validateExist(rule, value, callback, state.ruleForm.menuId !== '');
|
||||
},
|
||||
trigger: 'blur',
|
||||
}],
|
||||
sortOrder: [{required: true, message: '排序不能为空', trigger: 'blur'}],
|
||||
component: [{min: 5, max: 255, message: '组件名称长度必须介于 5 和 255 之间', trigger: 'blur'},
|
||||
{
|
||||
validator: (rule: any, value: any, callback: any) => {
|
||||
if (state.ruleForm.menuType === '0' && state.ruleForm.param === '1' && validateNull(state.ruleForm.component)) {
|
||||
callback(new Error('请输入组件名称'));
|
||||
} else {
|
||||
return callback();
|
||||
}
|
||||
},
|
||||
trigger: 'blur',
|
||||
}],
|
||||
menuType: [{ required: true, message: '菜单类型不能为空', trigger: 'blur' }],
|
||||
parentId: [{ required: true, message: '上级菜单不能为空', trigger: 'blur' }],
|
||||
name: [
|
||||
{ validator: rule.overLength, trigger: 'blur' },
|
||||
{
|
||||
required: true,
|
||||
message: '菜单不能为空',
|
||||
trigger: 'blur',
|
||||
},
|
||||
{
|
||||
validator: (rule: any, value: any, callback: any) => {
|
||||
// 如果是按钮类型菜单,跳过名称唯一性校验
|
||||
if (state.ruleForm.menuType === '1') {
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
// 如果是编辑状态且菜单名称未改变,跳过校验
|
||||
if (state.ruleForm.menuId !== '' && value === originalName.value) {
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
// 其他情况下,验证菜单名称唯一性
|
||||
validateExist(rule, value, callback, false);
|
||||
},
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
path: [
|
||||
{ validator: rule.overLength, trigger: 'blur' },
|
||||
{ required: true, message: '路径不能为空', trigger: 'blur' },
|
||||
],
|
||||
permission: [
|
||||
{ validator: rule.overLength, trigger: 'blur' },
|
||||
{
|
||||
required: true,
|
||||
message: '权限代码不能为空',
|
||||
trigger: 'blur',
|
||||
},
|
||||
{
|
||||
validator: (rule: any, value: any, callback: any) => {
|
||||
validateExist(rule, value, callback, state.ruleForm.menuId !== '');
|
||||
},
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
sortOrder: [{ required: true, message: '排序不能为空', trigger: 'blur' }],
|
||||
component: [
|
||||
{ min: 5, max: 255, message: '组件名称长度必须介于 5 和 255 之间', trigger: 'blur' },
|
||||
{
|
||||
validator: (rule: any, value: any, callback: any) => {
|
||||
if (state.ruleForm.menuType === '0' && state.ruleForm.param === '1' && validateNull(state.ruleForm.component)) {
|
||||
callback(new Error('请输入组件名称'));
|
||||
} else {
|
||||
return callback();
|
||||
}
|
||||
},
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
// 打开弹窗
|
||||
const openDialog = (type: string, row?: any) => {
|
||||
state.ruleForm.menuId = '';
|
||||
visible.value = true;
|
||||
originalName.value = ''; // Reset the original name
|
||||
state.ruleForm.menuId = '';
|
||||
visible.value = true;
|
||||
originalName.value = ''; // Reset the original name
|
||||
|
||||
nextTick(() => {
|
||||
menuDialogFormRef.value?.resetFields();
|
||||
state.ruleForm.parentId = row?.id || '-1';
|
||||
});
|
||||
nextTick(() => {
|
||||
menuDialogFormRef.value?.resetFields();
|
||||
state.ruleForm.parentId = row?.id || '-1';
|
||||
});
|
||||
|
||||
if (row?.id && type === 'edit') {
|
||||
state.ruleForm.menuId = row.id;
|
||||
// 获取当前节点菜单信息
|
||||
getMenuDetail(row.id);
|
||||
}
|
||||
// 渲染上级菜单列表树
|
||||
getAllMenuData();
|
||||
if (row?.id && type === 'edit') {
|
||||
state.ruleForm.menuId = row.id;
|
||||
// 获取当前节点菜单信息
|
||||
getMenuDetail(row.id);
|
||||
}
|
||||
// 渲染上级菜单列表树
|
||||
getAllMenuData();
|
||||
};
|
||||
|
||||
// 获取菜单节点的详细信息
|
||||
const getMenuDetail = (id: string) => {
|
||||
getObj({menuId: id}).then((res) => {
|
||||
if (res.data[0].component) {
|
||||
state.ruleForm.param = '1'
|
||||
}
|
||||
originalName.value = res.data[0].name; // Store the original name
|
||||
Object.assign(state.ruleForm, res.data[0]);
|
||||
});
|
||||
getObj({ menuId: id }).then((res) => {
|
||||
if (res.data[0].component) {
|
||||
state.ruleForm.param = '1';
|
||||
}
|
||||
originalName.value = res.data[0].name; // Store the original name
|
||||
Object.assign(state.ruleForm, res.data[0]);
|
||||
});
|
||||
};
|
||||
|
||||
// 从后端获取菜单信息(含层级)
|
||||
const getAllMenuData = () => {
|
||||
state.parentData = [];
|
||||
pageList({
|
||||
type: '0',
|
||||
}).then((res) => {
|
||||
let menu = {
|
||||
id: '-1',
|
||||
name: '根菜单',
|
||||
children: [],
|
||||
};
|
||||
menu.children = res.data;
|
||||
state.parentData.push(menu);
|
||||
});
|
||||
state.parentData = [];
|
||||
pageList({
|
||||
type: '0',
|
||||
}).then((res) => {
|
||||
let menu = {
|
||||
id: '-1',
|
||||
name: '根菜单',
|
||||
children: [],
|
||||
};
|
||||
menu.children = res.data;
|
||||
state.parentData.push(menu);
|
||||
});
|
||||
};
|
||||
|
||||
// 保存数据
|
||||
const onSubmit = async () => {
|
||||
// 立即设置 loading,防止重复点击
|
||||
if (loading.value) return;
|
||||
loading.value = true;
|
||||
|
||||
try {
|
||||
const valid = await menuDialogFormRef.value.validate().catch(() => {
|
||||
});
|
||||
if (!valid) {
|
||||
loading.value = false;
|
||||
return false;
|
||||
}
|
||||
// 立即设置 loading,防止重复点击
|
||||
if (loading.value) return;
|
||||
loading.value = true;
|
||||
|
||||
state.ruleForm.menuId ? await putObj(state.ruleForm) : await addObj(state.ruleForm);
|
||||
useMessage().success(t(state.ruleForm.menuId ? 'common.editSuccessText' : 'common.addSuccessText'));
|
||||
visible.value = false;
|
||||
emit('refresh');
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg);
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
try {
|
||||
const valid = await menuDialogFormRef.value.validate().catch(() => {});
|
||||
if (!valid) {
|
||||
loading.value = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
state.ruleForm.menuId ? await putObj(state.ruleForm) : await addObj(state.ruleForm);
|
||||
useMessage().success(t(state.ruleForm.menuId ? 'common.editSuccessText' : 'common.addSuccessText'));
|
||||
visible.value = false;
|
||||
emit('refresh');
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg);
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
// 暴露变量 只有暴漏出来的变量 父组件才能使用
|
||||
defineExpose({
|
||||
openDialog,
|
||||
openDialog,
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -1,37 +1,37 @@
|
||||
export default {
|
||||
sysmenu: {
|
||||
index: '#',
|
||||
name: 'menu name',
|
||||
buttonName: 'button name',
|
||||
sortOrder: 'sortOrder',
|
||||
path: 'path',
|
||||
menuType: 'menuType',
|
||||
keepAlive: 'keepAlive',
|
||||
permission: 'permission',
|
||||
inputNameTip: 'input name',
|
||||
parentId: 'parent menu',
|
||||
embedded: 'embedded',
|
||||
param: 'param',
|
||||
component: 'component',
|
||||
visible: 'visible',
|
||||
icon: 'icon',
|
||||
inputMenuIdTip: 'input menuId',
|
||||
inputPermissionTip: 'input permission',
|
||||
inputPathTip: 'input path',
|
||||
inputParentIdTip: 'input parentId',
|
||||
inputIconTip: 'input icon',
|
||||
inputVisibleTip: 'input visible',
|
||||
inputSortOrderTip: 'input sortOrder',
|
||||
inputKeepAliveTip: 'input keepAlive',
|
||||
inputMenuTypeTip: 'input menuType',
|
||||
inputCreateByTip: 'input createBy',
|
||||
inputCreateTimeTip: 'input createTime',
|
||||
inputUpdateByTip: 'input updateBy',
|
||||
inputUpdateTimeTip: 'input updateTime',
|
||||
inputDelFlagTip: 'input delFlag',
|
||||
inputTenantIdTip: 'input tenantId',
|
||||
inputEmbeddedTip: 'input embedded',
|
||||
inputComponentTip: 'input component',
|
||||
deleteDisabledTip: 'menu inclusion subordinates cannot be deleted',
|
||||
},
|
||||
sysmenu: {
|
||||
index: '#',
|
||||
name: 'menu name',
|
||||
buttonName: 'button name',
|
||||
sortOrder: 'sortOrder',
|
||||
path: 'path',
|
||||
menuType: 'menuType',
|
||||
keepAlive: 'keepAlive',
|
||||
permission: 'permission',
|
||||
inputNameTip: 'input name',
|
||||
parentId: 'parent menu',
|
||||
embedded: 'embedded',
|
||||
param: 'param',
|
||||
component: 'component',
|
||||
visible: 'visible',
|
||||
icon: 'icon',
|
||||
inputMenuIdTip: 'input menuId',
|
||||
inputPermissionTip: 'input permission',
|
||||
inputPathTip: 'input path',
|
||||
inputParentIdTip: 'input parentId',
|
||||
inputIconTip: 'input icon',
|
||||
inputVisibleTip: 'input visible',
|
||||
inputSortOrderTip: 'input sortOrder',
|
||||
inputKeepAliveTip: 'input keepAlive',
|
||||
inputMenuTypeTip: 'input menuType',
|
||||
inputCreateByTip: 'input createBy',
|
||||
inputCreateTimeTip: 'input createTime',
|
||||
inputUpdateByTip: 'input updateBy',
|
||||
inputUpdateTimeTip: 'input updateTime',
|
||||
inputDelFlagTip: 'input delFlag',
|
||||
inputTenantIdTip: 'input tenantId',
|
||||
inputEmbeddedTip: 'input embedded',
|
||||
inputComponentTip: 'input component',
|
||||
deleteDisabledTip: 'menu inclusion subordinates cannot be deleted',
|
||||
},
|
||||
};
|
||||
|
||||
@@ -1,31 +1,31 @@
|
||||
export default {
|
||||
sysmenu: {
|
||||
index: '#',
|
||||
name: '菜单名称',
|
||||
buttonName: '按钮名称',
|
||||
sortOrder: '排序',
|
||||
path: '路由',
|
||||
menuType: '类型',
|
||||
keepAlive: '缓冲',
|
||||
permission: '权限标识',
|
||||
inputNameTip: '请输入菜单名称',
|
||||
parentId: '上级菜单',
|
||||
embedded: '内嵌',
|
||||
param: '带参',
|
||||
component: '组件',
|
||||
visible: '显示',
|
||||
icon: '图标',
|
||||
inputMenuIdTip: '',
|
||||
inputPermissionTip: '请输入权限标识',
|
||||
inputPathTip: '请输入路由路径',
|
||||
inputParentIdTip: '请选择上级菜单',
|
||||
inputIconTip: '请选择图标',
|
||||
inputVisibleTip: '请选择是否显示',
|
||||
inputSortOrderTip: '请输入排序',
|
||||
inputKeepAliveTip: '请选择是否缓冲',
|
||||
inputMenuTypeTip: '请选择菜单类型',
|
||||
inputEmbeddedTip: '请选择是否内嵌',
|
||||
inputComponentTip: '请输入组件名称',
|
||||
deleteDisabledTip: '菜单包含下级不能删除',
|
||||
},
|
||||
sysmenu: {
|
||||
index: '#',
|
||||
name: '菜单名称',
|
||||
buttonName: '按钮名称',
|
||||
sortOrder: '排序',
|
||||
path: '路由',
|
||||
menuType: '类型',
|
||||
keepAlive: '缓冲',
|
||||
permission: '权限标识',
|
||||
inputNameTip: '请输入菜单名称',
|
||||
parentId: '上级菜单',
|
||||
embedded: '内嵌',
|
||||
param: '带参',
|
||||
component: '组件',
|
||||
visible: '显示',
|
||||
icon: '图标',
|
||||
inputMenuIdTip: '',
|
||||
inputPermissionTip: '请输入权限标识',
|
||||
inputPathTip: '请输入路由路径',
|
||||
inputParentIdTip: '请选择上级菜单',
|
||||
inputIconTip: '请选择图标',
|
||||
inputVisibleTip: '请选择是否显示',
|
||||
inputSortOrderTip: '请输入排序',
|
||||
inputKeepAliveTip: '请选择是否缓冲',
|
||||
inputMenuTypeTip: '请选择菜单类型',
|
||||
inputEmbeddedTip: '请选择是否内嵌',
|
||||
inputComponentTip: '请输入组件名称',
|
||||
deleteDisabledTip: '菜单包含下级不能删除',
|
||||
},
|
||||
};
|
||||
|
||||
@@ -198,6 +198,6 @@ const handleDelete = async (row: any) => {
|
||||
|
||||
<style scoped>
|
||||
:deep(.el-table__body tr td) {
|
||||
text-align: left !important;
|
||||
text-align: left !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
import { useMessage } from '/@/hooks/message';
|
||||
import { getObj, addObj, putObj, validatePostCode, validatePostName } from '/@/api/admin/post';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import {rule} from "/@/utils/validate";
|
||||
import { rule } from '/@/utils/validate';
|
||||
|
||||
// 定义子组件向父组件传值/事件
|
||||
const emit = defineEmits(['refresh']);
|
||||
@@ -56,7 +56,7 @@ const form = reactive({
|
||||
// 定义校验规则
|
||||
const dataRules = ref({
|
||||
postCode: [
|
||||
{ validator: rule.overLength, trigger: 'blur' },
|
||||
{ validator: rule.overLength, trigger: 'blur' },
|
||||
{ required: true, message: '岗位编码不能为空', trigger: 'blur' },
|
||||
{
|
||||
validator: (rule: any, value: any, callback: any) => {
|
||||
@@ -66,7 +66,7 @@ const dataRules = ref({
|
||||
},
|
||||
],
|
||||
postName: [
|
||||
{ validator: rule.overLength, trigger: 'blur' },
|
||||
{ validator: rule.overLength, trigger: 'blur' },
|
||||
{ required: true, message: '岗位名称不能为空', trigger: 'blur' },
|
||||
{
|
||||
validator: (rule: any, value: any, callback: any) => {
|
||||
@@ -75,8 +75,14 @@ const dataRules = ref({
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
postSort: [{ validator: rule.overLength, trigger: 'blur' },{ required: true, message: '岗位排序不能为空', trigger: 'blur' }],
|
||||
remark: [{ validator: rule.overLength, trigger: 'blur' },{ required: true, message: '岗位描述不能为空', trigger: 'blur' }],
|
||||
postSort: [
|
||||
{ validator: rule.overLength, trigger: 'blur' },
|
||||
{ required: true, message: '岗位排序不能为空', trigger: 'blur' },
|
||||
],
|
||||
remark: [
|
||||
{ validator: rule.overLength, trigger: 'blur' },
|
||||
{ required: true, message: '岗位描述不能为空', trigger: 'blur' },
|
||||
],
|
||||
});
|
||||
|
||||
// 打开弹窗
|
||||
|
||||
@@ -40,7 +40,7 @@
|
||||
@selection-change="handleSelectionChange"
|
||||
style="width: 100%"
|
||||
v-loading="state.loading"
|
||||
row-key="postId"
|
||||
row-key="postId"
|
||||
border
|
||||
:cell-style="tableStyle?.cellStyle"
|
||||
:header-cell-style="tableStyle?.headerCellStyle"
|
||||
@@ -115,7 +115,7 @@ const resetQuery = () => {
|
||||
|
||||
// 导出excel
|
||||
const exportExcel = () => {
|
||||
downBlobFile('/admin/post/export', Object.assign(state.queryForm,{ids:selectObjs}), 'post.xlsx');
|
||||
downBlobFile('/admin/post/export', Object.assign(state.queryForm, { ids: selectObjs }), 'post.xlsx');
|
||||
};
|
||||
|
||||
// 多选事件
|
||||
|
||||
@@ -1,178 +1,169 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
v-model="visible"
|
||||
:title="dialogTitle"
|
||||
width="80%"
|
||||
:show-close="false"
|
||||
:close-on-click-modal="false"
|
||||
:close-on-press-escape="false"
|
||||
:before-close="handleBeforeClose"
|
||||
center
|
||||
>
|
||||
<el-form>
|
||||
<el-form-item class="role-form-item">
|
||||
<el-radio-group v-model="radio" class="role-radio-group" @change="handleChangeRole">
|
||||
<template v-for="(roles, groupName) in allRoleGroups" :key="groupName">
|
||||
<el-card class="role-group-card" shadow="hover">
|
||||
<template #header>
|
||||
<span class="group-name">{{ groupName }}</span>
|
||||
</template>
|
||||
<div class="role-group">
|
||||
<el-radio-button
|
||||
v-for="item in roles"
|
||||
:key="item.roleCode"
|
||||
:label="item.roleCode"
|
||||
size="small"
|
||||
>
|
||||
{{ item.roleName }}
|
||||
</el-radio-button>
|
||||
</div>
|
||||
</el-card>
|
||||
</template>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<el-dialog
|
||||
v-model="visible"
|
||||
:title="dialogTitle"
|
||||
width="80%"
|
||||
:show-close="false"
|
||||
:close-on-click-modal="false"
|
||||
:close-on-press-escape="false"
|
||||
:before-close="handleBeforeClose"
|
||||
center
|
||||
>
|
||||
<el-form>
|
||||
<el-form-item class="role-form-item">
|
||||
<el-radio-group v-model="radio" class="role-radio-group" @change="handleChangeRole">
|
||||
<template v-for="(roles, groupName) in allRoleGroups" :key="groupName">
|
||||
<el-card class="role-group-card" shadow="hover">
|
||||
<template #header>
|
||||
<span class="group-name">{{ groupName }}</span>
|
||||
</template>
|
||||
<div class="role-group">
|
||||
<el-radio-button v-for="item in roles" :key="item.roleCode" :label="item.roleCode" size="small">
|
||||
{{ item.roleName }}
|
||||
</el-radio-button>
|
||||
</div>
|
||||
</el-card>
|
||||
</template>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<template v-if="!requireSelectToClose" #footer>
|
||||
<el-button @click="handleFooterClose">关 闭</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
<template v-if="!requireSelectToClose" #footer>
|
||||
<el-button @click="handleFooterClose">关 闭</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, toRef } from 'vue'
|
||||
import { listAllRole } from '/@/api/admin/role'
|
||||
import { Local, Session } from '/@/utils/storage'
|
||||
import { useMessage } from '/@/hooks/message'
|
||||
import { ref, computed, toRef } from 'vue';
|
||||
import { listAllRole } from '/@/api/admin/role';
|
||||
import { Local, Session } from '/@/utils/storage';
|
||||
import { useMessage } from '/@/hooks/message';
|
||||
|
||||
/** 弹框标题,如「角色切换」「登录角色选择」 */
|
||||
const props = withDefaults(
|
||||
defineProps<{ title?: string; requireSelectToClose?: boolean }>(),
|
||||
{ title: '角色切换', requireSelectToClose: false }
|
||||
)
|
||||
const dialogTitle = computed(() => props.title)
|
||||
const props = withDefaults(defineProps<{ title?: string; requireSelectToClose?: boolean }>(), { title: '角色切换', requireSelectToClose: false });
|
||||
const dialogTitle = computed(() => props.title);
|
||||
|
||||
const visible = ref(false)
|
||||
const radio = ref('')
|
||||
const visible = ref(false);
|
||||
const radio = ref('');
|
||||
/** 按分组名分组的角色列表:{ "未分组": [{ roleId, roleName, roleCode, ... }], ... } */
|
||||
const allRoleGroups = ref<Record<string, any[]>>({})
|
||||
const requireSelectToClose = toRef(props, 'requireSelectToClose')
|
||||
const allRoleGroups = ref<Record<string, any[]>>({});
|
||||
const requireSelectToClose = toRef(props, 'requireSelectToClose');
|
||||
|
||||
const open = () => {
|
||||
if (visible.value) return
|
||||
visible.value = true
|
||||
listAllRole().then((res) => {
|
||||
allRoleGroups.value = res.data && typeof res.data === 'object' && !Array.isArray(res.data)
|
||||
? res.data
|
||||
: { '未分组': Array.isArray(res.data) ? res.data : [] }
|
||||
radio.value = Local.get('roleCode')
|
||||
})
|
||||
}
|
||||
if (visible.value) return;
|
||||
visible.value = true;
|
||||
listAllRole().then((res) => {
|
||||
allRoleGroups.value =
|
||||
res.data && typeof res.data === 'object' && !Array.isArray(res.data) ? res.data : { 未分组: Array.isArray(res.data) ? res.data : [] };
|
||||
radio.value = Local.get('roleCode');
|
||||
});
|
||||
};
|
||||
|
||||
/** 根据 roleCode 从分组数据中查找角色 */
|
||||
const findRoleByCode = (code: string) => {
|
||||
for (const roles of Object.values(allRoleGroups.value)) {
|
||||
if (!Array.isArray(roles)) continue
|
||||
const found = roles.find((r: any) => r.roleCode === code)
|
||||
if (found) return found
|
||||
}
|
||||
return null
|
||||
}
|
||||
for (const roles of Object.values(allRoleGroups.value)) {
|
||||
if (!Array.isArray(roles)) continue;
|
||||
const found = roles.find((r: any) => r.roleCode === code);
|
||||
if (found) return found;
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
const canClose = () => {
|
||||
if (!radio.value) {
|
||||
useMessage().warning('请选择一个角色')
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
if (!radio.value) {
|
||||
useMessage().warning('请选择一个角色');
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
const handleBeforeClose = (done: () => void) => {
|
||||
if (requireSelectToClose.value) {
|
||||
useMessage().warning('请先选择登录角色')
|
||||
return
|
||||
}
|
||||
if (!canClose()) return
|
||||
done()
|
||||
}
|
||||
if (requireSelectToClose.value) {
|
||||
useMessage().warning('请先选择登录角色');
|
||||
return;
|
||||
}
|
||||
if (!canClose()) return;
|
||||
done();
|
||||
};
|
||||
|
||||
const handleFooterClose = () => {
|
||||
if (!canClose()) return
|
||||
visible.value = false
|
||||
}
|
||||
if (!canClose()) return;
|
||||
visible.value = false;
|
||||
};
|
||||
|
||||
const handleChangeRole = (label: string) => {
|
||||
const obj = findRoleByCode(label)
|
||||
if (!obj) return
|
||||
Local.set('roleCode', obj.roleCode)
|
||||
Local.set('roleName', obj.roleName)
|
||||
Local.set('roleId', obj.roleId)
|
||||
useMessage().success('操作成功')
|
||||
// 清掉 tags 缓存,重载后只保留首页 tag
|
||||
Session.remove('tagsViewList')
|
||||
// 清除 pinia 持久化的 tagsView 路由,避免重载后先恢复旧角色菜单再被新路由覆盖前就初始化出“不存在的 tag”
|
||||
try {
|
||||
window.localStorage.removeItem('tagsViewRoutes')
|
||||
} catch (_) {}
|
||||
setTimeout(() => {
|
||||
window.location.hash = '#/home'
|
||||
window.location.reload()
|
||||
}, 500)
|
||||
}
|
||||
const obj = findRoleByCode(label);
|
||||
if (!obj) return;
|
||||
Local.set('roleCode', obj.roleCode);
|
||||
Local.set('roleName', obj.roleName);
|
||||
Local.set('roleId', obj.roleId);
|
||||
useMessage().success('操作成功');
|
||||
// 清掉 tags 缓存,重载后只保留首页 tag
|
||||
Session.remove('tagsViewList');
|
||||
// 清除 pinia 持久化的 tagsView 路由,避免重载后先恢复旧角色菜单再被新路由覆盖前就初始化出“不存在的 tag”
|
||||
try {
|
||||
window.localStorage.removeItem('tagsViewRoutes');
|
||||
} catch (_) {}
|
||||
setTimeout(() => {
|
||||
window.location.hash = '#/home';
|
||||
window.location.reload();
|
||||
}, 500);
|
||||
};
|
||||
|
||||
defineExpose({
|
||||
open
|
||||
})
|
||||
open,
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.role-form-item {
|
||||
:deep(.el-form-item__content) {
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
:deep(.el-form-item__content) {
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
}
|
||||
.role-radio-group {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 6px;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 6px;
|
||||
width: 100%;
|
||||
|
||||
:deep(.el-radio-button) {
|
||||
margin: 0;
|
||||
}
|
||||
:deep(.el-radio-button__inner) {
|
||||
border-radius: 6px !important;
|
||||
border: 1px solid var(--el-border-color) !important;
|
||||
margin-left: 0 !important;
|
||||
line-height: 1.3;
|
||||
}
|
||||
:deep(.el-radio-button.is-active .el-radio-button__inner) {
|
||||
border-color: var(--el-color-primary) !important;
|
||||
}
|
||||
:deep(.el-radio-button) {
|
||||
margin: 0;
|
||||
}
|
||||
:deep(.el-radio-button__inner) {
|
||||
border-radius: 6px !important;
|
||||
border: 1px solid var(--el-border-color) !important;
|
||||
margin-left: 0 !important;
|
||||
line-height: 1.3;
|
||||
}
|
||||
:deep(.el-radio-button.is-active .el-radio-button__inner) {
|
||||
border-color: var(--el-color-primary) !important;
|
||||
}
|
||||
}
|
||||
.role-group-card {
|
||||
width: 100%;
|
||||
flex: 0 0 auto;
|
||||
width: 100%;
|
||||
flex: 0 0 auto;
|
||||
|
||||
:deep(.el-card__header) {
|
||||
padding: 6px 12px;
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: var(--el-text-color-primary);
|
||||
}
|
||||
:deep(.el-card__body) {
|
||||
padding: 6px 12px 8px;
|
||||
}
|
||||
:deep(.el-card__header) {
|
||||
padding: 6px 12px;
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: var(--el-text-color-primary);
|
||||
}
|
||||
:deep(.el-card__body) {
|
||||
padding: 6px 12px 8px;
|
||||
}
|
||||
}
|
||||
.role-group {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
gap: 4px 8px;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
gap: 4px 8px;
|
||||
}
|
||||
.group-name {
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: var(--el-text-color-primary);
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: var(--el-text-color-primary);
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
||||
@@ -47,7 +47,6 @@
|
||||
style="width: 100%"
|
||||
row-key="roleId"
|
||||
:tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
|
||||
|
||||
@selection-change="handleSelectionChange"
|
||||
border
|
||||
:cell-style="tableStyle.cellStyle"
|
||||
@@ -67,7 +66,7 @@
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="roleSort" label="排序" width="80" align="center">
|
||||
<template #default="scope">{{ scope.row._isGroup ? '—' : (scope.row.roleSort ?? 0) }}</template>
|
||||
<template #default="scope">{{ scope.row._isGroup ? '—' : scope.row.roleSort ?? 0 }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="roleCode" :label="$t('sysrole.roleCode')" show-overflow-tooltip min-width="120">
|
||||
<template #default="scope">{{ scope.row._isGroup ? '—' : scope.row.roleCode }}</template>
|
||||
@@ -133,9 +132,18 @@
|
||||
title="批量指定关联用户"
|
||||
width="720px"
|
||||
destroy-on-close
|
||||
@close="assignUserKeyword = ''; assignUserType = ''; assignUserList = []; assignUserTree = []; assignSelectedIds = []">
|
||||
@close="
|
||||
assignUserKeyword = '';
|
||||
assignUserType = '';
|
||||
assignUserList = [];
|
||||
assignUserTree = [];
|
||||
assignSelectedIds = [];
|
||||
"
|
||||
>
|
||||
<template v-if="assignCurrentRole">
|
||||
<div class="mb12"><el-text type="info">当前角色:{{ assignCurrentRole.roleName }}({{ assignCurrentRole.roleCode }})</el-text></div>
|
||||
<div class="mb12">
|
||||
<el-text type="info">当前角色:{{ assignCurrentRole.roleName }}({{ assignCurrentRole.roleCode }})</el-text>
|
||||
</div>
|
||||
<el-form :inline="true" class="mb12">
|
||||
<el-form-item label="用户类型" required>
|
||||
<el-radio-group v-model="assignUserType">
|
||||
@@ -161,7 +169,8 @@
|
||||
v-loading="assignUserLoading"
|
||||
max-height="360"
|
||||
border
|
||||
@selection-change="handleAssignUserSelectionChange">
|
||||
@selection-change="handleAssignUserSelectionChange"
|
||||
>
|
||||
<el-table-column type="selection" width="50" align="left" :selectable="(row: any) => !row._isDept" />
|
||||
<el-table-column prop="label" label="部门 / 姓名" min-width="200">
|
||||
<template #default="{ row }">
|
||||
@@ -173,20 +182,24 @@
|
||||
<template #default="{ row }">{{ row._isDept ? '—' : row.username }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="deptName" label="部门" width="140">
|
||||
<template #default="{ row }">{{ row._isDept ? '—' : (row.deptName || '—') }}</template>
|
||||
<template #default="{ row }">{{ row._isDept ? '—' : row.deptName || '—' }}</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</template>
|
||||
<template #footer>
|
||||
<el-button @click="showAssignUserDialog = false">取消</el-button>
|
||||
<el-button type="primary" :loading="assignSubmitLoading" :disabled="assignSelectedIds.length === 0" @click="handleAssignUsersSubmit">确定(已选 {{ assignSelectedIds.length }} 人)</el-button>
|
||||
<el-button type="primary" :loading="assignSubmitLoading" :disabled="assignSelectedIds.length === 0" @click="handleAssignUsersSubmit"
|
||||
>确定(已选 {{ assignSelectedIds.length }} 人)</el-button
|
||||
>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 查看角色关联用户弹窗 -->
|
||||
<el-dialog v-model="showRoleUsersDialog" title="关联用户" width="560px" destroy-on-close>
|
||||
<template v-if="currentRoleForUsers">
|
||||
<div class="mb12"><el-text type="info">角色:{{ currentRoleForUsers.roleName }}({{ currentRoleForUsers.roleCode }})</el-text></div>
|
||||
<div class="mb12">
|
||||
<el-text type="info">角色:{{ currentRoleForUsers.roleName }}({{ currentRoleForUsers.roleCode }})</el-text>
|
||||
</div>
|
||||
<el-table :data="roleUsersList" v-loading="roleUsersLoading" max-height="400" border>
|
||||
<el-table-column prop="deptName" label="部门" min-width="140" show-overflow-tooltip />
|
||||
<el-table-column prop="realName" label="姓名" width="100" show-overflow-tooltip />
|
||||
@@ -298,9 +311,7 @@ const state: BasicTableProps = reactive<BasicTableProps>({
|
||||
const kw = String(params.roleName).trim().toLowerCase();
|
||||
if (kw) {
|
||||
data = data.filter(
|
||||
(r: any) =>
|
||||
(r.roleName && r.roleName.toLowerCase().includes(kw)) ||
|
||||
(r.roleCode && r.roleCode.toLowerCase().includes(kw))
|
||||
(r: any) => (r.roleName && r.roleName.toLowerCase().includes(kw)) || (r.roleCode && r.roleCode.toLowerCase().includes(kw))
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -353,10 +364,10 @@ const dictType = ref([
|
||||
label: '本级',
|
||||
value: '3',
|
||||
},
|
||||
{
|
||||
label: '本人',
|
||||
value: '4',
|
||||
},
|
||||
{
|
||||
label: '本人',
|
||||
value: '4',
|
||||
},
|
||||
]);
|
||||
|
||||
// table hook(无分页,不暴露 currentChangeHandle/sizeChangeHandle)
|
||||
@@ -370,7 +381,7 @@ const resetQuery = () => {
|
||||
|
||||
// 导出excel
|
||||
const exportExcel = () => {
|
||||
downBlobFile('/admin/role/export',Object.assign(state.queryForm,{ids:selectObjs}), 'role.xlsx');
|
||||
downBlobFile('/admin/role/export', Object.assign(state.queryForm, { ids: selectObjs }), 'role.xlsx');
|
||||
};
|
||||
|
||||
// 是否可以多选(分组行不可选,管理员角色不可选)
|
||||
@@ -470,9 +481,7 @@ async function loadAssignUserList() {
|
||||
}
|
||||
|
||||
function handleAssignUserSelectionChange(rows: any[]) {
|
||||
assignSelectedIds.value = (rows || [])
|
||||
.filter((r: any) => !r._isDept && r.userId)
|
||||
.map((r: any) => r.userId);
|
||||
assignSelectedIds.value = (rows || []).filter((r: any) => !r._isDept && r.userId).map((r: any) => r.userId);
|
||||
}
|
||||
|
||||
async function handleAssignUsersSubmit() {
|
||||
@@ -520,9 +529,21 @@ const handleBatchGroup = async () => {
|
||||
font-weight: 600;
|
||||
color: var(--el-text-color-primary);
|
||||
}
|
||||
.mb12 { margin-bottom: 12px; }
|
||||
.mb8 { margin-bottom: 8px; }
|
||||
.mt8 { margin-top: 8px; }
|
||||
.assign-user-tip { color: var(--el-text-color-secondary); font-size: 13px; }
|
||||
.dept-row { font-weight: 600; color: var(--el-text-color-primary); }
|
||||
.mb12 {
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
.mb8 {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
.mt8 {
|
||||
margin-top: 8px;
|
||||
}
|
||||
.assign-user-tip {
|
||||
color: var(--el-text-color-secondary);
|
||||
font-size: 13px;
|
||||
}
|
||||
.dept-row {
|
||||
font-weight: 600;
|
||||
color: var(--el-text-color-primary);
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -15,12 +15,24 @@
|
||||
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item :label="t('tenant.startTime')" prop="startTime">
|
||||
<el-date-picker class="!w-full" v-model="form.startTime" type="date" :placeholder="t('tenant.inputstartTimeTip')" :value-format="dateTimeStr" />
|
||||
<el-date-picker
|
||||
class="!w-full"
|
||||
v-model="form.startTime"
|
||||
type="date"
|
||||
:placeholder="t('tenant.inputstartTimeTip')"
|
||||
:value-format="dateTimeStr"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item :label="t('tenant.endTime')" prop="endTime">
|
||||
<el-date-picker class="!w-full" v-model="form.endTime" type="date" :placeholder="t('tenant.inputendTimeTip')" :value-format="dateTimeStr" />
|
||||
<el-date-picker
|
||||
class="!w-full"
|
||||
v-model="form.endTime"
|
||||
type="date"
|
||||
:placeholder="t('tenant.inputendTimeTip')"
|
||||
:value-format="dateTimeStr"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12" class="mb20">
|
||||
@@ -71,11 +83,11 @@
|
||||
import { validateTenantCode, validateTenantName } from '/@/api/admin/tenant';
|
||||
import { useDict } from '/@/hooks/dict';
|
||||
import { useMessage } from '/@/hooks/message';
|
||||
import { getObj, addObj, putObj, treemenu,fetchList } from '/@/api/admin/tenant';
|
||||
import { getObj, addObj, putObj, treemenu, fetchList } from '/@/api/admin/tenant';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import other from '/@/utils/other';
|
||||
import { CheckboxValueType } from 'element-plus';
|
||||
import {rule} from "/@/utils/validate";
|
||||
import { rule } from '/@/utils/validate';
|
||||
|
||||
// 定义子组件向父组件传值/事件
|
||||
const emit = defineEmits(['refresh']);
|
||||
@@ -120,7 +132,7 @@ const checkedMenu = ref<any[]>([]);
|
||||
// 定义校验规则
|
||||
const dataRules = ref({
|
||||
name: [
|
||||
{ validator: rule.overLength, trigger: 'blur' },
|
||||
{ validator: rule.overLength, trigger: 'blur' },
|
||||
{ required: true, message: '名称不能为空', trigger: 'blur' },
|
||||
{
|
||||
validator: (rule: any, value: any, callback: any) => {
|
||||
@@ -130,7 +142,7 @@ const dataRules = ref({
|
||||
},
|
||||
],
|
||||
code: [
|
||||
{ validator: rule.overLength, trigger: 'blur' },
|
||||
{ validator: rule.overLength, trigger: 'blur' },
|
||||
{ required: true, message: '编码不能为空', trigger: 'blur' },
|
||||
{
|
||||
validator: (rule: any, value: any, callback: any) => {
|
||||
@@ -183,7 +195,7 @@ const onSubmit = async () => {
|
||||
}
|
||||
|
||||
if (menuTreeRef.value?.getCheckedKeys()) {
|
||||
let checkMenu = [...menuTreeRef.value.getCheckedKeys(), ...menuTreeRef.value.getHalfCheckedKeys()]
|
||||
let checkMenu = [...menuTreeRef.value.getCheckedKeys(), ...menuTreeRef.value.getHalfCheckedKeys()];
|
||||
|
||||
if (!checkMenu.includes('1300')) {
|
||||
useMessage().error('必须分配角色管理功能');
|
||||
@@ -207,7 +219,7 @@ const onSubmit = async () => {
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg);
|
||||
} finally {
|
||||
await fetchList()
|
||||
await fetchList();
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,53 +1,53 @@
|
||||
export default {
|
||||
tenant: {
|
||||
index: '#',
|
||||
importTenantTip: '导入租户',
|
||||
id: '租户id',
|
||||
name: '租户名称',
|
||||
code: '编码',
|
||||
tenantDomain: '域名',
|
||||
startTime: '开始时间',
|
||||
endTime: '结束时间',
|
||||
status: '状态',
|
||||
delFlag: 'delFlag',
|
||||
createBy: '创建人',
|
||||
updateBy: '修改人',
|
||||
createTime: '创建',
|
||||
updateTime: '更新时间',
|
||||
menuId: '租户套餐',
|
||||
individuationBtn: '个性化',
|
||||
inputidTip: '请输入租户id',
|
||||
inputnameTip: '请输入名称',
|
||||
inputcodeTip: '请输入编码',
|
||||
inputtenantDomainTip: '请输入域名',
|
||||
inputstartTimeTip: '请输入开始时间',
|
||||
inputendTimeTip: '请输入结束时间',
|
||||
inputstatusTip: '请输入status',
|
||||
inputdelFlagTip: '请输入delFlag',
|
||||
inputcreateByTip: '请输入创建人',
|
||||
inputupdateByTip: '请输入修改人',
|
||||
inputcreateTimeTip: '请输入创建',
|
||||
inputupdateTimeTip: '请输入更新时间',
|
||||
inputmenuIdTip: '请选择租户套餐',
|
||||
deleteDisabledTip: '基础租户不允许删除',
|
||||
},
|
||||
tenantmenu: {
|
||||
name: '套餐',
|
||||
index: '#',
|
||||
status: '状态',
|
||||
createTime: '创建',
|
||||
},
|
||||
tenant: {
|
||||
index: '#',
|
||||
importTenantTip: '导入租户',
|
||||
id: '租户id',
|
||||
name: '租户名称',
|
||||
code: '编码',
|
||||
tenantDomain: '域名',
|
||||
startTime: '开始时间',
|
||||
endTime: '结束时间',
|
||||
status: '状态',
|
||||
delFlag: 'delFlag',
|
||||
createBy: '创建人',
|
||||
updateBy: '修改人',
|
||||
createTime: '创建',
|
||||
updateTime: '更新时间',
|
||||
menuId: '租户套餐',
|
||||
individuationBtn: '个性化',
|
||||
inputidTip: '请输入租户id',
|
||||
inputnameTip: '请输入名称',
|
||||
inputcodeTip: '请输入编码',
|
||||
inputtenantDomainTip: '请输入域名',
|
||||
inputstartTimeTip: '请输入开始时间',
|
||||
inputendTimeTip: '请输入结束时间',
|
||||
inputstatusTip: '请输入status',
|
||||
inputdelFlagTip: '请输入delFlag',
|
||||
inputcreateByTip: '请输入创建人',
|
||||
inputupdateByTip: '请输入修改人',
|
||||
inputcreateTimeTip: '请输入创建',
|
||||
inputupdateTimeTip: '请输入更新时间',
|
||||
inputmenuIdTip: '请选择租户套餐',
|
||||
deleteDisabledTip: '基础租户不允许删除',
|
||||
},
|
||||
tenantmenu: {
|
||||
name: '套餐',
|
||||
index: '#',
|
||||
status: '状态',
|
||||
createTime: '创建',
|
||||
},
|
||||
|
||||
individuation: {
|
||||
websiteName: '网站名称',
|
||||
miniQr: '移动端二维码',
|
||||
logo: '网站图标',
|
||||
footerAuthor: '页脚信息',
|
||||
background: '登录页背景图',
|
||||
inputIndividuationNameTip: '请输入网站名称',
|
||||
inputMiniQrTip: '请输入网站图标',
|
||||
inputLogoTip: '请输入网站Logo',
|
||||
inputFooterAuthorTip: '请输入页脚信息',
|
||||
inputBackgroundTip: '请输入登录页背景图',
|
||||
}
|
||||
individuation: {
|
||||
websiteName: '网站名称',
|
||||
miniQr: '移动端二维码',
|
||||
logo: '网站图标',
|
||||
footerAuthor: '页脚信息',
|
||||
background: '登录页背景图',
|
||||
inputIndividuationNameTip: '请输入网站名称',
|
||||
inputMiniQrTip: '请输入网站图标',
|
||||
inputLogoTip: '请输入网站Logo',
|
||||
inputFooterAuthorTip: '请输入页脚信息',
|
||||
inputBackgroundTip: '请输入登录页背景图',
|
||||
},
|
||||
};
|
||||
|
||||
@@ -1,60 +1,60 @@
|
||||
<template>
|
||||
<el-drawer :title="$t('tenant.individuationBtn')" v-model="visible" :close-on-click-modal="false">
|
||||
<el-form ref="dataFormRef" :model="form" :rules="dataRules" v-loading="loading">
|
||||
<el-row>
|
||||
<el-col :span="24" class="mt-4">
|
||||
<el-form-item :label="t('individuation.websiteName')" prop="websiteName" label-width="120px" align="left">
|
||||
<el-input v-model="form.websiteName" :placeholder="t('individuation.inputIndividuationNameTip')"/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24" class="mt-4">
|
||||
<el-form-item prop="footerAuthor" label-width="120px" align="left">
|
||||
<template #label>
|
||||
{{ t('individuation.footerAuthor') }}
|
||||
<tip content="浏览器底部版权信息、备案信息"/>
|
||||
</template>
|
||||
<el-input v-model="form.footer" :placeholder="t('individuation.inputFooterAuthorTip')"/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24" class="mt-4">
|
||||
<el-form-item prop="icon" label-width="120px" align="left">
|
||||
<template #label>
|
||||
{{ t('individuation.miniQr') }}
|
||||
<tip content="登录页右下角显示的移动端二维码"/>
|
||||
</template>
|
||||
<upload-img v-model:image-url="form.miniQr"/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24" class="mt-4">
|
||||
<el-form-item :label="t('individuation.background')" prop="background" label-width="120px" align="left">
|
||||
<upload-img v-model:image-url="form.background"/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-drawer :title="$t('tenant.individuationBtn')" v-model="visible" :close-on-click-modal="false">
|
||||
<el-form ref="dataFormRef" :model="form" :rules="dataRules" v-loading="loading">
|
||||
<el-row>
|
||||
<el-col :span="24" class="mt-4">
|
||||
<el-form-item :label="t('individuation.websiteName')" prop="websiteName" label-width="120px" align="left">
|
||||
<el-input v-model="form.websiteName" :placeholder="t('individuation.inputIndividuationNameTip')" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24" class="mt-4">
|
||||
<el-form-item prop="footerAuthor" label-width="120px" align="left">
|
||||
<template #label>
|
||||
{{ t('individuation.footerAuthor') }}
|
||||
<tip content="浏览器底部版权信息、备案信息" />
|
||||
</template>
|
||||
<el-input v-model="form.footer" :placeholder="t('individuation.inputFooterAuthorTip')" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24" class="mt-4">
|
||||
<el-form-item prop="icon" label-width="120px" align="left">
|
||||
<template #label>
|
||||
{{ t('individuation.miniQr') }}
|
||||
<tip content="登录页右下角显示的移动端二维码" />
|
||||
</template>
|
||||
<upload-img v-model:image-url="form.miniQr" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24" class="mt-4">
|
||||
<el-form-item :label="t('individuation.background')" prop="background" label-width="120px" align="left">
|
||||
<upload-img v-model:image-url="form.background" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="visible = false">{{ $t('common.cancelButtonText') }}</el-button>
|
||||
<el-button type="primary" @click="onSubmit" :disabled="loading">{{ $t('common.confirmButtonText') }}</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-drawer>
|
||||
</template>
|
||||
</el-drawer>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="systemTenantDialog">
|
||||
import {useDict} from '/@/hooks/dict';
|
||||
import {useMessage} from '/@/hooks/message';
|
||||
import {getObj, putObj} from '/@/api/admin/tenant';
|
||||
import {useI18n} from 'vue-i18n';
|
||||
import UploadImg from "/@/components/Upload/Image.vue";
|
||||
import {useThemeConfig} from "/@/stores/themeConfig";
|
||||
import pinia from "/@/stores";
|
||||
import {storeToRefs} from "pinia";
|
||||
import Tip from "/@/components/Tip/index.vue";
|
||||
import { useDict } from '/@/hooks/dict';
|
||||
import { useMessage } from '/@/hooks/message';
|
||||
import { getObj, putObj } from '/@/api/admin/tenant';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import UploadImg from '/@/components/Upload/Image.vue';
|
||||
import { useThemeConfig } from '/@/stores/themeConfig';
|
||||
import pinia from '/@/stores';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import Tip from '/@/components/Tip/index.vue';
|
||||
|
||||
// 定义子组件向父组件传值/事件
|
||||
const emit = defineEmits(['refresh']);
|
||||
const {t} = useI18n();
|
||||
const { t } = useI18n();
|
||||
|
||||
// 定义变量内容
|
||||
const dataFormRef = ref();
|
||||
@@ -62,42 +62,38 @@ const visible = ref(false);
|
||||
const loading = ref(false);
|
||||
|
||||
// 字典
|
||||
const {status_type} = useDict('status_type');
|
||||
const { status_type } = useDict('status_type');
|
||||
|
||||
// 导入配置文件
|
||||
const stores = useThemeConfig(pinia);
|
||||
const {themeConfig} = storeToRefs(stores);
|
||||
const { themeConfig } = storeToRefs(stores);
|
||||
|
||||
// 提交表单数据
|
||||
const form = reactive({
|
||||
id: '',
|
||||
websiteName: themeConfig.value.globalTitle,
|
||||
background: '',
|
||||
miniQr: '',
|
||||
footer: themeConfig.value.footerAuthor,
|
||||
id: '',
|
||||
websiteName: themeConfig.value.globalTitle,
|
||||
background: '',
|
||||
miniQr: '',
|
||||
footer: themeConfig.value.footerAuthor,
|
||||
});
|
||||
|
||||
|
||||
// 定义校验规则
|
||||
const dataRules = ref({
|
||||
});
|
||||
const dataRules = ref({});
|
||||
|
||||
// 打开弹窗
|
||||
const openDialog = (id: string): void => {
|
||||
visible.value = true;
|
||||
form.id = ''
|
||||
visible.value = true;
|
||||
form.id = '';
|
||||
|
||||
// 重置表单数据
|
||||
nextTick(() => {
|
||||
dataFormRef.value?.resetFields();
|
||||
});
|
||||
|
||||
// 重置表单数据
|
||||
nextTick(() => {
|
||||
dataFormRef.value?.resetFields();
|
||||
});
|
||||
|
||||
if (id) {
|
||||
form.id = id;
|
||||
getTenantData(id);
|
||||
}
|
||||
|
||||
if (id) {
|
||||
form.id = id;
|
||||
getTenantData(id);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -105,33 +101,30 @@ const openDialog = (id: string): void => {
|
||||
* @param {string} id - 部门 ID。
|
||||
*/
|
||||
const getTenantData = async (id: any) => {
|
||||
const res = await getObj(id);
|
||||
Object.assign(form, res.data);
|
||||
const res = await getObj(id);
|
||||
Object.assign(form, res.data);
|
||||
};
|
||||
|
||||
|
||||
// 提交
|
||||
const onSubmit = async () => {
|
||||
const valid = await dataFormRef.value.validate().catch(() => {
|
||||
});
|
||||
if (!valid) return false;
|
||||
const valid = await dataFormRef.value.validate().catch(() => {});
|
||||
if (!valid) return false;
|
||||
|
||||
try {
|
||||
loading.value = true;
|
||||
await putObj(form);
|
||||
useMessage().success(t('common.editSuccessText'));
|
||||
visible.value = false;
|
||||
emit('refresh');
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg);
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
try {
|
||||
loading.value = true;
|
||||
await putObj(form);
|
||||
useMessage().success(t('common.editSuccessText'));
|
||||
visible.value = false;
|
||||
emit('refresh');
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg);
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// 暴露变量
|
||||
defineExpose({
|
||||
openDialog,
|
||||
openDialog,
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -3,41 +3,41 @@
|
||||
<el-dialog :close-on-click-modal="false" :title="dataForm.userId ? $t('common.editBtn') : $t('common.addBtn')" draggable v-model="visible">
|
||||
<el-form :model="dataForm" :rules="dataRules" label-width="90px" ref="dataFormRef" v-loading="loading">
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item :label="$t('sysuser.username')" prop="username">
|
||||
<el-input
|
||||
:disabled="dataForm.userId !== ''"
|
||||
:placeholder="$t('sysuser.inputUsernameTip')"
|
||||
v-model="dataForm.username"
|
||||
autocomplete="off"
|
||||
:readonly="formState.usernameReadonly"
|
||||
@focus="formState.usernameReadonly = false"
|
||||
></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item :label="$t('sysuser.password')" prop="password">
|
||||
<el-input
|
||||
clearable
|
||||
:placeholder="$t('sysuser.inputPasswordTip')"
|
||||
type="password"
|
||||
v-model="dataForm.password"
|
||||
autocomplete="new-password"
|
||||
:readonly="formState.passwordReadonly"
|
||||
@focus="formState.passwordReadonly = false"
|
||||
></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item :label="$t('sysuser.username')" prop="username">
|
||||
<el-input
|
||||
:disabled="dataForm.userId !== ''"
|
||||
:placeholder="$t('sysuser.inputUsernameTip')"
|
||||
v-model="dataForm.username"
|
||||
autocomplete="off"
|
||||
:readonly="formState.usernameReadonly"
|
||||
@focus="formState.usernameReadonly = false"
|
||||
></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item :label="$t('sysuser.password')" prop="password">
|
||||
<el-input
|
||||
clearable
|
||||
:placeholder="$t('sysuser.inputPasswordTip')"
|
||||
type="password"
|
||||
v-model="dataForm.password"
|
||||
autocomplete="new-password"
|
||||
:readonly="formState.passwordReadonly"
|
||||
@focus="formState.passwordReadonly = false"
|
||||
></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item :label="$t('sysuser.name')" prop="realName">
|
||||
<el-input clearable :placeholder="$t('sysuser.inputNameTip')" v-model="dataForm.realName"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<!-- <el-col :span="12" class="mb20">-->
|
||||
<!-- <el-form-item :label="$t('sysuser.phone')" prop="phone">-->
|
||||
<!-- <el-input clearable :placeholder="$t('sysuser.inputPhoneTip')" v-model="dataForm.phone"></el-input>-->
|
||||
<!-- </el-form-item>-->
|
||||
<!-- </el-col>-->
|
||||
<!-- <el-col :span="12" class="mb20">-->
|
||||
<!-- <el-form-item :label="$t('sysuser.phone')" prop="phone">-->
|
||||
<!-- <el-input clearable :placeholder="$t('sysuser.inputPhoneTip')" v-model="dataForm.phone"></el-input>-->
|
||||
<!-- </el-form-item>-->
|
||||
<!-- </el-col>-->
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item :label="$t('sysuser.role')" prop="role">
|
||||
<el-select clearable multiple :placeholder="$t('sysuser.selectRole')" v-model="dataForm.role" filterable>
|
||||
@@ -45,13 +45,13 @@
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<!-- <el-col :span="12" class="mb20">-->
|
||||
<!-- <el-form-item :label="$t('sysuser.post')" prop="post">-->
|
||||
<!-- <el-select clearable multiple :placeholder="$t('sysuser.selectPost')" v-model="dataForm.post">-->
|
||||
<!-- <el-option :key="item.postId" :label="item.postName" :value="item.postId" v-for="item in postData" />-->
|
||||
<!-- </el-select>-->
|
||||
<!-- </el-form-item>-->
|
||||
<!-- </el-col>-->
|
||||
<!-- <el-col :span="12" class="mb20">-->
|
||||
<!-- <el-form-item :label="$t('sysuser.post')" prop="post">-->
|
||||
<!-- <el-select clearable multiple :placeholder="$t('sysuser.selectPost')" v-model="dataForm.post">-->
|
||||
<!-- <el-option :key="item.postId" :label="item.postName" :value="item.postId" v-for="item in postData" />-->
|
||||
<!-- </el-select>-->
|
||||
<!-- </el-form-item>-->
|
||||
<!-- </el-col>-->
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item :label="$t('sysuser.dept')" prop="deptId">
|
||||
<el-tree-select
|
||||
@@ -67,11 +67,11 @@
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
<!-- <el-col :span="12" class="mb20">-->
|
||||
<!-- <el-form-item :label="$t('sysuser.email')" prop="email">-->
|
||||
<!-- <el-input clearable :placeholder="$t('sysuser.inputEmailTip')" v-model="dataForm.email"></el-input>-->
|
||||
<!-- </el-form-item>-->
|
||||
<!-- </el-col>-->
|
||||
<!-- <el-col :span="12" class="mb20">-->
|
||||
<!-- <el-form-item :label="$t('sysuser.email')" prop="email">-->
|
||||
<!-- <el-input clearable :placeholder="$t('sysuser.inputEmailTip')" v-model="dataForm.email"></el-input>-->
|
||||
<!-- </el-form-item>-->
|
||||
<!-- </el-col>-->
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item :label="$t('sysuser.lockFlag')" prop="lockFlag">
|
||||
<el-radio-group v-model="dataForm.lockFlag">
|
||||
@@ -135,7 +135,7 @@ const dataForm = reactive({
|
||||
deptId: '',
|
||||
roleList: [],
|
||||
postList: [],
|
||||
realName: '',
|
||||
realName: '',
|
||||
email: '',
|
||||
post: [] as string[],
|
||||
role: [] as string[],
|
||||
@@ -227,7 +227,7 @@ const onSubmit = async () => {
|
||||
// 立即设置 loading,防止重复点击
|
||||
if (loading.value) return;
|
||||
loading.value = true;
|
||||
|
||||
|
||||
try {
|
||||
const valid = await dataFormRef.value.validate().catch(() => {});
|
||||
if (!valid) {
|
||||
|
||||
@@ -79,12 +79,12 @@
|
||||
<el-table-column :label="$t('sysuser.index')" type="index" width="60" fixed="left" />
|
||||
<el-table-column :label="$t('sysuser.username')" prop="username" fixed="left" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column :label="$t('sysuser.name')" prop="realName" show-overflow-tooltip></el-table-column>
|
||||
<!-- <el-table-column :label="$t('sysuser.phone')" prop="phone" show-overflow-tooltip></el-table-column>-->
|
||||
<!-- <el-table-column :label="$t('sysuser.post')" show-overflow-tooltip>-->
|
||||
<!-- <template #default="scope">-->
|
||||
<!-- <el-tag v-for="(item, index) in scope.row.postList" :key="index">{{ item.postName }}</el-tag>-->
|
||||
<!-- </template>-->
|
||||
<!-- </el-table-column>-->
|
||||
<!-- <el-table-column :label="$t('sysuser.phone')" prop="phone" show-overflow-tooltip></el-table-column>-->
|
||||
<!-- <el-table-column :label="$t('sysuser.post')" show-overflow-tooltip>-->
|
||||
<!-- <template #default="scope">-->
|
||||
<!-- <el-tag v-for="(item, index) in scope.row.postList" :key="index">{{ item.postName }}</el-tag>-->
|
||||
<!-- </template>-->
|
||||
<!-- </el-table-column>-->
|
||||
<el-table-column :label="$t('sysuser.role')" show-overflow-tooltip>
|
||||
<template #default="scope">
|
||||
<el-tag v-for="(item, index) in scope.row.roleList" :key="index">{{ item.roleName }}</el-tag>
|
||||
|
||||
@@ -2,12 +2,16 @@
|
||||
<el-drawer v-model="visible" :title="$t('personal.name')" size="40%">
|
||||
<el-tabs style="height: 200px" class="demo-tabs">
|
||||
<el-tab-pane label="基本信息" v-loading="loading">
|
||||
<template #label>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-4">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M17.982 18.725A7.488 7.488 0 0 0 12 15.75a7.488 7.488 0 0 0-5.982 2.975m11.963 0a9 9 0 1 0-11.963 0m11.963 0A8.966 8.966 0 0 1 12 21a8.966 8.966 0 0 1-5.982-2.275M15 9.75a3 3 0 1 1-6 0 3 3 0 0 1 6 0Z" />
|
||||
</svg>
|
||||
基本信息
|
||||
</template>
|
||||
<template #label>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-4">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
d="M17.982 18.725A7.488 7.488 0 0 0 12 15.75a7.488 7.488 0 0 0-5.982 2.975m11.963 0a9 9 0 1 0-11.963 0m11.963 0A8.966 8.966 0 0 1 12 21a8.966 8.966 0 0 1-5.982-2.275M15 9.75a3 3 0 1 1-6 0 3 3 0 0 1 6 0Z"
|
||||
/>
|
||||
</svg>
|
||||
基本信息
|
||||
</template>
|
||||
<el-form :model="formData" :rules="ruleForm" label-width="100px" class="mt30" ref="formdataRef">
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="24" class="mb20">
|
||||
@@ -55,26 +59,36 @@
|
||||
</el-form>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="安全信息">
|
||||
<template #label>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-4">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M9 12.75 11.25 15 15 9.75m-3-7.036A11.959 11.959 0 0 1 3.598 6 11.99 11.99 0 0 0 3 9.749c0 5.592 3.824 10.29 9 11.623 5.176-1.332 9-6.03 9-11.622 0-1.31-.21-2.571-.598-3.751h-.152c-3.196 0-6.1-1.248-8.25-3.285Z" />
|
||||
</svg>
|
||||
安全信息
|
||||
</template>
|
||||
<template #label>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-4">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
d="M9 12.75 11.25 15 15 9.75m-3-7.036A11.959 11.959 0 0 1 3.598 6 11.99 11.99 0 0 0 3 9.749c0 5.592 3.824 10.29 9 11.623 5.176-1.332 9-6.03 9-11.622 0-1.31-.21-2.571-.598-3.751h-.152c-3.196 0-6.1-1.248-8.25-3.285Z"
|
||||
/>
|
||||
</svg>
|
||||
安全信息
|
||||
</template>
|
||||
<el-form :model="passwordFormData" :rules="passwordRuleForm" label-width="100px" class="mt30" ref="passwordFormdataRef">
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="24" class="mb20">
|
||||
<el-form-item label="原密码" prop="password">
|
||||
<el-input v-model="passwordFormData.password" :type="showPassword ? 'text' : 'password'" placeholder="请输入密码" clearable type="password">
|
||||
<template #suffix>
|
||||
<i
|
||||
class="iconfont el-input__icon login-content-password"
|
||||
:class="showPassword ? 'icon-yincangmima' : 'icon-xianshimima'"
|
||||
@click="showPassword = !showPassword"
|
||||
>
|
||||
</i>
|
||||
</template>
|
||||
</el-input>
|
||||
<el-input
|
||||
v-model="passwordFormData.password"
|
||||
:type="showPassword ? 'text' : 'password'"
|
||||
placeholder="请输入密码"
|
||||
clearable
|
||||
type="password"
|
||||
>
|
||||
<template #suffix>
|
||||
<i
|
||||
class="iconfont el-input__icon login-content-password"
|
||||
:class="showPassword ? 'icon-yincangmima' : 'icon-xianshimima'"
|
||||
@click="showPassword = !showPassword"
|
||||
>
|
||||
</i>
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24" class="mb20">
|
||||
@@ -103,13 +117,17 @@
|
||||
</el-form>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="第三方账号">
|
||||
<template #label>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-4">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M7.864 4.243A7.5 7.5 0 0 1 19.5 10.5c0 2.92-.556 5.709-1.568 8.268M5.742 6.364A7.465 7.465 0 0 0 4.5 10.5a7.464 7.464 0 0 1-1.15 3.993m1.989 3.559A11.209 11.209 0 0 0 8.25 10.5a3.75 3.75 0 1 1 7.5 0c0 .527-.021 1.049-.064 1.565M12 10.5a14.94 14.94 0 0 1-3.6 9.75m6.633-4.596a18.666 18.666 0 0 1-2.485 5.33" />
|
||||
</svg>
|
||||
<template #label>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-4">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
d="M7.864 4.243A7.5 7.5 0 0 1 19.5 10.5c0 2.92-.556 5.709-1.568 8.268M5.742 6.364A7.465 7.465 0 0 0 4.5 10.5a7.464 7.464 0 0 1-1.15 3.993m1.989 3.559A11.209 11.209 0 0 0 8.25 10.5a3.75 3.75 0 1 1 7.5 0c0 .527-.021 1.049-.064 1.565M12 10.5a14.94 14.94 0 0 1-3.6 9.75m6.633-4.596a18.666 18.666 0 0 1-2.485 5.33"
|
||||
/>
|
||||
</svg>
|
||||
|
||||
社交登录
|
||||
</template>
|
||||
社交登录
|
||||
</template>
|
||||
<el-table :data="socialList" class="mt10">
|
||||
<el-table-column type="index" label="序号" width="80"></el-table-column>
|
||||
<el-table-column prop="name" label="平台"></el-table-column>
|
||||
@@ -132,14 +150,14 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="personal">
|
||||
import {useUserInfo} from '/@/stores/userInfo';
|
||||
import {editInfo, getObj, password, unbindingUser} from '/@/api/admin/user';
|
||||
import {useMessage} from '/@/hooks/message';
|
||||
import {rule, validateNull} from '/@/utils/validate';
|
||||
import { useUserInfo } from '/@/stores/userInfo';
|
||||
import { editInfo, getObj, password, unbindingUser } from '/@/api/admin/user';
|
||||
import { useMessage } from '/@/hooks/message';
|
||||
import { rule, validateNull } from '/@/utils/validate';
|
||||
import other from '/@/utils/other';
|
||||
import {Session} from '/@/utils/storage';
|
||||
import {useI18n} from 'vue-i18n';
|
||||
import {getLoginAppList} from "/@/api/admin/social";
|
||||
import { Session } from '/@/utils/storage';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { getLoginAppList } from '/@/api/admin/social';
|
||||
import { SocialLoginEnum } from '/@/api/login';
|
||||
|
||||
const { t } = useI18n();
|
||||
@@ -177,9 +195,18 @@ const ruleForm = reactive({
|
||||
{ required: true, message: '手机号不能为空', trigger: 'blur' },
|
||||
{ validator: rule.validatePhone, trigger: 'blur' },
|
||||
],
|
||||
nickname: [{ validator: rule.overLength, trigger: 'blur' },{ required: true, message: '昵称不能为空', trigger: 'blur' }],
|
||||
email: [{ validator: rule.overLength, trigger: 'blur' },{ required: true, message: '邮箱不能为空', trigger: 'blur' }],
|
||||
name: [{ validator: rule.overLength, trigger: 'blur' },{ required: true, message: '姓名不能为空', trigger: 'blur' }],
|
||||
nickname: [
|
||||
{ validator: rule.overLength, trigger: 'blur' },
|
||||
{ required: true, message: '昵称不能为空', trigger: 'blur' },
|
||||
],
|
||||
email: [
|
||||
{ validator: rule.overLength, trigger: 'blur' },
|
||||
{ required: true, message: '邮箱不能为空', trigger: 'blur' },
|
||||
],
|
||||
name: [
|
||||
{ validator: rule.overLength, trigger: 'blur' },
|
||||
{ required: true, message: '姓名不能为空', trigger: 'blur' },
|
||||
],
|
||||
});
|
||||
const validatorPassword2 = (rule: any, value: any, callback: any) => {
|
||||
if (value !== passwordFormData.newpassword1) {
|
||||
|
||||
@@ -1,71 +1,72 @@
|
||||
<template>
|
||||
<el-dialog :title="form.id ? '编辑' : '新增'" v-model="visible"
|
||||
width="40%"
|
||||
:close-on-click-modal="false" draggable>
|
||||
<el-form ref="dataFormRef" :model="form" :rules="dataRules" formDialogRef label-width="90px" v-loading="loading">
|
||||
<el-form-item label="联系人" prop="contactName" class="mb20">
|
||||
<el-input v-model="form.contactName" placeholder="请输入联系人"/>
|
||||
</el-form-item>
|
||||
<el-dialog :title="form.id ? '编辑' : '新增'" v-model="visible" width="40%" :close-on-click-modal="false" draggable>
|
||||
<el-form ref="dataFormRef" :model="form" :rules="dataRules" formDialogRef label-width="90px" v-loading="loading">
|
||||
<el-form-item label="联系人" prop="contactName" class="mb20">
|
||||
<el-input v-model="form.contactName" placeholder="请输入联系人" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="手机号" prop="contactPhone" class="mb20">
|
||||
<el-input v-model="form.contactPhone" placeholder="请输入手机号"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="手机号" prop="contactPhone" class="mb20">
|
||||
<el-input v-model="form.contactPhone" placeholder="请输入手机号" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="备注" prop="remark" class="mb20">
|
||||
<el-input v-model="form.remark" type="textarea" rows="3" placeholder="请输入备注"/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="visible = false">取消</el-button>
|
||||
<el-button type="primary" @click="onSubmit" :disabled="loading">确认</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
<el-form-item label="备注" prop="remark" class="mb20">
|
||||
<el-input v-model="form.remark" type="textarea" rows="3" placeholder="请输入备注" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="visible = false">取消</el-button>
|
||||
<el-button type="primary" @click="onSubmit" :disabled="loading">确认</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="AppContactsDialog">
|
||||
import { useDict } from '/@/hooks/dict';
|
||||
import { useMessage } from "/@/hooks/message";
|
||||
import { getObj, addObj, putObj } from '/@/api/app/appContacts'
|
||||
import { useMessage } from '/@/hooks/message';
|
||||
import { getObj, addObj, putObj } from '/@/api/app/appContacts';
|
||||
import { rule } from '/@/utils/validate';
|
||||
const emit = defineEmits(['refresh']);
|
||||
|
||||
// 定义变量内容
|
||||
const dataFormRef = ref();
|
||||
const visible = ref(false)
|
||||
const loading = ref(false)
|
||||
const visible = ref(false);
|
||||
const loading = ref(false);
|
||||
// 定义字典
|
||||
|
||||
// 提交表单数据
|
||||
const form = reactive({
|
||||
id:'',
|
||||
contactName: '',
|
||||
contactPhone: '',
|
||||
remark: '',
|
||||
id: '',
|
||||
contactName: '',
|
||||
contactPhone: '',
|
||||
remark: '',
|
||||
});
|
||||
|
||||
// 定义校验规则
|
||||
const dataRules = ref({
|
||||
contactName: [{required: true, message: '联系人不能为空', trigger: 'blur'}],
|
||||
contactPhone: [{required: true, message: '手机号不能为空', trigger: 'blur'}, { validator: rule.mobilePhone, trigger: 'blur' }],
|
||||
})
|
||||
contactName: [{ required: true, message: '联系人不能为空', trigger: 'blur' }],
|
||||
contactPhone: [
|
||||
{ required: true, message: '手机号不能为空', trigger: 'blur' },
|
||||
{ validator: rule.mobilePhone, trigger: 'blur' },
|
||||
],
|
||||
});
|
||||
|
||||
// 打开弹窗
|
||||
const openDialog = (id: string) => {
|
||||
visible.value = true
|
||||
form.id = ''
|
||||
visible.value = true;
|
||||
form.id = '';
|
||||
|
||||
// 重置表单数据
|
||||
// 重置表单数据
|
||||
nextTick(() => {
|
||||
dataFormRef.value?.resetFields();
|
||||
});
|
||||
|
||||
// 获取appContacts信息
|
||||
if (id) {
|
||||
form.id = id
|
||||
getappContactsData(id)
|
||||
}
|
||||
// 获取appContacts信息
|
||||
if (id) {
|
||||
form.id = id;
|
||||
getappContactsData(id);
|
||||
}
|
||||
};
|
||||
|
||||
// 提交
|
||||
@@ -74,7 +75,7 @@ const onSubmit = async () => {
|
||||
if (!valid) return false;
|
||||
|
||||
try {
|
||||
loading.value = true;
|
||||
loading.value = true;
|
||||
form.id ? await putObj(form) : await addObj(form);
|
||||
useMessage().success(form.id ? '修改成功' : '添加成功');
|
||||
visible.value = false;
|
||||
@@ -82,24 +83,25 @@ const onSubmit = async () => {
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg);
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// 初始化表单数据
|
||||
const getappContactsData = (id: string) => {
|
||||
// 获取数据
|
||||
loading.value = true
|
||||
getObj(id).then((res: any) => {
|
||||
Object.assign(form, res.data)
|
||||
}).finally(() => {
|
||||
loading.value = false
|
||||
})
|
||||
// 获取数据
|
||||
loading.value = true;
|
||||
getObj(id)
|
||||
.then((res: any) => {
|
||||
Object.assign(form, res.data);
|
||||
})
|
||||
.finally(() => {
|
||||
loading.value = false;
|
||||
});
|
||||
};
|
||||
|
||||
// 暴露变量
|
||||
defineExpose({
|
||||
openDialog
|
||||
openDialog,
|
||||
});
|
||||
</script>
|
||||
</script>
|
||||
|
||||
@@ -1,67 +1,73 @@
|
||||
<template>
|
||||
<div class="layout-padding">
|
||||
<div class="layout-padding-auto layout-padding-view">
|
||||
<el-row v-show="showSearch">
|
||||
<el-form :model="state.queryForm" ref="queryRef" :inline="true" @keyup.enter="getDataList">
|
||||
<el-form-item label="联系人" prop="contactName" >
|
||||
<el-input placeholder="请输入联系人" v-model="state.queryForm.contactName" />
|
||||
</el-form-item>
|
||||
<el-form-item label="手机号" prop="contactPhone" >
|
||||
<el-input placeholder="请输入手机号" v-model="state.queryForm.contactPhone" />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button icon="search" type="primary" @click="getDataList">
|
||||
查询
|
||||
</el-button>
|
||||
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<div class="mb8" style="width: 100%">
|
||||
<el-button icon="folder-add" type="primary" class="ml10" @click="formDialogRef.openDialog()"
|
||||
v-auth="'app_appContacts_add'">
|
||||
新 增
|
||||
</el-button>
|
||||
<el-button plain :disabled="multiple" icon="Delete" type="primary"
|
||||
v-auth="'app_appContacts_del'" @click="handleDelete(selectObjs)">
|
||||
删除
|
||||
</el-button>
|
||||
<right-toolbar v-model:showSearch="showSearch" :export="'app_appContacts_export'"
|
||||
@exportExcel="exportExcel" class="ml10 mr20" style="float: right;"
|
||||
@queryTable="getDataList"></right-toolbar>
|
||||
</div>
|
||||
</el-row>
|
||||
<el-table :data="state.dataList" v-loading="state.loading" border
|
||||
:cell-style="tableStyle.cellStyle" :header-cell-style="tableStyle.headerCellStyle"
|
||||
<div class="layout-padding">
|
||||
<div class="layout-padding-auto layout-padding-view">
|
||||
<el-row v-show="showSearch">
|
||||
<el-form :model="state.queryForm" ref="queryRef" :inline="true" @keyup.enter="getDataList">
|
||||
<el-form-item label="联系人" prop="contactName">
|
||||
<el-input placeholder="请输入联系人" v-model="state.queryForm.contactName" />
|
||||
</el-form-item>
|
||||
<el-form-item label="手机号" prop="contactPhone">
|
||||
<el-input placeholder="请输入手机号" v-model="state.queryForm.contactPhone" />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button icon="search" type="primary" @click="getDataList"> 查询 </el-button>
|
||||
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<div class="mb8" style="width: 100%">
|
||||
<el-button icon="folder-add" type="primary" class="ml10" @click="formDialogRef.openDialog()" v-auth="'app_appContacts_add'">
|
||||
新 增
|
||||
</el-button>
|
||||
<el-button plain :disabled="multiple" icon="Delete" type="primary" v-auth="'app_appContacts_del'" @click="handleDelete(selectObjs)">
|
||||
删除
|
||||
</el-button>
|
||||
<right-toolbar
|
||||
v-model:showSearch="showSearch"
|
||||
:export="'app_appContacts_export'"
|
||||
@exportExcel="exportExcel"
|
||||
class="ml10 mr20"
|
||||
style="float: right"
|
||||
@queryTable="getDataList"
|
||||
></right-toolbar>
|
||||
</div>
|
||||
</el-row>
|
||||
<el-table
|
||||
:data="state.dataList"
|
||||
v-loading="state.loading"
|
||||
border
|
||||
:cell-style="tableStyle.cellStyle"
|
||||
:header-cell-style="tableStyle.headerCellStyle"
|
||||
@selection-change="selectionChangHandle"
|
||||
@sort-change="sortChangeHandle">
|
||||
<el-table-column type="selection" width="40" align="center" />
|
||||
<el-table-column type="index" label="#" width="40" />
|
||||
<el-table-column prop="contactName" label="联系人" show-overflow-tooltip/>
|
||||
<el-table-column prop="contactPhone" label="手机号" show-overflow-tooltip/>
|
||||
<el-table-column prop="remark" label="备注" show-overflow-tooltip/>
|
||||
<el-table-column label="操作" width="150">
|
||||
<template #default="scope">
|
||||
<el-button icon="edit-pen" text type="primary" v-auth="'app_appContacts_edit'"
|
||||
@click="formDialogRef.openDialog(scope.row.id)">编辑</el-button>
|
||||
<el-button icon="delete" text type="primary" v-auth="'app_appContacts_del'" @click="handleDelete([scope.row.id])">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<pagination @size-change="sizeChangeHandle" @current-change="currentChangeHandle" v-bind="state.pagination" />
|
||||
</div>
|
||||
@sort-change="sortChangeHandle"
|
||||
>
|
||||
<el-table-column type="selection" width="40" align="center" />
|
||||
<el-table-column type="index" label="#" width="40" />
|
||||
<el-table-column prop="contactName" label="联系人" show-overflow-tooltip />
|
||||
<el-table-column prop="contactPhone" label="手机号" show-overflow-tooltip />
|
||||
<el-table-column prop="remark" label="备注" show-overflow-tooltip />
|
||||
<el-table-column label="操作" width="150">
|
||||
<template #default="scope">
|
||||
<el-button icon="edit-pen" text type="primary" v-auth="'app_appContacts_edit'" @click="formDialogRef.openDialog(scope.row.id)"
|
||||
>编辑</el-button
|
||||
>
|
||||
<el-button icon="delete" text type="primary" v-auth="'app_appContacts_del'" @click="handleDelete([scope.row.id])">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<pagination @size-change="sizeChangeHandle" @current-change="currentChangeHandle" v-bind="state.pagination" />
|
||||
</div>
|
||||
|
||||
<!-- 编辑、新增 -->
|
||||
<form-dialog ref="formDialogRef" @refresh="getDataList(false)" />
|
||||
|
||||
</div>
|
||||
<!-- 编辑、新增 -->
|
||||
<form-dialog ref="formDialogRef" @refresh="getDataList(false)" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="systemAppContacts">
|
||||
import { BasicTableProps, useTable } from "/@/hooks/table";
|
||||
import { fetchList, delObjs } from "/@/api/app/appContacts";
|
||||
import { useMessage, useMessageBox } from "/@/hooks/message";
|
||||
import { BasicTableProps, useTable } from '/@/hooks/table';
|
||||
import { fetchList, delObjs } from '/@/api/app/appContacts';
|
||||
import { useMessage, useMessageBox } from '/@/hooks/message';
|
||||
import { useDict } from '/@/hooks/dict';
|
||||
|
||||
// 引入组件
|
||||
@@ -69,63 +75,56 @@ const FormDialog = defineAsyncComponent(() => import('./form.vue'));
|
||||
// 定义查询字典
|
||||
|
||||
// 定义变量内容
|
||||
const formDialogRef = ref()
|
||||
const formDialogRef = ref();
|
||||
// 搜索变量
|
||||
const queryRef = ref()
|
||||
const showSearch = ref(true)
|
||||
const queryRef = ref();
|
||||
const showSearch = ref(true);
|
||||
// 多选变量
|
||||
const selectObjs = ref([]) as any
|
||||
const multiple = ref(true)
|
||||
const selectObjs = ref([]) as any;
|
||||
const multiple = ref(true);
|
||||
|
||||
const state: BasicTableProps = reactive<BasicTableProps>({
|
||||
queryForm: {},
|
||||
pageList: fetchList
|
||||
})
|
||||
queryForm: {},
|
||||
pageList: fetchList,
|
||||
});
|
||||
|
||||
// table hook
|
||||
const {
|
||||
getDataList,
|
||||
currentChangeHandle,
|
||||
sizeChangeHandle,
|
||||
sortChangeHandle,
|
||||
downBlobFile,
|
||||
tableStyle
|
||||
} = useTable(state)
|
||||
const { getDataList, currentChangeHandle, sizeChangeHandle, sortChangeHandle, downBlobFile, tableStyle } = useTable(state);
|
||||
|
||||
// 清空搜索条件
|
||||
const resetQuery = () => {
|
||||
// 清空搜索条件
|
||||
queryRef.value?.resetFields()
|
||||
// 清空多选
|
||||
selectObjs.value = []
|
||||
getDataList()
|
||||
}
|
||||
// 清空搜索条件
|
||||
queryRef.value?.resetFields();
|
||||
// 清空多选
|
||||
selectObjs.value = [];
|
||||
getDataList();
|
||||
};
|
||||
|
||||
// 导出excel
|
||||
const exportExcel = () => {
|
||||
downBlobFile('/app/appContacts/export', Object.assign(state.queryForm, { ids: selectObjs }), 'appContacts.xlsx')
|
||||
}
|
||||
downBlobFile('/app/appContacts/export', Object.assign(state.queryForm, { ids: selectObjs }), 'appContacts.xlsx');
|
||||
};
|
||||
|
||||
// 多选事件
|
||||
const selectionChangHandle = (objs: { id: string }[]) => {
|
||||
selectObjs.value = objs.map(({ id }) => id);
|
||||
multiple.value = !objs.length;
|
||||
selectObjs.value = objs.map(({ id }) => id);
|
||||
multiple.value = !objs.length;
|
||||
};
|
||||
|
||||
// 删除操作
|
||||
const handleDelete = async (ids: string[]) => {
|
||||
try {
|
||||
await useMessageBox().confirm('此操作将永久删除');
|
||||
} catch {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
await useMessageBox().confirm('此操作将永久删除');
|
||||
} catch {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await delObjs(ids);
|
||||
getDataList();
|
||||
useMessage().success('删除成功');
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg);
|
||||
}
|
||||
try {
|
||||
await delObjs(ids);
|
||||
getDataList();
|
||||
useMessage().success('删除成功');
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg);
|
||||
}
|
||||
};
|
||||
</script>
|
||||
</script>
|
||||
|
||||
@@ -1,292 +1,273 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
title="班级概况"
|
||||
v-model="visible"
|
||||
:close-on-click-modal="false"
|
||||
draggable
|
||||
width="1400px">
|
||||
<div v-loading="loading">
|
||||
<!-- 基本信息 -->
|
||||
<el-descriptions :column="3" border v-if="detailData" class="mb20">
|
||||
<el-descriptions-item label="班号">{{ detailData.classNo || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="班级名称">{{ detailData.className || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="班级规范名称">{{ detailData.classProName || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="学院">{{ detailData.deptName || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="班主任">{{ detailData.teacherRealName || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="班主任电话">{{ detailData.teacherTel || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="入学年份">{{ detailData.grade || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="入学时间">{{ detailData.enterDate || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="班级状态">
|
||||
<span>{{ detailData.classStatus === '0' ? '正常' : detailData.classStatus === '1' ? '离校' : '-' }}</span>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="班级人数/原始人数">
|
||||
{{ detailData.stuNum || 0 }}/{{ detailData.preStuNum || 0 }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="流失率">
|
||||
<span>{{ detailData.stuLoseRate ? `${detailData.stuLoseRate}%` : '-' }}</span>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="联院">
|
||||
<span>{{ detailData.isUnion === 1 ? '是' : detailData.isUnion === 0 ? '否' : '-' }}</span>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="门禁规则" :span="3">{{ detailData.ruleName || '-' }}</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
<el-dialog title="班级概况" v-model="visible" :close-on-click-modal="false" draggable width="1400px">
|
||||
<div v-loading="loading">
|
||||
<!-- 基本信息 -->
|
||||
<el-descriptions :column="3" border v-if="detailData" class="mb20">
|
||||
<el-descriptions-item label="班号">{{ detailData.classNo || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="班级名称">{{ detailData.className || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="班级规范名称">{{ detailData.classProName || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="学院">{{ detailData.deptName || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="班主任">{{ detailData.teacherRealName || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="班主任电话">{{ detailData.teacherTel || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="入学年份">{{ detailData.grade || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="入学时间">{{ detailData.enterDate || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="班级状态">
|
||||
<span>{{ detailData.classStatus === '0' ? '正常' : detailData.classStatus === '1' ? '离校' : '-' }}</span>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="班级人数/原始人数"> {{ detailData.stuNum || 0 }}/{{ detailData.preStuNum || 0 }} </el-descriptions-item>
|
||||
<el-descriptions-item label="流失率">
|
||||
<span>{{ detailData.stuLoseRate ? `${detailData.stuLoseRate}%` : '-' }}</span>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="联院">
|
||||
<span>{{ detailData.isUnion === 1 ? '是' : detailData.isUnion === 0 ? '否' : '-' }}</span>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="门禁规则" :span="3">{{ detailData.ruleName || '-' }}</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
|
||||
<!-- 详细信息 - 使用 tabs 展示六个接口的数据 -->
|
||||
<el-tabs v-model="activeTab" type="border-card">
|
||||
<el-tab-pane label="班级荣誉" name="honor">
|
||||
<el-table :data="honorList" border style="width: 100%" v-loading="honorLoading">
|
||||
<el-table-column type="index" label="序号" width="60" align="center" />
|
||||
<el-table-column prop="title" label="标题" show-overflow-tooltip />
|
||||
<el-table-column prop="author" label="作者" width="120" />
|
||||
<el-table-column prop="createTime" label="更新时间" width="120" />
|
||||
<el-table-column prop="belong" label="归档级别" width="120" />
|
||||
</el-table>
|
||||
<div v-if="honorList.length === 0 && !honorLoading" style="text-align: center; padding: 20px; color: #909399;">
|
||||
暂无数据
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
<!-- 详细信息 - 使用 tabs 展示六个接口的数据 -->
|
||||
<el-tabs v-model="activeTab" type="border-card">
|
||||
<el-tab-pane label="班级荣誉" name="honor">
|
||||
<el-table :data="honorList" border style="width: 100%" v-loading="honorLoading">
|
||||
<el-table-column type="index" label="序号" width="60" align="center" />
|
||||
<el-table-column prop="title" label="标题" show-overflow-tooltip />
|
||||
<el-table-column prop="author" label="作者" width="120" />
|
||||
<el-table-column prop="createTime" label="更新时间" width="120" />
|
||||
<el-table-column prop="belong" label="归档级别" width="120" />
|
||||
</el-table>
|
||||
<div v-if="honorList.length === 0 && !honorLoading" style="text-align: center; padding: 20px; color: #909399">暂无数据</div>
|
||||
</el-tab-pane>
|
||||
|
||||
<el-tab-pane label="班级宣传" name="publicity">
|
||||
<el-table :data="publicityList" border style="width: 100%" v-loading="publicityLoading">
|
||||
<el-table-column type="index" label="序号" width="60" align="center" />
|
||||
<el-table-column prop="title" label="标题" show-overflow-tooltip />
|
||||
<el-table-column prop="author" label="作者" width="120" />
|
||||
<el-table-column prop="createTime" label="更新时间" width="120" />
|
||||
<el-table-column prop="belong" label="归档级别" width="120" />
|
||||
<el-table-column prop="website" label="网址" show-overflow-tooltip />
|
||||
</el-table>
|
||||
<div v-if="publicityList.length === 0 && !publicityLoading" style="text-align: center; padding: 20px; color: #909399;">
|
||||
暂无数据
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="班级宣传" name="publicity">
|
||||
<el-table :data="publicityList" border style="width: 100%" v-loading="publicityLoading">
|
||||
<el-table-column type="index" label="序号" width="60" align="center" />
|
||||
<el-table-column prop="title" label="标题" show-overflow-tooltip />
|
||||
<el-table-column prop="author" label="作者" width="120" />
|
||||
<el-table-column prop="createTime" label="更新时间" width="120" />
|
||||
<el-table-column prop="belong" label="归档级别" width="120" />
|
||||
<el-table-column prop="website" label="网址" show-overflow-tooltip />
|
||||
</el-table>
|
||||
<div v-if="publicityList.length === 0 && !publicityLoading" style="text-align: center; padding: 20px; color: #909399">暂无数据</div>
|
||||
</el-tab-pane>
|
||||
|
||||
<el-tab-pane label="教室分配" name="classroom">
|
||||
<el-table :data="classroomList" border style="width: 100%" v-loading="classroomLoading">
|
||||
<el-table-column type="index" label="序号" width="60" align="center" />
|
||||
<el-table-column prop="buildingNo" label="教学楼号" show-overflow-tooltip />
|
||||
<el-table-column prop="roomNo" label="教室号" show-overflow-tooltip />
|
||||
<el-table-column prop="roomName" label="教室名称" show-overflow-tooltip />
|
||||
</el-table>
|
||||
<div v-if="classroomList.length === 0 && !classroomLoading" style="text-align: center; padding: 20px; color: #909399;">
|
||||
暂无数据
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="教室分配" name="classroom">
|
||||
<el-table :data="classroomList" border style="width: 100%" v-loading="classroomLoading">
|
||||
<el-table-column type="index" label="序号" width="60" align="center" />
|
||||
<el-table-column prop="buildingNo" label="教学楼号" show-overflow-tooltip />
|
||||
<el-table-column prop="roomNo" label="教室号" show-overflow-tooltip />
|
||||
<el-table-column prop="roomName" label="教室名称" show-overflow-tooltip />
|
||||
</el-table>
|
||||
<div v-if="classroomList.length === 0 && !classroomLoading" style="text-align: center; padding: 20px; color: #909399">暂无数据</div>
|
||||
</el-tab-pane>
|
||||
|
||||
<el-tab-pane label="学生数量" name="studentNum">
|
||||
<el-table :data="studentNumList" border style="width: 100%" v-loading="studentNumLoading">
|
||||
<el-table-column type="index" label="序号" width="60" align="center" />
|
||||
<el-table-column prop="stuNo" label="学号" show-overflow-tooltip />
|
||||
<el-table-column prop="realName" label="姓名" show-overflow-tooltip />
|
||||
<el-table-column prop="sex" label="性别" width="80" align="center">
|
||||
<template #default="scope">
|
||||
<span>{{ scope.row.sex === '1' ? '男' : scope.row.sex === '0' ? '女' : '-' }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="phone" label="电话" show-overflow-tooltip />
|
||||
</el-table>
|
||||
<div v-if="studentNumList.length === 0 && !studentNumLoading" style="text-align: center; padding: 20px; color: #909399;">
|
||||
暂无数据
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="学生数量" name="studentNum">
|
||||
<el-table :data="studentNumList" border style="width: 100%" v-loading="studentNumLoading">
|
||||
<el-table-column type="index" label="序号" width="60" align="center" />
|
||||
<el-table-column prop="stuNo" label="学号" show-overflow-tooltip />
|
||||
<el-table-column prop="realName" label="姓名" show-overflow-tooltip />
|
||||
<el-table-column prop="sex" label="性别" width="80" align="center">
|
||||
<template #default="scope">
|
||||
<span>{{ scope.row.sex === '1' ? '男' : scope.row.sex === '0' ? '女' : '-' }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="phone" label="电话" show-overflow-tooltip />
|
||||
</el-table>
|
||||
<div v-if="studentNumList.length === 0 && !studentNumLoading" style="text-align: center; padding: 20px; color: #909399">暂无数据</div>
|
||||
</el-tab-pane>
|
||||
|
||||
<el-tab-pane label="宿舍学生" name="dormStudent">
|
||||
<el-table :data="dormStudentList" border style="width: 100%" v-loading="dormStudentLoading">
|
||||
<el-table-column type="index" label="序号" width="60" align="center" />
|
||||
<el-table-column prop="buildingNo" label="楼号" show-overflow-tooltip />
|
||||
<el-table-column prop="roomNo" label="宿舍号" show-overflow-tooltip />
|
||||
<el-table-column prop="stuNo" label="学号" show-overflow-tooltip />
|
||||
<el-table-column prop="realName" label="姓名" show-overflow-tooltip />
|
||||
</el-table>
|
||||
<div v-if="dormStudentList.length === 0 && !dormStudentLoading" style="text-align: center; padding: 20px; color: #909399;">
|
||||
暂无数据
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="宿舍学生" name="dormStudent">
|
||||
<el-table :data="dormStudentList" border style="width: 100%" v-loading="dormStudentLoading">
|
||||
<el-table-column type="index" label="序号" width="60" align="center" />
|
||||
<el-table-column prop="buildingNo" label="楼号" show-overflow-tooltip />
|
||||
<el-table-column prop="roomNo" label="宿舍号" show-overflow-tooltip />
|
||||
<el-table-column prop="stuNo" label="学号" show-overflow-tooltip />
|
||||
<el-table-column prop="realName" label="姓名" show-overflow-tooltip />
|
||||
</el-table>
|
||||
<div v-if="dormStudentList.length === 0 && !dormStudentLoading" style="text-align: center; padding: 20px; color: #909399">暂无数据</div>
|
||||
</el-tab-pane>
|
||||
|
||||
<el-tab-pane label="惩罚记录" name="punish">
|
||||
<el-table :data="punishList" border style="width: 100%" v-loading="punishLoading">
|
||||
<el-table-column type="index" label="序号" width="60" align="center" />
|
||||
<el-table-column prop="stuNo" label="学号" show-overflow-tooltip />
|
||||
<el-table-column prop="realName" label="姓名" show-overflow-tooltip />
|
||||
<el-table-column prop="punishType" label="惩罚类型" show-overflow-tooltip />
|
||||
<el-table-column prop="punishReason" label="惩罚原因" show-overflow-tooltip />
|
||||
<el-table-column prop="createTime" label="惩罚时间" width="120" />
|
||||
</el-table>
|
||||
<div v-if="punishList.length === 0 && !punishLoading" style="text-align: center; padding: 20px; color: #909399;">
|
||||
暂无数据
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</div>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="visible = false">关 闭</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
<el-tab-pane label="惩罚记录" name="punish">
|
||||
<el-table :data="punishList" border style="width: 100%" v-loading="punishLoading">
|
||||
<el-table-column type="index" label="序号" width="60" align="center" />
|
||||
<el-table-column prop="stuNo" label="学号" show-overflow-tooltip />
|
||||
<el-table-column prop="realName" label="姓名" show-overflow-tooltip />
|
||||
<el-table-column prop="punishType" label="惩罚类型" show-overflow-tooltip />
|
||||
<el-table-column prop="punishReason" label="惩罚原因" show-overflow-tooltip />
|
||||
<el-table-column prop="createTime" label="惩罚时间" width="120" />
|
||||
</el-table>
|
||||
<div v-if="punishList.length === 0 && !punishLoading" style="text-align: center; padding: 20px; color: #909399">暂无数据</div>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</div>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="visible = false">关 闭</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="BasicClassDetail">
|
||||
import { ref } from 'vue'
|
||||
import { useMessage } from "/@/hooks/message";
|
||||
import { queryClassHonorByClassCode } from '/@/api/stuwork/classhonor'
|
||||
import { queryDataByClassCode } from '/@/api/stuwork/classpublicity'
|
||||
import { getClassRoomByClassCode } from '/@/api/stuwork/teachclassroomassign'
|
||||
import { queryStuNumByClassCode } from '/@/api/basic/basicstudent'
|
||||
import { fearchStuNumByClassCode } from '/@/api/stuwork/dormroomstudent'
|
||||
import { queryPunlishNumByClass } from '/@/api/stuwork/stupunlish'
|
||||
import { ref } from 'vue';
|
||||
import { useMessage } from '/@/hooks/message';
|
||||
import { queryClassHonorByClassCode } from '/@/api/stuwork/classhonor';
|
||||
import { queryDataByClassCode } from '/@/api/stuwork/classpublicity';
|
||||
import { getClassRoomByClassCode } from '/@/api/stuwork/teachclassroomassign';
|
||||
import { queryStuNumByClassCode } from '/@/api/basic/basicstudent';
|
||||
import { fearchStuNumByClassCode } from '/@/api/stuwork/dormroomstudent';
|
||||
import { queryPunlishNumByClass } from '/@/api/stuwork/stupunlish';
|
||||
|
||||
// 定义变量内容
|
||||
const visible = ref(false)
|
||||
const loading = ref(false)
|
||||
const detailData = ref<any>(null)
|
||||
const activeTab = ref('honor')
|
||||
const visible = ref(false);
|
||||
const loading = ref(false);
|
||||
const detailData = ref<any>(null);
|
||||
const activeTab = ref('honor');
|
||||
|
||||
// 六个接口的数据
|
||||
const honorList = ref<any[]>([])
|
||||
const honorLoading = ref(false)
|
||||
const publicityList = ref<any[]>([])
|
||||
const publicityLoading = ref(false)
|
||||
const classroomList = ref<any[]>([])
|
||||
const classroomLoading = ref(false)
|
||||
const studentNumList = ref<any[]>([])
|
||||
const studentNumLoading = ref(false)
|
||||
const dormStudentList = ref<any[]>([])
|
||||
const dormStudentLoading = ref(false)
|
||||
const punishList = ref<any[]>([])
|
||||
const punishLoading = ref(false)
|
||||
const honorList = ref<any[]>([]);
|
||||
const honorLoading = ref(false);
|
||||
const publicityList = ref<any[]>([]);
|
||||
const publicityLoading = ref(false);
|
||||
const classroomList = ref<any[]>([]);
|
||||
const classroomLoading = ref(false);
|
||||
const studentNumList = ref<any[]>([]);
|
||||
const studentNumLoading = ref(false);
|
||||
const dormStudentList = ref<any[]>([]);
|
||||
const dormStudentLoading = ref(false);
|
||||
const punishList = ref<any[]>([]);
|
||||
const punishLoading = ref(false);
|
||||
|
||||
// 打开弹窗
|
||||
const openDialog = async (rowData: any) => {
|
||||
visible.value = true
|
||||
detailData.value = rowData || null
|
||||
|
||||
// 如果有班级代码,加载六个接口的数据
|
||||
if (rowData?.classCode) {
|
||||
await loadAllData(rowData.classCode)
|
||||
}
|
||||
}
|
||||
visible.value = true;
|
||||
detailData.value = rowData || null;
|
||||
|
||||
// 如果有班级代码,加载六个接口的数据
|
||||
if (rowData?.classCode) {
|
||||
await loadAllData(rowData.classCode);
|
||||
}
|
||||
};
|
||||
|
||||
// 加载所有六个接口的数据
|
||||
const loadAllData = async (classCode: string) => {
|
||||
loading.value = true
|
||||
|
||||
// 并行加载所有接口数据
|
||||
await Promise.all([
|
||||
loadHonorData(classCode),
|
||||
loadPublicityData(classCode),
|
||||
loadClassroomData(classCode),
|
||||
loadStudentNumData(classCode),
|
||||
loadDormStudentData(classCode),
|
||||
loadPunishData(classCode),
|
||||
])
|
||||
|
||||
loading.value = false
|
||||
}
|
||||
loading.value = true;
|
||||
|
||||
// 并行加载所有接口数据
|
||||
await Promise.all([
|
||||
loadHonorData(classCode),
|
||||
loadPublicityData(classCode),
|
||||
loadClassroomData(classCode),
|
||||
loadStudentNumData(classCode),
|
||||
loadDormStudentData(classCode),
|
||||
loadPunishData(classCode),
|
||||
]);
|
||||
|
||||
loading.value = false;
|
||||
};
|
||||
|
||||
// 加载班级荣誉数据
|
||||
const loadHonorData = async (classCode: string) => {
|
||||
honorLoading.value = true
|
||||
try {
|
||||
const res = await queryClassHonorByClassCode(classCode)
|
||||
if (res.data) {
|
||||
honorList.value = Array.isArray(res.data) ? res.data : []
|
||||
}
|
||||
} catch (err: any) {
|
||||
console.error('获取班级荣誉失败', err)
|
||||
honorList.value = []
|
||||
} finally {
|
||||
honorLoading.value = false
|
||||
}
|
||||
}
|
||||
honorLoading.value = true;
|
||||
try {
|
||||
const res = await queryClassHonorByClassCode(classCode);
|
||||
if (res.data) {
|
||||
honorList.value = Array.isArray(res.data) ? res.data : [];
|
||||
}
|
||||
} catch (err: any) {
|
||||
console.error('获取班级荣誉失败', err);
|
||||
honorList.value = [];
|
||||
} finally {
|
||||
honorLoading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
// 加载班级宣传数据
|
||||
const loadPublicityData = async (classCode: string) => {
|
||||
publicityLoading.value = true
|
||||
try {
|
||||
const res = await queryDataByClassCode(classCode)
|
||||
if (res.data) {
|
||||
publicityList.value = Array.isArray(res.data) ? res.data : []
|
||||
}
|
||||
} catch (err: any) {
|
||||
console.error('获取班级宣传失败', err)
|
||||
publicityList.value = []
|
||||
} finally {
|
||||
publicityLoading.value = false
|
||||
}
|
||||
}
|
||||
publicityLoading.value = true;
|
||||
try {
|
||||
const res = await queryDataByClassCode(classCode);
|
||||
if (res.data) {
|
||||
publicityList.value = Array.isArray(res.data) ? res.data : [];
|
||||
}
|
||||
} catch (err: any) {
|
||||
console.error('获取班级宣传失败', err);
|
||||
publicityList.value = [];
|
||||
} finally {
|
||||
publicityLoading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
// 加载教室分配数据
|
||||
const loadClassroomData = async (classCode: string) => {
|
||||
classroomLoading.value = true
|
||||
try {
|
||||
const res = await getClassRoomByClassCode(classCode)
|
||||
if (res.data) {
|
||||
classroomList.value = Array.isArray(res.data) ? res.data : []
|
||||
}
|
||||
} catch (err: any) {
|
||||
console.error('获取教室分配失败', err)
|
||||
classroomList.value = []
|
||||
} finally {
|
||||
classroomLoading.value = false
|
||||
}
|
||||
}
|
||||
classroomLoading.value = true;
|
||||
try {
|
||||
const res = await getClassRoomByClassCode(classCode);
|
||||
if (res.data) {
|
||||
classroomList.value = Array.isArray(res.data) ? res.data : [];
|
||||
}
|
||||
} catch (err: any) {
|
||||
console.error('获取教室分配失败', err);
|
||||
classroomList.value = [];
|
||||
} finally {
|
||||
classroomLoading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
// 加载学生数量数据
|
||||
const loadStudentNumData = async (classCode: string) => {
|
||||
studentNumLoading.value = true
|
||||
try {
|
||||
const res = await queryStuNumByClassCode({ classCode })
|
||||
if (res.data) {
|
||||
studentNumList.value = Array.isArray(res.data) ? res.data : []
|
||||
}
|
||||
} catch (err: any) {
|
||||
console.error('获取学生数量失败', err)
|
||||
studentNumList.value = []
|
||||
} finally {
|
||||
studentNumLoading.value = false
|
||||
}
|
||||
}
|
||||
studentNumLoading.value = true;
|
||||
try {
|
||||
const res = await queryStuNumByClassCode({ classCode });
|
||||
if (res.data) {
|
||||
studentNumList.value = Array.isArray(res.data) ? res.data : [];
|
||||
}
|
||||
} catch (err: any) {
|
||||
console.error('获取学生数量失败', err);
|
||||
studentNumList.value = [];
|
||||
} finally {
|
||||
studentNumLoading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
// 加载宿舍学生数据
|
||||
const loadDormStudentData = async (classCode: string) => {
|
||||
dormStudentLoading.value = true
|
||||
try {
|
||||
const res = await fearchStuNumByClassCode(classCode)
|
||||
if (res.data) {
|
||||
dormStudentList.value = Array.isArray(res.data) ? res.data : []
|
||||
}
|
||||
} catch (err: any) {
|
||||
console.error('获取宿舍学生失败', err)
|
||||
dormStudentList.value = []
|
||||
} finally {
|
||||
dormStudentLoading.value = false
|
||||
}
|
||||
}
|
||||
dormStudentLoading.value = true;
|
||||
try {
|
||||
const res = await fearchStuNumByClassCode(classCode);
|
||||
if (res.data) {
|
||||
dormStudentList.value = Array.isArray(res.data) ? res.data : [];
|
||||
}
|
||||
} catch (err: any) {
|
||||
console.error('获取宿舍学生失败', err);
|
||||
dormStudentList.value = [];
|
||||
} finally {
|
||||
dormStudentLoading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
// 加载惩罚记录数据
|
||||
const loadPunishData = async (classCode: string) => {
|
||||
punishLoading.value = true
|
||||
try {
|
||||
const res = await queryPunlishNumByClass(classCode)
|
||||
if (res.data) {
|
||||
punishList.value = Array.isArray(res.data) ? res.data : []
|
||||
}
|
||||
} catch (err: any) {
|
||||
console.error('获取惩罚记录失败', err)
|
||||
punishList.value = []
|
||||
} finally {
|
||||
punishLoading.value = false
|
||||
}
|
||||
}
|
||||
punishLoading.value = true;
|
||||
try {
|
||||
const res = await queryPunlishNumByClass(classCode);
|
||||
if (res.data) {
|
||||
punishList.value = Array.isArray(res.data) ? res.data : [];
|
||||
}
|
||||
} catch (err: any) {
|
||||
console.error('获取惩罚记录失败', err);
|
||||
punishList.value = [];
|
||||
} finally {
|
||||
punishLoading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
// 暴露方法给父组件
|
||||
defineExpose({
|
||||
openDialog
|
||||
openDialog,
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.mb20 {
|
||||
margin-bottom: 20px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,449 +1,373 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
:title="form.id ? '编辑' : '新增'"
|
||||
v-model="visible"
|
||||
:close-on-click-modal="false"
|
||||
draggable
|
||||
width="800px">
|
||||
<el-form
|
||||
ref="dataFormRef"
|
||||
:model="form"
|
||||
:rules="dataRules"
|
||||
label-width="120px"
|
||||
:validate-on-rule-change="false"
|
||||
v-loading="loading">
|
||||
<el-row :gutter="24">
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item label="入学日期" prop="enterDate">
|
||||
<el-date-picker
|
||||
v-model="form.enterDate"
|
||||
type="date"
|
||||
placeholder="选择日期"
|
||||
format="YYYY-MM-DD"
|
||||
value-format="YYYY-MM-DD"
|
||||
style="width: 100%" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-dialog :title="form.id ? '编辑' : '新增'" v-model="visible" :close-on-click-modal="false" draggable width="800px">
|
||||
<el-form ref="dataFormRef" :model="form" :rules="dataRules" label-width="120px" :validate-on-rule-change="false" v-loading="loading">
|
||||
<el-row :gutter="24">
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item label="入学日期" prop="enterDate">
|
||||
<el-date-picker
|
||||
v-model="form.enterDate"
|
||||
type="date"
|
||||
placeholder="选择日期"
|
||||
format="YYYY-MM-DD"
|
||||
value-format="YYYY-MM-DD"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item label="专业" prop="majorCode">
|
||||
<el-select
|
||||
v-model="form.majorCode"
|
||||
placeholder="请选择"
|
||||
clearable
|
||||
filterable
|
||||
style="width: 100%">
|
||||
<el-option
|
||||
v-for="item in majorList"
|
||||
:key="item.majorCode"
|
||||
:label="item.majorName"
|
||||
:value="item.majorCode">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item label="专业" prop="majorCode">
|
||||
<el-select v-model="form.majorCode" placeholder="请选择" clearable filterable style="width: 100%">
|
||||
<el-option v-for="item in majorList" :key="item.majorCode" :label="item.majorName" :value="item.majorCode"> </el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item label="学院" prop="deptCode">
|
||||
<el-select
|
||||
v-model="form.deptCode"
|
||||
placeholder="请选择"
|
||||
clearable
|
||||
filterable
|
||||
style="width: 100%">
|
||||
<el-option
|
||||
v-for="item in deptList"
|
||||
:key="item.deptCode"
|
||||
:label="item.deptName"
|
||||
:value="item.deptCode">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item label="学院" prop="deptCode">
|
||||
<el-select v-model="form.deptCode" placeholder="请选择" clearable filterable style="width: 100%">
|
||||
<el-option v-for="item in deptList" :key="item.deptCode" :label="item.deptName" :value="item.deptCode"> </el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item label="班级代码" prop="classCode">
|
||||
<el-input
|
||||
v-model="form.classCode"
|
||||
placeholder="请输入班级代码"
|
||||
clearable />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item label="班级代码" prop="classCode">
|
||||
<el-input v-model="form.classCode" placeholder="请输入班级代码" clearable />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item label="班号" prop="classNo">
|
||||
<el-input
|
||||
v-model="form.classNo"
|
||||
placeholder="自动填充班号"
|
||||
:disabled="true" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item label="班号" prop="classNo">
|
||||
<el-input v-model="form.classNo" placeholder="自动填充班号" :disabled="true" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item label="班级名称" prop="className">
|
||||
<el-input
|
||||
v-model="form.className"
|
||||
placeholder="请输入班级名称"
|
||||
clearable />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item label="班级名称" prop="className">
|
||||
<el-input v-model="form.className" placeholder="请输入班级名称" clearable />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item label="班级规范名称" prop="classProName">
|
||||
<el-input
|
||||
v-model="form.classProName"
|
||||
placeholder="自动拼接班级规范名称"
|
||||
:disabled="true" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item label="班级规范名称" prop="classProName">
|
||||
<el-input v-model="form.classProName" placeholder="自动拼接班级规范名称" :disabled="true" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item label="入学年份" prop="grade">
|
||||
<el-input
|
||||
v-model="form.grade"
|
||||
placeholder="自动填充入学年份"
|
||||
:disabled="true" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item label="入学年份" prop="grade">
|
||||
<el-input v-model="form.grade" placeholder="自动填充入学年份" :disabled="true" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item label="班主任" prop="teacherNos">
|
||||
<el-select
|
||||
v-model="form.teacherNos"
|
||||
placeholder="请选择班主任"
|
||||
clearable
|
||||
filterable
|
||||
style="width: 100%">
|
||||
<el-option
|
||||
v-for="item in teacherList"
|
||||
:key="item.teacherNo"
|
||||
:label="item.realName"
|
||||
:value="item.teacherNo">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item label="班主任" prop="teacherNos">
|
||||
<el-select v-model="form.teacherNos" placeholder="请选择班主任" clearable filterable style="width: 100%">
|
||||
<el-option v-for="item in teacherList" :key="item.teacherNo" :label="item.realName" :value="item.teacherNo"> </el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item label="预计招生人数" prop="preStuNum">
|
||||
<el-input-number
|
||||
v-model="form.preStuNum"
|
||||
:precision="0"
|
||||
:step="1"
|
||||
:min="0"
|
||||
placeholder="请输入预计招生人数"
|
||||
style="width: 100%" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item label="预计招生人数" prop="preStuNum">
|
||||
<el-input-number v-model="form.preStuNum" :precision="0" :step="1" :min="0" placeholder="请输入预计招生人数" style="width: 100%" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="24" class="mb20">
|
||||
<el-form-item label="备注" prop="remark">
|
||||
<el-input
|
||||
v-model="form.remark"
|
||||
type="textarea"
|
||||
:rows="4"
|
||||
placeholder="请输入备注"
|
||||
maxlength="500"
|
||||
show-word-limit />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="visible = false">取 消</el-button>
|
||||
<el-button type="primary" @click="onSubmit" :disabled="loading">确 认</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
<el-col :span="24" class="mb20">
|
||||
<el-form-item label="备注" prop="remark">
|
||||
<el-input v-model="form.remark" type="textarea" :rows="4" placeholder="请输入备注" maxlength="500" show-word-limit />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="visible = false">取 消</el-button>
|
||||
<el-button type="primary" @click="onSubmit" :disabled="loading">确 认</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="BasicClassDialog">
|
||||
import { ref, reactive, nextTick, onMounted, watch, computed } from 'vue'
|
||||
import { useMessage } from "/@/hooks/message";
|
||||
import { getDetail, addObj, putObj, getMajorNameList, getDeptList } from '/@/api/basic/basicclass'
|
||||
import { getTeacherBaseList } from '/@/api/professional/professionaluser/teacherbase'
|
||||
import { ref, reactive, nextTick, onMounted, watch, computed } from 'vue';
|
||||
import { useMessage } from '/@/hooks/message';
|
||||
import { getDetail, addObj, putObj, getMajorNameList, getDeptList } from '/@/api/basic/basicclass';
|
||||
import { getTeacherBaseList } from '/@/api/professional/professionaluser/teacherbase';
|
||||
|
||||
const emit = defineEmits(['refresh']);
|
||||
|
||||
// 定义变量内容
|
||||
const dataFormRef = ref();
|
||||
const visible = ref(false)
|
||||
const loading = ref(false)
|
||||
const majorList = ref<any[]>([])
|
||||
const deptList = ref<any[]>([])
|
||||
const teacherList = ref<any[]>([])
|
||||
const yearLast = ref('') // 年份后两位
|
||||
const majorName = ref('') // 专业名称
|
||||
const visible = ref(false);
|
||||
const loading = ref(false);
|
||||
const majorList = ref<any[]>([]);
|
||||
const deptList = ref<any[]>([]);
|
||||
const teacherList = ref<any[]>([]);
|
||||
const yearLast = ref(''); // 年份后两位
|
||||
const majorName = ref(''); // 专业名称
|
||||
|
||||
// 提交表单数据
|
||||
const form = reactive({
|
||||
id: '',
|
||||
enterDate: '',
|
||||
majorCode: '',
|
||||
deptCode: '',
|
||||
classCode: '',
|
||||
classNo: '',
|
||||
className: '',
|
||||
classProName: '',
|
||||
grade: '',
|
||||
teacherNos: '',
|
||||
preStuNum: 0,
|
||||
remark: ''
|
||||
id: '',
|
||||
enterDate: '',
|
||||
majorCode: '',
|
||||
deptCode: '',
|
||||
classCode: '',
|
||||
classNo: '',
|
||||
className: '',
|
||||
classProName: '',
|
||||
grade: '',
|
||||
teacherNos: '',
|
||||
preStuNum: 0,
|
||||
remark: '',
|
||||
});
|
||||
|
||||
// 定义校验规则
|
||||
const dataRules = ref({
|
||||
enterDate: [
|
||||
{ required: true, message: '入学日期不能为空', trigger: 'change' }
|
||||
],
|
||||
majorCode: [
|
||||
{ required: true, message: '专业不能为空', trigger: 'change' }
|
||||
],
|
||||
deptCode: [
|
||||
{ required: true, message: '学院不能为空', trigger: 'change' }
|
||||
],
|
||||
classCode: [
|
||||
{ required: true, message: '班级代码不能为空', trigger: 'blur' },
|
||||
{ min: 4, message: '班级代码至少4位(班号取后4位)', trigger: 'blur' }
|
||||
],
|
||||
classNo: [
|
||||
{ required: true, message: '班号不能为空', trigger: 'blur' }
|
||||
],
|
||||
className: [
|
||||
{ required: true, message: '班级名称不能为空', trigger: 'blur' }
|
||||
],
|
||||
classProName: [
|
||||
{ required: true, message: '班级规范名称不能为空', trigger: 'blur' }
|
||||
],
|
||||
grade: [
|
||||
{ required: true, message: '入学年份不能为空', trigger: 'blur' }
|
||||
],
|
||||
teacherNos: [
|
||||
{ required: true, message: '请选择班主任', trigger: 'change' }
|
||||
],
|
||||
preStuNum: [
|
||||
{ required: true, message: '预计招生人数不能为空', trigger: 'blur' }
|
||||
]
|
||||
})
|
||||
enterDate: [{ required: true, message: '入学日期不能为空', trigger: 'change' }],
|
||||
majorCode: [{ required: true, message: '专业不能为空', trigger: 'change' }],
|
||||
deptCode: [{ required: true, message: '学院不能为空', trigger: 'change' }],
|
||||
classCode: [
|
||||
{ required: true, message: '班级代码不能为空', trigger: 'blur' },
|
||||
{ min: 4, message: '班级代码至少4位(班号取后4位)', trigger: 'blur' },
|
||||
],
|
||||
classNo: [{ required: true, message: '班号不能为空', trigger: 'blur' }],
|
||||
className: [{ required: true, message: '班级名称不能为空', trigger: 'blur' }],
|
||||
classProName: [{ required: true, message: '班级规范名称不能为空', trigger: 'blur' }],
|
||||
grade: [{ required: true, message: '入学年份不能为空', trigger: 'blur' }],
|
||||
teacherNos: [{ required: true, message: '请选择班主任', trigger: 'change' }],
|
||||
preStuNum: [{ required: true, message: '预计招生人数不能为空', trigger: 'blur' }],
|
||||
});
|
||||
|
||||
// 打开弹窗
|
||||
const openDialog = (id?: string) => {
|
||||
visible.value = true
|
||||
|
||||
// 重置表单数据
|
||||
Object.assign(form, {
|
||||
id: '',
|
||||
enterDate: '',
|
||||
majorCode: '',
|
||||
deptCode: '',
|
||||
classCode: '',
|
||||
classNo: '',
|
||||
className: '',
|
||||
classProName: '',
|
||||
grade: '',
|
||||
teacherNos: '',
|
||||
preStuNum: 0,
|
||||
remark: ''
|
||||
})
|
||||
|
||||
// 重置辅助变量
|
||||
yearLast.value = ''
|
||||
majorName.value = ''
|
||||
visible.value = true;
|
||||
|
||||
// 清除表单验证状态,不触发验证
|
||||
nextTick(() => {
|
||||
dataFormRef.value?.clearValidate();
|
||||
dataFormRef.value?.resetFields();
|
||||
});
|
||||
// 重置表单数据
|
||||
Object.assign(form, {
|
||||
id: '',
|
||||
enterDate: '',
|
||||
majorCode: '',
|
||||
deptCode: '',
|
||||
classCode: '',
|
||||
classNo: '',
|
||||
className: '',
|
||||
classProName: '',
|
||||
grade: '',
|
||||
teacherNos: '',
|
||||
preStuNum: 0,
|
||||
remark: '',
|
||||
});
|
||||
|
||||
// 获取详情
|
||||
if (id) {
|
||||
form.id = id
|
||||
getBasicClassData(id)
|
||||
} else {
|
||||
// 新增时,确保验证状态已清除
|
||||
nextTick(() => {
|
||||
dataFormRef.value?.clearValidate();
|
||||
});
|
||||
}
|
||||
// 重置辅助变量
|
||||
yearLast.value = '';
|
||||
majorName.value = '';
|
||||
|
||||
// 清除表单验证状态,不触发验证
|
||||
nextTick(() => {
|
||||
dataFormRef.value?.clearValidate();
|
||||
dataFormRef.value?.resetFields();
|
||||
});
|
||||
|
||||
// 获取详情
|
||||
if (id) {
|
||||
form.id = id;
|
||||
getBasicClassData(id);
|
||||
} else {
|
||||
// 新增时,确保验证状态已清除
|
||||
nextTick(() => {
|
||||
dataFormRef.value?.clearValidate();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// 提交
|
||||
const onSubmit = async () => {
|
||||
const valid = await dataFormRef.value.validate().catch(() => {});
|
||||
if (!valid) return false;
|
||||
const valid = await dataFormRef.value.validate().catch(() => {});
|
||||
if (!valid) return false;
|
||||
|
||||
try {
|
||||
loading.value = true;
|
||||
// 构建提交数据,将班主任工号放到 teacherNo 字段
|
||||
const submitData = {
|
||||
...form,
|
||||
teacherNo: form.teacherNos // 将 teacherNos 的值赋值给 teacherNo
|
||||
};
|
||||
|
||||
if (form.id) {
|
||||
await putObj(submitData);
|
||||
useMessage().success('编辑成功');
|
||||
} else {
|
||||
await addObj(submitData);
|
||||
useMessage().success('新增成功');
|
||||
}
|
||||
visible.value = false;
|
||||
emit('refresh');
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg || (form.id ? '编辑失败' : '新增失败'));
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
try {
|
||||
loading.value = true;
|
||||
// 构建提交数据,将班主任工号放到 teacherNo 字段
|
||||
const submitData = {
|
||||
...form,
|
||||
teacherNo: form.teacherNos, // 将 teacherNos 的值赋值给 teacherNo
|
||||
};
|
||||
|
||||
if (form.id) {
|
||||
await putObj(submitData);
|
||||
useMessage().success('编辑成功');
|
||||
} else {
|
||||
await addObj(submitData);
|
||||
useMessage().success('新增成功');
|
||||
}
|
||||
visible.value = false;
|
||||
emit('refresh');
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg || (form.id ? '编辑失败' : '新增失败'));
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
// 获取详情
|
||||
const getBasicClassData = async (id: string) => {
|
||||
loading.value = true
|
||||
try {
|
||||
const res = await getDetail(id)
|
||||
if (res.data) {
|
||||
Object.assign(form, {
|
||||
id: res.data.id || '',
|
||||
enterDate: res.data.enterDate || '',
|
||||
majorCode: res.data.majorCode || '',
|
||||
deptCode: res.data.deptCode || '',
|
||||
classCode: res.data.classCode || '',
|
||||
classNo: res.data.classNo || '',
|
||||
className: res.data.className || '',
|
||||
classProName: res.data.classProName || '',
|
||||
grade: res.data.grade || '',
|
||||
teacherNos: res.data.teacherNos || '',
|
||||
preStuNum: res.data.preStuNum || 0,
|
||||
remark: res.data.remark || ''
|
||||
})
|
||||
|
||||
// 设置辅助变量(编辑时不自动填充,保持原有数据)
|
||||
if (res.data.enterDate && res.data.enterDate.length >= 4) {
|
||||
yearLast.value = res.data.enterDate.substring(2, 4)
|
||||
}
|
||||
// 确保专业列表已加载后再设置专业名称
|
||||
if (res.data.majorCode && majorList.value.length > 0) {
|
||||
const major = majorList.value.find(item => item.majorCode === res.data.majorCode)
|
||||
if (major) {
|
||||
majorName.value = major.majorName || ''
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (err: any) {
|
||||
console.error('获取详情失败', err)
|
||||
useMessage().error('获取详情失败')
|
||||
} finally {
|
||||
loading.value = false
|
||||
// 数据加载完成后,清除验证状态,避免触发验证
|
||||
nextTick(() => {
|
||||
dataFormRef.value?.clearValidate();
|
||||
});
|
||||
}
|
||||
}
|
||||
loading.value = true;
|
||||
try {
|
||||
const res = await getDetail(id);
|
||||
if (res.data) {
|
||||
Object.assign(form, {
|
||||
id: res.data.id || '',
|
||||
enterDate: res.data.enterDate || '',
|
||||
majorCode: res.data.majorCode || '',
|
||||
deptCode: res.data.deptCode || '',
|
||||
classCode: res.data.classCode || '',
|
||||
classNo: res.data.classNo || '',
|
||||
className: res.data.className || '',
|
||||
classProName: res.data.classProName || '',
|
||||
grade: res.data.grade || '',
|
||||
teacherNos: res.data.teacherNos || '',
|
||||
preStuNum: res.data.preStuNum || 0,
|
||||
remark: res.data.remark || '',
|
||||
});
|
||||
|
||||
// 设置辅助变量(编辑时不自动填充,保持原有数据)
|
||||
if (res.data.enterDate && res.data.enterDate.length >= 4) {
|
||||
yearLast.value = res.data.enterDate.substring(2, 4);
|
||||
}
|
||||
// 确保专业列表已加载后再设置专业名称
|
||||
if (res.data.majorCode && majorList.value.length > 0) {
|
||||
const major = majorList.value.find((item) => item.majorCode === res.data.majorCode);
|
||||
if (major) {
|
||||
majorName.value = major.majorName || '';
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (err: any) {
|
||||
console.error('获取详情失败', err);
|
||||
useMessage().error('获取详情失败');
|
||||
} finally {
|
||||
loading.value = false;
|
||||
// 数据加载完成后,清除验证状态,避免触发验证
|
||||
nextTick(() => {
|
||||
dataFormRef.value?.clearValidate();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// 获取专业列表
|
||||
const getMajorListData = async () => {
|
||||
try {
|
||||
const res = await getMajorNameList()
|
||||
if (res.data) {
|
||||
majorList.value = Array.isArray(res.data) ? res.data : []
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('获取专业列表失败', err)
|
||||
majorList.value = []
|
||||
}
|
||||
}
|
||||
try {
|
||||
const res = await getMajorNameList();
|
||||
if (res.data) {
|
||||
majorList.value = Array.isArray(res.data) ? res.data : [];
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('获取专业列表失败', err);
|
||||
majorList.value = [];
|
||||
}
|
||||
};
|
||||
|
||||
// 获取学院列表
|
||||
const getDeptListData = async () => {
|
||||
try {
|
||||
const res = await getDeptList()
|
||||
if (res.data) {
|
||||
deptList.value = Array.isArray(res.data) ? res.data : []
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('获取学院列表失败', err)
|
||||
deptList.value = []
|
||||
}
|
||||
}
|
||||
try {
|
||||
const res = await getDeptList();
|
||||
if (res.data) {
|
||||
deptList.value = Array.isArray(res.data) ? res.data : [];
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('获取学院列表失败', err);
|
||||
deptList.value = [];
|
||||
}
|
||||
};
|
||||
|
||||
// 获取班主任列表
|
||||
const getTeacherListData = async () => {
|
||||
try {
|
||||
const res = await getTeacherBaseList()
|
||||
if (res.data) {
|
||||
teacherList.value = Array.isArray(res.data) ? res.data : []
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('获取班主任列表失败', err)
|
||||
teacherList.value = []
|
||||
}
|
||||
}
|
||||
try {
|
||||
const res = await getTeacherBaseList();
|
||||
if (res.data) {
|
||||
teacherList.value = Array.isArray(res.data) ? res.data : [];
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('获取班主任列表失败', err);
|
||||
teacherList.value = [];
|
||||
}
|
||||
};
|
||||
|
||||
// 拼接班级规范名称
|
||||
const montageClassProName = () => {
|
||||
// 只在新增模式下自动填充,编辑模式下不覆盖已有数据
|
||||
if (!form.id && yearLast.value && majorName.value) {
|
||||
form.classProName = yearLast.value + majorName.value
|
||||
if (form.classNo) {
|
||||
form.classProName = yearLast.value + majorName.value + '(' + form.classNo + ')'
|
||||
}
|
||||
console.log('classProName', form.classProName)
|
||||
}
|
||||
}
|
||||
// 只在新增模式下自动填充,编辑模式下不覆盖已有数据
|
||||
if (!form.id && yearLast.value && majorName.value) {
|
||||
form.classProName = yearLast.value + majorName.value;
|
||||
if (form.classNo) {
|
||||
form.classProName = yearLast.value + majorName.value + '(' + form.classNo + ')';
|
||||
}
|
||||
console.log('classProName', form.classProName);
|
||||
}
|
||||
};
|
||||
|
||||
// 监听入学日期,取年份后两位
|
||||
watch(() => form.enterDate, (newVal) => {
|
||||
if (newVal && newVal.length >= 4) {
|
||||
console.log('newdate:', newVal)
|
||||
yearLast.value = newVal.substring(2, 4)
|
||||
// 只在新增模式下自动填充入学年份
|
||||
if (!form.id) {
|
||||
form.grade = newVal.substring(0, 4)
|
||||
}
|
||||
montageClassProName()
|
||||
}
|
||||
})
|
||||
watch(
|
||||
() => form.enterDate,
|
||||
(newVal) => {
|
||||
if (newVal && newVal.length >= 4) {
|
||||
console.log('newdate:', newVal);
|
||||
yearLast.value = newVal.substring(2, 4);
|
||||
// 只在新增模式下自动填充入学年份
|
||||
if (!form.id) {
|
||||
form.grade = newVal.substring(0, 4);
|
||||
}
|
||||
montageClassProName();
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// 监听班级代码,取后四位为班号(班级代码至少4位)
|
||||
watch(() => form.classCode, (newVal) => {
|
||||
if (newVal) {
|
||||
const length = newVal.length
|
||||
if (length >= 4) {
|
||||
// 只在新增模式下自动填充班号,编辑模式下如果班号为空才填充
|
||||
if (!form.id || !form.classNo) {
|
||||
form.classNo = newVal.substring(length - 4, length)
|
||||
montageClassProName()
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
watch(
|
||||
() => form.classCode,
|
||||
(newVal) => {
|
||||
if (newVal) {
|
||||
const length = newVal.length;
|
||||
if (length >= 4) {
|
||||
// 只在新增模式下自动填充班号,编辑模式下如果班号为空才填充
|
||||
if (!form.id || !form.classNo) {
|
||||
form.classNo = newVal.substring(length - 4, length);
|
||||
montageClassProName();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// 监听专业代码变化,获取专业名称
|
||||
watch(() => form.majorCode, (newVal) => {
|
||||
if (newVal) {
|
||||
const major = majorList.value.find(item => item.majorCode === newVal)
|
||||
if (major) {
|
||||
majorName.value = major.majorName || ''
|
||||
montageClassProName()
|
||||
}
|
||||
} else {
|
||||
majorName.value = ''
|
||||
montageClassProName()
|
||||
}
|
||||
})
|
||||
watch(
|
||||
() => form.majorCode,
|
||||
(newVal) => {
|
||||
if (newVal) {
|
||||
const major = majorList.value.find((item) => item.majorCode === newVal);
|
||||
if (major) {
|
||||
majorName.value = major.majorName || '';
|
||||
montageClassProName();
|
||||
}
|
||||
} else {
|
||||
majorName.value = '';
|
||||
montageClassProName();
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// 初始化
|
||||
onMounted(() => {
|
||||
getMajorListData()
|
||||
getDeptListData()
|
||||
getTeacherListData()
|
||||
})
|
||||
getMajorListData();
|
||||
getDeptListData();
|
||||
getTeacherListData();
|
||||
});
|
||||
|
||||
// 暴露变量
|
||||
defineExpose({
|
||||
openDialog
|
||||
openDialog,
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -1,532 +1,438 @@
|
||||
<template>
|
||||
<div class="modern-page-container">
|
||||
<div class="page-wrapper">
|
||||
<!-- 搜索表单卡片 -->
|
||||
<el-card v-show="showSearch" class="search-card" shadow="never">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span class="card-title">
|
||||
<el-icon class="title-icon"><Search /></el-icon>
|
||||
筛选条件
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
<el-form :model="searchForm" ref="searchFormRef" :inline="true" @keyup.enter="handleSearch" class="search-form">
|
||||
<el-form-item label="学院" prop="deptCode">
|
||||
<el-select
|
||||
v-model="searchForm.deptCode"
|
||||
placeholder="请选择学院"
|
||||
clearable
|
||||
filterable
|
||||
style="width: 200px"
|
||||
@change="handleDeptChange">
|
||||
<el-option
|
||||
v-for="item in deptList"
|
||||
:key="item.deptCode"
|
||||
:label="item.deptName"
|
||||
:value="item.deptCode">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="班号" prop="classNo">
|
||||
<el-input
|
||||
v-model="searchForm.classNo"
|
||||
placeholder="请输入班号"
|
||||
clearable
|
||||
style="width: 200px" />
|
||||
</el-form-item>
|
||||
<el-form-item label="联院" prop="isUnion">
|
||||
<el-select
|
||||
v-model="searchForm.isUnion"
|
||||
placeholder="请选择联院"
|
||||
clearable
|
||||
style="width: 200px">
|
||||
<el-option label="是" value="1" />
|
||||
<el-option label="否" value="0" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="流失率" prop="stuLoseRate">
|
||||
<el-input
|
||||
v-model="searchForm.stuLoseRate"
|
||||
placeholder="请输入流失率"
|
||||
clearable
|
||||
style="width: 200px" />
|
||||
</el-form-item>
|
||||
<el-form-item label="入学年份" prop="grade">
|
||||
<el-input
|
||||
v-model="searchForm.grade"
|
||||
placeholder="请输入入学年份"
|
||||
clearable
|
||||
style="width: 200px" />
|
||||
</el-form-item>
|
||||
<el-form-item label="班主任" prop="teacherRealName">
|
||||
<el-input
|
||||
v-model="searchForm.teacherRealName"
|
||||
placeholder="请输入班主任姓名"
|
||||
clearable
|
||||
style="width: 200px" />
|
||||
</el-form-item>
|
||||
<el-form-item label="班级状态" prop="classStatus">
|
||||
<el-select
|
||||
v-model="searchForm.classStatus"
|
||||
placeholder="请选择班级状态"
|
||||
clearable
|
||||
style="width: 200px">
|
||||
<el-option label="正常" value="0" />
|
||||
<el-option label="离校" value="1" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" plain icon="Search" @click="handleSearch">查询</el-button>
|
||||
<el-button icon="Refresh" @click="handleReset">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
<div class="modern-page-container">
|
||||
<div class="page-wrapper">
|
||||
<!-- 搜索表单卡片 -->
|
||||
<el-card v-show="showSearch" class="search-card" shadow="never">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span class="card-title">
|
||||
<el-icon class="title-icon"><Search /></el-icon>
|
||||
筛选条件
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
<el-form :model="searchForm" ref="searchFormRef" :inline="true" @keyup.enter="handleSearch" class="search-form">
|
||||
<el-form-item label="学院" prop="deptCode">
|
||||
<el-select v-model="searchForm.deptCode" placeholder="请选择学院" clearable filterable style="width: 200px" @change="handleDeptChange">
|
||||
<el-option v-for="item in deptList" :key="item.deptCode" :label="item.deptName" :value="item.deptCode"> </el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="班号" prop="classNo">
|
||||
<el-input v-model="searchForm.classNo" placeholder="请输入班号" clearable style="width: 200px" />
|
||||
</el-form-item>
|
||||
<el-form-item label="联院" prop="isUnion">
|
||||
<el-select v-model="searchForm.isUnion" placeholder="请选择联院" clearable style="width: 200px">
|
||||
<el-option label="是" value="1" />
|
||||
<el-option label="否" value="0" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="流失率" prop="stuLoseRate">
|
||||
<el-input v-model="searchForm.stuLoseRate" placeholder="请输入流失率" clearable style="width: 200px" />
|
||||
</el-form-item>
|
||||
<el-form-item label="入学年份" prop="grade">
|
||||
<el-input v-model="searchForm.grade" placeholder="请输入入学年份" clearable style="width: 200px" />
|
||||
</el-form-item>
|
||||
<el-form-item label="班主任" prop="teacherRealName">
|
||||
<el-input v-model="searchForm.teacherRealName" placeholder="请输入班主任姓名" clearable style="width: 200px" />
|
||||
</el-form-item>
|
||||
<el-form-item label="班级状态" prop="classStatus">
|
||||
<el-select v-model="searchForm.classStatus" placeholder="请选择班级状态" clearable style="width: 200px">
|
||||
<el-option label="正常" value="0" />
|
||||
<el-option label="离校" value="1" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" plain icon="Search" @click="handleSearch">查询</el-button>
|
||||
<el-button icon="Refresh" @click="handleReset">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
|
||||
<!-- 内容卡片 -->
|
||||
<el-card class="content-card" shadow="never">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span class="card-title">
|
||||
<el-icon class="title-icon"><Document /></el-icon>
|
||||
班级列表
|
||||
</span>
|
||||
<div class="header-actions">
|
||||
<el-button
|
||||
icon="FolderAdd"
|
||||
type="primary"
|
||||
@click="formDialogRef.openDialog()">
|
||||
新增
|
||||
</el-button>
|
||||
<el-button
|
||||
icon="Link"
|
||||
type="success"
|
||||
class="ml10"
|
||||
@click="handleLinkRule">
|
||||
关联门禁规则
|
||||
</el-button>
|
||||
<el-button
|
||||
icon="Download"
|
||||
type="warning"
|
||||
class="ml10"
|
||||
@click="handleExport">
|
||||
导出
|
||||
</el-button>
|
||||
<el-button
|
||||
icon="DocumentAdd"
|
||||
type="info"
|
||||
class="ml10"
|
||||
@click="handleGenerateAssessment">
|
||||
生成考核班级
|
||||
</el-button>
|
||||
<right-toolbar
|
||||
v-model:showSearch="showSearch"
|
||||
class="ml10"
|
||||
@queryTable="getDataList">
|
||||
<TableColumnControl
|
||||
ref="columnControlRef"
|
||||
:columns="tableColumns"
|
||||
v-model="visibleColumns"
|
||||
trigger-type="default"
|
||||
trigger-circle
|
||||
@change="handleColumnChange"
|
||||
@order-change="handleColumnOrderChange"
|
||||
>
|
||||
<template #trigger>
|
||||
<el-tooltip class="item" effect="dark" content="列设置" placement="top">
|
||||
<el-button circle style="margin-left: 0;">
|
||||
<el-icon><Menu /></el-icon>
|
||||
</el-button>
|
||||
</el-tooltip>
|
||||
</template>
|
||||
</TableColumnControl>
|
||||
</right-toolbar>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<!-- 内容卡片 -->
|
||||
<el-card class="content-card" shadow="never">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span class="card-title">
|
||||
<el-icon class="title-icon"><Document /></el-icon>
|
||||
班级列表
|
||||
</span>
|
||||
<div class="header-actions">
|
||||
<el-button icon="FolderAdd" type="primary" @click="formDialogRef.openDialog()"> 新增 </el-button>
|
||||
<el-button icon="Link" type="success" class="ml10" @click="handleLinkRule"> 关联门禁规则 </el-button>
|
||||
<el-button icon="Download" type="warning" class="ml10" @click="handleExport"> 导出 </el-button>
|
||||
<el-button icon="DocumentAdd" type="info" class="ml10" @click="handleGenerateAssessment"> 生成考核班级 </el-button>
|
||||
<right-toolbar v-model:showSearch="showSearch" class="ml10" @queryTable="getDataList">
|
||||
<TableColumnControl
|
||||
ref="columnControlRef"
|
||||
:columns="tableColumns"
|
||||
v-model="visibleColumns"
|
||||
trigger-type="default"
|
||||
trigger-circle
|
||||
@change="handleColumnChange"
|
||||
@order-change="handleColumnOrderChange"
|
||||
>
|
||||
<template #trigger>
|
||||
<el-tooltip class="item" effect="dark" content="列设置" placement="top">
|
||||
<el-button circle style="margin-left: 0">
|
||||
<el-icon><Menu /></el-icon>
|
||||
</el-button>
|
||||
</el-tooltip>
|
||||
</template>
|
||||
</TableColumnControl>
|
||||
</right-toolbar>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- 表格 -->
|
||||
<el-table
|
||||
:data="state.dataList"
|
||||
v-loading="state.loading"
|
||||
stripe
|
||||
:cell-style="tableStyle.cellStyle"
|
||||
:header-cell-style="tableStyle.headerCellStyle"
|
||||
class="modern-table"
|
||||
row-key="id"
|
||||
@selection-change="handleSelectionChange"
|
||||
@sort-change="sortChangeHandle">
|
||||
<el-table-column type="selection" width="55" align="center" />
|
||||
<el-table-column type="index" label="序号" width="70" align="center">
|
||||
<template #header>
|
||||
<el-icon><List /></el-icon>
|
||||
</template>
|
||||
<template #default="{ $index }">
|
||||
{{ $index + 1 + ((state.pagination?.current || 1) - 1) * (state.pagination?.size || 10) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
v-for="col in visibleColumnsSorted"
|
||||
:key="col.prop"
|
||||
:prop="col.prop"
|
||||
:label="col.label"
|
||||
:width="col.width"
|
||||
:min-width="col.minWidth"
|
||||
:show-overflow-tooltip="col.showOverflowTooltip !== false"
|
||||
:align="col.align">
|
||||
<template #header>
|
||||
<el-icon v-if="col.icon"><component :is="col.icon" /></el-icon>
|
||||
<span :style="{ marginLeft: col.icon ? '4px' : '0' }">{{ col.label }}</span>
|
||||
</template>
|
||||
<template #default="scope" v-if="col.prop === 'stuNum'">
|
||||
<el-tag size="small" type="primary" effect="plain">
|
||||
{{ scope.row.stuNum || 0 }}/{{ scope.row.preStuNum || 0 }}
|
||||
</el-tag>
|
||||
</template>
|
||||
<template #default="scope" v-else-if="col.prop === 'classStatus'">
|
||||
<StatusTag
|
||||
:value="scope.row.classStatus"
|
||||
:options="[{ label: '正常', value: '0' }, { label: '离校', value: '1' }]"
|
||||
:type-map="{ '0': { type: 'success', effect: 'light' }, '1': { type: 'warning', effect: 'light' } }"
|
||||
/>
|
||||
</template>
|
||||
<template #default="scope" v-else-if="col.prop === 'stuLoseRate'">
|
||||
<el-tag size="small" type="danger" effect="plain">
|
||||
{{ scope.row.stuLoseRate ? `${scope.row.stuLoseRate}%` : '0%' }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" align="center" fixed="right" width="260">
|
||||
<template #default="scope">
|
||||
<el-button
|
||||
icon="View"
|
||||
link
|
||||
type="primary"
|
||||
@click="handleViewDetail(scope.row)">
|
||||
班级概况
|
||||
</el-button>
|
||||
<el-button
|
||||
icon="Edit"
|
||||
link
|
||||
type="primary"
|
||||
@click="formDialogRef.openDialog(scope.row.id)">
|
||||
编辑
|
||||
</el-button>
|
||||
<el-button
|
||||
icon="Delete"
|
||||
link
|
||||
type="danger"
|
||||
@click="handleDelete([scope.row.id])">
|
||||
删除
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<!-- 表格 -->
|
||||
<el-table
|
||||
:data="state.dataList"
|
||||
v-loading="state.loading"
|
||||
stripe
|
||||
:cell-style="tableStyle.cellStyle"
|
||||
:header-cell-style="tableStyle.headerCellStyle"
|
||||
class="modern-table"
|
||||
row-key="id"
|
||||
@selection-change="handleSelectionChange"
|
||||
@sort-change="sortChangeHandle"
|
||||
>
|
||||
<el-table-column type="selection" width="55" align="center" />
|
||||
<el-table-column type="index" label="序号" width="70" align="center">
|
||||
<template #header>
|
||||
<el-icon><List /></el-icon>
|
||||
</template>
|
||||
<template #default="{ $index }">
|
||||
{{ $index + 1 + ((state.pagination?.current || 1) - 1) * (state.pagination?.size || 10) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
v-for="col in visibleColumnsSorted"
|
||||
:key="col.prop"
|
||||
:prop="col.prop"
|
||||
:label="col.label"
|
||||
:width="col.width"
|
||||
:min-width="col.minWidth"
|
||||
:show-overflow-tooltip="col.showOverflowTooltip !== false"
|
||||
:align="col.align"
|
||||
>
|
||||
<template #header>
|
||||
<el-icon v-if="col.icon"><component :is="col.icon" /></el-icon>
|
||||
<span :style="{ marginLeft: col.icon ? '4px' : '0' }">{{ col.label }}</span>
|
||||
</template>
|
||||
<template #default="scope" v-if="col.prop === 'stuNum'">
|
||||
<el-tag size="small" type="primary" effect="plain"> {{ scope.row.stuNum || 0 }}/{{ scope.row.preStuNum || 0 }} </el-tag>
|
||||
</template>
|
||||
<template #default="scope" v-else-if="col.prop === 'classStatus'">
|
||||
<StatusTag
|
||||
:value="scope.row.classStatus"
|
||||
:options="[
|
||||
{ label: '正常', value: '0' },
|
||||
{ label: '离校', value: '1' },
|
||||
]"
|
||||
:type-map="{ '0': { type: 'success', effect: 'light' }, '1': { type: 'warning', effect: 'light' } }"
|
||||
/>
|
||||
</template>
|
||||
<template #default="scope" v-else-if="col.prop === 'stuLoseRate'">
|
||||
<el-tag size="small" type="danger" effect="plain">
|
||||
{{ scope.row.stuLoseRate ? `${scope.row.stuLoseRate}%` : '0%' }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" align="center" fixed="right" width="260">
|
||||
<template #default="scope">
|
||||
<el-button icon="View" link type="primary" @click="handleViewDetail(scope.row)"> 班级概况 </el-button>
|
||||
<el-button icon="Edit" link type="primary" @click="formDialogRef.openDialog(scope.row.id)"> 编辑 </el-button>
|
||||
<el-button icon="Delete" link type="danger" @click="handleDelete([scope.row.id])"> 删除 </el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<!-- 分页 -->
|
||||
<div class="pagination-wrapper">
|
||||
<pagination
|
||||
@size-change="sizeChangeHandle"
|
||||
@current-change="currentChangeHandle"
|
||||
v-bind="state.pagination" />
|
||||
</div>
|
||||
</el-card>
|
||||
</div>
|
||||
<!-- 分页 -->
|
||||
<div class="pagination-wrapper">
|
||||
<pagination @size-change="sizeChangeHandle" @current-change="currentChangeHandle" v-bind="state.pagination" />
|
||||
</div>
|
||||
</el-card>
|
||||
</div>
|
||||
|
||||
<!-- 编辑、新增 -->
|
||||
<FormDialog ref="formDialogRef" @refresh="getDataList(false)" />
|
||||
|
||||
<!-- 班级概况详情 -->
|
||||
<DetailDialog ref="detailDialogRef" />
|
||||
|
||||
<!-- 关联门禁规则对话框 -->
|
||||
<el-dialog
|
||||
title="关联门禁规则"
|
||||
v-model="linkRuleDialogVisible"
|
||||
:close-on-click-modal="false"
|
||||
draggable
|
||||
width="600px">
|
||||
<el-form :model="linkRuleForm" label-width="120px">
|
||||
<el-form-item label="选择规则">
|
||||
<el-select
|
||||
v-model="linkRuleForm.ruleId"
|
||||
placeholder="请选择门禁规则"
|
||||
clearable
|
||||
filterable
|
||||
style="width: 100%">
|
||||
<el-option
|
||||
v-for="item in ruleList"
|
||||
:key="item.id"
|
||||
:label="item.ruleName"
|
||||
:value="item.id">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="linkRuleDialogVisible = false">取 消</el-button>
|
||||
<el-button type="primary" @click="confirmLinkRule" :loading="linkRuleLoading">确 认</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
<!-- 编辑、新增 -->
|
||||
<FormDialog ref="formDialogRef" @refresh="getDataList(false)" />
|
||||
|
||||
<!-- 班级概况详情 -->
|
||||
<DetailDialog ref="detailDialogRef" />
|
||||
|
||||
<!-- 关联门禁规则对话框 -->
|
||||
<el-dialog title="关联门禁规则" v-model="linkRuleDialogVisible" :close-on-click-modal="false" draggable width="600px">
|
||||
<el-form :model="linkRuleForm" label-width="120px">
|
||||
<el-form-item label="选择规则">
|
||||
<el-select v-model="linkRuleForm.ruleId" placeholder="请选择门禁规则" clearable filterable style="width: 100%">
|
||||
<el-option v-for="item in ruleList" :key="item.id" :label="item.ruleName" :value="item.id"> </el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="linkRuleDialogVisible = false">取 消</el-button>
|
||||
<el-button type="primary" @click="confirmLinkRule" :loading="linkRuleLoading">确 认</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="BasicClass">
|
||||
import { ref, reactive, defineAsyncComponent, computed, onMounted } from 'vue'
|
||||
import { useRoute } from 'vue-router'
|
||||
import { BasicTableProps, useTable } from "/@/hooks/table";
|
||||
import { fetchList, delObj, putObjs, classExportData, getDeptList, getClassListByRole } from "/@/api/basic/basicclass";
|
||||
import { makeExportClassOverviewTask } from "/@/api/stuwork/file";
|
||||
import { useMessage, useMessageBox } from "/@/hooks/message";
|
||||
import { fetchList as getRuleList } from "/@/api/stuwork/entrancerule";
|
||||
import TableColumnControl from '/@/components/TableColumnControl/index.vue'
|
||||
import { List, OfficeBuilding, Grid, Document, UserFilled, Phone, User, Lock, CircleCheck, TrendCharts, Setting, Menu, Search } from '@element-plus/icons-vue'
|
||||
import { useTableColumnControl } from '/@/hooks/tableColumn'
|
||||
import { defineAsyncComponent as defineStatusTag } from 'vue'
|
||||
const StatusTag = defineStatusTag(() => import('/@/components/StatusTag/index.vue'))
|
||||
import { ref, reactive, defineAsyncComponent, computed, onMounted } from 'vue';
|
||||
import { useRoute } from 'vue-router';
|
||||
import { BasicTableProps, useTable } from '/@/hooks/table';
|
||||
import { fetchList, delObj, putObjs, classExportData, getDeptList, getClassListByRole } from '/@/api/basic/basicclass';
|
||||
import { makeExportClassOverviewTask } from '/@/api/stuwork/file';
|
||||
import { useMessage, useMessageBox } from '/@/hooks/message';
|
||||
import { fetchList as getRuleList } from '/@/api/stuwork/entrancerule';
|
||||
import TableColumnControl from '/@/components/TableColumnControl/index.vue';
|
||||
import {
|
||||
List,
|
||||
OfficeBuilding,
|
||||
Grid,
|
||||
Document,
|
||||
UserFilled,
|
||||
Phone,
|
||||
User,
|
||||
Lock,
|
||||
CircleCheck,
|
||||
TrendCharts,
|
||||
Setting,
|
||||
Menu,
|
||||
Search,
|
||||
} from '@element-plus/icons-vue';
|
||||
import { useTableColumnControl } from '/@/hooks/tableColumn';
|
||||
import { defineAsyncComponent as defineStatusTag } from 'vue';
|
||||
const StatusTag = defineStatusTag(() => import('/@/components/StatusTag/index.vue'));
|
||||
|
||||
// 引入组件
|
||||
const FormDialog = defineAsyncComponent(() => import('./form.vue'));
|
||||
const DetailDialog = defineAsyncComponent(() => import('./detail.vue'));
|
||||
|
||||
// 定义变量内容
|
||||
const route = useRoute()
|
||||
const formDialogRef = ref()
|
||||
const detailDialogRef = ref()
|
||||
const searchFormRef = ref()
|
||||
const columnControlRef = ref()
|
||||
const route = useRoute();
|
||||
const formDialogRef = ref();
|
||||
const detailDialogRef = ref();
|
||||
const searchFormRef = ref();
|
||||
const columnControlRef = ref();
|
||||
// 搜索变量
|
||||
const showSearch = ref(true)
|
||||
const deptList = ref<any[]>([])
|
||||
const classList = ref<any[]>([])
|
||||
const ruleList = ref<any[]>([])
|
||||
const linkRuleDialogVisible = ref(false)
|
||||
const linkRuleLoading = ref(false)
|
||||
const selectedClassCodes = ref<string[]>([])
|
||||
const showSearch = ref(true);
|
||||
const deptList = ref<any[]>([]);
|
||||
const classList = ref<any[]>([]);
|
||||
const ruleList = ref<any[]>([]);
|
||||
const linkRuleDialogVisible = ref(false);
|
||||
const linkRuleLoading = ref(false);
|
||||
const selectedClassCodes = ref<string[]>([]);
|
||||
|
||||
// 表格列配置
|
||||
const tableColumns = [
|
||||
{ prop: 'deptName', label: '学院', icon: OfficeBuilding },
|
||||
{ prop: 'classNo', label: '班号', icon: Grid },
|
||||
{ prop: 'classProName', label: '班级规范名称', icon: Document },
|
||||
{ prop: 'teacherRealName', label: '班主任', icon: UserFilled },
|
||||
{ prop: 'teacherTel', label: '班主任电话号码', icon: Phone },
|
||||
{ prop: 'stuNum', label: '班级人数/原始人数', icon: User },
|
||||
{ prop: 'ruleName', label: '门禁规则', icon: Lock },
|
||||
{ prop: 'classStatus', label: '班级状态', icon: CircleCheck },
|
||||
{ prop: 'stuLoseRate', label: '流失率', icon: TrendCharts }
|
||||
]
|
||||
{ prop: 'deptName', label: '学院', icon: OfficeBuilding },
|
||||
{ prop: 'classNo', label: '班号', icon: Grid },
|
||||
{ prop: 'classProName', label: '班级规范名称', icon: Document },
|
||||
{ prop: 'teacherRealName', label: '班主任', icon: UserFilled },
|
||||
{ prop: 'teacherTel', label: '班主任电话号码', icon: Phone },
|
||||
{ prop: 'stuNum', label: '班级人数/原始人数', icon: User },
|
||||
{ prop: 'ruleName', label: '门禁规则', icon: Lock },
|
||||
{ prop: 'classStatus', label: '班级状态', icon: CircleCheck },
|
||||
{ prop: 'stuLoseRate', label: '流失率', icon: TrendCharts },
|
||||
];
|
||||
|
||||
// 使用表格列控制hook
|
||||
const {
|
||||
visibleColumns,
|
||||
visibleColumnsSorted,
|
||||
checkColumnVisible,
|
||||
handleColumnChange,
|
||||
handleColumnOrderChange
|
||||
} = useTableColumnControl(tableColumns)
|
||||
const { visibleColumns, visibleColumnsSorted, checkColumnVisible, handleColumnChange, handleColumnOrderChange } = useTableColumnControl(tableColumns);
|
||||
|
||||
// 搜索表单
|
||||
const searchForm = reactive({
|
||||
deptCode: '',
|
||||
classNo: '',
|
||||
isUnion: '',
|
||||
stuLoseRate: '',
|
||||
grade: '',
|
||||
teacherRealName: '',
|
||||
classStatus: ''
|
||||
})
|
||||
deptCode: '',
|
||||
classNo: '',
|
||||
isUnion: '',
|
||||
stuLoseRate: '',
|
||||
grade: '',
|
||||
teacherRealName: '',
|
||||
classStatus: '',
|
||||
});
|
||||
|
||||
// 关联门禁规则表单
|
||||
const linkRuleForm = reactive({
|
||||
ruleId: ''
|
||||
})
|
||||
ruleId: '',
|
||||
});
|
||||
|
||||
// 配置 useTable
|
||||
const state: BasicTableProps = reactive<BasicTableProps>({
|
||||
queryForm: searchForm,
|
||||
pageList: fetchList,
|
||||
props: {
|
||||
item: 'records',
|
||||
totalCount: 'total'
|
||||
},
|
||||
createdIsNeed: true
|
||||
})
|
||||
queryForm: searchForm,
|
||||
pageList: fetchList,
|
||||
props: {
|
||||
item: 'records',
|
||||
totalCount: 'total',
|
||||
},
|
||||
createdIsNeed: true,
|
||||
});
|
||||
|
||||
// table hook
|
||||
const {
|
||||
getDataList,
|
||||
currentChangeHandle,
|
||||
sizeChangeHandle,
|
||||
sortChangeHandle,
|
||||
tableStyle
|
||||
} = useTable(state)
|
||||
const { getDataList, currentChangeHandle, sizeChangeHandle, sortChangeHandle, tableStyle } = useTable(state);
|
||||
|
||||
// 表格多选
|
||||
const handleSelectionChange = (rows: any[]) => {
|
||||
selectedClassCodes.value = (rows || [])
|
||||
.map((item) => item.classCode)
|
||||
.filter((item) => !!item)
|
||||
}
|
||||
selectedClassCodes.value = (rows || []).map((item) => item.classCode).filter((item) => !!item);
|
||||
};
|
||||
|
||||
// 学院选择变化
|
||||
const handleDeptChange = () => {
|
||||
// 可以根据需要清空班号选择
|
||||
}
|
||||
// 可以根据需要清空班号选择
|
||||
};
|
||||
|
||||
// 查询
|
||||
const handleSearch = () => {
|
||||
getDataList()
|
||||
}
|
||||
getDataList();
|
||||
};
|
||||
|
||||
// 重置
|
||||
const handleReset = () => {
|
||||
searchFormRef.value?.resetFields()
|
||||
searchForm.deptCode = ''
|
||||
searchForm.classNo = ''
|
||||
searchForm.isUnion = ''
|
||||
searchForm.stuLoseRate = ''
|
||||
searchForm.grade = ''
|
||||
searchForm.teacherRealName = ''
|
||||
searchForm.classStatus = ''
|
||||
getDataList()
|
||||
}
|
||||
searchFormRef.value?.resetFields();
|
||||
searchForm.deptCode = '';
|
||||
searchForm.classNo = '';
|
||||
searchForm.isUnion = '';
|
||||
searchForm.stuLoseRate = '';
|
||||
searchForm.grade = '';
|
||||
searchForm.teacherRealName = '';
|
||||
searchForm.classStatus = '';
|
||||
getDataList();
|
||||
};
|
||||
|
||||
// 删除
|
||||
const handleDelete = async (ids: string[]) => {
|
||||
try {
|
||||
await useMessageBox().confirm('确定要删除选中的记录吗?', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
})
|
||||
} catch {
|
||||
return
|
||||
}
|
||||
try {
|
||||
await useMessageBox().confirm('确定要删除选中的记录吗?', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
});
|
||||
} catch {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// 根据API文件,delObj接受单个id,需要循环删除
|
||||
for (const id of ids) {
|
||||
await delObj(id)
|
||||
}
|
||||
useMessage().success('删除成功')
|
||||
getDataList()
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg || '删除失败')
|
||||
}
|
||||
}
|
||||
try {
|
||||
// 根据API文件,delObj接受单个id,需要循环删除
|
||||
for (const id of ids) {
|
||||
await delObj(id);
|
||||
}
|
||||
useMessage().success('删除成功');
|
||||
getDataList();
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg || '删除失败');
|
||||
}
|
||||
};
|
||||
|
||||
// 查看班级概况 - 直接使用表格行数据
|
||||
const handleViewDetail = (row: any) => {
|
||||
if (detailDialogRef.value) {
|
||||
detailDialogRef.value.openDialog(row)
|
||||
}
|
||||
}
|
||||
if (detailDialogRef.value) {
|
||||
detailDialogRef.value.openDialog(row);
|
||||
}
|
||||
};
|
||||
|
||||
// 关联门禁规则
|
||||
const handleLinkRule = () => {
|
||||
if (!selectedClassCodes.value.length) {
|
||||
useMessage().warning('请先勾选要关联的班级')
|
||||
return
|
||||
}
|
||||
linkRuleDialogVisible.value = true
|
||||
linkRuleForm.ruleId = ''
|
||||
// 加载规则列表
|
||||
getRuleListData()
|
||||
}
|
||||
if (!selectedClassCodes.value.length) {
|
||||
useMessage().warning('请先勾选要关联的班级');
|
||||
return;
|
||||
}
|
||||
linkRuleDialogVisible.value = true;
|
||||
linkRuleForm.ruleId = '';
|
||||
// 加载规则列表
|
||||
getRuleListData();
|
||||
};
|
||||
|
||||
// 确认关联门禁规则
|
||||
const confirmLinkRule = async () => {
|
||||
if (!selectedClassCodes.value.length) {
|
||||
useMessage().warning('请先勾选要关联的班级')
|
||||
return
|
||||
}
|
||||
if (!linkRuleForm.ruleId) {
|
||||
useMessage().warning('请选择门禁规则')
|
||||
return
|
||||
}
|
||||
if (!selectedClassCodes.value.length) {
|
||||
useMessage().warning('请先勾选要关联的班级');
|
||||
return;
|
||||
}
|
||||
if (!linkRuleForm.ruleId) {
|
||||
useMessage().warning('请选择门禁规则');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
linkRuleLoading.value = true
|
||||
await putObjs({
|
||||
ruleId: linkRuleForm.ruleId,
|
||||
classCodes: selectedClassCodes.value
|
||||
})
|
||||
useMessage().success('关联成功')
|
||||
linkRuleDialogVisible.value = false
|
||||
getDataList()
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg || '关联失败')
|
||||
} finally {
|
||||
linkRuleLoading.value = false
|
||||
}
|
||||
}
|
||||
try {
|
||||
linkRuleLoading.value = true;
|
||||
await putObjs({
|
||||
ruleId: linkRuleForm.ruleId,
|
||||
classCodes: selectedClassCodes.value,
|
||||
});
|
||||
useMessage().success('关联成功');
|
||||
linkRuleDialogVisible.value = false;
|
||||
getDataList();
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg || '关联失败');
|
||||
} finally {
|
||||
linkRuleLoading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
// 导出
|
||||
const handleExport = async () => {
|
||||
try {
|
||||
await makeExportClassOverviewTask(searchForm)
|
||||
useMessage().success('导出任务已创建,请在文件管理中下载')
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg || '导出失败')
|
||||
}
|
||||
}
|
||||
try {
|
||||
await makeExportClassOverviewTask(searchForm);
|
||||
useMessage().success('导出任务已创建,请在文件管理中下载');
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg || '导出失败');
|
||||
}
|
||||
};
|
||||
|
||||
// 生成考核班级(占位,待确认接口)
|
||||
const handleGenerateAssessment = () => {
|
||||
useMessage().warning('生成考核班级功能待确认接口后启用')
|
||||
}
|
||||
useMessage().warning('生成考核班级功能待确认接口后启用');
|
||||
};
|
||||
|
||||
// 获取学院列表
|
||||
const getDeptListData = async () => {
|
||||
try {
|
||||
const res = await getDeptList()
|
||||
if (res.data) {
|
||||
deptList.value = Array.isArray(res.data) ? res.data : []
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('获取学院列表失败', err)
|
||||
deptList.value = []
|
||||
}
|
||||
}
|
||||
try {
|
||||
const res = await getDeptList();
|
||||
if (res.data) {
|
||||
deptList.value = Array.isArray(res.data) ? res.data : [];
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('获取学院列表失败', err);
|
||||
deptList.value = [];
|
||||
}
|
||||
};
|
||||
|
||||
// 获取班号列表
|
||||
const getClassListData = async () => {
|
||||
try {
|
||||
const res = await getClassListByRole()
|
||||
if (res.data) {
|
||||
classList.value = Array.isArray(res.data) ? res.data : []
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('获取班号列表失败', err)
|
||||
classList.value = []
|
||||
}
|
||||
}
|
||||
try {
|
||||
const res = await getClassListByRole();
|
||||
if (res.data) {
|
||||
classList.value = Array.isArray(res.data) ? res.data : [];
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('获取班号列表失败', err);
|
||||
classList.value = [];
|
||||
}
|
||||
};
|
||||
|
||||
// 获取门禁规则列表
|
||||
const getRuleListData = async () => {
|
||||
try {
|
||||
const res = await getRuleList({ current: 1, size: 9999 })
|
||||
if (res.data && res.data.records) {
|
||||
ruleList.value = Array.isArray(res.data.records) ? res.data.records : []
|
||||
} else if (Array.isArray(res.data)) {
|
||||
ruleList.value = res.data
|
||||
} else {
|
||||
ruleList.value = []
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('获取门禁规则列表失败', err)
|
||||
ruleList.value = []
|
||||
}
|
||||
}
|
||||
try {
|
||||
const res = await getRuleList({ current: 1, size: 9999 });
|
||||
if (res.data && res.data.records) {
|
||||
ruleList.value = Array.isArray(res.data.records) ? res.data.records : [];
|
||||
} else if (Array.isArray(res.data)) {
|
||||
ruleList.value = res.data;
|
||||
} else {
|
||||
ruleList.value = [];
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('获取门禁规则列表失败', err);
|
||||
ruleList.value = [];
|
||||
}
|
||||
};
|
||||
|
||||
// 初始化
|
||||
onMounted(() => {
|
||||
getDeptListData()
|
||||
getClassListData()
|
||||
})
|
||||
getDeptListData();
|
||||
getClassListData();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
|
||||
@@ -1,117 +1,94 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
title="简单信息维护"
|
||||
v-model="visible"
|
||||
:close-on-click-modal="false"
|
||||
draggable
|
||||
width="600px">
|
||||
<el-form
|
||||
ref="dataFormRef"
|
||||
:model="form"
|
||||
:rules="dataRules"
|
||||
label-width="120px"
|
||||
:validate-on-rule-change="false"
|
||||
v-loading="loading">
|
||||
<el-form-item label="姓名" prop="realName">
|
||||
<el-input
|
||||
v-model="form.realName"
|
||||
placeholder="请输入姓名"
|
||||
clearable />
|
||||
</el-form-item>
|
||||
<el-form-item label="曾用名" prop="oldName">
|
||||
<el-input
|
||||
v-model="form.oldName"
|
||||
placeholder="请输入曾用名"
|
||||
clearable />
|
||||
</el-form-item>
|
||||
<el-form-item label="身份证号" prop="idCard">
|
||||
<el-input
|
||||
v-model="form.idCard"
|
||||
placeholder="请输入身份证号"
|
||||
clearable />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="visible = false">取 消</el-button>
|
||||
<el-button type="primary" @click="onSubmit" :disabled="loading">确 认</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
<el-dialog title="简单信息维护" v-model="visible" :close-on-click-modal="false" draggable width="600px">
|
||||
<el-form ref="dataFormRef" :model="form" :rules="dataRules" label-width="120px" :validate-on-rule-change="false" v-loading="loading">
|
||||
<el-form-item label="姓名" prop="realName">
|
||||
<el-input v-model="form.realName" placeholder="请输入姓名" clearable />
|
||||
</el-form-item>
|
||||
<el-form-item label="曾用名" prop="oldName">
|
||||
<el-input v-model="form.oldName" placeholder="请输入曾用名" clearable />
|
||||
</el-form-item>
|
||||
<el-form-item label="身份证号" prop="idCard">
|
||||
<el-input v-model="form.idCard" placeholder="请输入身份证号" clearable />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="visible = false">取 消</el-button>
|
||||
<el-button type="primary" @click="onSubmit" :disabled="loading">确 认</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="SimpleEditDialog">
|
||||
import { ref, reactive, nextTick } from 'vue'
|
||||
import { useMessage } from "/@/hooks/message";
|
||||
import { updateStuSimpleInfo } from '/@/api/basic/basicstudent'
|
||||
import { ref, reactive, nextTick } from 'vue';
|
||||
import { useMessage } from '/@/hooks/message';
|
||||
import { updateStuSimpleInfo } from '/@/api/basic/basicstudent';
|
||||
|
||||
const emit = defineEmits(['refresh']);
|
||||
|
||||
// 定义变量内容
|
||||
const dataFormRef = ref();
|
||||
const visible = ref(false)
|
||||
const loading = ref(false)
|
||||
const visible = ref(false);
|
||||
const loading = ref(false);
|
||||
|
||||
// 提交表单数据
|
||||
const form = reactive({
|
||||
id: '',
|
||||
realName: '',
|
||||
oldName: '',
|
||||
idCard: ''
|
||||
id: '',
|
||||
realName: '',
|
||||
oldName: '',
|
||||
idCard: '',
|
||||
});
|
||||
|
||||
// 定义校验规则 - 只有姓名和身份证号是必填的,曾用名不是必填
|
||||
const dataRules = ref({
|
||||
realName: [
|
||||
{ required: true, message: '姓名不能为空', trigger: 'blur' }
|
||||
],
|
||||
idCard: [
|
||||
{ required: true, message: '身份证号不能为空', trigger: 'blur' },
|
||||
{ pattern: /(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/, message: '请输入正确的身份证号', trigger: 'blur' }
|
||||
]
|
||||
// oldName 不是必填,不需要验证规则
|
||||
})
|
||||
realName: [{ required: true, message: '姓名不能为空', trigger: 'blur' }],
|
||||
idCard: [
|
||||
{ required: true, message: '身份证号不能为空', trigger: 'blur' },
|
||||
{ pattern: /(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/, message: '请输入正确的身份证号', trigger: 'blur' },
|
||||
],
|
||||
// oldName 不是必填,不需要验证规则
|
||||
});
|
||||
|
||||
// 打开弹窗
|
||||
const openDialog = (rowData: any) => {
|
||||
visible.value = true
|
||||
|
||||
// 重置表单数据
|
||||
Object.assign(form, {
|
||||
id: rowData.id || '',
|
||||
realName: rowData.realName || '',
|
||||
oldName: rowData.oldName || '',
|
||||
idCard: rowData.idCard || ''
|
||||
})
|
||||
visible.value = true;
|
||||
|
||||
// 清除表单验证状态
|
||||
nextTick(() => {
|
||||
dataFormRef.value?.clearValidate();
|
||||
dataFormRef.value?.resetFields();
|
||||
});
|
||||
// 重置表单数据
|
||||
Object.assign(form, {
|
||||
id: rowData.id || '',
|
||||
realName: rowData.realName || '',
|
||||
oldName: rowData.oldName || '',
|
||||
idCard: rowData.idCard || '',
|
||||
});
|
||||
|
||||
// 清除表单验证状态
|
||||
nextTick(() => {
|
||||
dataFormRef.value?.clearValidate();
|
||||
dataFormRef.value?.resetFields();
|
||||
});
|
||||
};
|
||||
|
||||
// 提交
|
||||
const onSubmit = async () => {
|
||||
const valid = await dataFormRef.value.validate().catch(() => {});
|
||||
if (!valid) return false;
|
||||
const valid = await dataFormRef.value.validate().catch(() => {});
|
||||
if (!valid) return false;
|
||||
|
||||
try {
|
||||
loading.value = true;
|
||||
await updateStuSimpleInfo(form);
|
||||
useMessage().success('更新成功');
|
||||
visible.value = false;
|
||||
emit('refresh');
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg || '更新失败');
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
try {
|
||||
loading.value = true;
|
||||
await updateStuSimpleInfo(form);
|
||||
useMessage().success('更新成功');
|
||||
visible.value = false;
|
||||
emit('refresh');
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg || '更新失败');
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
// 暴露方法给父组件
|
||||
defineExpose({
|
||||
openDialog
|
||||
openDialog,
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
@@ -1,213 +1,194 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
title="班级概况"
|
||||
v-model="visible"
|
||||
:close-on-click-modal="false"
|
||||
draggable
|
||||
width="1400px">
|
||||
<div v-loading="loading">
|
||||
<!-- 基本信息 -->
|
||||
<el-descriptions :column="3" border v-if="detailData" class="mb20">
|
||||
<el-descriptions-item label="班号">{{ detailData.classNo || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="班级名称">{{ detailData.className || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="班级规范名称">{{ detailData.classProName || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="学院">{{ detailData.deptName || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="班主任">{{ detailData.teacherRealName || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="班主任电话">{{ detailData.teacherTel || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="入学年份">{{ detailData.grade || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="入学时间">{{ detailData.enterDate || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="班级状态">
|
||||
<span>{{ detailData.classStatus === '0' ? '正常' : detailData.classStatus === '1' ? '离校' : '-' }}</span>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="班级人数/原始人数">
|
||||
{{ detailData.stuNum || 0 }}/{{ detailData.preStuNum || 0 }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="流失率">
|
||||
<span>{{ detailData.stuLoseRate ? `${detailData.stuLoseRate}%` : '-' }}</span>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="联院">
|
||||
<span>{{ detailData.isUnion === 1 ? '是' : detailData.isUnion === 0 ? '否' : '-' }}</span>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="门禁规则" :span="3">{{ detailData.ruleName || '-' }}</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
<el-dialog title="班级概况" v-model="visible" :close-on-click-modal="false" draggable width="1400px">
|
||||
<div v-loading="loading">
|
||||
<!-- 基本信息 -->
|
||||
<el-descriptions :column="3" border v-if="detailData" class="mb20">
|
||||
<el-descriptions-item label="班号">{{ detailData.classNo || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="班级名称">{{ detailData.className || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="班级规范名称">{{ detailData.classProName || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="学院">{{ detailData.deptName || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="班主任">{{ detailData.teacherRealName || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="班主任电话">{{ detailData.teacherTel || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="入学年份">{{ detailData.grade || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="入学时间">{{ detailData.enterDate || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="班级状态">
|
||||
<span>{{ detailData.classStatus === '0' ? '正常' : detailData.classStatus === '1' ? '离校' : '-' }}</span>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="班级人数/原始人数"> {{ detailData.stuNum || 0 }}/{{ detailData.preStuNum || 0 }} </el-descriptions-item>
|
||||
<el-descriptions-item label="流失率">
|
||||
<span>{{ detailData.stuLoseRate ? `${detailData.stuLoseRate}%` : '-' }}</span>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="联院">
|
||||
<span>{{ detailData.isUnion === 1 ? '是' : detailData.isUnion === 0 ? '否' : '-' }}</span>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="门禁规则" :span="3">{{ detailData.ruleName || '-' }}</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
|
||||
<!-- 详细信息 - 使用 tabs 展示六个接口的数据 -->
|
||||
<el-tabs v-model="activeTab" type="border-card">
|
||||
<el-tab-pane label="班级荣誉" name="honor">
|
||||
<el-table :data="honorList" border style="width: 100%" v-loading="honorLoading">
|
||||
<el-table-column type="index" label="序号" width="60" align="center" />
|
||||
<el-table-column prop="title" label="标题" show-overflow-tooltip />
|
||||
<el-table-column prop="author" label="作者" width="120" />
|
||||
<el-table-column prop="createTime" label="更新时间" width="120" />
|
||||
<el-table-column prop="belong" label="归档级别" width="120" />
|
||||
</el-table>
|
||||
<div v-if="honorList.length === 0 && !honorLoading" style="text-align: center; padding: 20px; color: #909399;">
|
||||
暂无数据
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
<!-- 详细信息 - 使用 tabs 展示六个接口的数据 -->
|
||||
<el-tabs v-model="activeTab" type="border-card">
|
||||
<el-tab-pane label="班级荣誉" name="honor">
|
||||
<el-table :data="honorList" border style="width: 100%" v-loading="honorLoading">
|
||||
<el-table-column type="index" label="序号" width="60" align="center" />
|
||||
<el-table-column prop="title" label="标题" show-overflow-tooltip />
|
||||
<el-table-column prop="author" label="作者" width="120" />
|
||||
<el-table-column prop="createTime" label="更新时间" width="120" />
|
||||
<el-table-column prop="belong" label="归档级别" width="120" />
|
||||
</el-table>
|
||||
<div v-if="honorList.length === 0 && !honorLoading" style="text-align: center; padding: 20px; color: #909399">暂无数据</div>
|
||||
</el-tab-pane>
|
||||
|
||||
<el-tab-pane label="班级宣传" name="publicity">
|
||||
<el-table :data="publicityList" border style="width: 100%" v-loading="publicityLoading">
|
||||
<el-table-column type="index" label="序号" width="60" align="center" />
|
||||
<el-table-column prop="title" label="标题" show-overflow-tooltip />
|
||||
<el-table-column prop="author" label="作者" width="120" />
|
||||
<el-table-column prop="createTime" label="更新时间" width="120" />
|
||||
<el-table-column prop="belong" label="归档级别" width="120" />
|
||||
<el-table-column prop="website" label="网址" show-overflow-tooltip />
|
||||
</el-table>
|
||||
<div v-if="publicityList.length === 0 && !publicityLoading" style="text-align: center; padding: 20px; color: #909399;">
|
||||
暂无数据
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="班级宣传" name="publicity">
|
||||
<el-table :data="publicityList" border style="width: 100%" v-loading="publicityLoading">
|
||||
<el-table-column type="index" label="序号" width="60" align="center" />
|
||||
<el-table-column prop="title" label="标题" show-overflow-tooltip />
|
||||
<el-table-column prop="author" label="作者" width="120" />
|
||||
<el-table-column prop="createTime" label="更新时间" width="120" />
|
||||
<el-table-column prop="belong" label="归档级别" width="120" />
|
||||
<el-table-column prop="website" label="网址" show-overflow-tooltip />
|
||||
</el-table>
|
||||
<div v-if="publicityList.length === 0 && !publicityLoading" style="text-align: center; padding: 20px; color: #909399">暂无数据</div>
|
||||
</el-tab-pane>
|
||||
|
||||
<el-tab-pane label="数据3" name="data3">
|
||||
<el-table :data="data3List" border style="width: 100%" v-loading="data3Loading">
|
||||
<el-table-column type="index" label="序号" width="60" align="center" />
|
||||
<el-table-column prop="title" label="标题" show-overflow-tooltip />
|
||||
<el-table-column prop="createTime" label="更新时间" width="120" />
|
||||
</el-table>
|
||||
<div v-if="data3List.length === 0 && !data3Loading" style="text-align: center; padding: 20px; color: #909399;">
|
||||
暂无数据
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="数据3" name="data3">
|
||||
<el-table :data="data3List" border style="width: 100%" v-loading="data3Loading">
|
||||
<el-table-column type="index" label="序号" width="60" align="center" />
|
||||
<el-table-column prop="title" label="标题" show-overflow-tooltip />
|
||||
<el-table-column prop="createTime" label="更新时间" width="120" />
|
||||
</el-table>
|
||||
<div v-if="data3List.length === 0 && !data3Loading" style="text-align: center; padding: 20px; color: #909399">暂无数据</div>
|
||||
</el-tab-pane>
|
||||
|
||||
<el-tab-pane label="数据4" name="data4">
|
||||
<el-table :data="data4List" border style="width: 100%" v-loading="data4Loading">
|
||||
<el-table-column type="index" label="序号" width="60" align="center" />
|
||||
<el-table-column prop="title" label="标题" show-overflow-tooltip />
|
||||
<el-table-column prop="createTime" label="更新时间" width="120" />
|
||||
</el-table>
|
||||
<div v-if="data4List.length === 0 && !data4Loading" style="text-align: center; padding: 20px; color: #909399;">
|
||||
暂无数据
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="数据4" name="data4">
|
||||
<el-table :data="data4List" border style="width: 100%" v-loading="data4Loading">
|
||||
<el-table-column type="index" label="序号" width="60" align="center" />
|
||||
<el-table-column prop="title" label="标题" show-overflow-tooltip />
|
||||
<el-table-column prop="createTime" label="更新时间" width="120" />
|
||||
</el-table>
|
||||
<div v-if="data4List.length === 0 && !data4Loading" style="text-align: center; padding: 20px; color: #909399">暂无数据</div>
|
||||
</el-tab-pane>
|
||||
|
||||
<el-tab-pane label="数据5" name="data5">
|
||||
<el-table :data="data5List" border style="width: 100%" v-loading="data5Loading">
|
||||
<el-table-column type="index" label="序号" width="60" align="center" />
|
||||
<el-table-column prop="title" label="标题" show-overflow-tooltip />
|
||||
<el-table-column prop="createTime" label="更新时间" width="120" />
|
||||
</el-table>
|
||||
<div v-if="data5List.length === 0 && !data5Loading" style="text-align: center; padding: 20px; color: #909399;">
|
||||
暂无数据
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="数据5" name="data5">
|
||||
<el-table :data="data5List" border style="width: 100%" v-loading="data5Loading">
|
||||
<el-table-column type="index" label="序号" width="60" align="center" />
|
||||
<el-table-column prop="title" label="标题" show-overflow-tooltip />
|
||||
<el-table-column prop="createTime" label="更新时间" width="120" />
|
||||
</el-table>
|
||||
<div v-if="data5List.length === 0 && !data5Loading" style="text-align: center; padding: 20px; color: #909399">暂无数据</div>
|
||||
</el-tab-pane>
|
||||
|
||||
<el-tab-pane label="数据6" name="data6">
|
||||
<el-table :data="data6List" border style="width: 100%" v-loading="data6Loading">
|
||||
<el-table-column type="index" label="序号" width="60" align="center" />
|
||||
<el-table-column prop="title" label="标题" show-overflow-tooltip />
|
||||
<el-table-column prop="createTime" label="更新时间" width="120" />
|
||||
</el-table>
|
||||
<div v-if="data6List.length === 0 && !data6Loading" style="text-align: center; padding: 20px; color: #909399;">
|
||||
暂无数据
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</div>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="visible = false">关 闭</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
<el-tab-pane label="数据6" name="data6">
|
||||
<el-table :data="data6List" border style="width: 100%" v-loading="data6Loading">
|
||||
<el-table-column type="index" label="序号" width="60" align="center" />
|
||||
<el-table-column prop="title" label="标题" show-overflow-tooltip />
|
||||
<el-table-column prop="createTime" label="更新时间" width="120" />
|
||||
</el-table>
|
||||
<div v-if="data6List.length === 0 && !data6Loading" style="text-align: center; padding: 20px; color: #909399">暂无数据</div>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</div>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="visible = false">关 闭</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="BasicClassDetail">
|
||||
import { ref, watch } from 'vue'
|
||||
import { useMessage } from "/@/hooks/message";
|
||||
import { queryClassHonorByClassCode } from '/@/api/stuwork/classhonor'
|
||||
import { queryDataByClassCode } from '/@/api/stuwork/classpublicity'
|
||||
import { ref, watch } from 'vue';
|
||||
import { useMessage } from '/@/hooks/message';
|
||||
import { queryClassHonorByClassCode } from '/@/api/stuwork/classhonor';
|
||||
import { queryDataByClassCode } from '/@/api/stuwork/classpublicity';
|
||||
|
||||
// 定义变量内容
|
||||
const visible = ref(false)
|
||||
const loading = ref(false)
|
||||
const detailData = ref<any>(null)
|
||||
const activeTab = ref('honor')
|
||||
const visible = ref(false);
|
||||
const loading = ref(false);
|
||||
const detailData = ref<any>(null);
|
||||
const activeTab = ref('honor');
|
||||
|
||||
// 六个接口的数据
|
||||
const honorList = ref<any[]>([])
|
||||
const honorLoading = ref(false)
|
||||
const publicityList = ref<any[]>([])
|
||||
const publicityLoading = ref(false)
|
||||
const data3List = ref<any[]>([])
|
||||
const data3Loading = ref(false)
|
||||
const data4List = ref<any[]>([])
|
||||
const data4Loading = ref(false)
|
||||
const data5List = ref<any[]>([])
|
||||
const data5Loading = ref(false)
|
||||
const data6List = ref<any[]>([])
|
||||
const data6Loading = ref(false)
|
||||
const honorList = ref<any[]>([]);
|
||||
const honorLoading = ref(false);
|
||||
const publicityList = ref<any[]>([]);
|
||||
const publicityLoading = ref(false);
|
||||
const data3List = ref<any[]>([]);
|
||||
const data3Loading = ref(false);
|
||||
const data4List = ref<any[]>([]);
|
||||
const data4Loading = ref(false);
|
||||
const data5List = ref<any[]>([]);
|
||||
const data5Loading = ref(false);
|
||||
const data6List = ref<any[]>([]);
|
||||
const data6Loading = ref(false);
|
||||
|
||||
// 打开弹窗
|
||||
const openDialog = async (rowData: any) => {
|
||||
visible.value = true
|
||||
detailData.value = rowData || null
|
||||
|
||||
// 如果有班级代码,加载六个接口的数据
|
||||
if (rowData?.classCode) {
|
||||
await loadAllData(rowData.classCode)
|
||||
}
|
||||
}
|
||||
visible.value = true;
|
||||
detailData.value = rowData || null;
|
||||
|
||||
// 如果有班级代码,加载六个接口的数据
|
||||
if (rowData?.classCode) {
|
||||
await loadAllData(rowData.classCode);
|
||||
}
|
||||
};
|
||||
|
||||
// 加载所有六个接口的数据
|
||||
const loadAllData = async (classCode: string) => {
|
||||
loading.value = true
|
||||
|
||||
// 并行加载所有接口数据
|
||||
await Promise.all([
|
||||
loadHonorData(classCode),
|
||||
loadPublicityData(classCode),
|
||||
// TODO: 添加其他四个接口的加载
|
||||
// loadData3(classCode),
|
||||
// loadData4(classCode),
|
||||
// loadData5(classCode),
|
||||
// loadData6(classCode),
|
||||
])
|
||||
|
||||
loading.value = false
|
||||
}
|
||||
loading.value = true;
|
||||
|
||||
// 并行加载所有接口数据
|
||||
await Promise.all([
|
||||
loadHonorData(classCode),
|
||||
loadPublicityData(classCode),
|
||||
// TODO: 添加其他四个接口的加载
|
||||
// loadData3(classCode),
|
||||
// loadData4(classCode),
|
||||
// loadData5(classCode),
|
||||
// loadData6(classCode),
|
||||
]);
|
||||
|
||||
loading.value = false;
|
||||
};
|
||||
|
||||
// 加载班级荣誉数据
|
||||
const loadHonorData = async (classCode: string) => {
|
||||
honorLoading.value = true
|
||||
try {
|
||||
const res = await queryClassHonorByClassCode(classCode)
|
||||
if (res.data) {
|
||||
honorList.value = Array.isArray(res.data) ? res.data : []
|
||||
}
|
||||
} catch (err: any) {
|
||||
console.error('获取班级荣誉失败', err)
|
||||
honorList.value = []
|
||||
} finally {
|
||||
honorLoading.value = false
|
||||
}
|
||||
}
|
||||
honorLoading.value = true;
|
||||
try {
|
||||
const res = await queryClassHonorByClassCode(classCode);
|
||||
if (res.data) {
|
||||
honorList.value = Array.isArray(res.data) ? res.data : [];
|
||||
}
|
||||
} catch (err: any) {
|
||||
console.error('获取班级荣誉失败', err);
|
||||
honorList.value = [];
|
||||
} finally {
|
||||
honorLoading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
// 加载班级宣传数据
|
||||
const loadPublicityData = async (classCode: string) => {
|
||||
publicityLoading.value = true
|
||||
try {
|
||||
const res = await queryDataByClassCode(classCode)
|
||||
if (res.data) {
|
||||
publicityList.value = Array.isArray(res.data) ? res.data : []
|
||||
}
|
||||
} catch (err: any) {
|
||||
console.error('获取班级宣传失败', err)
|
||||
publicityList.value = []
|
||||
} finally {
|
||||
publicityLoading.value = false
|
||||
}
|
||||
}
|
||||
publicityLoading.value = true;
|
||||
try {
|
||||
const res = await queryDataByClassCode(classCode);
|
||||
if (res.data) {
|
||||
publicityList.value = Array.isArray(res.data) ? res.data : [];
|
||||
}
|
||||
} catch (err: any) {
|
||||
console.error('获取班级宣传失败', err);
|
||||
publicityList.value = [];
|
||||
} finally {
|
||||
publicityLoading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
// 暴露方法给父组件
|
||||
defineExpose({
|
||||
openDialog
|
||||
openDialog,
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.mb20 {
|
||||
margin-bottom: 20px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,536 +1,407 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
:title="form.id ? '编辑' : '新增'"
|
||||
v-model="visible"
|
||||
:close-on-click-modal="false"
|
||||
draggable
|
||||
width="900px">
|
||||
<el-form
|
||||
ref="dataFormRef"
|
||||
:model="form"
|
||||
:rules="dataRules"
|
||||
label-width="140px"
|
||||
:validate-on-rule-change="false"
|
||||
v-loading="loading">
|
||||
<el-row :gutter="24">
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item label="姓名" prop="realName">
|
||||
<el-input
|
||||
v-model="form.realName"
|
||||
placeholder="请输入姓名"
|
||||
clearable />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-dialog :title="form.id ? '编辑' : '新增'" v-model="visible" :close-on-click-modal="false" draggable width="900px">
|
||||
<el-form ref="dataFormRef" :model="form" :rules="dataRules" label-width="140px" :validate-on-rule-change="false" v-loading="loading">
|
||||
<el-row :gutter="24">
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item label="姓名" prop="realName">
|
||||
<el-input v-model="form.realName" placeholder="请输入姓名" clearable />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item label="身份证" prop="idCard">
|
||||
<el-input
|
||||
v-model="form.idCard"
|
||||
placeholder="请输入身份证号"
|
||||
clearable />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item label="身份证" prop="idCard">
|
||||
<el-input v-model="form.idCard" placeholder="请输入身份证号" clearable />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item label="性别" prop="sex">
|
||||
<el-select
|
||||
v-model="form.sex"
|
||||
placeholder="请选择"
|
||||
clearable
|
||||
style="width: 100%">
|
||||
<el-option label="男" value="1" />
|
||||
<el-option label="女" value="0" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item label="性别" prop="sex">
|
||||
<el-select v-model="form.sex" placeholder="请选择" clearable style="width: 100%">
|
||||
<el-option label="男" value="1" />
|
||||
<el-option label="女" value="0" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item label="出生日期" prop="birthday">
|
||||
<el-date-picker
|
||||
v-model="form.birthday"
|
||||
type="date"
|
||||
placeholder="选择日期"
|
||||
format="YYYY-MM-DD"
|
||||
value-format="YYYY-MM-DD"
|
||||
style="width: 100%" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item label="出生日期" prop="birthday">
|
||||
<el-date-picker
|
||||
v-model="form.birthday"
|
||||
type="date"
|
||||
placeholder="选择日期"
|
||||
format="YYYY-MM-DD"
|
||||
value-format="YYYY-MM-DD"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item label="户口所在地" prop="householdAddress">
|
||||
<el-input
|
||||
v-model="form.householdAddress"
|
||||
placeholder="请输入户口所在地"
|
||||
clearable />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item label="户口所在地" prop="householdAddress">
|
||||
<el-input v-model="form.householdAddress" placeholder="请输入户口所在地" clearable />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item label="班级" prop="classCode">
|
||||
<el-select
|
||||
v-model="form.classCode"
|
||||
placeholder="请选择班级"
|
||||
clearable
|
||||
filterable
|
||||
style="width: 100%">
|
||||
<el-option
|
||||
v-for="item in classList"
|
||||
:key="item.classCode"
|
||||
:label="item.classNo"
|
||||
:value="item.classCode">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item label="班级" prop="classCode">
|
||||
<el-select v-model="form.classCode" placeholder="请选择班级" clearable filterable style="width: 100%">
|
||||
<el-option v-for="item in classList" :key="item.classCode" :label="item.classNo" :value="item.classCode"> </el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item label="学号" prop="stuNo">
|
||||
<el-input
|
||||
v-model="form.stuNo"
|
||||
placeholder="请输入学号"
|
||||
clearable />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item label="学号" prop="stuNo">
|
||||
<el-input v-model="form.stuNo" placeholder="请输入学号" clearable />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item label="辩色力" prop="colourSense">
|
||||
<el-select
|
||||
v-model="form.colourSense"
|
||||
placeholder="请选择辩色力"
|
||||
clearable
|
||||
filterable
|
||||
style="width: 100%">
|
||||
<el-option
|
||||
v-for="item in eyeStatusList"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item label="辩色力" prop="colourSense">
|
||||
<el-select v-model="form.colourSense" placeholder="请选择辩色力" clearable filterable style="width: 100%">
|
||||
<el-option v-for="item in eyeStatusList" :key="item.value" :label="item.label" :value="item.value"> </el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item label="退伍军人" prop="veteran">
|
||||
<el-select
|
||||
v-model="form.veteran"
|
||||
placeholder="请选择"
|
||||
clearable
|
||||
filterable
|
||||
style="width: 100%">
|
||||
<el-option
|
||||
v-for="item in veteranStatusList"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item label="退伍军人" prop="veteran">
|
||||
<el-select v-model="form.veteran" placeholder="请选择" clearable filterable style="width: 100%">
|
||||
<el-option v-for="item in veteranStatusList" :key="item.value" :label="item.label" :value="item.value"> </el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item label="政治面貌" prop="politicsStatus">
|
||||
<el-select
|
||||
v-model="form.politicsStatus"
|
||||
placeholder="请选择政治面貌"
|
||||
clearable
|
||||
filterable
|
||||
style="width: 100%">
|
||||
<el-option
|
||||
v-for="item in politicsStatusList"
|
||||
:key="item.id"
|
||||
:label="item.name"
|
||||
:value="item.id">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item label="政治面貌" prop="politicsStatus">
|
||||
<el-select v-model="form.politicsStatus" placeholder="请选择政治面貌" clearable filterable style="width: 100%">
|
||||
<el-option v-for="item in politicsStatusList" :key="item.id" :label="item.name" :value="item.id"> </el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item label="民族" prop="national">
|
||||
<el-select
|
||||
v-model="form.national"
|
||||
placeholder="请选择民族"
|
||||
clearable
|
||||
filterable
|
||||
style="width: 100%">
|
||||
<el-option
|
||||
v-for="item in nationalList"
|
||||
:key="item.nationCode"
|
||||
:label="item.nationName"
|
||||
:value="item.nationCode">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item label="民族" prop="national">
|
||||
<el-select v-model="form.national" placeholder="请选择民族" clearable filterable style="width: 100%">
|
||||
<el-option v-for="item in nationalList" :key="item.nationCode" :label="item.nationName" :value="item.nationCode"> </el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item label="是否10万以下民族" prop="isLowPopulation">
|
||||
<el-select
|
||||
v-model="form.isLowPopulation"
|
||||
placeholder="请选择"
|
||||
clearable
|
||||
style="width: 100%">
|
||||
<el-option label="是" value="1" />
|
||||
<el-option label="否" value="0" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item label="是否10万以下民族" prop="isLowPopulation">
|
||||
<el-select v-model="form.isLowPopulation" placeholder="请选择" clearable style="width: 100%">
|
||||
<el-option label="是" value="1" />
|
||||
<el-option label="否" value="0" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item label="既往病史" prop="medicalHistory">
|
||||
<el-input
|
||||
v-model="form.medicalHistory"
|
||||
placeholder="请输入既往病史"
|
||||
clearable />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item label="既往病史" prop="medicalHistory">
|
||||
<el-input v-model="form.medicalHistory" placeholder="请输入既往病史" clearable />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item label="入学前文化程度" prop="beforeEducation">
|
||||
<el-select
|
||||
v-model="form.beforeEducation"
|
||||
placeholder="请选择入学前文化程度"
|
||||
clearable
|
||||
filterable
|
||||
style="width: 100%">
|
||||
<el-option
|
||||
v-for="item in preSchoolEducationList"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item label="入学前文化程度" prop="beforeEducation">
|
||||
<el-select v-model="form.beforeEducation" placeholder="请选择入学前文化程度" clearable filterable style="width: 100%">
|
||||
<el-option v-for="item in preSchoolEducationList" :key="item.value" :label="item.label" :value="item.value"> </el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item label="入学前毕业学校" prop="beforeSchool">
|
||||
<el-input
|
||||
v-model="form.beforeSchool"
|
||||
placeholder="请输入入学前毕业学校"
|
||||
clearable />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item label="入学前毕业学校" prop="beforeSchool">
|
||||
<el-input v-model="form.beforeSchool" placeholder="请输入入学前毕业学校" clearable />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item label="毕业学校省市" prop="schoolProvince">
|
||||
<el-select
|
||||
v-model="form.schoolProvince"
|
||||
placeholder="请选择毕业学校省市"
|
||||
clearable
|
||||
filterable
|
||||
style="width: 100%">
|
||||
<el-option
|
||||
v-for="item in schoolProvinceList"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="visible = false">取 消</el-button>
|
||||
<el-button type="primary" @click="onSubmit" :disabled="loading">确 认</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item label="毕业学校省市" prop="schoolProvince">
|
||||
<el-select v-model="form.schoolProvince" placeholder="请选择毕业学校省市" clearable filterable style="width: 100%">
|
||||
<el-option v-for="item in schoolProvinceList" :key="item.value" :label="item.label" :value="item.value"> </el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="visible = false">取 消</el-button>
|
||||
<el-button type="primary" @click="onSubmit" :disabled="loading">确 认</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="BasicStudentDialog">
|
||||
import { ref, reactive, nextTick, onMounted } from 'vue'
|
||||
import { useMessage } from "/@/hooks/message";
|
||||
import { getObj, addObj, putObj } from '/@/api/basic/basicstudent'
|
||||
import { getClassListByRole } from '/@/api/basic/basicclass'
|
||||
import { getNationalList } from '/@/api/basic/basicnation'
|
||||
import { getPoliticsStatusDict } from '/@/api/basic/basicpoliticsstatusbase'
|
||||
import { queryDictByTypeList } from '/@/api/admin/dict'
|
||||
import { ref, reactive, nextTick, onMounted } from 'vue';
|
||||
import { useMessage } from '/@/hooks/message';
|
||||
import { getObj, addObj, putObj } from '/@/api/basic/basicstudent';
|
||||
import { getClassListByRole } from '/@/api/basic/basicclass';
|
||||
import { getNationalList } from '/@/api/basic/basicnation';
|
||||
import { getPoliticsStatusDict } from '/@/api/basic/basicpoliticsstatusbase';
|
||||
import { queryDictByTypeList } from '/@/api/admin/dict';
|
||||
|
||||
const emit = defineEmits(['refresh']);
|
||||
|
||||
// 定义变量内容
|
||||
const dataFormRef = ref();
|
||||
const visible = ref(false)
|
||||
const loading = ref(false)
|
||||
const classList = ref<any[]>([])
|
||||
const nationalList = ref<any[]>([])
|
||||
const politicsStatusList = ref<any[]>([])
|
||||
const eyeStatusList = ref<any[]>([])
|
||||
const veteranStatusList = ref<any[]>([])
|
||||
const preSchoolEducationList = ref<any[]>([])
|
||||
const schoolProvinceList = ref<any[]>([])
|
||||
const visible = ref(false);
|
||||
const loading = ref(false);
|
||||
const classList = ref<any[]>([]);
|
||||
const nationalList = ref<any[]>([]);
|
||||
const politicsStatusList = ref<any[]>([]);
|
||||
const eyeStatusList = ref<any[]>([]);
|
||||
const veteranStatusList = ref<any[]>([]);
|
||||
const preSchoolEducationList = ref<any[]>([]);
|
||||
const schoolProvinceList = ref<any[]>([]);
|
||||
|
||||
// 提交表单数据
|
||||
const form = reactive({
|
||||
id: '',
|
||||
realName: '',
|
||||
idCard: '',
|
||||
sex: '',
|
||||
birthday: '',
|
||||
householdAddress: '',
|
||||
classCode: '',
|
||||
stuNo: '',
|
||||
colourSense: '',
|
||||
veteran: '',
|
||||
politicsStatus: '',
|
||||
national: '',
|
||||
isLowPopulation: '',
|
||||
medicalHistory: '',
|
||||
beforeEducation: '',
|
||||
beforeSchool: '',
|
||||
schoolProvince: ''
|
||||
id: '',
|
||||
realName: '',
|
||||
idCard: '',
|
||||
sex: '',
|
||||
birthday: '',
|
||||
householdAddress: '',
|
||||
classCode: '',
|
||||
stuNo: '',
|
||||
colourSense: '',
|
||||
veteran: '',
|
||||
politicsStatus: '',
|
||||
national: '',
|
||||
isLowPopulation: '',
|
||||
medicalHistory: '',
|
||||
beforeEducation: '',
|
||||
beforeSchool: '',
|
||||
schoolProvince: '',
|
||||
});
|
||||
|
||||
// 定义校验规则 - 除了"是否10万以下民族"外,其他字段都是必填
|
||||
const dataRules = ref({
|
||||
realName: [
|
||||
{ required: true, message: '姓名不能为空', trigger: 'blur' }
|
||||
],
|
||||
idCard: [
|
||||
{ required: true, message: '身份证不能为空', trigger: 'blur' },
|
||||
{ pattern: /(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/, message: '请输入正确的身份证号', trigger: 'blur' }
|
||||
],
|
||||
sex: [
|
||||
{ required: true, message: '性别不能为空', trigger: 'change' }
|
||||
],
|
||||
birthday: [
|
||||
{ required: true, message: '出生日期不能为空', trigger: 'change' }
|
||||
],
|
||||
householdAddress: [
|
||||
{ required: true, message: '户口所在地不能为空', trigger: 'blur' }
|
||||
],
|
||||
classCode: [
|
||||
{ required: true, message: '班级不能为空', trigger: 'change' }
|
||||
],
|
||||
stuNo: [
|
||||
{ required: true, message: '学号不能为空', trigger: 'blur' }
|
||||
],
|
||||
colourSense: [
|
||||
{ required: true, message: '辩色力不能为空', trigger: 'blur' }
|
||||
],
|
||||
veteran: [
|
||||
{ required: true, message: '退伍军人不能为空', trigger: 'change' }
|
||||
],
|
||||
politicsStatus: [
|
||||
{ required: true, message: '政治面貌不能为空', trigger: 'change' }
|
||||
],
|
||||
national: [
|
||||
{ required: true, message: '民族不能为空', trigger: 'change' }
|
||||
],
|
||||
medicalHistory: [
|
||||
{ required: true, message: '既往病史不能为空', trigger: 'blur' }
|
||||
],
|
||||
beforeEducation: [
|
||||
{ required: true, message: '入学前文化程度不能为空', trigger: 'blur' }
|
||||
],
|
||||
beforeSchool: [
|
||||
{ required: true, message: '入学前毕业学校不能为空', trigger: 'blur' }
|
||||
],
|
||||
schoolProvince: [
|
||||
{ required: true, message: '毕业学校省市不能为空', trigger: 'blur' }
|
||||
]
|
||||
// isLowPopulation 不需要必填验证
|
||||
})
|
||||
realName: [{ required: true, message: '姓名不能为空', trigger: 'blur' }],
|
||||
idCard: [
|
||||
{ required: true, message: '身份证不能为空', trigger: 'blur' },
|
||||
{ pattern: /(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/, message: '请输入正确的身份证号', trigger: 'blur' },
|
||||
],
|
||||
sex: [{ required: true, message: '性别不能为空', trigger: 'change' }],
|
||||
birthday: [{ required: true, message: '出生日期不能为空', trigger: 'change' }],
|
||||
householdAddress: [{ required: true, message: '户口所在地不能为空', trigger: 'blur' }],
|
||||
classCode: [{ required: true, message: '班级不能为空', trigger: 'change' }],
|
||||
stuNo: [{ required: true, message: '学号不能为空', trigger: 'blur' }],
|
||||
colourSense: [{ required: true, message: '辩色力不能为空', trigger: 'blur' }],
|
||||
veteran: [{ required: true, message: '退伍军人不能为空', trigger: 'change' }],
|
||||
politicsStatus: [{ required: true, message: '政治面貌不能为空', trigger: 'change' }],
|
||||
national: [{ required: true, message: '民族不能为空', trigger: 'change' }],
|
||||
medicalHistory: [{ required: true, message: '既往病史不能为空', trigger: 'blur' }],
|
||||
beforeEducation: [{ required: true, message: '入学前文化程度不能为空', trigger: 'blur' }],
|
||||
beforeSchool: [{ required: true, message: '入学前毕业学校不能为空', trigger: 'blur' }],
|
||||
schoolProvince: [{ required: true, message: '毕业学校省市不能为空', trigger: 'blur' }],
|
||||
// isLowPopulation 不需要必填验证
|
||||
});
|
||||
|
||||
// 打开弹窗
|
||||
const openDialog = (id?: string) => {
|
||||
visible.value = true
|
||||
|
||||
// 重置表单数据
|
||||
Object.assign(form, {
|
||||
id: '',
|
||||
realName: '',
|
||||
idCard: '',
|
||||
sex: '',
|
||||
birthday: '',
|
||||
householdAddress: '',
|
||||
classCode: '',
|
||||
stuNo: '',
|
||||
colourSense: '',
|
||||
veteran: '',
|
||||
politicsStatus: '',
|
||||
national: '',
|
||||
isLowPopulation: '',
|
||||
medicalHistory: '',
|
||||
beforeEducation: '',
|
||||
beforeSchool: '',
|
||||
schoolProvince: ''
|
||||
})
|
||||
visible.value = true;
|
||||
|
||||
// 清除表单验证状态,不触发验证
|
||||
nextTick(() => {
|
||||
dataFormRef.value?.clearValidate();
|
||||
dataFormRef.value?.resetFields();
|
||||
});
|
||||
// 重置表单数据
|
||||
Object.assign(form, {
|
||||
id: '',
|
||||
realName: '',
|
||||
idCard: '',
|
||||
sex: '',
|
||||
birthday: '',
|
||||
householdAddress: '',
|
||||
classCode: '',
|
||||
stuNo: '',
|
||||
colourSense: '',
|
||||
veteran: '',
|
||||
politicsStatus: '',
|
||||
national: '',
|
||||
isLowPopulation: '',
|
||||
medicalHistory: '',
|
||||
beforeEducation: '',
|
||||
beforeSchool: '',
|
||||
schoolProvince: '',
|
||||
});
|
||||
|
||||
// 获取详情
|
||||
if (id) {
|
||||
form.id = id
|
||||
getStudentData(id)
|
||||
} else {
|
||||
// 新增时,确保验证状态已清除
|
||||
nextTick(() => {
|
||||
dataFormRef.value?.clearValidate();
|
||||
});
|
||||
}
|
||||
// 清除表单验证状态,不触发验证
|
||||
nextTick(() => {
|
||||
dataFormRef.value?.clearValidate();
|
||||
dataFormRef.value?.resetFields();
|
||||
});
|
||||
|
||||
// 获取详情
|
||||
if (id) {
|
||||
form.id = id;
|
||||
getStudentData(id);
|
||||
} else {
|
||||
// 新增时,确保验证状态已清除
|
||||
nextTick(() => {
|
||||
dataFormRef.value?.clearValidate();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// 提交
|
||||
const onSubmit = async () => {
|
||||
const valid = await dataFormRef.value.validate().catch(() => {});
|
||||
if (!valid) return false;
|
||||
const valid = await dataFormRef.value.validate().catch(() => {});
|
||||
if (!valid) return false;
|
||||
|
||||
try {
|
||||
loading.value = true;
|
||||
if (form.id) {
|
||||
await putObj(form);
|
||||
useMessage().success('编辑成功');
|
||||
} else {
|
||||
await addObj(form);
|
||||
useMessage().success('新增成功');
|
||||
}
|
||||
visible.value = false;
|
||||
emit('refresh');
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg || (form.id ? '编辑失败' : '新增失败'));
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
try {
|
||||
loading.value = true;
|
||||
if (form.id) {
|
||||
await putObj(form);
|
||||
useMessage().success('编辑成功');
|
||||
} else {
|
||||
await addObj(form);
|
||||
useMessage().success('新增成功');
|
||||
}
|
||||
visible.value = false;
|
||||
emit('refresh');
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg || (form.id ? '编辑失败' : '新增失败'));
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
// 获取详情
|
||||
const getStudentData = (id: string) => {
|
||||
loading.value = true
|
||||
getObj(id).then((res: any) => {
|
||||
if (res.data) {
|
||||
Object.assign(form, {
|
||||
id: res.data.id || '',
|
||||
realName: res.data.realName || '',
|
||||
idCard: res.data.idCard || '',
|
||||
sex: res.data.sex || '',
|
||||
birthday: res.data.birthday || '',
|
||||
householdAddress: res.data.householdAddress || '',
|
||||
classCode: res.data.classCode || '',
|
||||
stuNo: res.data.stuNo || '',
|
||||
colourSense: res.data.colourSense || '',
|
||||
veteran: res.data.veteran || '',
|
||||
politicsStatus: res.data.politicsStatus || '',
|
||||
national: res.data.national || '',
|
||||
isLowPopulation: res.data.isLowPopulation || '',
|
||||
medicalHistory: res.data.medicalHistory || '',
|
||||
beforeEducation: res.data.beforeEducation || '',
|
||||
beforeSchool: res.data.beforeSchool || '',
|
||||
schoolProvince: res.data.schoolProvince || ''
|
||||
})
|
||||
}
|
||||
}).catch((err: any) => {
|
||||
console.error('获取详情失败', err)
|
||||
useMessage().error('获取详情失败')
|
||||
}).finally(() => {
|
||||
loading.value = false
|
||||
// 数据加载完成后,清除验证状态,避免触发验证
|
||||
nextTick(() => {
|
||||
dataFormRef.value?.clearValidate();
|
||||
});
|
||||
})
|
||||
}
|
||||
loading.value = true;
|
||||
getObj(id)
|
||||
.then((res: any) => {
|
||||
if (res.data) {
|
||||
Object.assign(form, {
|
||||
id: res.data.id || '',
|
||||
realName: res.data.realName || '',
|
||||
idCard: res.data.idCard || '',
|
||||
sex: res.data.sex || '',
|
||||
birthday: res.data.birthday || '',
|
||||
householdAddress: res.data.householdAddress || '',
|
||||
classCode: res.data.classCode || '',
|
||||
stuNo: res.data.stuNo || '',
|
||||
colourSense: res.data.colourSense || '',
|
||||
veteran: res.data.veteran || '',
|
||||
politicsStatus: res.data.politicsStatus || '',
|
||||
national: res.data.national || '',
|
||||
isLowPopulation: res.data.isLowPopulation || '',
|
||||
medicalHistory: res.data.medicalHistory || '',
|
||||
beforeEducation: res.data.beforeEducation || '',
|
||||
beforeSchool: res.data.beforeSchool || '',
|
||||
schoolProvince: res.data.schoolProvince || '',
|
||||
});
|
||||
}
|
||||
})
|
||||
.catch((err: any) => {
|
||||
console.error('获取详情失败', err);
|
||||
useMessage().error('获取详情失败');
|
||||
})
|
||||
.finally(() => {
|
||||
loading.value = false;
|
||||
// 数据加载完成后,清除验证状态,避免触发验证
|
||||
nextTick(() => {
|
||||
dataFormRef.value?.clearValidate();
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
// 获取班级列表
|
||||
const getClassListData = async () => {
|
||||
try {
|
||||
const res = await getClassListByRole()
|
||||
if (res.data) {
|
||||
classList.value = Array.isArray(res.data) ? res.data : []
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('获取班级列表失败', err)
|
||||
classList.value = []
|
||||
}
|
||||
}
|
||||
try {
|
||||
const res = await getClassListByRole();
|
||||
if (res.data) {
|
||||
classList.value = Array.isArray(res.data) ? res.data : [];
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('获取班级列表失败', err);
|
||||
classList.value = [];
|
||||
}
|
||||
};
|
||||
|
||||
// 获取民族列表
|
||||
const getNationalListData = async () => {
|
||||
try {
|
||||
const res = await getNationalList()
|
||||
if (res.data) {
|
||||
nationalList.value = Array.isArray(res.data) ? res.data : []
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('获取民族列表失败', err)
|
||||
nationalList.value = []
|
||||
}
|
||||
}
|
||||
try {
|
||||
const res = await getNationalList();
|
||||
if (res.data) {
|
||||
nationalList.value = Array.isArray(res.data) ? res.data : [];
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('获取民族列表失败', err);
|
||||
nationalList.value = [];
|
||||
}
|
||||
};
|
||||
|
||||
// 获取政治面貌列表
|
||||
const getPoliticsStatusListData = async () => {
|
||||
try {
|
||||
const res = await getPoliticsStatusDict()
|
||||
if (res.data) {
|
||||
politicsStatusList.value = Array.isArray(res.data) ? res.data : []
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('获取政治面貌列表失败', err)
|
||||
politicsStatusList.value = []
|
||||
}
|
||||
}
|
||||
try {
|
||||
const res = await getPoliticsStatusDict();
|
||||
if (res.data) {
|
||||
politicsStatusList.value = Array.isArray(res.data) ? res.data : [];
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('获取政治面貌列表失败', err);
|
||||
politicsStatusList.value = [];
|
||||
}
|
||||
};
|
||||
|
||||
// 获取字典数据
|
||||
const getDictData = async () => {
|
||||
try {
|
||||
const dictTypes = ['eye_status', 'veteran_status', 'pre_school_education', 'school_province']
|
||||
const res = await queryDictByTypeList(dictTypes)
|
||||
if (res.data && typeof res.data === 'object') {
|
||||
// 解析返回的字典数据,统一转换为 {label, value} 格式
|
||||
const parseDictList = (dictData: any) => {
|
||||
if (!Array.isArray(dictData)) return []
|
||||
return dictData.map((item: any) => ({
|
||||
label: item.label || item.name || item.dictLabel || '',
|
||||
value: item.value || item.code || item.dictValue || ''
|
||||
})).filter((item: any) => item.label && item.value !== undefined && item.value !== null && item.value !== '')
|
||||
}
|
||||
|
||||
if (res.data.eye_status) {
|
||||
eyeStatusList.value = parseDictList(res.data.eye_status)
|
||||
}
|
||||
if (res.data.veteran_status) {
|
||||
veteranStatusList.value = parseDictList(res.data.veteran_status)
|
||||
}
|
||||
if (res.data.pre_school_education) {
|
||||
preSchoolEducationList.value = parseDictList(res.data.pre_school_education)
|
||||
}
|
||||
if (res.data.school_province) {
|
||||
schoolProvinceList.value = parseDictList(res.data.school_province)
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('获取字典数据失败', err)
|
||||
eyeStatusList.value = []
|
||||
veteranStatusList.value = []
|
||||
preSchoolEducationList.value = []
|
||||
schoolProvinceList.value = []
|
||||
}
|
||||
}
|
||||
try {
|
||||
const dictTypes = ['eye_status', 'veteran_status', 'pre_school_education', 'school_province'];
|
||||
const res = await queryDictByTypeList(dictTypes);
|
||||
if (res.data && typeof res.data === 'object') {
|
||||
// 解析返回的字典数据,统一转换为 {label, value} 格式
|
||||
const parseDictList = (dictData: any) => {
|
||||
if (!Array.isArray(dictData)) return [];
|
||||
return dictData
|
||||
.map((item: any) => ({
|
||||
label: item.label || item.name || item.dictLabel || '',
|
||||
value: item.value || item.code || item.dictValue || '',
|
||||
}))
|
||||
.filter((item: any) => item.label && item.value !== undefined && item.value !== null && item.value !== '');
|
||||
};
|
||||
|
||||
if (res.data.eye_status) {
|
||||
eyeStatusList.value = parseDictList(res.data.eye_status);
|
||||
}
|
||||
if (res.data.veteran_status) {
|
||||
veteranStatusList.value = parseDictList(res.data.veteran_status);
|
||||
}
|
||||
if (res.data.pre_school_education) {
|
||||
preSchoolEducationList.value = parseDictList(res.data.pre_school_education);
|
||||
}
|
||||
if (res.data.school_province) {
|
||||
schoolProvinceList.value = parseDictList(res.data.school_province);
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('获取字典数据失败', err);
|
||||
eyeStatusList.value = [];
|
||||
veteranStatusList.value = [];
|
||||
preSchoolEducationList.value = [];
|
||||
schoolProvinceList.value = [];
|
||||
}
|
||||
};
|
||||
|
||||
// 初始化
|
||||
onMounted(() => {
|
||||
getClassListData()
|
||||
getNationalListData()
|
||||
getPoliticsStatusListData()
|
||||
getDictData()
|
||||
})
|
||||
getClassListData();
|
||||
getNationalListData();
|
||||
getPoliticsStatusListData();
|
||||
getDictData();
|
||||
});
|
||||
|
||||
// 暴露变量
|
||||
defineExpose({
|
||||
openDialog
|
||||
openDialog,
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.mb20 {
|
||||
margin-bottom: 20px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
</style>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,246 +1,255 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<!-- 搜索 -->
|
||||
<el-card shadow="never" class="mb12">
|
||||
<el-form :inline="true" :model="searchForm" ref="searchFormRef" label-width="90px">
|
||||
<el-form-item label="学号" prop="stuNo">
|
||||
<el-input v-model="searchForm.stuNo" placeholder="请输入学号" clearable />
|
||||
</el-form-item>
|
||||
<el-form-item label="姓名" prop="stuName">
|
||||
<el-input v-model="searchForm.stuName" placeholder="请输入姓名" clearable />
|
||||
</el-form-item>
|
||||
<el-form-item label="身份证" prop="idCard">
|
||||
<el-input v-model="searchForm.idCard" placeholder="请输入身份证" clearable />
|
||||
</el-form-item>
|
||||
<el-form-item label="电话" prop="phone">
|
||||
<el-input v-model="searchForm.phone" placeholder="请输入电话" clearable />
|
||||
</el-form-item>
|
||||
<el-form-item label="家长电话" prop="parentPhone">
|
||||
<el-input v-model="searchForm.parentPhone" placeholder="请输入家长电话" clearable />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="handleSearch">
|
||||
<el-icon><Search /></el-icon>
|
||||
查询
|
||||
</el-button>
|
||||
<el-button @click="handleReset">
|
||||
<el-icon><Refresh /></el-icon>
|
||||
重置
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
<div class="app-container">
|
||||
<!-- 搜索 -->
|
||||
<el-card shadow="never" class="mb12">
|
||||
<el-form :inline="true" :model="searchForm" ref="searchFormRef" label-width="90px">
|
||||
<el-form-item label="学号" prop="stuNo">
|
||||
<el-input v-model="searchForm.stuNo" placeholder="请输入学号" clearable />
|
||||
</el-form-item>
|
||||
<el-form-item label="姓名" prop="stuName">
|
||||
<el-input v-model="searchForm.stuName" placeholder="请输入姓名" clearable />
|
||||
</el-form-item>
|
||||
<el-form-item label="身份证" prop="idCard">
|
||||
<el-input v-model="searchForm.idCard" placeholder="请输入身份证" clearable />
|
||||
</el-form-item>
|
||||
<el-form-item label="电话" prop="phone">
|
||||
<el-input v-model="searchForm.phone" placeholder="请输入电话" clearable />
|
||||
</el-form-item>
|
||||
<el-form-item label="家长电话" prop="parentPhone">
|
||||
<el-input v-model="searchForm.parentPhone" placeholder="请输入家长电话" clearable />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="handleSearch">
|
||||
<el-icon><Search /></el-icon>
|
||||
查询
|
||||
</el-button>
|
||||
<el-button @click="handleReset">
|
||||
<el-icon><Refresh /></el-icon>
|
||||
重置
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
|
||||
<!-- 表格 -->
|
||||
<el-card shadow="never">
|
||||
<el-table
|
||||
:data="state.dataList"
|
||||
v-loading="state.loading"
|
||||
border
|
||||
:cell-style="tableStyle.cellStyle"
|
||||
:header-cell-style="tableStyle.headerCellStyle"
|
||||
@sort-change="sortChangeHandle"
|
||||
style="width: 100%;">
|
||||
<el-table-column type="index" label="序号" width="70" align="center">
|
||||
<template #header>
|
||||
<el-icon><List /></el-icon>
|
||||
<span style="margin-left: 4px;">序号</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="deptName" label="学院" show-overflow-tooltip>
|
||||
<template #header>
|
||||
<el-icon><OfficeBuilding /></el-icon>
|
||||
<span style="margin-left: 4px;">学院</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="majorName" label="专业" show-overflow-tooltip>
|
||||
<template #header>
|
||||
<el-icon><Briefcase /></el-icon>
|
||||
<span style="margin-left: 4px;">专业</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="className" label="班级" show-overflow-tooltip>
|
||||
<template #header>
|
||||
<el-icon><Grid /></el-icon>
|
||||
<span style="margin-left: 4px;">班级</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="stuNo" label="学号" show-overflow-tooltip width="130">
|
||||
<template #header>
|
||||
<el-icon><Document /></el-icon>
|
||||
<span style="margin-left: 4px;">学号</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="stuName" label="姓名" show-overflow-tooltip>
|
||||
<template #header>
|
||||
<el-icon><UserFilled /></el-icon>
|
||||
<span style="margin-left: 4px;">姓名</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="idCard" label="身份证" show-overflow-tooltip width="180">
|
||||
<template #header>
|
||||
<el-icon><CreditCard /></el-icon>
|
||||
<span style="margin-left: 4px;">身份证</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="phone" label="电话" show-overflow-tooltip width="130">
|
||||
<template #header>
|
||||
<el-icon><Phone /></el-icon>
|
||||
<span style="margin-left: 4px;">电话</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="parentPhone" label="家长电话" show-overflow-tooltip width="140">
|
||||
<template #header>
|
||||
<el-icon><Phone /></el-icon>
|
||||
<span style="margin-left: 4px;">家长电话</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="gender" label="性别" width="90" align="center">
|
||||
<template #header>
|
||||
<el-icon><User /></el-icon>
|
||||
<span style="margin-left: 4px;">性别</span>
|
||||
</template>
|
||||
<template #default="scope">
|
||||
<GenderTag :gender="scope.row.gender" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="dormNo" label="宿舍号" show-overflow-tooltip width="120">
|
||||
<template #header>
|
||||
<el-icon><HomeFilled /></el-icon>
|
||||
<span style="margin-left: 4px;">宿舍号</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="teacherName" label="班主任" show-overflow-tooltip>
|
||||
<template #header>
|
||||
<el-icon><UserFilled /></el-icon>
|
||||
<span style="margin-left: 4px;">班主任</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="teacherPhone" label="班主任电话" show-overflow-tooltip width="140">
|
||||
<template #header>
|
||||
<el-icon><Phone /></el-icon>
|
||||
<span style="margin-left: 4px;">班主任电话</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="schoolRollStatus" label="学籍状态" show-overflow-tooltip width="110" align="center">
|
||||
<template #header>
|
||||
<el-icon><CircleCheck /></el-icon>
|
||||
<span style="margin-left: 4px;">学籍状态</span>
|
||||
</template>
|
||||
<template #default="scope">
|
||||
<StatusTag :status="scope.row.schoolRollStatus" :options="rollStatusOptions" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="stuStatus" label="学生状态" show-overflow-tooltip width="110" align="center">
|
||||
<template #header>
|
||||
<el-icon><Tickets /></el-icon>
|
||||
<span style="margin-left: 4px;">学生状态</span>
|
||||
</template>
|
||||
<template #default="scope">
|
||||
<StatusTag :status="scope.row.stuStatus" :options="stuStatusOptions" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="avatarUrl" label="头像" width="120" align="center">
|
||||
<template #header>
|
||||
<el-icon><Picture /></el-icon>
|
||||
<span style="margin-left: 4px;">头像</span>
|
||||
</template>
|
||||
<template #default="scope">
|
||||
<el-image
|
||||
v-if="scope.row.avatarUrl"
|
||||
:src="scope.row.avatarUrl"
|
||||
:preview-src-list="[scope.row.avatarUrl]"
|
||||
fit="cover"
|
||||
style="width: 60px; height: 60px; border-radius: 6px;" />
|
||||
<el-tag v-else type="info" effect="plain">无</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="120" fixed="right" align="center">
|
||||
<template #header>
|
||||
<el-icon><Setting /></el-icon>
|
||||
<span style="margin-left: 4px;">操作</span>
|
||||
</template>
|
||||
<template #default>
|
||||
<span style="color: #999;">—</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<!-- 表格 -->
|
||||
<el-card shadow="never">
|
||||
<el-table
|
||||
:data="state.dataList"
|
||||
v-loading="state.loading"
|
||||
border
|
||||
:cell-style="tableStyle.cellStyle"
|
||||
:header-cell-style="tableStyle.headerCellStyle"
|
||||
@sort-change="sortChangeHandle"
|
||||
style="width: 100%"
|
||||
>
|
||||
<el-table-column type="index" label="序号" width="70" align="center">
|
||||
<template #header>
|
||||
<el-icon><List /></el-icon>
|
||||
<span style="margin-left: 4px">序号</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="deptName" label="学院" show-overflow-tooltip>
|
||||
<template #header>
|
||||
<el-icon><OfficeBuilding /></el-icon>
|
||||
<span style="margin-left: 4px">学院</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="majorName" label="专业" show-overflow-tooltip>
|
||||
<template #header>
|
||||
<el-icon><Briefcase /></el-icon>
|
||||
<span style="margin-left: 4px">专业</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="className" label="班级" show-overflow-tooltip>
|
||||
<template #header>
|
||||
<el-icon><Grid /></el-icon>
|
||||
<span style="margin-left: 4px">班级</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="stuNo" label="学号" show-overflow-tooltip width="130">
|
||||
<template #header>
|
||||
<el-icon><Document /></el-icon>
|
||||
<span style="margin-left: 4px">学号</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="stuName" label="姓名" show-overflow-tooltip>
|
||||
<template #header>
|
||||
<el-icon><UserFilled /></el-icon>
|
||||
<span style="margin-left: 4px">姓名</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="idCard" label="身份证" show-overflow-tooltip width="180">
|
||||
<template #header>
|
||||
<el-icon><CreditCard /></el-icon>
|
||||
<span style="margin-left: 4px">身份证</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="phone" label="电话" show-overflow-tooltip width="130">
|
||||
<template #header>
|
||||
<el-icon><Phone /></el-icon>
|
||||
<span style="margin-left: 4px">电话</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="parentPhone" label="家长电话" show-overflow-tooltip width="140">
|
||||
<template #header>
|
||||
<el-icon><Phone /></el-icon>
|
||||
<span style="margin-left: 4px">家长电话</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="gender" label="性别" width="90" align="center">
|
||||
<template #header>
|
||||
<el-icon><User /></el-icon>
|
||||
<span style="margin-left: 4px">性别</span>
|
||||
</template>
|
||||
<template #default="scope">
|
||||
<GenderTag :gender="scope.row.gender" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="dormNo" label="宿舍号" show-overflow-tooltip width="120">
|
||||
<template #header>
|
||||
<el-icon><HomeFilled /></el-icon>
|
||||
<span style="margin-left: 4px">宿舍号</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="teacherName" label="班主任" show-overflow-tooltip>
|
||||
<template #header>
|
||||
<el-icon><UserFilled /></el-icon>
|
||||
<span style="margin-left: 4px">班主任</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="teacherPhone" label="班主任电话" show-overflow-tooltip width="140">
|
||||
<template #header>
|
||||
<el-icon><Phone /></el-icon>
|
||||
<span style="margin-left: 4px">班主任电话</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="schoolRollStatus" label="学籍状态" show-overflow-tooltip width="110" align="center">
|
||||
<template #header>
|
||||
<el-icon><CircleCheck /></el-icon>
|
||||
<span style="margin-left: 4px">学籍状态</span>
|
||||
</template>
|
||||
<template #default="scope">
|
||||
<StatusTag :status="scope.row.schoolRollStatus" :options="rollStatusOptions" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="stuStatus" label="学生状态" show-overflow-tooltip width="110" align="center">
|
||||
<template #header>
|
||||
<el-icon><Tickets /></el-icon>
|
||||
<span style="margin-left: 4px">学生状态</span>
|
||||
</template>
|
||||
<template #default="scope">
|
||||
<StatusTag :status="scope.row.stuStatus" :options="stuStatusOptions" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="avatarUrl" label="头像" width="120" align="center">
|
||||
<template #header>
|
||||
<el-icon><Picture /></el-icon>
|
||||
<span style="margin-left: 4px">头像</span>
|
||||
</template>
|
||||
<template #default="scope">
|
||||
<el-image
|
||||
v-if="scope.row.avatarUrl"
|
||||
:src="scope.row.avatarUrl"
|
||||
:preview-src-list="[scope.row.avatarUrl]"
|
||||
fit="cover"
|
||||
style="width: 60px; height: 60px; border-radius: 6px"
|
||||
/>
|
||||
<el-tag v-else type="info" effect="plain">无</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="120" fixed="right" align="center">
|
||||
<template #header>
|
||||
<el-icon><Setting /></el-icon>
|
||||
<span style="margin-left: 4px">操作</span>
|
||||
</template>
|
||||
<template #default>
|
||||
<span style="color: #999">—</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<pagination
|
||||
v-show="state.total > 0"
|
||||
:total="state.total"
|
||||
v-model:page="state.page"
|
||||
v-model:limit="state.limit"
|
||||
@pagination="getDataList" />
|
||||
</el-card>
|
||||
</div>
|
||||
<pagination v-show="state.total > 0" :total="state.total" v-model:page="state.page" v-model:limit="state.limit" @pagination="getDataList" />
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="QueryStuindex">
|
||||
import { ref, reactive } from 'vue'
|
||||
import { Search, Refresh, List, OfficeBuilding, Grid, Document, UserFilled, CreditCard, Phone, User, HomeFilled, CircleCheck, Tickets, Setting, Picture, Briefcase } from '@element-plus/icons-vue'
|
||||
import { BasicTableProps, useTable } from '/@/hooks/table'
|
||||
import { queryStuindex } from '/@/api/basic/basicstudent'
|
||||
import GenderTag from '/@/components/GenderTag/index.vue'
|
||||
import StatusTag from '/@/components/StatusTag/index.vue'
|
||||
import { ref, reactive } from 'vue';
|
||||
import {
|
||||
Search,
|
||||
Refresh,
|
||||
List,
|
||||
OfficeBuilding,
|
||||
Grid,
|
||||
Document,
|
||||
UserFilled,
|
||||
CreditCard,
|
||||
Phone,
|
||||
User,
|
||||
HomeFilled,
|
||||
CircleCheck,
|
||||
Tickets,
|
||||
Setting,
|
||||
Picture,
|
||||
Briefcase,
|
||||
} from '@element-plus/icons-vue';
|
||||
import { BasicTableProps, useTable } from '/@/hooks/table';
|
||||
import { queryStuindex } from '/@/api/basic/basicstudent';
|
||||
import GenderTag from '/@/components/GenderTag/index.vue';
|
||||
import StatusTag from '/@/components/StatusTag/index.vue';
|
||||
|
||||
// 搜索表单
|
||||
const searchFormRef = ref()
|
||||
const searchFormRef = ref();
|
||||
const searchForm = reactive({
|
||||
stuNo: '',
|
||||
stuName: '',
|
||||
idCard: '',
|
||||
phone: '',
|
||||
parentPhone: ''
|
||||
})
|
||||
stuNo: '',
|
||||
stuName: '',
|
||||
idCard: '',
|
||||
phone: '',
|
||||
parentPhone: '',
|
||||
});
|
||||
|
||||
// 状态映射(可根据实际字典调整)
|
||||
const rollStatusOptions = [
|
||||
{ value: '0', label: '在籍', type: 'success' },
|
||||
{ value: '1', label: '离校', type: 'warning' },
|
||||
{ value: '2', label: '休学', type: 'info' }
|
||||
]
|
||||
{ value: '0', label: '在籍', type: 'success' },
|
||||
{ value: '1', label: '离校', type: 'warning' },
|
||||
{ value: '2', label: '休学', type: 'info' },
|
||||
];
|
||||
const stuStatusOptions = [
|
||||
{ value: '0', label: '正常', type: 'success' },
|
||||
{ value: '1', label: '预警', type: 'warning' },
|
||||
{ value: '2', label: '异常', type: 'danger' }
|
||||
]
|
||||
{ value: '0', label: '正常', type: 'success' },
|
||||
{ value: '1', label: '预警', type: 'warning' },
|
||||
{ value: '2', label: '异常', type: 'danger' },
|
||||
];
|
||||
|
||||
// 表格配置
|
||||
const state: BasicTableProps = reactive<BasicTableProps>({
|
||||
queryForm: searchForm,
|
||||
pageList: queryStuindex,
|
||||
props: {
|
||||
item: 'records',
|
||||
totalCount: 'total'
|
||||
},
|
||||
createdIsNeed: true
|
||||
})
|
||||
queryForm: searchForm,
|
||||
pageList: queryStuindex,
|
||||
props: {
|
||||
item: 'records',
|
||||
totalCount: 'total',
|
||||
},
|
||||
createdIsNeed: true,
|
||||
});
|
||||
|
||||
const {
|
||||
getDataList,
|
||||
sortChangeHandle,
|
||||
tableStyle
|
||||
} = useTable(state)
|
||||
const { getDataList, sortChangeHandle, tableStyle } = useTable(state);
|
||||
|
||||
const handleSearch = () => {
|
||||
state.page = 1
|
||||
getDataList()
|
||||
}
|
||||
state.page = 1;
|
||||
getDataList();
|
||||
};
|
||||
|
||||
const handleReset = () => {
|
||||
searchFormRef.value?.resetFields()
|
||||
state.page = 1
|
||||
getDataList()
|
||||
}
|
||||
searchFormRef.value?.resetFields();
|
||||
state.page = 1;
|
||||
getDataList();
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.app-container {
|
||||
padding: 16px;
|
||||
padding: 16px;
|
||||
}
|
||||
.mb12 {
|
||||
margin-bottom: 12px;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
@@ -1,270 +1,245 @@
|
||||
<template>
|
||||
<div class="modern-page-container">
|
||||
<div class="page-wrapper">
|
||||
<!-- 搜索表单卡片 -->
|
||||
<el-card v-show="showSearch" class="search-card" shadow="never">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span class="card-title">
|
||||
<el-icon class="title-icon"><Search /></el-icon>
|
||||
筛选条件
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
<el-form :model="searchForm" ref="searchFormRef" :inline="true" @keyup.enter="handleSearch" class="search-form">
|
||||
<el-form-item label="班级" prop="classCode">
|
||||
<el-select
|
||||
v-model="searchForm.classCode"
|
||||
placeholder="请选择班级"
|
||||
clearable
|
||||
filterable
|
||||
style="width: 200px">
|
||||
<el-option
|
||||
v-for="item in classList"
|
||||
:key="item.classCode"
|
||||
:label="item.classNo"
|
||||
:value="item.classCode">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" plain icon="Search" @click="handleSearch">查询</el-button>
|
||||
<el-button icon="Refresh" @click="handleReset">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
<div class="modern-page-container">
|
||||
<div class="page-wrapper">
|
||||
<!-- 搜索表单卡片 -->
|
||||
<el-card v-show="showSearch" class="search-card" shadow="never">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span class="card-title">
|
||||
<el-icon class="title-icon"><Search /></el-icon>
|
||||
筛选条件
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
<el-form :model="searchForm" ref="searchFormRef" :inline="true" @keyup.enter="handleSearch" class="search-form">
|
||||
<el-form-item label="班级" prop="classCode">
|
||||
<el-select v-model="searchForm.classCode" placeholder="请选择班级" clearable filterable style="width: 200px">
|
||||
<el-option v-for="item in classList" :key="item.classCode" :label="item.classNo" :value="item.classCode"> </el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" plain icon="Search" @click="handleSearch">查询</el-button>
|
||||
<el-button icon="Refresh" @click="handleReset">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
|
||||
<!-- 内容卡片 -->
|
||||
<el-card class="content-card" shadow="never">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span class="card-title">
|
||||
<el-icon class="title-icon"><Document /></el-icon>
|
||||
学生头像列表
|
||||
</span>
|
||||
<div class="header-actions">
|
||||
<right-toolbar
|
||||
v-model:showSearch="showSearch"
|
||||
class="ml10"
|
||||
@queryTable="getDataList">
|
||||
<TableColumnControl
|
||||
ref="columnControlRef"
|
||||
:columns="tableColumns"
|
||||
v-model="visibleColumns"
|
||||
trigger-type="default"
|
||||
trigger-circle
|
||||
@change="handleColumnChange"
|
||||
@order-change="handleColumnOrderChange"
|
||||
>
|
||||
<template #trigger>
|
||||
<el-tooltip class="item" effect="dark" content="列设置" placement="top">
|
||||
<el-button circle style="margin-left: 0;">
|
||||
<el-icon><Menu /></el-icon>
|
||||
</el-button>
|
||||
</el-tooltip>
|
||||
</template>
|
||||
</TableColumnControl>
|
||||
</right-toolbar>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<!-- 内容卡片 -->
|
||||
<el-card class="content-card" shadow="never">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span class="card-title">
|
||||
<el-icon class="title-icon"><Document /></el-icon>
|
||||
学生头像列表
|
||||
</span>
|
||||
<div class="header-actions">
|
||||
<right-toolbar v-model:showSearch="showSearch" class="ml10" @queryTable="getDataList">
|
||||
<TableColumnControl
|
||||
ref="columnControlRef"
|
||||
:columns="tableColumns"
|
||||
v-model="visibleColumns"
|
||||
trigger-type="default"
|
||||
trigger-circle
|
||||
@change="handleColumnChange"
|
||||
@order-change="handleColumnOrderChange"
|
||||
>
|
||||
<template #trigger>
|
||||
<el-tooltip class="item" effect="dark" content="列设置" placement="top">
|
||||
<el-button circle style="margin-left: 0">
|
||||
<el-icon><Menu /></el-icon>
|
||||
</el-button>
|
||||
</el-tooltip>
|
||||
</template>
|
||||
</TableColumnControl>
|
||||
</right-toolbar>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- 表格 -->
|
||||
<el-table
|
||||
:data="state.dataList"
|
||||
v-loading="state.loading"
|
||||
stripe
|
||||
:cell-style="tableStyle.cellStyle"
|
||||
:header-cell-style="tableStyle.headerCellStyle"
|
||||
class="modern-table"
|
||||
@sort-change="sortChangeHandle">
|
||||
<el-table-column type="index" label="序号" width="70" align="center">
|
||||
<template #header>
|
||||
<el-icon><List /></el-icon>
|
||||
</template>
|
||||
<template #default="{ $index }">
|
||||
{{ $index + 1 + ((state.pagination?.current || 1) - 1) * (state.pagination?.size || 10) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
v-for="col in visibleColumnsSorted"
|
||||
:key="col.prop"
|
||||
:prop="col.prop"
|
||||
:label="col.label"
|
||||
:width="col.width"
|
||||
:min-width="col.minWidth"
|
||||
:show-overflow-tooltip="col.showOverflowTooltip !== false"
|
||||
:align="col.align">
|
||||
<template #header>
|
||||
<el-icon v-if="col.icon"><component :is="col.icon" /></el-icon>
|
||||
<span :style="{ marginLeft: col.icon ? '4px' : '0' }">{{ col.label }}</span>
|
||||
</template>
|
||||
<template #default="scope" v-if="col.prop === 'headImg'">
|
||||
<el-image
|
||||
v-if="scope.row.headImg || scope.row.imageUrl || scope.row.qrCode"
|
||||
:src="scope.row.headImg || scope.row.imageUrl || scope.row.qrCode"
|
||||
:preview-src-list="[scope.row.headImg || scope.row.imageUrl || scope.row.qrCode]"
|
||||
fit="cover"
|
||||
style="width: 80px; height: 100px; cursor: pointer;"
|
||||
lazy>
|
||||
<template #error>
|
||||
<div class="image-slot">
|
||||
<el-icon><Picture /></el-icon>
|
||||
</div>
|
||||
</template>
|
||||
</el-image>
|
||||
<span v-else>-</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<!-- 表格 -->
|
||||
<el-table
|
||||
:data="state.dataList"
|
||||
v-loading="state.loading"
|
||||
stripe
|
||||
:cell-style="tableStyle.cellStyle"
|
||||
:header-cell-style="tableStyle.headerCellStyle"
|
||||
class="modern-table"
|
||||
@sort-change="sortChangeHandle"
|
||||
>
|
||||
<el-table-column type="index" label="序号" width="70" align="center">
|
||||
<template #header>
|
||||
<el-icon><List /></el-icon>
|
||||
</template>
|
||||
<template #default="{ $index }">
|
||||
{{ $index + 1 + ((state.pagination?.current || 1) - 1) * (state.pagination?.size || 10) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
v-for="col in visibleColumnsSorted"
|
||||
:key="col.prop"
|
||||
:prop="col.prop"
|
||||
:label="col.label"
|
||||
:width="col.width"
|
||||
:min-width="col.minWidth"
|
||||
:show-overflow-tooltip="col.showOverflowTooltip !== false"
|
||||
:align="col.align"
|
||||
>
|
||||
<template #header>
|
||||
<el-icon v-if="col.icon"><component :is="col.icon" /></el-icon>
|
||||
<span :style="{ marginLeft: col.icon ? '4px' : '0' }">{{ col.label }}</span>
|
||||
</template>
|
||||
<template #default="scope" v-if="col.prop === 'headImg'">
|
||||
<el-image
|
||||
v-if="scope.row.headImg || scope.row.imageUrl || scope.row.qrCode"
|
||||
:src="scope.row.headImg || scope.row.imageUrl || scope.row.qrCode"
|
||||
:preview-src-list="[scope.row.headImg || scope.row.imageUrl || scope.row.qrCode]"
|
||||
fit="cover"
|
||||
style="width: 80px; height: 100px; cursor: pointer"
|
||||
lazy
|
||||
>
|
||||
<template #error>
|
||||
<div class="image-slot">
|
||||
<el-icon><Picture /></el-icon>
|
||||
</div>
|
||||
</template>
|
||||
</el-image>
|
||||
<span v-else>-</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<!-- 分页 -->
|
||||
<div class="pagination-wrapper">
|
||||
<pagination
|
||||
@size-change="sizeChangeHandle"
|
||||
@current-change="currentChangeHandle"
|
||||
v-bind="state.pagination" />
|
||||
</div>
|
||||
</el-card>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 分页 -->
|
||||
<div class="pagination-wrapper">
|
||||
<pagination @size-change="sizeChangeHandle" @current-change="currentChangeHandle" v-bind="state.pagination" />
|
||||
</div>
|
||||
</el-card>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="BasicStudentAvatar">
|
||||
import { ref, reactive, computed, onMounted } from 'vue'
|
||||
import { useRoute } from 'vue-router'
|
||||
import { BasicTableProps, useTable } from "/@/hooks/table";
|
||||
import { fetchList } from "/@/api/basic/basicstudentavatar";
|
||||
import { getClassListByRole } from "/@/api/basic/basicclass";
|
||||
import TableColumnControl from '/@/components/TableColumnControl/index.vue'
|
||||
import { Picture, List, Document, UserFilled, Grid, Menu, Search } from '@element-plus/icons-vue'
|
||||
import { useTableColumnControl } from '/@/hooks/tableColumn'
|
||||
import { ref, reactive, computed, onMounted } from 'vue';
|
||||
import { useRoute } from 'vue-router';
|
||||
import { BasicTableProps, useTable } from '/@/hooks/table';
|
||||
import { fetchList } from '/@/api/basic/basicstudentavatar';
|
||||
import { getClassListByRole } from '/@/api/basic/basicclass';
|
||||
import TableColumnControl from '/@/components/TableColumnControl/index.vue';
|
||||
import { Picture, List, Document, UserFilled, Grid, Menu, Search } from '@element-plus/icons-vue';
|
||||
import { useTableColumnControl } from '/@/hooks/tableColumn';
|
||||
|
||||
// 定义变量内容
|
||||
const route = useRoute()
|
||||
const searchFormRef = ref()
|
||||
const columnControlRef = ref()
|
||||
const showSearch = ref(true)
|
||||
const classList = ref<any[]>([])
|
||||
const route = useRoute();
|
||||
const searchFormRef = ref();
|
||||
const columnControlRef = ref();
|
||||
const showSearch = ref(true);
|
||||
const classList = ref<any[]>([]);
|
||||
|
||||
// 表格列配置
|
||||
const tableColumns = [
|
||||
{ prop: 'stuNo', label: '学号', icon: Document },
|
||||
{ prop: 'realName', label: '姓名', icon: UserFilled },
|
||||
{ prop: 'className', label: '班级', icon: Grid },
|
||||
{ prop: 'headImg', label: '头像', icon: Picture, width: 120 }
|
||||
]
|
||||
{ prop: 'stuNo', label: '学号', icon: Document },
|
||||
{ prop: 'realName', label: '姓名', icon: UserFilled },
|
||||
{ prop: 'className', label: '班级', icon: Grid },
|
||||
{ prop: 'headImg', label: '头像', icon: Picture, width: 120 },
|
||||
];
|
||||
|
||||
// 使用表格列控制hook
|
||||
const {
|
||||
visibleColumns,
|
||||
visibleColumnsSorted,
|
||||
checkColumnVisible,
|
||||
handleColumnChange,
|
||||
handleColumnOrderChange
|
||||
} = useTableColumnControl(tableColumns)
|
||||
const { visibleColumns, visibleColumnsSorted, checkColumnVisible, handleColumnChange, handleColumnOrderChange } = useTableColumnControl(tableColumns);
|
||||
|
||||
// 搜索表单
|
||||
const searchForm = reactive({
|
||||
classCode: ''
|
||||
})
|
||||
classCode: '',
|
||||
});
|
||||
|
||||
// 配置 useTable - 接口返回的数据结构是 { classes: [], students: [] }
|
||||
const state: BasicTableProps = reactive<BasicTableProps>({
|
||||
queryForm: searchForm,
|
||||
pageList: async (queryParams: any) => {
|
||||
const res = await fetchList(queryParams)
|
||||
// 接口返回的数据结构是 { classes: [], students: [] }
|
||||
// 需要将 students 数组转换为表格数据,并关联班级信息
|
||||
if (res.data && res.data.students) {
|
||||
const students = res.data.students || []
|
||||
const classes = res.data.classes || []
|
||||
const classMap = new Map()
|
||||
classes.forEach((cls: any) => {
|
||||
classMap.set(cls.classCode, cls)
|
||||
})
|
||||
|
||||
// 将学生数据与班级信息合并
|
||||
const dataList = students.map((stu: any) => {
|
||||
const classInfo = classMap.get(stu.classCode)
|
||||
return {
|
||||
...stu,
|
||||
className: classInfo ? classInfo.classNo : stu.className || '',
|
||||
classNo: classInfo ? classInfo.classNo : ''
|
||||
}
|
||||
})
|
||||
|
||||
return {
|
||||
...res,
|
||||
data: {
|
||||
records: dataList,
|
||||
total: dataList.length,
|
||||
current: 1,
|
||||
size: dataList.length,
|
||||
pages: 1
|
||||
}
|
||||
}
|
||||
}
|
||||
return res
|
||||
},
|
||||
props: {
|
||||
item: 'records',
|
||||
totalCount: 'total'
|
||||
},
|
||||
createdIsNeed: true
|
||||
})
|
||||
queryForm: searchForm,
|
||||
pageList: async (queryParams: any) => {
|
||||
const res = await fetchList(queryParams);
|
||||
// 接口返回的数据结构是 { classes: [], students: [] }
|
||||
// 需要将 students 数组转换为表格数据,并关联班级信息
|
||||
if (res.data && res.data.students) {
|
||||
const students = res.data.students || [];
|
||||
const classes = res.data.classes || [];
|
||||
const classMap = new Map();
|
||||
classes.forEach((cls: any) => {
|
||||
classMap.set(cls.classCode, cls);
|
||||
});
|
||||
|
||||
// 将学生数据与班级信息合并
|
||||
const dataList = students.map((stu: any) => {
|
||||
const classInfo = classMap.get(stu.classCode);
|
||||
return {
|
||||
...stu,
|
||||
className: classInfo ? classInfo.classNo : stu.className || '',
|
||||
classNo: classInfo ? classInfo.classNo : '',
|
||||
};
|
||||
});
|
||||
|
||||
return {
|
||||
...res,
|
||||
data: {
|
||||
records: dataList,
|
||||
total: dataList.length,
|
||||
current: 1,
|
||||
size: dataList.length,
|
||||
pages: 1,
|
||||
},
|
||||
};
|
||||
}
|
||||
return res;
|
||||
},
|
||||
props: {
|
||||
item: 'records',
|
||||
totalCount: 'total',
|
||||
},
|
||||
createdIsNeed: true,
|
||||
});
|
||||
|
||||
// table hook
|
||||
const {
|
||||
getDataList,
|
||||
currentChangeHandle,
|
||||
sizeChangeHandle,
|
||||
sortChangeHandle,
|
||||
tableStyle
|
||||
} = useTable(state)
|
||||
const { getDataList, currentChangeHandle, sizeChangeHandle, sortChangeHandle, tableStyle } = useTable(state);
|
||||
|
||||
// 查询
|
||||
const handleSearch = () => {
|
||||
getDataList()
|
||||
}
|
||||
getDataList();
|
||||
};
|
||||
|
||||
// 重置
|
||||
const handleReset = () => {
|
||||
searchFormRef.value?.resetFields()
|
||||
searchForm.classCode = ''
|
||||
getDataList()
|
||||
}
|
||||
searchFormRef.value?.resetFields();
|
||||
searchForm.classCode = '';
|
||||
getDataList();
|
||||
};
|
||||
|
||||
// 获取班级列表
|
||||
const getClassListData = async () => {
|
||||
try {
|
||||
const res = await getClassListByRole()
|
||||
if (res.data) {
|
||||
classList.value = Array.isArray(res.data) ? res.data : []
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('获取班级列表失败', err)
|
||||
classList.value = []
|
||||
}
|
||||
}
|
||||
try {
|
||||
const res = await getClassListByRole();
|
||||
if (res.data) {
|
||||
classList.value = Array.isArray(res.data) ? res.data : [];
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('获取班级列表失败', err);
|
||||
classList.value = [];
|
||||
}
|
||||
};
|
||||
|
||||
// 初始化
|
||||
onMounted(() => {
|
||||
getClassListData()
|
||||
})
|
||||
getClassListData();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import '/@/assets/styles/modern-page.scss';
|
||||
|
||||
.image-slot {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: #f5f7fa;
|
||||
color: #909399;
|
||||
font-size: 30px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: #f5f7fa;
|
||||
color: #909399;
|
||||
font-size: 30px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,502 +1,462 @@
|
||||
<template>
|
||||
<div class="modern-page-container">
|
||||
<div class="page-wrapper">
|
||||
<!-- 搜索表单卡片 -->
|
||||
<el-card v-show="showSearch" class="search-card" shadow="never">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span class="card-title">
|
||||
<el-icon class="title-icon"><Search /></el-icon>
|
||||
筛选条件
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
<el-form :model="searchForm" ref="searchFormRef" :inline="true" @keyup.enter="handleSearch" class="search-form">
|
||||
<el-form-item label="批次号" prop="batchNo">
|
||||
<el-input
|
||||
v-model="searchForm.batchNo"
|
||||
placeholder="请输入批次号"
|
||||
clearable
|
||||
style="width: 180px" />
|
||||
</el-form-item>
|
||||
<el-form-item label="学号" prop="stuNo">
|
||||
<el-input
|
||||
v-model="searchForm.stuNo"
|
||||
placeholder="请输入学号"
|
||||
clearable
|
||||
style="width: 150px" />
|
||||
</el-form-item>
|
||||
<el-form-item label="姓名" prop="systemRealName">
|
||||
<el-input
|
||||
v-model="searchForm.systemRealName"
|
||||
placeholder="请输入姓名"
|
||||
clearable
|
||||
style="width: 120px" />
|
||||
</el-form-item>
|
||||
<el-form-item label="异常类型" prop="exceptionType">
|
||||
<el-select
|
||||
v-model="searchForm.exceptionType"
|
||||
placeholder="请选择异常类型"
|
||||
clearable
|
||||
style="width: 150px">
|
||||
<el-option label="姓名不一致" value="1" />
|
||||
<el-option label="身份证不一致" value="2" />
|
||||
<el-option label="学籍号不一致" value="3" />
|
||||
<el-option label="毕业院校不一致" value="4" />
|
||||
<el-option label="系统有学籍无" value="5" />
|
||||
<el-option label="学籍有系统无" value="6" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="复核状态" prop="reviewStatus">
|
||||
<el-select
|
||||
v-model="searchForm.reviewStatus"
|
||||
placeholder="请选择复核状态"
|
||||
clearable
|
||||
style="width: 120px">
|
||||
<el-option label="待复核" value="0" />
|
||||
<el-option label="已复核" value="1" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="Search" @click="handleSearch">查询</el-button>
|
||||
<el-button icon="Refresh" @click="handleReset">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
<div class="modern-page-container">
|
||||
<div class="page-wrapper">
|
||||
<!-- 搜索表单卡片 -->
|
||||
<el-card v-show="showSearch" class="search-card" shadow="never">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span class="card-title">
|
||||
<el-icon class="title-icon"><Search /></el-icon>
|
||||
筛选条件
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
<el-form :model="searchForm" ref="searchFormRef" :inline="true" @keyup.enter="handleSearch" class="search-form">
|
||||
<el-form-item label="批次号" prop="batchNo">
|
||||
<el-input v-model="searchForm.batchNo" placeholder="请输入批次号" clearable style="width: 180px" />
|
||||
</el-form-item>
|
||||
<el-form-item label="学号" prop="stuNo">
|
||||
<el-input v-model="searchForm.stuNo" placeholder="请输入学号" clearable style="width: 150px" />
|
||||
</el-form-item>
|
||||
<el-form-item label="姓名" prop="systemRealName">
|
||||
<el-input v-model="searchForm.systemRealName" placeholder="请输入姓名" clearable style="width: 120px" />
|
||||
</el-form-item>
|
||||
<el-form-item label="异常类型" prop="exceptionType">
|
||||
<el-select v-model="searchForm.exceptionType" placeholder="请选择异常类型" clearable style="width: 150px">
|
||||
<el-option label="姓名不一致" value="1" />
|
||||
<el-option label="身份证不一致" value="2" />
|
||||
<el-option label="学籍号不一致" value="3" />
|
||||
<el-option label="毕业院校不一致" value="4" />
|
||||
<el-option label="系统有学籍无" value="5" />
|
||||
<el-option label="学籍有系统无" value="6" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="复核状态" prop="reviewStatus">
|
||||
<el-select v-model="searchForm.reviewStatus" placeholder="请选择复核状态" clearable style="width: 120px">
|
||||
<el-option label="待复核" value="0" />
|
||||
<el-option label="已复核" value="1" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="Search" @click="handleSearch">查询</el-button>
|
||||
<el-button icon="Refresh" @click="handleReset">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
|
||||
<!-- 内容卡片 -->
|
||||
<el-card class="content-card" shadow="never">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span class="card-title">
|
||||
<el-icon class="title-icon"><DocumentChecked /></el-icon>
|
||||
学籍比对异常数据
|
||||
</span>
|
||||
<div class="header-actions">
|
||||
<el-upload
|
||||
:show-file-list="false"
|
||||
:before-upload="beforeUpload"
|
||||
:http-request="handleImport"
|
||||
accept=".xlsx,.xls"
|
||||
class="upload-btn">
|
||||
<el-button type="primary" icon="Upload" :loading="importLoading">导入比对</el-button>
|
||||
</el-upload>
|
||||
<el-button type="success" icon="Download" @click="handleDownloadTemplate">下载模板</el-button>
|
||||
<el-button type="warning" icon="Download" @click="handleExport">导出异常</el-button>
|
||||
<el-button type="info" icon="Bell" @click="handleSend" :disabled="!searchForm.batchNo">下发班主任</el-button>
|
||||
<right-toolbar
|
||||
v-model:showSearch="showSearch"
|
||||
class="ml10"
|
||||
@queryTable="getDataList" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<!-- 内容卡片 -->
|
||||
<el-card class="content-card" shadow="never">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span class="card-title">
|
||||
<el-icon class="title-icon"><DocumentChecked /></el-icon>
|
||||
学籍比对异常数据
|
||||
</span>
|
||||
<div class="header-actions">
|
||||
<el-upload :show-file-list="false" :before-upload="beforeUpload" :http-request="handleImport" accept=".xlsx,.xls" class="upload-btn">
|
||||
<el-button type="primary" icon="Upload" :loading="importLoading">导入比对</el-button>
|
||||
</el-upload>
|
||||
<el-button type="success" icon="Download" @click="handleDownloadTemplate">下载模板</el-button>
|
||||
<el-button type="warning" icon="Download" @click="handleExport">导出异常</el-button>
|
||||
<el-button type="info" icon="Bell" @click="handleSend" :disabled="!searchForm.batchNo">下发班主任</el-button>
|
||||
<right-toolbar v-model:showSearch="showSearch" class="ml10" @queryTable="getDataList" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- 统计卡片 -->
|
||||
<el-row :gutter="16" class="stat-row">
|
||||
<el-col :span="4">
|
||||
<el-statistic title="总异常数" :value="statistics.total" />
|
||||
</el-col>
|
||||
<el-col :span="4">
|
||||
<el-statistic title="待复核" :value="statistics.pending" />
|
||||
</el-col>
|
||||
<el-col :span="4">
|
||||
<el-statistic title="已复核" :value="statistics.reviewed" />
|
||||
</el-col>
|
||||
</el-row>
|
||||
<!-- 统计卡片 -->
|
||||
<el-row :gutter="16" class="stat-row">
|
||||
<el-col :span="4">
|
||||
<el-statistic title="总异常数" :value="statistics.total" />
|
||||
</el-col>
|
||||
<el-col :span="4">
|
||||
<el-statistic title="待复核" :value="statistics.pending" />
|
||||
</el-col>
|
||||
<el-col :span="4">
|
||||
<el-statistic title="已复核" :value="statistics.reviewed" />
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<!-- 表格 -->
|
||||
<el-table
|
||||
:data="dataList"
|
||||
v-loading="loading"
|
||||
stripe
|
||||
:cell-style="tableStyle.cellStyle"
|
||||
:header-cell-style="tableStyle.headerCellStyle"
|
||||
class="modern-table">
|
||||
<el-table-column type="index" label="序号" width="70" align="center">
|
||||
<template #default="{ $index }">
|
||||
{{ (page.currentPage - 1) * page.pageSize + $index + 1 }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="batchNo" label="批次号" width="160" align="center" />
|
||||
<el-table-column prop="stuNo" label="学号" width="120" align="center" />
|
||||
<el-table-column label="姓名" width="160" align="center">
|
||||
<template #default="{ row }">
|
||||
<div>
|
||||
<span v-if="row.systemRealName">{{ row.systemRealName }}</span>
|
||||
<span v-if="row.systemRealName && row.enrollRealName && row.systemRealName !== row.enrollRealName"
|
||||
class="text-danger">
|
||||
/ {{ row.enrollRealName }}
|
||||
</span>
|
||||
<span v-else-if="row.enrollRealName && !row.systemRealName">{{ row.enrollRealName }}</span>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="身份证号" width="200" align="center">
|
||||
<template #default="{ row }">
|
||||
<div>
|
||||
<div v-if="row.systemIdCard">系统:{{ row.systemIdCard }}</div>
|
||||
<div v-if="row.enrollIdCard && row.enrollIdCard !== row.systemIdCard" class="text-warning">
|
||||
学籍:{{ row.enrollIdCard }}
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="学籍号" width="200" align="center">
|
||||
<template #default="{ row }">
|
||||
<div>
|
||||
<div v-if="row.systemEnrollNo">系统:{{ row.systemEnrollNo }}</div>
|
||||
<div v-if="row.nationalEnrollNo && row.nationalEnrollNo !== row.systemEnrollNo" class="text-warning">
|
||||
全国:{{ row.nationalEnrollNo }}
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="className" label="班级" width="150" />
|
||||
<el-table-column prop="classMasterName" label="班主任" width="100" align="center" />
|
||||
<el-table-column prop="exceptionType" label="异常类型" width="140" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-tag :type="getExceptionTagType(row.exceptionType)" size="small">
|
||||
{{ getExceptionTypeName(row.exceptionType) }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="exceptionDesc" label="异常说明" min-width="250" show-overflow-tooltip />
|
||||
<el-table-column prop="reviewStatus" label="复核状态" width="100" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-tag :type="row.reviewStatus === '1' ? 'success' : 'warning'" size="small">
|
||||
{{ row.reviewStatus === '1' ? '已复核' : '待复核' }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="reviewResult" label="复核结果" width="150" show-overflow-tooltip />
|
||||
<el-table-column label="操作" width="120" align="center" fixed="right">
|
||||
<template #default="{ row }">
|
||||
<el-button
|
||||
v-if="row.reviewStatus === '0'"
|
||||
icon="Edit"
|
||||
link
|
||||
type="primary"
|
||||
@click="handleReview(row)">
|
||||
复核
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<template #empty>
|
||||
<el-empty description="暂无数据" :image-size="120" />
|
||||
</template>
|
||||
</el-table>
|
||||
<!-- 表格 -->
|
||||
<el-table
|
||||
:data="dataList"
|
||||
v-loading="loading"
|
||||
stripe
|
||||
:cell-style="tableStyle.cellStyle"
|
||||
:header-cell-style="tableStyle.headerCellStyle"
|
||||
class="modern-table"
|
||||
>
|
||||
<el-table-column type="index" label="序号" width="70" align="center">
|
||||
<template #default="{ $index }">
|
||||
{{ (page.currentPage - 1) * page.pageSize + $index + 1 }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="batchNo" label="批次号" width="160" align="center" />
|
||||
<el-table-column prop="stuNo" label="学号" width="120" align="center" />
|
||||
<el-table-column label="姓名" width="160" align="center">
|
||||
<template #default="{ row }">
|
||||
<div>
|
||||
<span v-if="row.systemRealName">{{ row.systemRealName }}</span>
|
||||
<span v-if="row.systemRealName && row.enrollRealName && row.systemRealName !== row.enrollRealName" class="text-danger">
|
||||
/ {{ row.enrollRealName }}
|
||||
</span>
|
||||
<span v-else-if="row.enrollRealName && !row.systemRealName">{{ row.enrollRealName }}</span>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="身份证号" width="200" align="center">
|
||||
<template #default="{ row }">
|
||||
<div>
|
||||
<div v-if="row.systemIdCard">系统:{{ row.systemIdCard }}</div>
|
||||
<div v-if="row.enrollIdCard && row.enrollIdCard !== row.systemIdCard" class="text-warning">学籍:{{ row.enrollIdCard }}</div>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="学籍号" width="200" align="center">
|
||||
<template #default="{ row }">
|
||||
<div>
|
||||
<div v-if="row.systemEnrollNo">系统:{{ row.systemEnrollNo }}</div>
|
||||
<div v-if="row.nationalEnrollNo && row.nationalEnrollNo !== row.systemEnrollNo" class="text-warning">
|
||||
全国:{{ row.nationalEnrollNo }}
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="className" label="班级" width="150" />
|
||||
<el-table-column prop="classMasterName" label="班主任" width="100" align="center" />
|
||||
<el-table-column prop="exceptionType" label="异常类型" width="140" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-tag :type="getExceptionTagType(row.exceptionType)" size="small">
|
||||
{{ getExceptionTypeName(row.exceptionType) }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="exceptionDesc" label="异常说明" min-width="250" show-overflow-tooltip />
|
||||
<el-table-column prop="reviewStatus" label="复核状态" width="100" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-tag :type="row.reviewStatus === '1' ? 'success' : 'warning'" size="small">
|
||||
{{ row.reviewStatus === '1' ? '已复核' : '待复核' }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="reviewResult" label="复核结果" width="150" show-overflow-tooltip />
|
||||
<el-table-column label="操作" width="120" align="center" fixed="right">
|
||||
<template #default="{ row }">
|
||||
<el-button v-if="row.reviewStatus === '0'" icon="Edit" link type="primary" @click="handleReview(row)"> 复核 </el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<template #empty>
|
||||
<el-empty description="暂无数据" :image-size="120" />
|
||||
</template>
|
||||
</el-table>
|
||||
|
||||
<!-- 分页 -->
|
||||
<el-pagination
|
||||
v-model:current-page="page.currentPage"
|
||||
v-model:page-size="page.pageSize"
|
||||
:page-sizes="[10, 20, 50, 100]"
|
||||
:total="page.total"
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
class="pagination"
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="handleCurrentChange" />
|
||||
</el-card>
|
||||
</div>
|
||||
<!-- 分页 -->
|
||||
<el-pagination
|
||||
v-model:current-page="page.currentPage"
|
||||
v-model:page-size="page.pageSize"
|
||||
:page-sizes="[10, 20, 50, 100]"
|
||||
:total="page.total"
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
class="pagination"
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="handleCurrentChange"
|
||||
/>
|
||||
</el-card>
|
||||
</div>
|
||||
|
||||
<!-- 复核弹窗 -->
|
||||
<el-dialog
|
||||
v-model="reviewDialogVisible"
|
||||
title="学籍信息复核"
|
||||
width="600px"
|
||||
:close-on-click-modal="false">
|
||||
<el-descriptions :column="2" border>
|
||||
<el-descriptions-item label="学号">{{ reviewData.stuNo }}</el-descriptions-item>
|
||||
<el-descriptions-item label="系统姓名">{{ reviewData.systemRealName }}</el-descriptions-item>
|
||||
<el-descriptions-item label="学籍姓名">{{ reviewData.enrollRealName }}</el-descriptions-item>
|
||||
<el-descriptions-item label="班级">{{ reviewData.className }}</el-descriptions-item>
|
||||
<el-descriptions-item label="系统身份证">{{ reviewData.systemIdCard }}</el-descriptions-item>
|
||||
<el-descriptions-item label="学籍身份证">{{ reviewData.enrollIdCard }}</el-descriptions-item>
|
||||
<el-descriptions-item label="系统学籍号">{{ reviewData.systemEnrollNo }}</el-descriptions-item>
|
||||
<el-descriptions-item label="全国学籍号">{{ reviewData.nationalEnrollNo }}</el-descriptions-item>
|
||||
<el-descriptions-item label="异常类型" :span="2">
|
||||
<el-tag :type="getExceptionTagType(reviewData.exceptionType)">
|
||||
{{ getExceptionTypeName(reviewData.exceptionType) }}
|
||||
</el-tag>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="异常说明" :span="2">{{ reviewData.exceptionDesc }}</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
<el-form :model="reviewForm" label-width="80px" class="review-form">
|
||||
<el-form-item label="复核结果">
|
||||
<el-radio-group v-model="reviewForm.reviewResult">
|
||||
<el-radio label="信息无误">信息无误</el-radio>
|
||||
<el-radio label="需修改系统">需修改系统</el-radio>
|
||||
<el-radio label="需修改学籍">需修改学籍</el-radio>
|
||||
<el-radio label="其他问题">其他问题</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button @click="reviewDialogVisible = false">取消</el-button>
|
||||
<el-button type="primary" @click="submitReview" :loading="reviewLoading">确定</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
<!-- 复核弹窗 -->
|
||||
<el-dialog v-model="reviewDialogVisible" title="学籍信息复核" width="600px" :close-on-click-modal="false">
|
||||
<el-descriptions :column="2" border>
|
||||
<el-descriptions-item label="学号">{{ reviewData.stuNo }}</el-descriptions-item>
|
||||
<el-descriptions-item label="系统姓名">{{ reviewData.systemRealName }}</el-descriptions-item>
|
||||
<el-descriptions-item label="学籍姓名">{{ reviewData.enrollRealName }}</el-descriptions-item>
|
||||
<el-descriptions-item label="班级">{{ reviewData.className }}</el-descriptions-item>
|
||||
<el-descriptions-item label="系统身份证">{{ reviewData.systemIdCard }}</el-descriptions-item>
|
||||
<el-descriptions-item label="学籍身份证">{{ reviewData.enrollIdCard }}</el-descriptions-item>
|
||||
<el-descriptions-item label="系统学籍号">{{ reviewData.systemEnrollNo }}</el-descriptions-item>
|
||||
<el-descriptions-item label="全国学籍号">{{ reviewData.nationalEnrollNo }}</el-descriptions-item>
|
||||
<el-descriptions-item label="异常类型" :span="2">
|
||||
<el-tag :type="getExceptionTagType(reviewData.exceptionType)">
|
||||
{{ getExceptionTypeName(reviewData.exceptionType) }}
|
||||
</el-tag>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="异常说明" :span="2">{{ reviewData.exceptionDesc }}</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
<el-form :model="reviewForm" label-width="80px" class="review-form">
|
||||
<el-form-item label="复核结果">
|
||||
<el-radio-group v-model="reviewForm.reviewResult">
|
||||
<el-radio label="信息无误">信息无误</el-radio>
|
||||
<el-radio label="需修改系统">需修改系统</el-radio>
|
||||
<el-radio label="需修改学籍">需修改学籍</el-radio>
|
||||
<el-radio label="其他问题">其他问题</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button @click="reviewDialogVisible = false">取消</el-button>
|
||||
<el-button type="primary" @click="submitReview" :loading="reviewLoading">确定</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="EnrollCompare">
|
||||
import { reactive, ref, onMounted, computed } from 'vue'
|
||||
import { fetchList, importData, exportData, sendToClassMaster, submitReview as submitReviewApi, downloadTemplate } from '/@/api/basic/enrollcompare'
|
||||
import { useMessage, useMessageBox } from '/@/hooks/message'
|
||||
import { Search, DocumentChecked, Upload, Download, Bell, Edit } from '@element-plus/icons-vue'
|
||||
import { reactive, ref, onMounted, computed } from 'vue';
|
||||
import { fetchList, importData, exportData, sendToClassMaster, submitReview as submitReviewApi, downloadTemplate } from '/@/api/basic/enrollcompare';
|
||||
import { useMessage, useMessageBox } from '/@/hooks/message';
|
||||
import { Search, DocumentChecked, Upload, Download, Bell, Edit } from '@element-plus/icons-vue';
|
||||
|
||||
// 定义变量内容
|
||||
const searchFormRef = ref()
|
||||
const showSearch = ref(true)
|
||||
const loading = ref(false)
|
||||
const importLoading = ref(false)
|
||||
const reviewLoading = ref(false)
|
||||
const dataList = ref<any[]>([])
|
||||
const reviewDialogVisible = ref(false)
|
||||
const reviewData = ref<any>({})
|
||||
const searchFormRef = ref();
|
||||
const showSearch = ref(true);
|
||||
const loading = ref(false);
|
||||
const importLoading = ref(false);
|
||||
const reviewLoading = ref(false);
|
||||
const dataList = ref<any[]>([]);
|
||||
const reviewDialogVisible = ref(false);
|
||||
const reviewData = ref<any>({});
|
||||
const reviewForm = reactive({
|
||||
id: '',
|
||||
reviewResult: '信息无误'
|
||||
})
|
||||
id: '',
|
||||
reviewResult: '信息无误',
|
||||
});
|
||||
|
||||
// 统计数据
|
||||
const statistics = reactive({
|
||||
total: 0,
|
||||
pending: 0,
|
||||
reviewed: 0
|
||||
})
|
||||
total: 0,
|
||||
pending: 0,
|
||||
reviewed: 0,
|
||||
});
|
||||
|
||||
// 分页
|
||||
const page = reactive({
|
||||
currentPage: 1,
|
||||
pageSize: 20,
|
||||
total: 0
|
||||
})
|
||||
currentPage: 1,
|
||||
pageSize: 20,
|
||||
total: 0,
|
||||
});
|
||||
|
||||
// 搜索表单
|
||||
const searchForm = reactive({
|
||||
batchNo: '',
|
||||
stuNo: '',
|
||||
systemRealName: '',
|
||||
exceptionType: '',
|
||||
reviewStatus: ''
|
||||
})
|
||||
batchNo: '',
|
||||
stuNo: '',
|
||||
systemRealName: '',
|
||||
exceptionType: '',
|
||||
reviewStatus: '',
|
||||
});
|
||||
|
||||
// 表格样式
|
||||
const tableStyle = {
|
||||
cellStyle: { textAlign: 'center' },
|
||||
headerCellStyle: {
|
||||
textAlign: 'center',
|
||||
background: 'var(--el-table-row-hover-bg-color)',
|
||||
color: 'var(--el-text-color-primary)'
|
||||
}
|
||||
}
|
||||
cellStyle: { textAlign: 'center' },
|
||||
headerCellStyle: {
|
||||
textAlign: 'center',
|
||||
background: 'var(--el-table-row-hover-bg-color)',
|
||||
color: 'var(--el-text-color-primary)',
|
||||
},
|
||||
};
|
||||
|
||||
// 获取异常类型名称
|
||||
const getExceptionTypeName = (type: string) => {
|
||||
const map: Record<string, string> = {
|
||||
'1': '姓名不一致',
|
||||
'2': '身份证不一致',
|
||||
'3': '学籍号不一致',
|
||||
'4': '毕业院校不一致',
|
||||
'5': '系统有学籍无',
|
||||
'6': '学籍有系统无'
|
||||
}
|
||||
return map[type] || type
|
||||
}
|
||||
const map: Record<string, string> = {
|
||||
'1': '姓名不一致',
|
||||
'2': '身份证不一致',
|
||||
'3': '学籍号不一致',
|
||||
'4': '毕业院校不一致',
|
||||
'5': '系统有学籍无',
|
||||
'6': '学籍有系统无',
|
||||
};
|
||||
return map[type] || type;
|
||||
};
|
||||
|
||||
// 获取异常类型标签颜色
|
||||
const getExceptionTagType = (type: string) => {
|
||||
const map: Record<string, string> = {
|
||||
'1': 'danger',
|
||||
'2': 'danger',
|
||||
'3': 'warning',
|
||||
'4': 'info',
|
||||
'5': 'warning',
|
||||
'6': 'warning'
|
||||
}
|
||||
return map[type] || 'info'
|
||||
}
|
||||
const map: Record<string, string> = {
|
||||
'1': 'danger',
|
||||
'2': 'danger',
|
||||
'3': 'warning',
|
||||
'4': 'info',
|
||||
'5': 'warning',
|
||||
'6': 'warning',
|
||||
};
|
||||
return map[type] || 'info';
|
||||
};
|
||||
|
||||
// 查询
|
||||
const handleSearch = () => {
|
||||
page.currentPage = 1
|
||||
getDataList()
|
||||
}
|
||||
page.currentPage = 1;
|
||||
getDataList();
|
||||
};
|
||||
|
||||
// 重置
|
||||
const handleReset = () => {
|
||||
searchFormRef.value?.resetFields()
|
||||
getDataList()
|
||||
}
|
||||
searchFormRef.value?.resetFields();
|
||||
getDataList();
|
||||
};
|
||||
|
||||
// 分页
|
||||
const handleSizeChange = (val: number) => {
|
||||
page.pageSize = val
|
||||
getDataList()
|
||||
}
|
||||
page.pageSize = val;
|
||||
getDataList();
|
||||
};
|
||||
|
||||
const handleCurrentChange = (val: number) => {
|
||||
page.currentPage = val
|
||||
getDataList()
|
||||
}
|
||||
page.currentPage = val;
|
||||
getDataList();
|
||||
};
|
||||
|
||||
// 获取数据列表
|
||||
const getDataList = async () => {
|
||||
loading.value = true
|
||||
try {
|
||||
const res = await fetchList({
|
||||
current: page.currentPage,
|
||||
size: page.pageSize,
|
||||
...searchForm
|
||||
})
|
||||
if (res.data && res.data.records) {
|
||||
dataList.value = res.data.records
|
||||
page.total = res.data.total
|
||||
loading.value = true;
|
||||
try {
|
||||
const res = await fetchList({
|
||||
current: page.currentPage,
|
||||
size: page.pageSize,
|
||||
...searchForm,
|
||||
});
|
||||
if (res.data && res.data.records) {
|
||||
dataList.value = res.data.records;
|
||||
page.total = res.data.total;
|
||||
|
||||
// 计算统计数据
|
||||
statistics.total = res.data.total
|
||||
statistics.pending = dataList.value.filter((item: any) => item.reviewStatus === '0').length
|
||||
statistics.reviewed = dataList.value.filter((item: any) => item.reviewStatus === '1').length
|
||||
} else {
|
||||
dataList.value = []
|
||||
page.total = 0
|
||||
}
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg || '获取数据失败')
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
// 计算统计数据
|
||||
statistics.total = res.data.total;
|
||||
statistics.pending = dataList.value.filter((item: any) => item.reviewStatus === '0').length;
|
||||
statistics.reviewed = dataList.value.filter((item: any) => item.reviewStatus === '1').length;
|
||||
} else {
|
||||
dataList.value = [];
|
||||
page.total = 0;
|
||||
}
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg || '获取数据失败');
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
// 上传前验证
|
||||
const beforeUpload = (file: File) => {
|
||||
const isExcel = file.name.endsWith('.xlsx') || file.name.endsWith('.xls')
|
||||
if (!isExcel) {
|
||||
useMessage().error('只能上传Excel文件')
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
const isExcel = file.name.endsWith('.xlsx') || file.name.endsWith('.xls');
|
||||
if (!isExcel) {
|
||||
useMessage().error('只能上传Excel文件');
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
// 导入比对
|
||||
const handleImport = async (options: any) => {
|
||||
importLoading.value = true
|
||||
try {
|
||||
const res = await importData(options.file)
|
||||
useMessage().success(res.msg || '导入比对成功')
|
||||
// 自动填充批次号
|
||||
if (res.data) {
|
||||
searchForm.batchNo = ''
|
||||
}
|
||||
getDataList()
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg || '导入失败')
|
||||
} finally {
|
||||
importLoading.value = false
|
||||
}
|
||||
}
|
||||
importLoading.value = true;
|
||||
try {
|
||||
const res = await importData(options.file);
|
||||
useMessage().success(res.msg || '导入比对成功');
|
||||
// 自动填充批次号
|
||||
if (res.data) {
|
||||
searchForm.batchNo = '';
|
||||
}
|
||||
getDataList();
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg || '导入失败');
|
||||
} finally {
|
||||
importLoading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
// 下载模板
|
||||
const handleDownloadTemplate = async () => {
|
||||
try {
|
||||
const res = await downloadTemplate()
|
||||
const blob = new Blob([res], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' })
|
||||
const url = window.URL.createObjectURL(blob)
|
||||
const link = document.createElement('a')
|
||||
link.href = url
|
||||
link.download = '全国学籍导入模板.xlsx'
|
||||
link.click()
|
||||
window.URL.revokeObjectURL(url)
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg || '下载失败')
|
||||
}
|
||||
}
|
||||
try {
|
||||
const res = await downloadTemplate();
|
||||
const blob = new Blob([res], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
|
||||
const url = window.URL.createObjectURL(blob);
|
||||
const link = document.createElement('a');
|
||||
link.href = url;
|
||||
link.download = '全国学籍导入模板.xlsx';
|
||||
link.click();
|
||||
window.URL.revokeObjectURL(url);
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg || '下载失败');
|
||||
}
|
||||
};
|
||||
|
||||
// 导出
|
||||
const handleExport = async () => {
|
||||
try {
|
||||
const res = await exportData(searchForm)
|
||||
const blob = new Blob([res], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' })
|
||||
const url = window.URL.createObjectURL(blob)
|
||||
const link = document.createElement('a')
|
||||
link.href = url
|
||||
link.download = '学籍比对异常数据.xlsx'
|
||||
link.click()
|
||||
window.URL.revokeObjectURL(url)
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg || '导出失败')
|
||||
}
|
||||
}
|
||||
try {
|
||||
const res = await exportData(searchForm);
|
||||
const blob = new Blob([res], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
|
||||
const url = window.URL.createObjectURL(blob);
|
||||
const link = document.createElement('a');
|
||||
link.href = url;
|
||||
link.download = '学籍比对异常数据.xlsx';
|
||||
link.click();
|
||||
window.URL.revokeObjectURL(url);
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg || '导出失败');
|
||||
}
|
||||
};
|
||||
|
||||
// 下发班主任
|
||||
const handleSend = async () => {
|
||||
if (!searchForm.batchNo) {
|
||||
useMessage().warning('请先选择批次号')
|
||||
return
|
||||
}
|
||||
try {
|
||||
await useMessageBox().confirm('确定要将该批次异常数据下发至班主任复核吗?')
|
||||
await sendToClassMaster(searchForm.batchNo)
|
||||
useMessage().success('下发成功')
|
||||
} catch (err: any) {
|
||||
if (err !== 'cancel') {
|
||||
useMessage().error(err.msg || '下发失败')
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!searchForm.batchNo) {
|
||||
useMessage().warning('请先选择批次号');
|
||||
return;
|
||||
}
|
||||
try {
|
||||
await useMessageBox().confirm('确定要将该批次异常数据下发至班主任复核吗?');
|
||||
await sendToClassMaster(searchForm.batchNo);
|
||||
useMessage().success('下发成功');
|
||||
} catch (err: any) {
|
||||
if (err !== 'cancel') {
|
||||
useMessage().error(err.msg || '下发失败');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// 复核
|
||||
const handleReview = (row: any) => {
|
||||
reviewData.value = row
|
||||
reviewForm.id = row.id
|
||||
reviewForm.reviewResult = '信息无误'
|
||||
reviewDialogVisible.value = true
|
||||
}
|
||||
reviewData.value = row;
|
||||
reviewForm.id = row.id;
|
||||
reviewForm.reviewResult = '信息无误';
|
||||
reviewDialogVisible.value = true;
|
||||
};
|
||||
|
||||
// 提交复核
|
||||
const submitReview = async () => {
|
||||
reviewLoading.value = true
|
||||
try {
|
||||
await submitReviewApi(reviewForm.id, reviewForm.reviewResult)
|
||||
useMessage().success('复核成功')
|
||||
reviewDialogVisible.value = false
|
||||
getDataList()
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg || '复核失败')
|
||||
} finally {
|
||||
reviewLoading.value = false
|
||||
}
|
||||
}
|
||||
reviewLoading.value = true;
|
||||
try {
|
||||
await submitReviewApi(reviewForm.id, reviewForm.reviewResult);
|
||||
useMessage().success('复核成功');
|
||||
reviewDialogVisible.value = false;
|
||||
getDataList();
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg || '复核失败');
|
||||
} finally {
|
||||
reviewLoading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
// 初始化
|
||||
onMounted(() => {
|
||||
getDataList()
|
||||
})
|
||||
getDataList();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import '/@/assets/styles/modern-page.scss';
|
||||
|
||||
.stat-row {
|
||||
margin-bottom: 16px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.upload-btn {
|
||||
display: inline-block;
|
||||
margin-right: 10px;
|
||||
display: inline-block;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.text-danger {
|
||||
color: var(--el-color-danger);
|
||||
color: var(--el-color-danger);
|
||||
}
|
||||
|
||||
.text-warning {
|
||||
color: var(--el-color-warning);
|
||||
color: var(--el-color-warning);
|
||||
}
|
||||
|
||||
.review-form {
|
||||
margin-top: 16px;
|
||||
margin-top: 16px;
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
||||
@@ -1,495 +1,450 @@
|
||||
<template>
|
||||
<div class="modern-page-container">
|
||||
<div class="page-wrapper">
|
||||
<!-- 搜索表单卡片 -->
|
||||
<el-card v-show="showSearch" class="search-card" shadow="never">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span class="card-title">
|
||||
<el-icon class="title-icon"><Search /></el-icon>
|
||||
筛选条件
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
<el-form :model="searchForm" ref="searchFormRef" :inline="true" @keyup.enter="handleSearch" class="search-form">
|
||||
<el-form-item label="批次号" prop="batchNo">
|
||||
<el-input
|
||||
v-model="searchForm.batchNo"
|
||||
placeholder="请输入批次号"
|
||||
clearable
|
||||
style="width: 180px" />
|
||||
</el-form-item>
|
||||
<el-form-item label="学号" prop="stuNo">
|
||||
<el-input
|
||||
v-model="searchForm.stuNo"
|
||||
placeholder="请输入学号"
|
||||
clearable
|
||||
style="width: 150px" />
|
||||
</el-form-item>
|
||||
<el-form-item label="姓名" prop="systemRealName">
|
||||
<el-input
|
||||
v-model="searchForm.systemRealName"
|
||||
placeholder="请输入姓名"
|
||||
clearable
|
||||
style="width: 120px" />
|
||||
</el-form-item>
|
||||
<el-form-item label="入学年份" prop="enterYear">
|
||||
<el-date-picker
|
||||
v-model="searchForm.enterYear"
|
||||
type="year"
|
||||
placeholder="选择年份"
|
||||
value-format="YYYY"
|
||||
style="width: 120px" />
|
||||
</el-form-item>
|
||||
<el-form-item label="是否一致" prop="isMatch">
|
||||
<el-select
|
||||
v-model="searchForm.isMatch"
|
||||
placeholder="请选择"
|
||||
clearable
|
||||
style="width: 120px">
|
||||
<el-option label="一致" value="1" />
|
||||
<el-option label="不一致" value="0" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="核对状态" prop="verifyStatus">
|
||||
<el-select
|
||||
v-model="searchForm.verifyStatus"
|
||||
placeholder="请选择核对状态"
|
||||
clearable
|
||||
style="width: 120px">
|
||||
<el-option label="待核对" value="0" />
|
||||
<el-option label="已核对" value="1" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="Search" @click="handleSearch">查询</el-button>
|
||||
<el-button icon="Refresh" @click="handleReset">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
<div class="modern-page-container">
|
||||
<div class="page-wrapper">
|
||||
<!-- 搜索表单卡片 -->
|
||||
<el-card v-show="showSearch" class="search-card" shadow="never">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span class="card-title">
|
||||
<el-icon class="title-icon"><Search /></el-icon>
|
||||
筛选条件
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
<el-form :model="searchForm" ref="searchFormRef" :inline="true" @keyup.enter="handleSearch" class="search-form">
|
||||
<el-form-item label="批次号" prop="batchNo">
|
||||
<el-input v-model="searchForm.batchNo" placeholder="请输入批次号" clearable style="width: 180px" />
|
||||
</el-form-item>
|
||||
<el-form-item label="学号" prop="stuNo">
|
||||
<el-input v-model="searchForm.stuNo" placeholder="请输入学号" clearable style="width: 150px" />
|
||||
</el-form-item>
|
||||
<el-form-item label="姓名" prop="systemRealName">
|
||||
<el-input v-model="searchForm.systemRealName" placeholder="请输入姓名" clearable style="width: 120px" />
|
||||
</el-form-item>
|
||||
<el-form-item label="入学年份" prop="enterYear">
|
||||
<el-date-picker v-model="searchForm.enterYear" type="year" placeholder="选择年份" value-format="YYYY" style="width: 120px" />
|
||||
</el-form-item>
|
||||
<el-form-item label="是否一致" prop="isMatch">
|
||||
<el-select v-model="searchForm.isMatch" placeholder="请选择" clearable style="width: 120px">
|
||||
<el-option label="一致" value="1" />
|
||||
<el-option label="不一致" value="0" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="核对状态" prop="verifyStatus">
|
||||
<el-select v-model="searchForm.verifyStatus" placeholder="请选择核对状态" clearable style="width: 120px">
|
||||
<el-option label="待核对" value="0" />
|
||||
<el-option label="已核对" value="1" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="Search" @click="handleSearch">查询</el-button>
|
||||
<el-button icon="Refresh" @click="handleReset">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
|
||||
<!-- 内容卡片 -->
|
||||
<el-card class="content-card" shadow="never">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span class="card-title">
|
||||
<el-icon class="title-icon"><User /></el-icon>
|
||||
毕业学生信息核对
|
||||
</span>
|
||||
<div class="header-actions">
|
||||
<el-upload
|
||||
:show-file-list="false"
|
||||
:before-upload="beforeUpload"
|
||||
:http-request="handleImport"
|
||||
accept=".xlsx,.xls"
|
||||
class="upload-btn">
|
||||
<el-button type="primary" icon="Upload" :loading="importLoading">导入核对</el-button>
|
||||
</el-upload>
|
||||
<el-button type="success" icon="Download" @click="handleDownloadTemplate">下载模板</el-button>
|
||||
<el-button type="warning" icon="Download" @click="handleExport">导出数据</el-button>
|
||||
<el-button type="info" icon="Bell" @click="handleSend" :disabled="!searchForm.batchNo">下发班主任</el-button>
|
||||
<right-toolbar
|
||||
v-model:showSearch="showSearch"
|
||||
class="ml10"
|
||||
@queryTable="getDataList" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<!-- 内容卡片 -->
|
||||
<el-card class="content-card" shadow="never">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span class="card-title">
|
||||
<el-icon class="title-icon"><User /></el-icon>
|
||||
毕业学生信息核对
|
||||
</span>
|
||||
<div class="header-actions">
|
||||
<el-upload :show-file-list="false" :before-upload="beforeUpload" :http-request="handleImport" accept=".xlsx,.xls" class="upload-btn">
|
||||
<el-button type="primary" icon="Upload" :loading="importLoading">导入核对</el-button>
|
||||
</el-upload>
|
||||
<el-button type="success" icon="Download" @click="handleDownloadTemplate">下载模板</el-button>
|
||||
<el-button type="warning" icon="Download" @click="handleExport">导出数据</el-button>
|
||||
<el-button type="info" icon="Bell" @click="handleSend" :disabled="!searchForm.batchNo">下发班主任</el-button>
|
||||
<right-toolbar v-model:showSearch="showSearch" class="ml10" @queryTable="getDataList" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- 统计卡片 -->
|
||||
<el-row :gutter="16" class="stat-row">
|
||||
<el-col :span="4">
|
||||
<el-statistic title="总核对数" :value="statistics.total" />
|
||||
</el-col>
|
||||
<el-col :span="4">
|
||||
<el-statistic title="信息一致" :value="statistics.matched">
|
||||
<template #suffix>
|
||||
<span class="text-success">人</span>
|
||||
</template>
|
||||
</el-statistic>
|
||||
</el-col>
|
||||
<el-col :span="4">
|
||||
<el-statistic title="信息不一致" :value="statistics.mismatched">
|
||||
<template #suffix>
|
||||
<span class="text-danger">人</span>
|
||||
</template>
|
||||
</el-statistic>
|
||||
</el-col>
|
||||
<el-col :span="4">
|
||||
<el-statistic title="待核对" :value="statistics.pending" />
|
||||
</el-col>
|
||||
<el-col :span="4">
|
||||
<el-statistic title="已核对" :value="statistics.verified" />
|
||||
</el-col>
|
||||
</el-row>
|
||||
<!-- 统计卡片 -->
|
||||
<el-row :gutter="16" class="stat-row">
|
||||
<el-col :span="4">
|
||||
<el-statistic title="总核对数" :value="statistics.total" />
|
||||
</el-col>
|
||||
<el-col :span="4">
|
||||
<el-statistic title="信息一致" :value="statistics.matched">
|
||||
<template #suffix>
|
||||
<span class="text-success">人</span>
|
||||
</template>
|
||||
</el-statistic>
|
||||
</el-col>
|
||||
<el-col :span="4">
|
||||
<el-statistic title="信息不一致" :value="statistics.mismatched">
|
||||
<template #suffix>
|
||||
<span class="text-danger">人</span>
|
||||
</template>
|
||||
</el-statistic>
|
||||
</el-col>
|
||||
<el-col :span="4">
|
||||
<el-statistic title="待核对" :value="statistics.pending" />
|
||||
</el-col>
|
||||
<el-col :span="4">
|
||||
<el-statistic title="已核对" :value="statistics.verified" />
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<!-- 表格 -->
|
||||
<el-table
|
||||
:data="dataList"
|
||||
v-loading="loading"
|
||||
stripe
|
||||
:cell-style="tableStyle.cellStyle"
|
||||
:header-cell-style="tableStyle.headerCellStyle"
|
||||
class="modern-table">
|
||||
<el-table-column type="index" label="序号" width="70" align="center">
|
||||
<template #default="{ $index }">
|
||||
{{ (page.currentPage - 1) * page.pageSize + $index + 1 }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="batchNo" label="批次号" width="160" align="center" />
|
||||
<el-table-column prop="stuNo" label="学号" width="120" align="center" />
|
||||
<el-table-column label="姓名" width="180" align="center">
|
||||
<template #default="{ row }">
|
||||
<div>
|
||||
<span v-if="row.systemRealName">系统:{{ row.systemRealName }}</span>
|
||||
<span v-if="row.systemRealName && row.enrollRealName && row.systemRealName !== row.enrollRealName"
|
||||
class="text-danger">
|
||||
<br />回流:{{ row.enrollRealName }}
|
||||
</span>
|
||||
<span v-else-if="row.enrollRealName && !row.systemRealName">回流:{{ row.enrollRealName }}</span>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="身份证号" width="220" align="center">
|
||||
<template #default="{ row }">
|
||||
<div v-if="row.systemIdCard || row.enrollIdCard">
|
||||
<div v-if="row.systemIdCard">系统:{{ row.systemIdCard }}</div>
|
||||
<div v-if="row.enrollIdCard && row.enrollIdCard !== row.systemIdCard" class="text-warning">
|
||||
回流:{{ row.enrollIdCard }}
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="enrollNo" label="学籍号" width="180" align="center" />
|
||||
<el-table-column prop="className" label="班级" width="150" />
|
||||
<el-table-column prop="classMasterName" label="班主任" width="100" align="center" />
|
||||
<el-table-column prop="enterYear" label="入学年份" width="100" align="center" />
|
||||
<el-table-column prop="isMatch" label="是否一致" width="100" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-tag :type="row.isMatch === '1' ? 'success' : 'danger'" size="small">
|
||||
{{ row.isMatch === '1' ? '一致' : '不一致' }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="verifyStatus" label="核对状态" width="100" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-tag :type="row.verifyStatus === '1' ? 'success' : 'warning'" size="small">
|
||||
{{ row.verifyStatus === '1' ? '已核对' : '待核对' }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="verifyResult" label="核对结果" width="150" show-overflow-tooltip />
|
||||
<el-table-column prop="remarks" label="备注" width="150" show-overflow-tooltip />
|
||||
<el-table-column label="操作" width="120" align="center" fixed="right">
|
||||
<template #default="{ row }">
|
||||
<el-button
|
||||
v-if="row.verifyStatus === '0'"
|
||||
icon="Edit"
|
||||
link
|
||||
type="primary"
|
||||
@click="handleVerify(row)">
|
||||
核对
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<template #empty>
|
||||
<el-empty description="暂无数据" :image-size="120" />
|
||||
</template>
|
||||
</el-table>
|
||||
<!-- 表格 -->
|
||||
<el-table
|
||||
:data="dataList"
|
||||
v-loading="loading"
|
||||
stripe
|
||||
:cell-style="tableStyle.cellStyle"
|
||||
:header-cell-style="tableStyle.headerCellStyle"
|
||||
class="modern-table"
|
||||
>
|
||||
<el-table-column type="index" label="序号" width="70" align="center">
|
||||
<template #default="{ $index }">
|
||||
{{ (page.currentPage - 1) * page.pageSize + $index + 1 }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="batchNo" label="批次号" width="160" align="center" />
|
||||
<el-table-column prop="stuNo" label="学号" width="120" align="center" />
|
||||
<el-table-column label="姓名" width="180" align="center">
|
||||
<template #default="{ row }">
|
||||
<div>
|
||||
<span v-if="row.systemRealName">系统:{{ row.systemRealName }}</span>
|
||||
<span v-if="row.systemRealName && row.enrollRealName && row.systemRealName !== row.enrollRealName" class="text-danger">
|
||||
<br />回流:{{ row.enrollRealName }}
|
||||
</span>
|
||||
<span v-else-if="row.enrollRealName && !row.systemRealName">回流:{{ row.enrollRealName }}</span>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="身份证号" width="220" align="center">
|
||||
<template #default="{ row }">
|
||||
<div v-if="row.systemIdCard || row.enrollIdCard">
|
||||
<div v-if="row.systemIdCard">系统:{{ row.systemIdCard }}</div>
|
||||
<div v-if="row.enrollIdCard && row.enrollIdCard !== row.systemIdCard" class="text-warning">回流:{{ row.enrollIdCard }}</div>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="enrollNo" label="学籍号" width="180" align="center" />
|
||||
<el-table-column prop="className" label="班级" width="150" />
|
||||
<el-table-column prop="classMasterName" label="班主任" width="100" align="center" />
|
||||
<el-table-column prop="enterYear" label="入学年份" width="100" align="center" />
|
||||
<el-table-column prop="isMatch" label="是否一致" width="100" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-tag :type="row.isMatch === '1' ? 'success' : 'danger'" size="small">
|
||||
{{ row.isMatch === '1' ? '一致' : '不一致' }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="verifyStatus" label="核对状态" width="100" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-tag :type="row.verifyStatus === '1' ? 'success' : 'warning'" size="small">
|
||||
{{ row.verifyStatus === '1' ? '已核对' : '待核对' }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="verifyResult" label="核对结果" width="150" show-overflow-tooltip />
|
||||
<el-table-column prop="remarks" label="备注" width="150" show-overflow-tooltip />
|
||||
<el-table-column label="操作" width="120" align="center" fixed="right">
|
||||
<template #default="{ row }">
|
||||
<el-button v-if="row.verifyStatus === '0'" icon="Edit" link type="primary" @click="handleVerify(row)"> 核对 </el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<template #empty>
|
||||
<el-empty description="暂无数据" :image-size="120" />
|
||||
</template>
|
||||
</el-table>
|
||||
|
||||
<!-- 分页 -->
|
||||
<el-pagination
|
||||
v-model:current-page="page.currentPage"
|
||||
v-model:page-size="page.pageSize"
|
||||
:page-sizes="[10, 20, 50, 100]"
|
||||
:total="page.total"
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
class="pagination"
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="handleCurrentChange" />
|
||||
</el-card>
|
||||
</div>
|
||||
<!-- 分页 -->
|
||||
<el-pagination
|
||||
v-model:current-page="page.currentPage"
|
||||
v-model:page-size="page.pageSize"
|
||||
:page-sizes="[10, 20, 50, 100]"
|
||||
:total="page.total"
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
class="pagination"
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="handleCurrentChange"
|
||||
/>
|
||||
</el-card>
|
||||
</div>
|
||||
|
||||
<!-- 核对弹窗 -->
|
||||
<el-dialog
|
||||
v-model="verifyDialogVisible"
|
||||
title="毕业学生信息核对"
|
||||
width="600px"
|
||||
:close-on-click-modal="false">
|
||||
<el-descriptions :column="2" border>
|
||||
<el-descriptions-item label="学号">{{ verifyData.stuNo }}</el-descriptions-item>
|
||||
<el-descriptions-item label="入学年份">{{ verifyData.enterYear }}</el-descriptions-item>
|
||||
<el-descriptions-item label="系统姓名">{{ verifyData.systemRealName }}</el-descriptions-item>
|
||||
<el-descriptions-item label="回流姓名">{{ verifyData.enrollRealName }}</el-descriptions-item>
|
||||
<el-descriptions-item label="系统身份证">{{ verifyData.systemIdCard }}</el-descriptions-item>
|
||||
<el-descriptions-item label="回流身份证">{{ verifyData.enrollIdCard }}</el-descriptions-item>
|
||||
<el-descriptions-item label="学籍号">{{ verifyData.enrollNo }}</el-descriptions-item>
|
||||
<el-descriptions-item label="班级">{{ verifyData.className }}</el-descriptions-item>
|
||||
<el-descriptions-item label="信息是否一致" :span="2">
|
||||
<el-tag :type="verifyData.isMatch === '1' ? 'success' : 'danger'">
|
||||
{{ verifyData.isMatch === '1' ? '一致' : '不一致' }}
|
||||
</el-tag>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item v-if="verifyData.remarks" label="备注" :span="2">{{ verifyData.remarks }}</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
<el-form :model="verifyForm" label-width="80px" class="verify-form">
|
||||
<el-form-item label="核对结果">
|
||||
<el-radio-group v-model="verifyForm.verifyResult">
|
||||
<el-radio label="信息无误">信息无误</el-radio>
|
||||
<el-radio label="需修改系统">需修改系统</el-radio>
|
||||
<el-radio label="需修改回流">需修改回流</el-radio>
|
||||
<el-radio label="其他问题">其他问题</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button @click="verifyDialogVisible = false">取消</el-button>
|
||||
<el-button type="primary" @click="submitVerify" :loading="verifyLoading">确定</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
<!-- 核对弹窗 -->
|
||||
<el-dialog v-model="verifyDialogVisible" title="毕业学生信息核对" width="600px" :close-on-click-modal="false">
|
||||
<el-descriptions :column="2" border>
|
||||
<el-descriptions-item label="学号">{{ verifyData.stuNo }}</el-descriptions-item>
|
||||
<el-descriptions-item label="入学年份">{{ verifyData.enterYear }}</el-descriptions-item>
|
||||
<el-descriptions-item label="系统姓名">{{ verifyData.systemRealName }}</el-descriptions-item>
|
||||
<el-descriptions-item label="回流姓名">{{ verifyData.enrollRealName }}</el-descriptions-item>
|
||||
<el-descriptions-item label="系统身份证">{{ verifyData.systemIdCard }}</el-descriptions-item>
|
||||
<el-descriptions-item label="回流身份证">{{ verifyData.enrollIdCard }}</el-descriptions-item>
|
||||
<el-descriptions-item label="学籍号">{{ verifyData.enrollNo }}</el-descriptions-item>
|
||||
<el-descriptions-item label="班级">{{ verifyData.className }}</el-descriptions-item>
|
||||
<el-descriptions-item label="信息是否一致" :span="2">
|
||||
<el-tag :type="verifyData.isMatch === '1' ? 'success' : 'danger'">
|
||||
{{ verifyData.isMatch === '1' ? '一致' : '不一致' }}
|
||||
</el-tag>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item v-if="verifyData.remarks" label="备注" :span="2">{{ verifyData.remarks }}</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
<el-form :model="verifyForm" label-width="80px" class="verify-form">
|
||||
<el-form-item label="核对结果">
|
||||
<el-radio-group v-model="verifyForm.verifyResult">
|
||||
<el-radio label="信息无误">信息无误</el-radio>
|
||||
<el-radio label="需修改系统">需修改系统</el-radio>
|
||||
<el-radio label="需修改回流">需修改回流</el-radio>
|
||||
<el-radio label="其他问题">其他问题</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button @click="verifyDialogVisible = false">取消</el-button>
|
||||
<el-button type="primary" @click="submitVerify" :loading="verifyLoading">确定</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="GraduVerify">
|
||||
import { reactive, ref, onMounted } from 'vue'
|
||||
import { fetchList, importData, exportData, sendToClassMaster, submitVerify as submitVerifyApi, downloadTemplate } from '/@/api/basic/graduverify'
|
||||
import { useMessage, useMessageBox } from '/@/hooks/message'
|
||||
import { Search, User, Upload, Download, Bell, Edit } from '@element-plus/icons-vue'
|
||||
import { reactive, ref, onMounted } from 'vue';
|
||||
import { fetchList, importData, exportData, sendToClassMaster, submitVerify as submitVerifyApi, downloadTemplate } from '/@/api/basic/graduverify';
|
||||
import { useMessage, useMessageBox } from '/@/hooks/message';
|
||||
import { Search, User, Upload, Download, Bell, Edit } from '@element-plus/icons-vue';
|
||||
|
||||
// 定义变量内容
|
||||
const searchFormRef = ref()
|
||||
const showSearch = ref(true)
|
||||
const loading = ref(false)
|
||||
const importLoading = ref(false)
|
||||
const verifyLoading = ref(false)
|
||||
const dataList = ref<any[]>([])
|
||||
const verifyDialogVisible = ref(false)
|
||||
const verifyData = ref<any>({})
|
||||
const searchFormRef = ref();
|
||||
const showSearch = ref(true);
|
||||
const loading = ref(false);
|
||||
const importLoading = ref(false);
|
||||
const verifyLoading = ref(false);
|
||||
const dataList = ref<any[]>([]);
|
||||
const verifyDialogVisible = ref(false);
|
||||
const verifyData = ref<any>({});
|
||||
const verifyForm = reactive({
|
||||
id: '',
|
||||
verifyResult: '信息无误'
|
||||
})
|
||||
id: '',
|
||||
verifyResult: '信息无误',
|
||||
});
|
||||
|
||||
// 统计数据
|
||||
const statistics = reactive({
|
||||
total: 0,
|
||||
matched: 0,
|
||||
mismatched: 0,
|
||||
pending: 0,
|
||||
verified: 0
|
||||
})
|
||||
total: 0,
|
||||
matched: 0,
|
||||
mismatched: 0,
|
||||
pending: 0,
|
||||
verified: 0,
|
||||
});
|
||||
|
||||
// 分页
|
||||
const page = reactive({
|
||||
currentPage: 1,
|
||||
pageSize: 20,
|
||||
total: 0
|
||||
})
|
||||
currentPage: 1,
|
||||
pageSize: 20,
|
||||
total: 0,
|
||||
});
|
||||
|
||||
// 搜索表单
|
||||
const searchForm = reactive({
|
||||
batchNo: '',
|
||||
stuNo: '',
|
||||
systemRealName: '',
|
||||
enterYear: undefined as number | undefined,
|
||||
isMatch: '',
|
||||
verifyStatus: ''
|
||||
})
|
||||
batchNo: '',
|
||||
stuNo: '',
|
||||
systemRealName: '',
|
||||
enterYear: undefined as number | undefined,
|
||||
isMatch: '',
|
||||
verifyStatus: '',
|
||||
});
|
||||
|
||||
// 表格样式
|
||||
const tableStyle = {
|
||||
cellStyle: { textAlign: 'center' },
|
||||
headerCellStyle: {
|
||||
textAlign: 'center',
|
||||
background: 'var(--el-table-row-hover-bg-color)',
|
||||
color: 'var(--el-text-color-primary)'
|
||||
}
|
||||
}
|
||||
cellStyle: { textAlign: 'center' },
|
||||
headerCellStyle: {
|
||||
textAlign: 'center',
|
||||
background: 'var(--el-table-row-hover-bg-color)',
|
||||
color: 'var(--el-text-color-primary)',
|
||||
},
|
||||
};
|
||||
|
||||
// 查询
|
||||
const handleSearch = () => {
|
||||
page.currentPage = 1
|
||||
getDataList()
|
||||
}
|
||||
page.currentPage = 1;
|
||||
getDataList();
|
||||
};
|
||||
|
||||
// 重置
|
||||
const handleReset = () => {
|
||||
searchFormRef.value?.resetFields()
|
||||
getDataList()
|
||||
}
|
||||
searchFormRef.value?.resetFields();
|
||||
getDataList();
|
||||
};
|
||||
|
||||
// 分页
|
||||
const handleSizeChange = (val: number) => {
|
||||
page.pageSize = val
|
||||
getDataList()
|
||||
}
|
||||
page.pageSize = val;
|
||||
getDataList();
|
||||
};
|
||||
|
||||
const handleCurrentChange = (val: number) => {
|
||||
page.currentPage = val
|
||||
getDataList()
|
||||
}
|
||||
page.currentPage = val;
|
||||
getDataList();
|
||||
};
|
||||
|
||||
// 获取数据列表
|
||||
const getDataList = async () => {
|
||||
loading.value = true
|
||||
try {
|
||||
const res = await fetchList({
|
||||
current: page.currentPage,
|
||||
size: page.pageSize,
|
||||
...searchForm,
|
||||
enterYear: searchForm.enterYear ? parseInt(searchForm.enterYear as any) : undefined
|
||||
})
|
||||
if (res.data && res.data.records) {
|
||||
dataList.value = res.data.records
|
||||
page.total = res.data.total
|
||||
loading.value = true;
|
||||
try {
|
||||
const res = await fetchList({
|
||||
current: page.currentPage,
|
||||
size: page.pageSize,
|
||||
...searchForm,
|
||||
enterYear: searchForm.enterYear ? parseInt(searchForm.enterYear as any) : undefined,
|
||||
});
|
||||
if (res.data && res.data.records) {
|
||||
dataList.value = res.data.records;
|
||||
page.total = res.data.total;
|
||||
|
||||
// 计算统计数据
|
||||
statistics.total = res.data.total
|
||||
statistics.matched = dataList.value.filter((item: any) => item.isMatch === '1').length
|
||||
statistics.mismatched = dataList.value.filter((item: any) => item.isMatch === '0').length
|
||||
statistics.pending = dataList.value.filter((item: any) => item.verifyStatus === '0').length
|
||||
statistics.verified = dataList.value.filter((item: any) => item.verifyStatus === '1').length
|
||||
} else {
|
||||
dataList.value = []
|
||||
page.total = 0
|
||||
}
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg || '获取数据失败')
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
// 计算统计数据
|
||||
statistics.total = res.data.total;
|
||||
statistics.matched = dataList.value.filter((item: any) => item.isMatch === '1').length;
|
||||
statistics.mismatched = dataList.value.filter((item: any) => item.isMatch === '0').length;
|
||||
statistics.pending = dataList.value.filter((item: any) => item.verifyStatus === '0').length;
|
||||
statistics.verified = dataList.value.filter((item: any) => item.verifyStatus === '1').length;
|
||||
} else {
|
||||
dataList.value = [];
|
||||
page.total = 0;
|
||||
}
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg || '获取数据失败');
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
// 上传前验证
|
||||
const beforeUpload = (file: File) => {
|
||||
const isExcel = file.name.endsWith('.xlsx') || file.name.endsWith('.xls')
|
||||
if (!isExcel) {
|
||||
useMessage().error('只能上传Excel文件')
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
const isExcel = file.name.endsWith('.xlsx') || file.name.endsWith('.xls');
|
||||
if (!isExcel) {
|
||||
useMessage().error('只能上传Excel文件');
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
// 导入核对
|
||||
const handleImport = async (options: any) => {
|
||||
importLoading.value = true
|
||||
try {
|
||||
const res = await importData(options.file)
|
||||
useMessage().success(res.msg || '导入核对成功')
|
||||
if (res.data) {
|
||||
searchForm.batchNo = ''
|
||||
}
|
||||
getDataList()
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg || '导入失败')
|
||||
} finally {
|
||||
importLoading.value = false
|
||||
}
|
||||
}
|
||||
importLoading.value = true;
|
||||
try {
|
||||
const res = await importData(options.file);
|
||||
useMessage().success(res.msg || '导入核对成功');
|
||||
if (res.data) {
|
||||
searchForm.batchNo = '';
|
||||
}
|
||||
getDataList();
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg || '导入失败');
|
||||
} finally {
|
||||
importLoading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
// 下载模板
|
||||
const handleDownloadTemplate = async () => {
|
||||
try {
|
||||
const res = await downloadTemplate()
|
||||
const blob = new Blob([res], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' })
|
||||
const url = window.URL.createObjectURL(blob)
|
||||
const link = document.createElement('a')
|
||||
link.href = url
|
||||
link.download = '毕业学籍回流导入模板.xlsx'
|
||||
link.click()
|
||||
window.URL.revokeObjectURL(url)
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg || '下载失败')
|
||||
}
|
||||
}
|
||||
try {
|
||||
const res = await downloadTemplate();
|
||||
const blob = new Blob([res], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
|
||||
const url = window.URL.createObjectURL(blob);
|
||||
const link = document.createElement('a');
|
||||
link.href = url;
|
||||
link.download = '毕业学籍回流导入模板.xlsx';
|
||||
link.click();
|
||||
window.URL.revokeObjectURL(url);
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg || '下载失败');
|
||||
}
|
||||
};
|
||||
|
||||
// 导出
|
||||
const handleExport = async () => {
|
||||
try {
|
||||
const res = await exportData(searchForm)
|
||||
const blob = new Blob([res], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' })
|
||||
const url = window.URL.createObjectURL(blob)
|
||||
const link = document.createElement('a')
|
||||
link.href = url
|
||||
link.download = '毕业学生核对数据.xlsx'
|
||||
link.click()
|
||||
window.URL.revokeObjectURL(url)
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg || '导出失败')
|
||||
}
|
||||
}
|
||||
try {
|
||||
const res = await exportData(searchForm);
|
||||
const blob = new Blob([res], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
|
||||
const url = window.URL.createObjectURL(blob);
|
||||
const link = document.createElement('a');
|
||||
link.href = url;
|
||||
link.download = '毕业学生核对数据.xlsx';
|
||||
link.click();
|
||||
window.URL.revokeObjectURL(url);
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg || '导出失败');
|
||||
}
|
||||
};
|
||||
|
||||
// 下发班主任
|
||||
const handleSend = async () => {
|
||||
if (!searchForm.batchNo) {
|
||||
useMessage().warning('请先选择批次号')
|
||||
return
|
||||
}
|
||||
try {
|
||||
await useMessageBox().confirm('确定要将该批次数据下发至班主任核对吗?')
|
||||
await sendToClassMaster(searchForm.batchNo)
|
||||
useMessage().success('下发成功')
|
||||
} catch (err: any) {
|
||||
if (err !== 'cancel') {
|
||||
useMessage().error(err.msg || '下发失败')
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!searchForm.batchNo) {
|
||||
useMessage().warning('请先选择批次号');
|
||||
return;
|
||||
}
|
||||
try {
|
||||
await useMessageBox().confirm('确定要将该批次数据下发至班主任核对吗?');
|
||||
await sendToClassMaster(searchForm.batchNo);
|
||||
useMessage().success('下发成功');
|
||||
} catch (err: any) {
|
||||
if (err !== 'cancel') {
|
||||
useMessage().error(err.msg || '下发失败');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// 核对
|
||||
const handleVerify = (row: any) => {
|
||||
verifyData.value = row
|
||||
verifyForm.id = row.id
|
||||
verifyForm.verifyResult = '信息无误'
|
||||
verifyDialogVisible.value = true
|
||||
}
|
||||
verifyData.value = row;
|
||||
verifyForm.id = row.id;
|
||||
verifyForm.verifyResult = '信息无误';
|
||||
verifyDialogVisible.value = true;
|
||||
};
|
||||
|
||||
// 提交核对
|
||||
const submitVerify = async () => {
|
||||
verifyLoading.value = true
|
||||
try {
|
||||
await submitVerifyApi(verifyForm.id, verifyForm.verifyResult)
|
||||
useMessage().success('核对成功')
|
||||
verifyDialogVisible.value = false
|
||||
getDataList()
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg || '核对失败')
|
||||
} finally {
|
||||
verifyLoading.value = false
|
||||
}
|
||||
}
|
||||
verifyLoading.value = true;
|
||||
try {
|
||||
await submitVerifyApi(verifyForm.id, verifyForm.verifyResult);
|
||||
useMessage().success('核对成功');
|
||||
verifyDialogVisible.value = false;
|
||||
getDataList();
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg || '核对失败');
|
||||
} finally {
|
||||
verifyLoading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
// 初始化
|
||||
onMounted(() => {
|
||||
getDataList()
|
||||
})
|
||||
getDataList();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import '/@/assets/styles/modern-page.scss';
|
||||
|
||||
.stat-row {
|
||||
margin-bottom: 16px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.upload-btn {
|
||||
display: inline-block;
|
||||
margin-right: 10px;
|
||||
display: inline-block;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.text-danger {
|
||||
color: var(--el-color-danger);
|
||||
color: var(--el-color-danger);
|
||||
}
|
||||
|
||||
.text-warning {
|
||||
color: var(--el-color-warning);
|
||||
color: var(--el-color-warning);
|
||||
}
|
||||
|
||||
.text-success {
|
||||
color: var(--el-color-success);
|
||||
color: var(--el-color-success);
|
||||
}
|
||||
|
||||
.verify-form {
|
||||
margin-top: 16px;
|
||||
margin-top: 16px;
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
||||
@@ -1,104 +1,105 @@
|
||||
<template>
|
||||
<div class="layout-padding-auto layout-padding-view">
|
||||
<el-card shadow="never">
|
||||
<el-form ref="dataFormRef" class="form" :model="form" label-width="85px" :rules="dataRules">
|
||||
<div class="flex">
|
||||
<div>
|
||||
<el-form-item label="文章标题" prop="title">
|
||||
<div class="w-80">
|
||||
<el-input
|
||||
v-model="form.title"
|
||||
placeholder="请输入文章标题"
|
||||
type="textarea"
|
||||
:autosize="{ minRows: 3, maxRows: 3 }"
|
||||
maxlength="64"
|
||||
show-word-limit
|
||||
clearable
|
||||
/>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="文章简介" prop="intro">
|
||||
<div class="w-80">
|
||||
<el-input
|
||||
v-model="form.intro"
|
||||
placeholder="请输入文章简介"
|
||||
type="textarea"
|
||||
:autosize="{ minRows: 3, maxRows: 6 }"
|
||||
:maxlength="200"
|
||||
show-word-limit
|
||||
clearable
|
||||
/>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="摘要" prop="summary">
|
||||
<div class="w-80">
|
||||
<el-input type="textarea" :autosize="{ minRows: 6, maxRows: 6 }" v-model="form.summary" maxlength="200"
|
||||
show-word-limit clearable/>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="文章封面" prop="image">
|
||||
<div>
|
||||
<div>
|
||||
<upload-img v-model:imageUrl="form.image"/>
|
||||
</div>
|
||||
<div class="form-tips">建议尺寸:240*180px</div>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</div>
|
||||
<div class="xl:ml-20">
|
||||
<el-row class="xl:mb-8">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="文章栏目" prop="cid">
|
||||
<el-select class="w-80" v-model="form.cid" placeholder="请选择文章栏目" clearable>
|
||||
<el-option v-for="item in articleCateList" :key="item.id" :label="item.name" :value="item.id"/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="作者" prop="author">
|
||||
<div class="w-80">
|
||||
<el-input v-model="form.author" placeholder="请输入作者名称"/>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<div class="layout-padding-auto layout-padding-view">
|
||||
<el-card shadow="never">
|
||||
<el-form ref="dataFormRef" class="form" :model="form" label-width="85px" :rules="dataRules">
|
||||
<div class="flex">
|
||||
<div>
|
||||
<el-form-item label="文章标题" prop="title">
|
||||
<div class="w-80">
|
||||
<el-input
|
||||
v-model="form.title"
|
||||
placeholder="请输入文章标题"
|
||||
type="textarea"
|
||||
:autosize="{ minRows: 3, maxRows: 3 }"
|
||||
maxlength="64"
|
||||
show-word-limit
|
||||
clearable
|
||||
/>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="文章简介" prop="intro">
|
||||
<div class="w-80">
|
||||
<el-input
|
||||
v-model="form.intro"
|
||||
placeholder="请输入文章简介"
|
||||
type="textarea"
|
||||
:autosize="{ minRows: 3, maxRows: 6 }"
|
||||
:maxlength="200"
|
||||
show-word-limit
|
||||
clearable
|
||||
/>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="摘要" prop="summary">
|
||||
<div class="w-80">
|
||||
<el-input type="textarea" :autosize="{ minRows: 6, maxRows: 6 }" v-model="form.summary" maxlength="200" show-word-limit clearable />
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="文章封面" prop="image">
|
||||
<div>
|
||||
<div>
|
||||
<upload-img v-model:imageUrl="form.image" />
|
||||
</div>
|
||||
<div class="form-tips">建议尺寸:240*180px</div>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</div>
|
||||
<div class="xl:ml-20">
|
||||
<el-row class="xl:mb-8">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="文章栏目" prop="cid">
|
||||
<el-select class="w-80" v-model="form.cid" placeholder="请选择文章栏目" clearable>
|
||||
<el-option v-for="item in articleCateList" :key="item.id" :label="item.name" :value="item.id" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="作者" prop="author">
|
||||
<div class="w-80">
|
||||
<el-input v-model="form.author" placeholder="请输入作者名称" />
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row class="xl:mb-8">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="初始浏览量" prop="visit">
|
||||
<template #label> 浏览量
|
||||
<tip content="初始值"/>
|
||||
</template>
|
||||
<el-input-number class="!w-80" v-model="form.visit" :min="0" :max="9999"/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item prop="sort">
|
||||
<template #label> 排序
|
||||
<tip content="默认为0, 数值越大越排前"/>
|
||||
</template>
|
||||
<el-input-number class="!w-80" v-model="form.sort" :min="0" :max="9999"/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-form-item label="文章内容" required prop="content">
|
||||
<editor v-model:get-html="form.content" height="500" width="600" :disable="form.id !== ''"/>
|
||||
</el-form-item>
|
||||
<div style="text-align: center">
|
||||
<el-button type="primary" @click="onSubmit">保存</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-form>
|
||||
</el-card>
|
||||
</div>
|
||||
<el-row class="xl:mb-8">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="初始浏览量" prop="visit">
|
||||
<template #label>
|
||||
浏览量
|
||||
<tip content="初始值" />
|
||||
</template>
|
||||
<el-input-number class="!w-80" v-model="form.visit" :min="0" :max="9999" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item prop="sort">
|
||||
<template #label>
|
||||
排序
|
||||
<tip content="默认为0, 数值越大越排前" />
|
||||
</template>
|
||||
<el-input-number class="!w-80" v-model="form.sort" :min="0" :max="9999" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-form-item label="文章内容" required prop="content">
|
||||
<editor v-model:get-html="form.content" height="500" width="600" :disable="form.id !== ''" />
|
||||
</el-form-item>
|
||||
<div style="text-align: center">
|
||||
<el-button type="primary" @click="onSubmit">保存</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-form>
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="AppArticleDialog">
|
||||
import mittBus from "/@/utils/mitt";
|
||||
import {useMessage} from '/@/hooks/message';
|
||||
import {getObj, addObj, putObj} from '/@/api/app/appArticle';
|
||||
import {getObjList} from '/@/api/app/appArticleCategory';
|
||||
import mittBus from '/@/utils/mitt';
|
||||
import { useMessage } from '/@/hooks/message';
|
||||
import { getObj, addObj, putObj } from '/@/api/app/appArticle';
|
||||
import { getObjList } from '/@/api/app/appArticleCategory';
|
||||
|
||||
const emit = defineEmits(['refresh']);
|
||||
const route = useRoute();
|
||||
@@ -112,93 +113,89 @@ const loading = ref(false);
|
||||
const articleCateList = ref([]);
|
||||
// 提交表单数据
|
||||
const form = reactive({
|
||||
id: '',
|
||||
cid: '',
|
||||
title: '',
|
||||
intro: '',
|
||||
summary: '',
|
||||
image: '',
|
||||
content: '',
|
||||
author: '',
|
||||
visit: 0,
|
||||
sort: 0,
|
||||
id: '',
|
||||
cid: '',
|
||||
title: '',
|
||||
intro: '',
|
||||
summary: '',
|
||||
image: '',
|
||||
content: '',
|
||||
author: '',
|
||||
visit: 0,
|
||||
sort: 0,
|
||||
});
|
||||
|
||||
// 定义校验规则
|
||||
const dataRules = ref({
|
||||
cid: [{required: true, message: '分类不能为空', trigger: 'blur'}],
|
||||
title: [{required: true, message: '标题不能为空', trigger: 'blur'}],
|
||||
intro: [{required: true, message: '简介不能为空', trigger: 'blur'}],
|
||||
summary: [{required: true, message: '摘要不能为空', trigger: 'blur'}],
|
||||
image: [{required: true, message: '封面不能为空', trigger: 'blur'}],
|
||||
content: [{required: true, message: '内容不能为空', trigger: 'blur'}],
|
||||
author: [{required: true, message: '作者不能为空', trigger: 'blur'}],
|
||||
visit: [{required: true, message: '浏览不能为空', trigger: 'blur'}],
|
||||
cid: [{ required: true, message: '分类不能为空', trigger: 'blur' }],
|
||||
title: [{ required: true, message: '标题不能为空', trigger: 'blur' }],
|
||||
intro: [{ required: true, message: '简介不能为空', trigger: 'blur' }],
|
||||
summary: [{ required: true, message: '摘要不能为空', trigger: 'blur' }],
|
||||
image: [{ required: true, message: '封面不能为空', trigger: 'blur' }],
|
||||
content: [{ required: true, message: '内容不能为空', trigger: 'blur' }],
|
||||
author: [{ required: true, message: '作者不能为空', trigger: 'blur' }],
|
||||
visit: [{ required: true, message: '浏览不能为空', trigger: 'blur' }],
|
||||
});
|
||||
|
||||
// 提交
|
||||
const onSubmit = async () => {
|
||||
const valid = await dataFormRef.value.validate().catch(() => {
|
||||
});
|
||||
if (!valid) return false;
|
||||
const valid = await dataFormRef.value.validate().catch(() => {});
|
||||
if (!valid) return false;
|
||||
|
||||
try {
|
||||
loading.value = true;
|
||||
form.id ? await putObj(form) : await addObj(form);
|
||||
useMessage().success(form.id ? '修改成功' : '添加成功');
|
||||
visible.value = false;
|
||||
emit('refresh');
|
||||
// 关闭当前tab
|
||||
mittBus.emit(
|
||||
"onCurrentContextmenuClick",
|
||||
Object.assign({}, {contextMenuClickId: 1, ...route})
|
||||
);
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg);
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
try {
|
||||
loading.value = true;
|
||||
form.id ? await putObj(form) : await addObj(form);
|
||||
useMessage().success(form.id ? '修改成功' : '添加成功');
|
||||
visible.value = false;
|
||||
emit('refresh');
|
||||
// 关闭当前tab
|
||||
mittBus.emit('onCurrentContextmenuClick', Object.assign({}, { contextMenuClickId: 1, ...route }));
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg);
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
// 初始化表单数据
|
||||
const getAppArticleData = (id: string) => {
|
||||
// 获取数据
|
||||
loading.value = true;
|
||||
getObj(id)
|
||||
.then((res: any) => {
|
||||
Object.assign(form, res.data);
|
||||
})
|
||||
.finally(() => {
|
||||
loading.value = false;
|
||||
});
|
||||
// 获取数据
|
||||
loading.value = true;
|
||||
getObj(id)
|
||||
.then((res: any) => {
|
||||
Object.assign(form, res.data);
|
||||
})
|
||||
.finally(() => {
|
||||
loading.value = false;
|
||||
});
|
||||
};
|
||||
|
||||
// 查询全部的分类
|
||||
const getAppCateList = () => {
|
||||
getObjList().then((res: any) => {
|
||||
articleCateList.value = res.data;
|
||||
});
|
||||
getObjList().then((res: any) => {
|
||||
articleCateList.value = res.data;
|
||||
});
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
getAppCateList();
|
||||
if (route.query?.id) {
|
||||
getAppArticleData(route.query?.id);
|
||||
}
|
||||
getAppCateList();
|
||||
if (route.query?.id) {
|
||||
getAppArticleData(route.query?.id);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.footer-btns {
|
||||
height: 60px;
|
||||
height: 60px;
|
||||
|
||||
&__content {
|
||||
bottom: 0;
|
||||
height: 60px;
|
||||
right: 0;
|
||||
left: 0;
|
||||
z-index: 99;
|
||||
@apply flex justify-center items-center shadow;
|
||||
}
|
||||
&__content {
|
||||
bottom: 0;
|
||||
height: 60px;
|
||||
right: 0;
|
||||
left: 0;
|
||||
z-index: 99;
|
||||
@apply flex justify-center items-center shadow;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -126,13 +126,13 @@ const onSubmit = async () => {
|
||||
|
||||
try {
|
||||
// 批量插入用户角色关联
|
||||
const userRoleList = selectedUsers.value.map(user => ({
|
||||
const userRoleList = selectedUsers.value.map((user) => ({
|
||||
userId: user.userId,
|
||||
roleId: props.roleId
|
||||
roleId: props.roleId,
|
||||
}));
|
||||
|
||||
await batchAddObj(userRoleList);
|
||||
|
||||
|
||||
useMessage().success(`成功为 ${selectedUsers.value.length} 个用户分配角色`);
|
||||
emit('refresh');
|
||||
closeDialog();
|
||||
@@ -156,4 +156,4 @@ defineExpose({
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
||||
@@ -99,13 +99,11 @@
|
||||
</span>
|
||||
</div>
|
||||
<div class="card-subtitle" v-if="selectedRoleId">
|
||||
<el-tag type="info" size="small">
|
||||
{{ userState.pagination?.total || 0 }} 个授权用户
|
||||
</el-tag>
|
||||
<el-tag type="info" size="small"> {{ userState.pagination?.total || 0 }} 个授权用户 </el-tag>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
<div v-if="!selectedRoleId" class="empty-state">
|
||||
<el-empty description="请在左侧选择角色以查看对应的用户列表">
|
||||
<template #image>
|
||||
@@ -138,9 +136,7 @@
|
||||
<!-- 操作按钮 -->
|
||||
<el-row>
|
||||
<div class="mb8" style="width: 100%">
|
||||
<el-button @click="addUserDialogRef.openDialog()" icon="folder-add" type="primary">
|
||||
新增用户
|
||||
</el-button>
|
||||
<el-button @click="addUserDialogRef.openDialog()" icon="folder-add" type="primary"> 新增用户 </el-button>
|
||||
<right-toolbar
|
||||
@queryTable="getUserDataList"
|
||||
class="ml10"
|
||||
@@ -164,9 +160,7 @@
|
||||
<el-table-column label="姓名" prop="name" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column label="操作" width="120">
|
||||
<template #default="scope">
|
||||
<el-button icon="delete" @click="handleRemoveUser(scope.row.userId)" text type="danger">
|
||||
取消授权
|
||||
</el-button>
|
||||
<el-button icon="delete" @click="handleRemoveUser(scope.row.userId)" text type="danger"> 取消授权 </el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<template #empty>
|
||||
@@ -253,18 +247,14 @@ const userState: BasicTableProps = reactive<BasicTableProps>({
|
||||
roleId: '',
|
||||
username: '',
|
||||
},
|
||||
pageList: fetchUserRoleList
|
||||
pageList: fetchUserRoleList,
|
||||
});
|
||||
|
||||
// 角色 table hook
|
||||
const { getDataList, currentChangeHandle, sizeChangeHandle, downBlobFile, tableStyle } = useTable(state);
|
||||
|
||||
// 用户角色关联 table hook
|
||||
const {
|
||||
getDataList: getUserDataList,
|
||||
currentChangeHandle: userCurrentChangeHandle,
|
||||
sizeChangeHandle: userSizeChangeHandle
|
||||
} = useTable(userState);
|
||||
const { getDataList: getUserDataList, currentChangeHandle: userCurrentChangeHandle, sizeChangeHandle: userSizeChangeHandle } = useTable(userState);
|
||||
|
||||
// 清空角色搜索条件
|
||||
const resetQuery = () => {
|
||||
@@ -382,7 +372,7 @@ const handleRemoveUser = async (userId: string) => {
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
|
||||
.card-subtitle {
|
||||
width: 100%;
|
||||
justify-content: flex-start;
|
||||
|
||||
@@ -1,30 +1,15 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
:close-on-click-modal="false"
|
||||
title="分配工作台菜单"
|
||||
width="800px"
|
||||
draggable
|
||||
v-model="visible"
|
||||
>
|
||||
<el-dialog :close-on-click-modal="false" title="分配工作台菜单" width="800px" draggable v-model="visible">
|
||||
<div v-loading="loading">
|
||||
<div class="mb-4">
|
||||
<el-alert
|
||||
title="请选择该角色可以访问的工作台菜单项"
|
||||
type="info"
|
||||
:closable="false"
|
||||
show-icon
|
||||
/>
|
||||
<el-alert title="请选择该角色可以访问的工作台菜单项" type="info" :closable="false" show-icon />
|
||||
</div>
|
||||
|
||||
|
||||
<div v-if="workbenchData.length > 0" class="workbench-menu-list">
|
||||
<div
|
||||
v-for="item in workbenchData"
|
||||
:key="item.id"
|
||||
class="menu-item"
|
||||
>
|
||||
<div v-for="item in workbenchData" :key="item.id" class="menu-item">
|
||||
<div class="menu-header">
|
||||
<div class="menu-info">
|
||||
<el-checkbox
|
||||
<el-checkbox
|
||||
:model-value="isModuleAllSelected(item)"
|
||||
:indeterminate="isModuleIndeterminate(item)"
|
||||
@change="toggleModuleSelection(item)"
|
||||
@@ -34,17 +19,17 @@
|
||||
<div class="menu-name">{{ item.name }}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div v-if="item.content && item.content.data" class="menu-content">
|
||||
<div class="content-grid">
|
||||
<div
|
||||
v-for="(dataItem, index) in item.content.data"
|
||||
<div
|
||||
v-for="(dataItem, index) in item.content.data"
|
||||
:key="dataItem.id || index"
|
||||
class="content-item"
|
||||
:class="{ 'selected': selectedMenuIds.includes(dataItem.id) }"
|
||||
:class="{ selected: selectedMenuIds.includes(dataItem.id) }"
|
||||
@click="toggleMenuItem(dataItem.id)"
|
||||
>
|
||||
<el-checkbox
|
||||
<el-checkbox
|
||||
:model-value="selectedMenuIds.includes(dataItem.id)"
|
||||
@change="toggleMenuItem(dataItem.id)"
|
||||
class="item-checkbox"
|
||||
@@ -65,12 +50,12 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div v-else class="empty-state">
|
||||
<el-empty description="暂无工作台菜单数据" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="visible = false">{{ $t('common.cancelButtonText') }}</el-button>
|
||||
@@ -105,13 +90,13 @@ const openDialog = async (roleId: string) => {
|
||||
visible.value = true;
|
||||
currentRoleId.value = roleId;
|
||||
selectedMenuIds.value = [];
|
||||
|
||||
|
||||
try {
|
||||
loading.value = true;
|
||||
|
||||
|
||||
// 获取工作台装饰数据
|
||||
await getWorkbenchData();
|
||||
|
||||
|
||||
// 获取角色当前的菜单配置
|
||||
if (roleId) {
|
||||
await getRoleMenuData(roleId);
|
||||
@@ -128,10 +113,10 @@ const getWorkbenchData = async () => {
|
||||
try {
|
||||
const response = await getWorkbenchDecorate();
|
||||
const { data } = response;
|
||||
|
||||
|
||||
if (data && data.pageData) {
|
||||
const pageData = JSON.parse(data.pageData);
|
||||
workbenchData.value = pageData
|
||||
workbenchData.value = pageData;
|
||||
}
|
||||
} catch (err: any) {
|
||||
console.error('获取工作台数据失败:', err);
|
||||
@@ -143,7 +128,7 @@ const getWorkbenchData = async () => {
|
||||
const getRoleMenuData = async (roleId: string) => {
|
||||
try {
|
||||
const { data } = await getObj(roleId);
|
||||
|
||||
|
||||
if (data && data.menuId) {
|
||||
selectedMenuIds.value = data.menuId.split(',').filter((id: string) => id.trim());
|
||||
}
|
||||
@@ -185,9 +170,9 @@ const toggleModuleSelection = (module: any) => {
|
||||
if (!module.content || !module.content.data) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
const isAllSelected = isModuleAllSelected(module);
|
||||
|
||||
|
||||
if (isAllSelected) {
|
||||
// 取消选择该模块下的所有项
|
||||
module.content.data.forEach((item: any) => {
|
||||
@@ -211,9 +196,9 @@ const onSubmit = async () => {
|
||||
try {
|
||||
loading.value = true;
|
||||
const menuId = selectedMenuIds.value.join(',');
|
||||
|
||||
|
||||
await updateRoleWorkbenchMenus(currentRoleId.value, menuId);
|
||||
|
||||
|
||||
useMessage().success('工作台菜单分配成功');
|
||||
visible.value = false;
|
||||
emit('refresh');
|
||||
@@ -297,12 +282,12 @@ defineExpose({
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
border: 1px solid transparent;
|
||||
|
||||
|
||||
&:hover {
|
||||
border-color: #409eff;
|
||||
box-shadow: 0 2px 8px rgba(64, 158, 255, 0.1);
|
||||
}
|
||||
|
||||
|
||||
&.selected {
|
||||
border-color: #409eff;
|
||||
background-color: #f0f9ff;
|
||||
@@ -358,4 +343,4 @@ defineExpose({
|
||||
justify-content: flex-end;
|
||||
gap: 12px;
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
||||
@@ -23,7 +23,15 @@
|
||||
<el-button plain @click="excelUploadRef.show()" class="ml10" icon="upload-filled" type="primary" v-auth="'app_appuser_export'">
|
||||
{{ $t('common.importBtn') }}
|
||||
</el-button>
|
||||
<el-button plain :disabled="multiple" @click="handleDelete(selectObjs)" class="ml10" icon="Delete" type="primary" v-auth="'app_appuser_del'">
|
||||
<el-button
|
||||
plain
|
||||
:disabled="multiple"
|
||||
@click="handleDelete(selectObjs)"
|
||||
class="ml10"
|
||||
icon="Delete"
|
||||
type="primary"
|
||||
v-auth="'app_appuser_del'"
|
||||
>
|
||||
{{ $t('common.delBtn') }}
|
||||
</el-button>
|
||||
<right-toolbar
|
||||
@@ -40,7 +48,7 @@
|
||||
:data="state.dataList"
|
||||
@selection-change="handleSelectionChange"
|
||||
style="width: 100%"
|
||||
row-key="userId"
|
||||
row-key="userId"
|
||||
v-loading="state.loading"
|
||||
border
|
||||
:cell-style="tableStyle.cellStyle"
|
||||
@@ -140,7 +148,7 @@ const resetQuery = () => {
|
||||
|
||||
// 导出excel
|
||||
const exportExcel = () => {
|
||||
downBlobFile('/app/appuser/export',Object.assign( state.queryForm,{ids:selectObjs}), 'users.xlsx');
|
||||
downBlobFile('/app/appuser/export', Object.assign(state.queryForm, { ids: selectObjs }), 'users.xlsx');
|
||||
};
|
||||
|
||||
// 多选事件
|
||||
|
||||
@@ -86,15 +86,15 @@ const handleAdd = () => {
|
||||
name: '功能名称',
|
||||
link: {},
|
||||
};
|
||||
|
||||
|
||||
if (props.showColor) {
|
||||
newItem.color = '#007aff';
|
||||
}
|
||||
|
||||
|
||||
if (props.showBadge) {
|
||||
newItem.badge = '';
|
||||
}
|
||||
|
||||
|
||||
workbenchLists.value.push(newItem);
|
||||
} else {
|
||||
useMessage().error(`最多添加${props.max}个`);
|
||||
@@ -109,4 +109,4 @@ const handleDelete = (index: number) => {
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
<style lang="scss" scoped></style>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<div class="user-info flex items-center mb-4">
|
||||
<div class="avatar w-12 h-12 bg-white/20 rounded-full flex items-center justify-center mr-3">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="white">
|
||||
<path d="M12 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm0 2c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z"/>
|
||||
<path d="M12 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm0 2c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z" />
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
@@ -14,13 +14,13 @@
|
||||
<div class="font-medium">管理员</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- 任务统计 -->
|
||||
<div class="task-stats grid grid-cols-3 gap-4">
|
||||
<div class="stat-item text-center">
|
||||
<div class="stat-icon w-8 h-8 bg-orange-400 rounded-full mx-auto mb-2 flex items-center justify-center">
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="white">
|
||||
<path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-2 15l-5-5 1.41-1.41L10 14.17l7.59-7.59L19 8l-9 9z"/>
|
||||
<path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-2 15l-5-5 1.41-1.41L10 14.17l7.59-7.59L19 8l-9 9z" />
|
||||
</svg>
|
||||
</div>
|
||||
<div class="text-xl font-bold">0</div>
|
||||
@@ -29,7 +29,7 @@
|
||||
<div class="stat-item text-center">
|
||||
<div class="stat-icon w-8 h-8 bg-blue-400 rounded-full mx-auto mb-2 flex items-center justify-center">
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="white">
|
||||
<path d="M19 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm-5 14H7v-2h7v2zm3-4H7v-2h10v2zm0-4H7V7h10v2z"/>
|
||||
<path d="M19 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm-5 14H7v-2h7v2zm3-4H7v-2h10v2zm0-4H7V7h10v2z" />
|
||||
</svg>
|
||||
</div>
|
||||
<div class="text-xl font-bold">0</div>
|
||||
@@ -38,7 +38,7 @@
|
||||
<div class="stat-item text-center">
|
||||
<div class="stat-icon w-8 h-8 bg-green-400 rounded-full mx-auto mb-2 flex items-center justify-center">
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="white">
|
||||
<path d="M9 16.2L4.8 12l-1.4 1.4L9 19 21 7l-1.4-1.4L9 16.2z"/>
|
||||
<path d="M9 16.2L4.8 12l-1.4 1.4L9 19 21 7l-1.4-1.4L9 16.2z" />
|
||||
</svg>
|
||||
</div>
|
||||
<div class="text-xl font-bold">0</div>
|
||||
@@ -111,15 +111,15 @@ const handleClick = (widget: any, index: number) => {
|
||||
height: 680px;
|
||||
color: #333;
|
||||
overflow-y: auto;
|
||||
|
||||
|
||||
&.workbench {
|
||||
height: 800px;
|
||||
}
|
||||
|
||||
|
||||
.widget-hoverable {
|
||||
@apply border-2 border-dashed border-[#dcdfe6] z-[100];
|
||||
}
|
||||
|
||||
|
||||
.widget-selected {
|
||||
@apply border-2 border-solid border-primary z-[101];
|
||||
box-shadow: 0 0 0 2px rgba(var(--color-primary), 0.1);
|
||||
|
||||
@@ -37,4 +37,4 @@ defineProps({
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
<style lang="scss" scoped></style>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<decoration-img v-if="item.icon" width="24px" height="24px" :src="item.icon" alt="" />
|
||||
<div v-else class="w-6 h-6 flex items-center justify-center">
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="white">
|
||||
<path d="M8 1L8 15M1 8L15 8" stroke="white" stroke-width="2" stroke-linecap="round"/>
|
||||
<path d="M8 1L8 15M1 8L15 8" stroke="white" stroke-width="2" stroke-linecap="round" />
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
@@ -50,4 +50,4 @@ defineProps({
|
||||
.icon-wrapper:hover {
|
||||
transform: scale(1.05);
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
||||
@@ -5,4 +5,4 @@ export default {
|
||||
attr,
|
||||
content,
|
||||
options,
|
||||
};
|
||||
};
|
||||
|
||||
@@ -19,4 +19,4 @@ export default () => ({
|
||||
],
|
||||
},
|
||||
styles: {},
|
||||
});
|
||||
});
|
||||
|
||||
@@ -43,4 +43,4 @@ defineProps({
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
<style lang="scss" scoped></style>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
</div>
|
||||
<div class="expand-icon">
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none">
|
||||
<path d="M6 12L10 8L6 4" stroke="#999" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M6 12L10 8L6 4" stroke="#999" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" />
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
@@ -17,7 +17,7 @@
|
||||
<decoration-img v-if="item.icon" width="24px" height="24px" :src="item.icon" alt="" />
|
||||
<div v-else class="w-6 h-6 bg-blue-500 rounded flex items-center justify-center">
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="white">
|
||||
<path d="M8 1L8 15M1 8L15 8" stroke="white" stroke-width="2" stroke-linecap="round"/>
|
||||
<path d="M8 1L8 15M1 8L15 8" stroke="white" stroke-width="2" stroke-linecap="round" />
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
@@ -59,4 +59,4 @@ defineProps({
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
||||
@@ -5,4 +5,4 @@ export default {
|
||||
attr,
|
||||
content,
|
||||
options,
|
||||
};
|
||||
};
|
||||
|
||||
@@ -29,4 +29,4 @@ export default () => ({
|
||||
],
|
||||
},
|
||||
styles: {},
|
||||
});
|
||||
});
|
||||
|
||||
@@ -43,4 +43,4 @@ defineProps({
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
<style lang="scss" scoped></style>
|
||||
|
||||
@@ -7,20 +7,27 @@
|
||||
</div>
|
||||
<div class="expand-icon">
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none">
|
||||
<path d="M6 12L10 8L6 4" stroke="#999" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M6 12L10 8L6 4" stroke="#999" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" />
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
<div class="grid grid-cols-3 gap-4">
|
||||
<div v-for="(item, index) in content.data" :key="index" class="relative flex flex-col items-center p-4 hover:bg-gray-50 rounded-lg cursor-pointer">
|
||||
<div
|
||||
v-for="(item, index) in content.data"
|
||||
:key="index"
|
||||
class="relative flex flex-col items-center p-4 hover:bg-gray-50 rounded-lg cursor-pointer"
|
||||
>
|
||||
<div class="icon-wrapper mb-2 relative">
|
||||
<decoration-img v-if="item.icon" width="32px" height="32px" :src="item.icon" alt="" />
|
||||
<div v-else class="w-8 h-8 bg-green-500 rounded flex items-center justify-center">
|
||||
<svg width="20" height="20" viewBox="0 0 16 16" fill="white">
|
||||
<path d="M8 1L8 15M1 8L15 8" stroke="white" stroke-width="2" stroke-linecap="round"/>
|
||||
<path d="M8 1L8 15M1 8L15 8" stroke="white" stroke-width="2" stroke-linecap="round" />
|
||||
</svg>
|
||||
</div>
|
||||
<div v-if="item.badge" class="absolute -top-2 -right-2 bg-red-500 text-white text-xs rounded-full min-w-[16px] h-4 flex items-center justify-center px-1">
|
||||
<div
|
||||
v-if="item.badge"
|
||||
class="absolute -top-2 -right-2 bg-red-500 text-white text-xs rounded-full min-w-[16px] h-4 flex items-center justify-center px-1"
|
||||
>
|
||||
{{ item.badge }}
|
||||
</div>
|
||||
</div>
|
||||
@@ -62,4 +69,4 @@ defineProps({
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
||||
@@ -5,4 +5,4 @@ export default {
|
||||
attr,
|
||||
content,
|
||||
options,
|
||||
};
|
||||
};
|
||||
|
||||
@@ -25,4 +25,4 @@ export default () => ({
|
||||
],
|
||||
},
|
||||
styles: {},
|
||||
});
|
||||
});
|
||||
|
||||
@@ -43,7 +43,7 @@ const generatePageData = (widgetNames: string[]) => {
|
||||
const menus: Record<
|
||||
string,
|
||||
{
|
||||
pageType: number;
|
||||
pageType: number;
|
||||
name: string;
|
||||
pageData: any[];
|
||||
}
|
||||
@@ -66,7 +66,7 @@ const menus: Record<
|
||||
[pagesTypeEnum.WORKBENCH]: {
|
||||
pageType: 4,
|
||||
name: '工作台装修',
|
||||
pageData: generatePageData(['workbench-shortcuts','workbench-system', 'workbench-tools']),
|
||||
pageData: generatePageData(['workbench-shortcuts', 'workbench-system', 'workbench-tools']),
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<div class="pages-preview mx-[30px]">
|
||||
<div class="flex tabbar dark:bg-gray-700">
|
||||
<div class="flex flex-col flex-1 justify-center items-center tabbar-item" v-for="(item, index) in tabbar.list" :key="index">
|
||||
<img class="w-[22px] h-[22px]" :src="item.unselected.includes('http') ? item.unselected: baseURL + item.unselected" alt="" />
|
||||
<img class="w-[22px] h-[22px]" :src="item.unselected.includes('http') ? item.unselected : baseURL + item.unselected" alt="" />
|
||||
<div class="leading-3 text-[12px] mt-[4px] dark:text-gray-300">{{ item.name }}</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -112,7 +112,7 @@ const setData = async () => {
|
||||
selected: item.selected,
|
||||
unselected: item.unselected,
|
||||
link: JSON.stringify(item.link), // 将link转为字符串
|
||||
sortOrder: index,
|
||||
sortOrder: index,
|
||||
};
|
||||
});
|
||||
await putObj(data);
|
||||
|
||||
@@ -141,10 +141,10 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="wx-auto-reply">
|
||||
import {fetchAccountList} from '/@/api/mp/wx-account';
|
||||
import {BasicTableProps, useTable} from '/@/hooks/table';
|
||||
import {useMessage, useMessageBox} from '/@/hooks/message';
|
||||
import {addObj, delObj, getPage, putObj} from '/@/api/mp/wx-auto-reply';
|
||||
import { fetchAccountList } from '/@/api/mp/wx-account';
|
||||
import { BasicTableProps, useTable } from '/@/hooks/table';
|
||||
import { useMessage, useMessageBox } from '/@/hooks/message';
|
||||
import { addObj, delObj, getPage, putObj } from '/@/api/mp/wx-auto-reply';
|
||||
|
||||
const QueryTree = defineAsyncComponent(() => import('/@/components/QueryTree/index.vue'));
|
||||
|
||||
@@ -343,10 +343,10 @@ const handleAdd = () => {
|
||||
|
||||
// 默认选择第一个公众号
|
||||
onMounted(async () => {
|
||||
const { data } = await deptData.queryList();
|
||||
if (data?.length > 0) {
|
||||
handleNodeClick(data[0]);
|
||||
}
|
||||
const { data } = await deptData.queryList();
|
||||
if (data?.length > 0) {
|
||||
handleNodeClick(data[0]);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<el-row v-show="showSearch">
|
||||
<el-form ref="queryRef" :inline="true" :model="state.queryForm" @keyup.enter="getDataList">
|
||||
<el-form-item :label="$t('wxFansMsg.appName')" prop="wxAccountAppid">
|
||||
<el-select v-model="state.queryForm.wxAccountAppid" :placeholder="$t('wxFansMsg.appName')" clearable >
|
||||
<el-select v-model="state.queryForm.wxAccountAppid" :placeholder="$t('wxFansMsg.appName')" clearable>
|
||||
<el-option v-for="item in accountList" :key="item.appid" :label="item.name" :value="item.appid" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
@@ -1,154 +1,144 @@
|
||||
<template>
|
||||
<div class="layout-padding">
|
||||
<splitpanes>
|
||||
<pane size="20">
|
||||
<div class="layout-padding-auto layout-padding-view">
|
||||
<el-scrollbar>
|
||||
<query-tree class="mt10" :query="deptData.queryList" @node-click="handleNodeClick" placeholder="请输入微信公众号名称" />
|
||||
</el-scrollbar>
|
||||
</div>
|
||||
</pane>
|
||||
<pane>
|
||||
<div class="layout-padding-auto layout-padding-view">
|
||||
<el-scrollbar>
|
||||
<div v-loading="loading" class="clearfix public-account-management">
|
||||
<div class="left">
|
||||
<div class="weixin-hd">
|
||||
<div class="weixin-title">{{ name }}</div>
|
||||
</div>
|
||||
<div class="clearfix weixin-menu menu_main">
|
||||
<div v-for="(item, i) of menuList" :key="i" class="menu_bottom">
|
||||
<div :class="{ active: isActive === i }" class="menu_item el-icon-s-fold" @click="menuClick(i, item)">
|
||||
{{ item.name }}
|
||||
</div>
|
||||
<!-- 以下为二级菜单-->
|
||||
<div v-if="isSubMenuFlag === i" class="submenu">
|
||||
<template v-for="(subItem, k) in item.sub_button">
|
||||
<div v-if="item.sub_button" :key="k" class="subtitle menu_bottom">
|
||||
<div :class="{ active: isSubMenuActive === i + '' + k }" class="menu_subItem" @click="subMenuClick(subItem, i, k)">
|
||||
{{ subItem.name }}
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<!-- 二级菜单加号, 当长度 小于 5 才显示二级菜单的加号 -->
|
||||
<div v-if="!item.sub_button || item.sub_button.length < 5" class="menu_bottom menu_addicon" @click="addSubMenu(i, item)">
|
||||
<el-icon>
|
||||
<el-icon><Plus /></el-icon>
|
||||
</el-icon>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 一级菜单加号 -->
|
||||
<div v-if="menuList.length < 3" class="menu_bottom menu_addicon" @click="addMenu">
|
||||
<el-icon>
|
||||
<el-icon><Plus /></el-icon>
|
||||
</el-icon>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center justify-center gap-4 mt-4 mb-6 save_div">
|
||||
<el-button
|
||||
class="save_btn !px-6 !h-9 hover:scale-105 transition-transform"
|
||||
type="primary"
|
||||
size="small"
|
||||
@click="handleSave"
|
||||
>
|
||||
<el-icon class="mr-1"><Check /></el-icon>
|
||||
保存发布
|
||||
</el-button>
|
||||
<el-button
|
||||
class="save_btn !px-6 !h-9 hover:scale-105 transition-transform"
|
||||
type="warning"
|
||||
size="small"
|
||||
@click="handleDelete"
|
||||
>
|
||||
<el-icon class="mr-1"><Delete /></el-icon>
|
||||
清空菜单
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layout-padding">
|
||||
<splitpanes>
|
||||
<pane size="20">
|
||||
<div class="layout-padding-auto layout-padding-view">
|
||||
<el-scrollbar>
|
||||
<query-tree class="mt10" :query="deptData.queryList" @node-click="handleNodeClick" placeholder="请输入微信公众号名称" />
|
||||
</el-scrollbar>
|
||||
</div>
|
||||
</pane>
|
||||
<pane>
|
||||
<div class="layout-padding-auto layout-padding-view">
|
||||
<el-scrollbar>
|
||||
<div v-loading="loading" class="clearfix public-account-management">
|
||||
<div class="left">
|
||||
<div class="weixin-hd">
|
||||
<div class="weixin-title">{{ name }}</div>
|
||||
</div>
|
||||
<div class="clearfix weixin-menu menu_main">
|
||||
<div v-for="(item, i) of menuList" :key="i" class="menu_bottom">
|
||||
<div :class="{ active: isActive === i }" class="menu_item el-icon-s-fold" @click="menuClick(i, item)">
|
||||
{{ item.name }}
|
||||
</div>
|
||||
<!-- 以下为二级菜单-->
|
||||
<div v-if="isSubMenuFlag === i" class="submenu">
|
||||
<template v-for="(subItem, k) in item.sub_button">
|
||||
<div v-if="item.sub_button" :key="k" class="subtitle menu_bottom">
|
||||
<div :class="{ active: isSubMenuActive === i + '' + k }" class="menu_subItem" @click="subMenuClick(subItem, i, k)">
|
||||
{{ subItem.name }}
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<!-- 二级菜单加号, 当长度 小于 5 才显示二级菜单的加号 -->
|
||||
<div v-if="!item.sub_button || item.sub_button.length < 5" class="menu_bottom menu_addicon" @click="addSubMenu(i, item)">
|
||||
<el-icon>
|
||||
<el-icon><Plus /></el-icon>
|
||||
</el-icon>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 一级菜单加号 -->
|
||||
<div v-if="menuList.length < 3" class="menu_bottom menu_addicon" @click="addMenu">
|
||||
<el-icon>
|
||||
<el-icon><Plus /></el-icon>
|
||||
</el-icon>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center justify-center gap-4 mt-4 mb-6 save_div">
|
||||
<el-button class="save_btn !px-6 !h-9 hover:scale-105 transition-transform" type="primary" size="small" @click="handleSave">
|
||||
<el-icon class="mr-1"><Check /></el-icon>
|
||||
保存发布
|
||||
</el-button>
|
||||
<el-button class="save_btn !px-6 !h-9 hover:scale-105 transition-transform" type="warning" size="small" @click="handleDelete">
|
||||
<el-icon class="mr-1"><Delete /></el-icon>
|
||||
清空菜单
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="showRightFlag" class="right">
|
||||
<div class="configure_page">
|
||||
<div class="delete_btn">
|
||||
<el-button icon="Delete" size="mini" type="danger" @click="deleteMenu(tempObj)">删除当前菜单 </el-button>
|
||||
</div>
|
||||
<div>
|
||||
<span>菜单名称:</span>
|
||||
<el-input v-model="tempObj.name" class="input_width" clearable placeholder="请输入菜单名称" />
|
||||
</div>
|
||||
<div v-if="showConfigureContent">
|
||||
<div class="menu_content">
|
||||
<span>菜单标识:</span>
|
||||
<el-input v-model="tempObj.key" class="input_width" clearable placeholder="请输入菜单 KEY" />
|
||||
</div>
|
||||
<div class="menu_content">
|
||||
<span>菜单内容:</span>
|
||||
<el-select v-model="tempObj.type" class="menu_option" clearable placeholder="请选择">
|
||||
<el-option v-for="item in menuOptions" :key="item.value" :label="item.label" :value="item.value" />
|
||||
</el-select>
|
||||
</div>
|
||||
<div class="configur_content" v-if="tempObj.type === 'view'">
|
||||
<span>跳转链接:</span>
|
||||
<el-input class="input_width" v-model="tempObj.url" placeholder="请输入链接" clearable />
|
||||
</div>
|
||||
<div class="configur_content" v-if="tempObj.type === 'miniprogram'">
|
||||
<div class="applet">
|
||||
<span>小程序的 appid :</span>
|
||||
<el-input class="input_width" v-model="tempObj.miniProgramAppId" placeholder="请输入小程序的appid" clearable />
|
||||
</div>
|
||||
<div class="applet">
|
||||
<span>小程序的页面路径:</span>
|
||||
<el-input
|
||||
class="input_width"
|
||||
v-model="tempObj.miniProgramPagePath"
|
||||
placeholder="请输入小程序的页面路径,如:pages/index"
|
||||
clearable
|
||||
/>
|
||||
</div>
|
||||
<div class="applet">
|
||||
<span>小程序的备用网页:</span>
|
||||
<el-input class="input_width" v-model="tempObj.url" placeholder="不支持小程序的老版本客户端将打开本网页" clearable />
|
||||
</div>
|
||||
<p class="blue">tips:需要和公众号进行关联才可以把小程序绑定带微信菜单上哟!</p>
|
||||
</div>
|
||||
<div class="configur_content" v-if="tempObj.type === 'article_view_limited'">
|
||||
<el-row>
|
||||
<div class="select-item" v-if="tempObj && tempObj.replyArticles">
|
||||
<wx-news :objData="tempObj.replyArticles" />
|
||||
<el-row class="ope-row">
|
||||
<el-button type="danger" icon="delete" circle @click="deleteMaterial" />
|
||||
</el-row>
|
||||
</div>
|
||||
<div v-else>
|
||||
<el-row>
|
||||
<el-col :span="24" style="text-align: center">
|
||||
<el-button type="success" @click="openMaterial"> 素材库选择<i class="fansel-icon--right"></i> </el-button>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
<wx-material-select ref="dialogNewsRef" @selectMaterial="selectMaterial" />
|
||||
</el-row>
|
||||
</div>
|
||||
<div class="configur_content" v-if="tempObj.type === 'click' || tempObj.type === 'scancode_waitmsg'">
|
||||
<wx-reply :objData="tempObj" v-if="hackResetWxReplySelect" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-scrollbar>
|
||||
</div>
|
||||
</pane>
|
||||
</splitpanes>
|
||||
</div>
|
||||
<div v-if="showRightFlag" class="right">
|
||||
<div class="configure_page">
|
||||
<div class="delete_btn">
|
||||
<el-button icon="Delete" size="mini" type="danger" @click="deleteMenu(tempObj)">删除当前菜单 </el-button>
|
||||
</div>
|
||||
<div>
|
||||
<span>菜单名称:</span>
|
||||
<el-input v-model="tempObj.name" class="input_width" clearable placeholder="请输入菜单名称" />
|
||||
</div>
|
||||
<div v-if="showConfigureContent">
|
||||
<div class="menu_content">
|
||||
<span>菜单标识:</span>
|
||||
<el-input v-model="tempObj.key" class="input_width" clearable placeholder="请输入菜单 KEY" />
|
||||
</div>
|
||||
<div class="menu_content">
|
||||
<span>菜单内容:</span>
|
||||
<el-select v-model="tempObj.type" class="menu_option" clearable placeholder="请选择">
|
||||
<el-option v-for="item in menuOptions" :key="item.value" :label="item.label" :value="item.value" />
|
||||
</el-select>
|
||||
</div>
|
||||
<div class="configur_content" v-if="tempObj.type === 'view'">
|
||||
<span>跳转链接:</span>
|
||||
<el-input class="input_width" v-model="tempObj.url" placeholder="请输入链接" clearable />
|
||||
</div>
|
||||
<div class="configur_content" v-if="tempObj.type === 'miniprogram'">
|
||||
<div class="applet">
|
||||
<span>小程序的 appid :</span>
|
||||
<el-input class="input_width" v-model="tempObj.miniProgramAppId" placeholder="请输入小程序的appid" clearable />
|
||||
</div>
|
||||
<div class="applet">
|
||||
<span>小程序的页面路径:</span>
|
||||
<el-input
|
||||
class="input_width"
|
||||
v-model="tempObj.miniProgramPagePath"
|
||||
placeholder="请输入小程序的页面路径,如:pages/index"
|
||||
clearable
|
||||
/>
|
||||
</div>
|
||||
<div class="applet">
|
||||
<span>小程序的备用网页:</span>
|
||||
<el-input class="input_width" v-model="tempObj.url" placeholder="不支持小程序的老版本客户端将打开本网页" clearable />
|
||||
</div>
|
||||
<p class="blue">tips:需要和公众号进行关联才可以把小程序绑定带微信菜单上哟!</p>
|
||||
</div>
|
||||
<div class="configur_content" v-if="tempObj.type === 'article_view_limited'">
|
||||
<el-row>
|
||||
<div class="select-item" v-if="tempObj && tempObj.replyArticles">
|
||||
<wx-news :objData="tempObj.replyArticles" />
|
||||
<el-row class="ope-row">
|
||||
<el-button type="danger" icon="delete" circle @click="deleteMaterial" />
|
||||
</el-row>
|
||||
</div>
|
||||
<div v-else>
|
||||
<el-row>
|
||||
<el-col :span="24" style="text-align: center">
|
||||
<el-button type="success" @click="openMaterial"> 素材库选择<i class="fansel-icon--right"></i> </el-button>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
<wx-material-select ref="dialogNewsRef" @selectMaterial="selectMaterial" />
|
||||
</el-row>
|
||||
</div>
|
||||
<div class="configur_content" v-if="tempObj.type === 'click' || tempObj.type === 'scancode_waitmsg'">
|
||||
<wx-reply :objData="tempObj" v-if="hackResetWxReplySelect" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-scrollbar>
|
||||
</div>
|
||||
</pane>
|
||||
</splitpanes>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" name="wx-menu" setup>
|
||||
import {getObj, publishObj, saveObj} from '/@/api/mp/wx-menu';
|
||||
import { getObj, publishObj, saveObj } from '/@/api/mp/wx-menu';
|
||||
|
||||
// 部门树使用的数据
|
||||
import {fetchAccountList} from '/@/api/mp/wx-account';
|
||||
import {useMessage, useMessageBox} from '/@/hooks/message';
|
||||
import { fetchAccountList } from '/@/api/mp/wx-account';
|
||||
import { useMessage, useMessageBox } from '/@/hooks/message';
|
||||
|
||||
const WxMaterialSelect = defineAsyncComponent(() => import('/@/components/Wechat/wx-material-select/main.vue'));
|
||||
|
||||
@@ -160,17 +150,17 @@ const WxNews = defineAsyncComponent(() => import('/@/components/Wechat/wx-news/i
|
||||
|
||||
// 点击树
|
||||
const handleNodeClick = (node: any) => {
|
||||
accountId.value = node.appid;
|
||||
name.value = node.name;
|
||||
getMenuFun();
|
||||
accountId.value = node.appid;
|
||||
name.value = node.name;
|
||||
getMenuFun();
|
||||
};
|
||||
|
||||
const deptData = reactive({
|
||||
queryList: (name?: string) => {
|
||||
return fetchAccountList({
|
||||
name: name,
|
||||
});
|
||||
},
|
||||
queryList: (name?: string) => {
|
||||
return fetchAccountList({
|
||||
name: name,
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
const loading = ref(false);
|
||||
@@ -186,228 +176,228 @@ const isSubMenuActive = ref('-1');
|
||||
const isSubMenuFlag = ref(-1);
|
||||
|
||||
const menuList = reactive([
|
||||
{
|
||||
name: '菜单名称',
|
||||
sub_button: [],
|
||||
},
|
||||
{
|
||||
name: '菜单名称',
|
||||
sub_button: [],
|
||||
},
|
||||
] as any);
|
||||
|
||||
const hackResetWxReplySelect = ref(false);
|
||||
|
||||
const menuOptions = ref([
|
||||
{
|
||||
value: 'view',
|
||||
label: '跳转网页',
|
||||
},
|
||||
{
|
||||
value: 'miniprogram',
|
||||
label: '跳转小程序',
|
||||
},
|
||||
{
|
||||
value: 'click',
|
||||
label: '点击回复',
|
||||
},
|
||||
{
|
||||
value: 'article_view_limited',
|
||||
label: '跳转图文消息',
|
||||
},
|
||||
{
|
||||
value: 'scancode_push',
|
||||
label: '扫码直接返回结果',
|
||||
},
|
||||
{
|
||||
value: 'scancode_waitmsg',
|
||||
label: '扫码回复',
|
||||
},
|
||||
{
|
||||
value: 'pic_sysphoto',
|
||||
label: '系统拍照发图',
|
||||
},
|
||||
{
|
||||
value: 'pic_photo_or_album',
|
||||
label: '拍照或者相册',
|
||||
},
|
||||
{
|
||||
value: 'pic_weixin',
|
||||
label: '微信相册',
|
||||
},
|
||||
{
|
||||
value: 'location_select',
|
||||
label: '选择地理位置',
|
||||
},
|
||||
{
|
||||
value: 'view',
|
||||
label: '跳转网页',
|
||||
},
|
||||
{
|
||||
value: 'miniprogram',
|
||||
label: '跳转小程序',
|
||||
},
|
||||
{
|
||||
value: 'click',
|
||||
label: '点击回复',
|
||||
},
|
||||
{
|
||||
value: 'article_view_limited',
|
||||
label: '跳转图文消息',
|
||||
},
|
||||
{
|
||||
value: 'scancode_push',
|
||||
label: '扫码直接返回结果',
|
||||
},
|
||||
{
|
||||
value: 'scancode_waitmsg',
|
||||
label: '扫码回复',
|
||||
},
|
||||
{
|
||||
value: 'pic_sysphoto',
|
||||
label: '系统拍照发图',
|
||||
},
|
||||
{
|
||||
value: 'pic_photo_or_album',
|
||||
label: '拍照或者相册',
|
||||
},
|
||||
{
|
||||
value: 'pic_weixin',
|
||||
label: '微信相册',
|
||||
},
|
||||
{
|
||||
value: 'location_select',
|
||||
label: '选择地理位置',
|
||||
},
|
||||
]);
|
||||
|
||||
const showRightFlag = ref(false);
|
||||
|
||||
let tempObj = ref({
|
||||
replyArticles: [] as any,
|
||||
articleId: '',
|
||||
appId: '',
|
||||
replyArticles: [] as any,
|
||||
articleId: '',
|
||||
appId: '',
|
||||
});
|
||||
|
||||
const tempSelfObj = reactive({
|
||||
grand: '', // 表示二级菜单
|
||||
index: '', // 表示一级菜单索引
|
||||
secondIndex: '', // 表示二级菜单索引
|
||||
grand: '', // 表示二级菜单
|
||||
index: '', // 表示一级菜单索引
|
||||
secondIndex: '', // 表示二级菜单索引
|
||||
});
|
||||
|
||||
const getMenuFun = () => {
|
||||
getObj(accountId.value).then((res) => {
|
||||
if (res.data) {
|
||||
const data = JSON.parse(res.data);
|
||||
if (data && data.button) {
|
||||
Object.assign(menuList, data.button);
|
||||
}
|
||||
} else {
|
||||
menuList.length = 0;
|
||||
Object.assign(menuList, {
|
||||
name: '菜单名称',
|
||||
sub_button: [],
|
||||
});
|
||||
}
|
||||
});
|
||||
getObj(accountId.value).then((res) => {
|
||||
if (res.data) {
|
||||
const data = JSON.parse(res.data);
|
||||
if (data && data.button) {
|
||||
Object.assign(menuList, data.button);
|
||||
}
|
||||
} else {
|
||||
menuList.length = 0;
|
||||
Object.assign(menuList, {
|
||||
name: '菜单名称',
|
||||
sub_button: [],
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const showConfigureContent = ref(true);
|
||||
|
||||
// 一级菜单点击事件
|
||||
const menuClick = (i, item) => {
|
||||
hackResetWxReplySelect.value = false;
|
||||
nextTick(() => {
|
||||
hackResetWxReplySelect.value = true;
|
||||
});
|
||||
showRightFlag.value = true; // 右边菜单
|
||||
tempObj.value = item;
|
||||
tempObj.value.appId = accountId.value;
|
||||
showConfigureContent.value = !(item.sub_button && item.sub_button.length > 0); // 有子菜单,就不显示配置内容
|
||||
isActive.value = i;
|
||||
isSubMenuFlag.value = i;
|
||||
isSubMenuActive.value = '-1';
|
||||
tempSelfObj.grand = '1'; //表示一级菜单
|
||||
tempSelfObj.index = i; //表示一级菜单索引
|
||||
hackResetWxReplySelect.value = false;
|
||||
nextTick(() => {
|
||||
hackResetWxReplySelect.value = true;
|
||||
});
|
||||
showRightFlag.value = true; // 右边菜单
|
||||
tempObj.value = item;
|
||||
tempObj.value.appId = accountId.value;
|
||||
showConfigureContent.value = !(item.sub_button && item.sub_button.length > 0); // 有子菜单,就不显示配置内容
|
||||
isActive.value = i;
|
||||
isSubMenuFlag.value = i;
|
||||
isSubMenuActive.value = '-1';
|
||||
tempSelfObj.grand = '1'; //表示一级菜单
|
||||
tempSelfObj.index = i; //表示一级菜单索引
|
||||
};
|
||||
|
||||
// 点击二级菜单
|
||||
const subMenuClick = (subItem, index, k) => {
|
||||
hackResetWxReplySelect.value = false;
|
||||
nextTick(() => {
|
||||
hackResetWxReplySelect.value = true;
|
||||
});
|
||||
showRightFlag.value = true; // 右边菜单
|
||||
// Object.assign(tempObj, subItem) // 这个如果放在顶部,flag 会没有。因为重新赋值了。
|
||||
tempObj.value = subItem;
|
||||
tempObj.value.appId = accountId.value;
|
||||
showConfigureContent.value = true;
|
||||
isActive.value = -1; // 一级菜单去除样式
|
||||
isSubMenuActive.value = index + '' + k; // 二级菜单选中样式
|
||||
tempSelfObj.grand = '2'; //表示二级菜单
|
||||
tempSelfObj.index = index; //表示一级菜单索引
|
||||
tempSelfObj.secondIndex = k; //表示二级菜单索引
|
||||
hackResetWxReplySelect.value = false;
|
||||
nextTick(() => {
|
||||
hackResetWxReplySelect.value = true;
|
||||
});
|
||||
showRightFlag.value = true; // 右边菜单
|
||||
// Object.assign(tempObj, subItem) // 这个如果放在顶部,flag 会没有。因为重新赋值了。
|
||||
tempObj.value = subItem;
|
||||
tempObj.value.appId = accountId.value;
|
||||
showConfigureContent.value = true;
|
||||
isActive.value = -1; // 一级菜单去除样式
|
||||
isSubMenuActive.value = index + '' + k; // 二级菜单选中样式
|
||||
tempSelfObj.grand = '2'; //表示二级菜单
|
||||
tempSelfObj.index = index; //表示一级菜单索引
|
||||
tempSelfObj.secondIndex = k; //表示二级菜单索引
|
||||
};
|
||||
|
||||
// 添加横向二级菜单;item 表示要操作的父菜单
|
||||
const addSubMenu = (i, item) => {
|
||||
if (!item.sub_button || item.sub_button.length <= 0) {
|
||||
item['sub_button'] = [];
|
||||
showConfigureContent.value = false;
|
||||
}
|
||||
let addButton = {
|
||||
name: '子菜单名称',
|
||||
reply: {
|
||||
// 用于存储回复内容
|
||||
type: 'text',
|
||||
accountId: accountId.value, // 保证组件里,可以使用到对应的公众号
|
||||
},
|
||||
};
|
||||
item.sub_button.push(addButton);
|
||||
if (!item.sub_button || item.sub_button.length <= 0) {
|
||||
item['sub_button'] = [];
|
||||
showConfigureContent.value = false;
|
||||
}
|
||||
let addButton = {
|
||||
name: '子菜单名称',
|
||||
reply: {
|
||||
// 用于存储回复内容
|
||||
type: 'text',
|
||||
accountId: accountId.value, // 保证组件里,可以使用到对应的公众号
|
||||
},
|
||||
};
|
||||
item.sub_button.push(addButton);
|
||||
};
|
||||
|
||||
// 添加横向一级菜单
|
||||
const addMenu = () => {
|
||||
const addButton = {
|
||||
name: '菜单名称',
|
||||
sub_button: [],
|
||||
reply: {
|
||||
// 用于存储回复内容
|
||||
type: 'text',
|
||||
accountId: accountId.value, // 保证组件里,可以使用到对应的公众号
|
||||
},
|
||||
};
|
||||
menuList.push(addButton);
|
||||
const addButton = {
|
||||
name: '菜单名称',
|
||||
sub_button: [],
|
||||
reply: {
|
||||
// 用于存储回复内容
|
||||
type: 'text',
|
||||
accountId: accountId.value, // 保证组件里,可以使用到对应的公众号
|
||||
},
|
||||
};
|
||||
menuList.push(addButton);
|
||||
};
|
||||
|
||||
const deleteMenu = () => {
|
||||
useMessageBox()
|
||||
.confirm('确定要删除吗?')
|
||||
.then(() => {
|
||||
if (tempSelfObj.grand === '1') {
|
||||
menuList.splice(tempSelfObj.index, 1);
|
||||
} else if (tempSelfObj.grand === '2') {
|
||||
menuList[tempSelfObj.index].sub_button.splice(tempSelfObj.secondIndex, 1);
|
||||
}
|
||||
useMessage().success('删除成功');
|
||||
Object.assign(tempObj, {});
|
||||
showRightFlag.value = false;
|
||||
isActive.value = -1;
|
||||
isSubMenuActive.value = '-1';
|
||||
})
|
||||
.catch((err) => {
|
||||
useMessage().error(err.msg);
|
||||
});
|
||||
useMessageBox()
|
||||
.confirm('确定要删除吗?')
|
||||
.then(() => {
|
||||
if (tempSelfObj.grand === '1') {
|
||||
menuList.splice(tempSelfObj.index, 1);
|
||||
} else if (tempSelfObj.grand === '2') {
|
||||
menuList[tempSelfObj.index].sub_button.splice(tempSelfObj.secondIndex, 1);
|
||||
}
|
||||
useMessage().success('删除成功');
|
||||
Object.assign(tempObj, {});
|
||||
showRightFlag.value = false;
|
||||
isActive.value = -1;
|
||||
isSubMenuActive.value = '-1';
|
||||
})
|
||||
.catch((err) => {
|
||||
useMessage().error(err.msg);
|
||||
});
|
||||
};
|
||||
|
||||
const handleSave = async () => {
|
||||
try {
|
||||
await useMessageBox().confirm('确定要保存该菜单吗?');
|
||||
await saveObj(accountId.value, { button: menuList });
|
||||
await publishObj(accountId.value);
|
||||
useMessage().success('发布成功');
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg);
|
||||
}
|
||||
try {
|
||||
await useMessageBox().confirm('确定要保存该菜单吗?');
|
||||
await saveObj(accountId.value, { button: menuList });
|
||||
await publishObj(accountId.value);
|
||||
useMessage().success('发布成功');
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg);
|
||||
}
|
||||
};
|
||||
|
||||
const deleteMaterial = () => {
|
||||
tempObj.value.replyArticles = [];
|
||||
tempObj.value.articleId = '';
|
||||
tempObj.value.replyArticles = [];
|
||||
tempObj.value.articleId = '';
|
||||
};
|
||||
|
||||
const dialogNewsRef = ref();
|
||||
const openMaterial = () => {
|
||||
dialogNewsRef.value.openDialog({ type: 'news', accountId: accountId.value });
|
||||
dialogNewsRef.value.openDialog({ type: 'news', accountId: accountId.value });
|
||||
};
|
||||
|
||||
const selectMaterial = (item) => {
|
||||
const articleId = item.articleId;
|
||||
const articles = item.content.newsItem;
|
||||
// 提示,针对多图文
|
||||
if (articles.length > 1) {
|
||||
// this.$alert('您选择的是多图文,将默认跳转第一篇', '提示', {
|
||||
// confirmButtonText: '确定'
|
||||
// })
|
||||
}
|
||||
const articleId = item.articleId;
|
||||
const articles = item.content.newsItem;
|
||||
// 提示,针对多图文
|
||||
if (articles.length > 1) {
|
||||
// this.$alert('您选择的是多图文,将默认跳转第一篇', '提示', {
|
||||
// confirmButtonText: '确定'
|
||||
// })
|
||||
}
|
||||
|
||||
// 设置菜单的回复
|
||||
tempObj.value.articleId = articleId;
|
||||
tempObj.value.replyArticles = [];
|
||||
articles.forEach((article) => {
|
||||
tempObj.value.replyArticles.push({
|
||||
title: article.title,
|
||||
description: article.digest,
|
||||
picUrl: article.picUrl,
|
||||
url: article.url,
|
||||
});
|
||||
});
|
||||
// 设置菜单的回复
|
||||
tempObj.value.articleId = articleId;
|
||||
tempObj.value.replyArticles = [];
|
||||
articles.forEach((article) => {
|
||||
tempObj.value.replyArticles.push({
|
||||
title: article.title,
|
||||
description: article.digest,
|
||||
picUrl: article.picUrl,
|
||||
url: article.url,
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
const handleDelete = () => {};
|
||||
|
||||
// 默认选择第一个公众号
|
||||
onMounted(async () => {
|
||||
const { data } = await deptData.queryList();
|
||||
if (data?.length > 0) {
|
||||
handleNodeClick(data[0]);
|
||||
}
|
||||
const { data } = await deptData.queryList();
|
||||
if (data?.length > 0) {
|
||||
handleNodeClick(data[0]);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
@@ -49,9 +49,9 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="wx-statistics">
|
||||
import {useMessage} from '/@/hooks/message';
|
||||
import {fetchAccountList, fetchStatistics} from '/@/api/mp/wx-account';
|
||||
import {markRaw} from 'vue';
|
||||
import { useMessage } from '/@/hooks/message';
|
||||
import { fetchAccountList, fetchStatistics } from '/@/api/mp/wx-account';
|
||||
import { markRaw } from 'vue';
|
||||
import * as echarts from 'echarts';
|
||||
|
||||
const QueryTree = defineAsyncComponent(() => import('/@/components/QueryTree/index.vue'));
|
||||
@@ -216,10 +216,10 @@ const initdata = () => {
|
||||
|
||||
// 默认选择第一个公众号
|
||||
onMounted(async () => {
|
||||
const { data } = await deptData.queryList();
|
||||
if (data?.length > 0) {
|
||||
handleNodeClick(data[0]);
|
||||
}
|
||||
const { data } = await deptData.queryList();
|
||||
if (data?.length > 0) {
|
||||
handleNodeClick(data[0]);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
@@ -118,10 +118,10 @@ const dictType = ref([
|
||||
label: '处理完成',
|
||||
value: '2',
|
||||
},
|
||||
{
|
||||
label: '退款成功',
|
||||
value: '5',
|
||||
},
|
||||
{
|
||||
label: '退款成功',
|
||||
value: '5',
|
||||
},
|
||||
]);
|
||||
|
||||
// table hook
|
||||
|
||||
@@ -136,7 +136,7 @@ const onSubmit = async () => {
|
||||
refundAmount: form.amount,
|
||||
remark: form.remark,
|
||||
channelId: form.channelId,
|
||||
channelMchId: form.channelMchId,
|
||||
channelMchId: form.channelMchId,
|
||||
});
|
||||
|
||||
useMessage().success(t('common.optSuccessText')); // 如果退款成功,则显示成功提示信息
|
||||
|
||||
@@ -1,178 +1,156 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
title="编辑评语"
|
||||
v-model="visible"
|
||||
:width="700"
|
||||
:close-on-click-modal="false"
|
||||
draggable>
|
||||
<el-form
|
||||
ref="dataFormRef"
|
||||
:model="form"
|
||||
:rules="dataRules"
|
||||
label-width="120px"
|
||||
v-loading="loading">
|
||||
<el-row :gutter="24">
|
||||
<el-col :span="24" class="mb20">
|
||||
<el-form-item label="学号">
|
||||
<el-input v-model="form.stuNo" disabled style="width: 100%" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24" class="mb20">
|
||||
<el-form-item label="姓名">
|
||||
<el-input v-model="form.realName" disabled style="width: 100%" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24" class="mb20">
|
||||
<el-form-item label="学年">
|
||||
<el-input v-model="form.schoolYear" disabled style="width: 100%" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24" class="mb20">
|
||||
<el-form-item label="学期">
|
||||
<el-input v-model="form.schoolTerm" disabled style="width: 100%" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24" class="mb20">
|
||||
<el-form-item label="评语" prop="comment">
|
||||
<el-input
|
||||
v-model="form.comment"
|
||||
type="textarea"
|
||||
:rows="6"
|
||||
placeholder="请输入评语"
|
||||
style="width: 100%" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24" class="mb20">
|
||||
<el-form-item label="家长寄语" prop="parentalMsg">
|
||||
<el-input
|
||||
v-model="form.parentalMsg"
|
||||
type="textarea"
|
||||
:rows="6"
|
||||
placeholder="请输入家长寄语"
|
||||
style="width: 100%" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="visible = false">取 消</el-button>
|
||||
<el-button type="primary" @click="onSubmit" :disabled="loading">确 认</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
<el-dialog title="编辑评语" v-model="visible" :width="700" :close-on-click-modal="false" draggable>
|
||||
<el-form ref="dataFormRef" :model="form" :rules="dataRules" label-width="120px" v-loading="loading">
|
||||
<el-row :gutter="24">
|
||||
<el-col :span="24" class="mb20">
|
||||
<el-form-item label="学号">
|
||||
<el-input v-model="form.stuNo" disabled style="width: 100%" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24" class="mb20">
|
||||
<el-form-item label="姓名">
|
||||
<el-input v-model="form.realName" disabled style="width: 100%" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24" class="mb20">
|
||||
<el-form-item label="学年">
|
||||
<el-input v-model="form.schoolYear" disabled style="width: 100%" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24" class="mb20">
|
||||
<el-form-item label="学期">
|
||||
<el-input v-model="form.schoolTerm" disabled style="width: 100%" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24" class="mb20">
|
||||
<el-form-item label="评语" prop="comment">
|
||||
<el-input v-model="form.comment" type="textarea" :rows="6" placeholder="请输入评语" style="width: 100%" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24" class="mb20">
|
||||
<el-form-item label="家长寄语" prop="parentalMsg">
|
||||
<el-input v-model="form.parentalMsg" type="textarea" :rows="6" placeholder="请输入家长寄语" style="width: 100%" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="visible = false">取 消</el-button>
|
||||
<el-button type="primary" @click="onSubmit" :disabled="loading">确 认</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="QualityReportEditDialog">
|
||||
import { ref, reactive, nextTick } from 'vue'
|
||||
import { useMessage } from '/@/hooks/message'
|
||||
import { updatePY } from '/@/api/ems/qualityReport'
|
||||
import { getDicts } from '/@/api/admin/dict'
|
||||
import { ref, reactive, nextTick } from 'vue';
|
||||
import { useMessage } from '/@/hooks/message';
|
||||
import { updatePY } from '/@/api/ems/qualityReport';
|
||||
import { getDicts } from '/@/api/admin/dict';
|
||||
|
||||
const emit = defineEmits(['refresh'])
|
||||
const emit = defineEmits(['refresh']);
|
||||
|
||||
// 定义变量内容
|
||||
const dataFormRef = ref()
|
||||
const visible = ref(false)
|
||||
const loading = ref(false)
|
||||
const schoolTermList = ref<any[]>([])
|
||||
const dataFormRef = ref();
|
||||
const visible = ref(false);
|
||||
const loading = ref(false);
|
||||
const schoolTermList = ref<any[]>([]);
|
||||
|
||||
// 提交表单数据
|
||||
const form = reactive({
|
||||
stuNo: '',
|
||||
realName: '',
|
||||
schoolYear: '',
|
||||
schoolTerm: '',
|
||||
comment: '',
|
||||
parentalMsg: ''
|
||||
})
|
||||
stuNo: '',
|
||||
realName: '',
|
||||
schoolYear: '',
|
||||
schoolTerm: '',
|
||||
comment: '',
|
||||
parentalMsg: '',
|
||||
});
|
||||
|
||||
// 定义校验规则
|
||||
const dataRules = {
|
||||
// comment 和 parentalMsg 非必填,不需要验证规则
|
||||
}
|
||||
// comment 和 parentalMsg 非必填,不需要验证规则
|
||||
};
|
||||
|
||||
// 格式化学期
|
||||
const formatSchoolTerm = (value: string | number) => {
|
||||
if (value === null || value === undefined || value === '') {
|
||||
return '-'
|
||||
}
|
||||
const dictItem = schoolTermList.value.find(item => item.value == value)
|
||||
return dictItem ? dictItem.label : value
|
||||
}
|
||||
if (value === null || value === undefined || value === '') {
|
||||
return '-';
|
||||
}
|
||||
const dictItem = schoolTermList.value.find((item) => item.value == value);
|
||||
return dictItem ? dictItem.label : value;
|
||||
};
|
||||
|
||||
// 打开弹窗
|
||||
const openDialog = async (row: any) => {
|
||||
visible.value = true
|
||||
|
||||
// 重置表单数据
|
||||
nextTick(() => {
|
||||
dataFormRef.value?.resetFields()
|
||||
form.stuNo = row.stuNo || ''
|
||||
form.realName = row.realName || ''
|
||||
form.schoolYear = row.schoolYear || ''
|
||||
form.schoolTerm = row.schoolTerm || ''
|
||||
form.comment = row.comment || ''
|
||||
form.parentalMsg = row.parentalMsg || ''
|
||||
})
|
||||
}
|
||||
visible.value = true;
|
||||
|
||||
// 重置表单数据
|
||||
nextTick(() => {
|
||||
dataFormRef.value?.resetFields();
|
||||
form.stuNo = row.stuNo || '';
|
||||
form.realName = row.realName || '';
|
||||
form.schoolYear = row.schoolYear || '';
|
||||
form.schoolTerm = row.schoolTerm || '';
|
||||
form.comment = row.comment || '';
|
||||
form.parentalMsg = row.parentalMsg || '';
|
||||
});
|
||||
};
|
||||
|
||||
// 提交表单
|
||||
const onSubmit = async () => {
|
||||
if (!dataFormRef.value) return
|
||||
|
||||
await dataFormRef.value.validate(async (valid: boolean) => {
|
||||
if (!valid) return
|
||||
|
||||
loading.value = true
|
||||
try {
|
||||
const submitData = {
|
||||
stuNo: form.stuNo,
|
||||
comment: form.comment || '',
|
||||
parentalMsg: form.parentalMsg || '',
|
||||
schoolYear: form.schoolYear,
|
||||
schoolTerm: form.schoolTerm
|
||||
}
|
||||
|
||||
await updatePY(submitData)
|
||||
useMessage().success('保存成功')
|
||||
visible.value = false
|
||||
emit('refresh')
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg || '保存失败')
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
})
|
||||
}
|
||||
if (!dataFormRef.value) return;
|
||||
|
||||
await dataFormRef.value.validate(async (valid: boolean) => {
|
||||
if (!valid) return;
|
||||
|
||||
loading.value = true;
|
||||
try {
|
||||
const submitData = {
|
||||
stuNo: form.stuNo,
|
||||
comment: form.comment || '',
|
||||
parentalMsg: form.parentalMsg || '',
|
||||
schoolYear: form.schoolYear,
|
||||
schoolTerm: form.schoolTerm,
|
||||
};
|
||||
|
||||
await updatePY(submitData);
|
||||
useMessage().success('保存成功');
|
||||
visible.value = false;
|
||||
emit('refresh');
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg || '保存失败');
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// 获取学期字典
|
||||
const getSchoolTermDict = async () => {
|
||||
try {
|
||||
const res = await getDicts('school_term')
|
||||
if (res.data && Array.isArray(res.data)) {
|
||||
schoolTermList.value = res.data.map((item: any) => ({
|
||||
label: item.label || item.dictLabel || item.name,
|
||||
value: item.value || item.dictValue || item.code
|
||||
}))
|
||||
} else {
|
||||
schoolTermList.value = []
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('获取学期字典失败', err)
|
||||
schoolTermList.value = []
|
||||
}
|
||||
}
|
||||
try {
|
||||
const res = await getDicts('school_term');
|
||||
if (res.data && Array.isArray(res.data)) {
|
||||
schoolTermList.value = res.data.map((item: any) => ({
|
||||
label: item.label || item.dictLabel || item.name,
|
||||
value: item.value || item.dictValue || item.code,
|
||||
}));
|
||||
} else {
|
||||
schoolTermList.value = [];
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('获取学期字典失败', err);
|
||||
schoolTermList.value = [];
|
||||
}
|
||||
};
|
||||
|
||||
// 初始化
|
||||
getSchoolTermDict()
|
||||
getSchoolTermDict();
|
||||
|
||||
// 暴露方法
|
||||
defineExpose({
|
||||
openDialog
|
||||
})
|
||||
openDialog,
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
</style>
|
||||
|
||||
<style scoped lang="scss"></style>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -13,9 +13,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="right">
|
||||
<img
|
||||
:src="errorPng"
|
||||
/>
|
||||
<img :src="errorPng" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,33 +1,33 @@
|
||||
<template>
|
||||
<el-dialog :title="dataForm.id ? '编辑' : '新增'" v-model="visible" width="600px" :close-on-click-modal="false" draggable>
|
||||
<el-form ref="formRef" :model="dataForm" :rules="dataRules" label-width="100px" v-loading="loading">
|
||||
<el-form-item label="项目名称" prop="projectName">
|
||||
<el-input v-model="dataForm.projectName" placeholder="请输入项目名称" clearable />
|
||||
</el-form-item>
|
||||
<el-form-item label="项目代码" prop="projectCode">
|
||||
<el-input v-model="dataForm.projectCode" placeholder="请输入项目代码" clearable />
|
||||
</el-form-item>
|
||||
<el-form-item label="年份" prop="year">
|
||||
<el-date-picker v-model="dataForm.year" type="year" placeholder="选择年份" value-format="YYYY" style="width: 100%" />
|
||||
</el-form-item>
|
||||
<el-form-item label="排序" prop="sort">
|
||||
<el-input-number v-model="dataForm.sort" :min="0" placeholder="请输入排序" style="width: 100%" />
|
||||
</el-form-item>
|
||||
<el-form-item label="备注" prop="remarks">
|
||||
<el-input v-model="dataForm.remarks" type="textarea" :rows="3" placeholder="请输入备注" clearable />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="visible = false">取 消</el-button>
|
||||
<el-button type="primary" @click="onSubmit" :disabled="loading">确 定</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
<el-dialog :title="dataForm.id ? '编辑' : '新增'" v-model="visible" width="600px" :close-on-click-modal="false" draggable>
|
||||
<el-form ref="formRef" :model="dataForm" :rules="dataRules" label-width="100px" v-loading="loading">
|
||||
<el-form-item label="项目名称" prop="projectName">
|
||||
<el-input v-model="dataForm.projectName" placeholder="请输入项目名称" clearable />
|
||||
</el-form-item>
|
||||
<el-form-item label="项目代码" prop="projectCode">
|
||||
<el-input v-model="dataForm.projectCode" placeholder="请输入项目代码" clearable />
|
||||
</el-form-item>
|
||||
<el-form-item label="年份" prop="year">
|
||||
<el-date-picker v-model="dataForm.year" type="year" placeholder="选择年份" value-format="YYYY" style="width: 100%" />
|
||||
</el-form-item>
|
||||
<el-form-item label="排序" prop="sort">
|
||||
<el-input-number v-model="dataForm.sort" :min="0" placeholder="请输入排序" style="width: 100%" />
|
||||
</el-form-item>
|
||||
<el-form-item label="备注" prop="remarks">
|
||||
<el-input v-model="dataForm.remarks" type="textarea" :rows="3" placeholder="请输入备注" clearable />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="visible = false">取 消</el-button>
|
||||
<el-button type="primary" @click="onSubmit" :disabled="loading">确 定</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="FinanceRecruitProjectForm">
|
||||
import { reactive, ref, nextTick } from 'vue'
|
||||
import { reactive, ref, nextTick } from 'vue';
|
||||
import { getObj, addObj, editObj } from '/@/api/finance/recruitProject';
|
||||
import { useMessage } from '/@/hooks/message';
|
||||
|
||||
@@ -35,86 +35,88 @@ const emit = defineEmits(['refresh']);
|
||||
|
||||
const formRef = ref();
|
||||
const dataForm = reactive({
|
||||
id: '',
|
||||
projectName: '',
|
||||
projectCode: '',
|
||||
year: '',
|
||||
sort: 0,
|
||||
remarks: '',
|
||||
id: '',
|
||||
projectName: '',
|
||||
projectCode: '',
|
||||
year: '',
|
||||
sort: 0,
|
||||
remarks: '',
|
||||
});
|
||||
const visible = ref(false);
|
||||
const loading = ref(false);
|
||||
|
||||
const dataRules = ref({
|
||||
projectName: [{ required: true, message: '请输入项目名称', trigger: 'blur' }],
|
||||
projectCode: [{ required: true, message: '请输入项目代码', trigger: 'blur' }],
|
||||
year: [{ required: true, message: '请选择年份', trigger: 'change' }],
|
||||
projectName: [{ required: true, message: '请输入项目名称', trigger: 'blur' }],
|
||||
projectCode: [{ required: true, message: '请输入项目代码', trigger: 'blur' }],
|
||||
year: [{ required: true, message: '请选择年份', trigger: 'change' }],
|
||||
});
|
||||
|
||||
const openDialog = async (type: string, rowData?: any) => {
|
||||
visible.value = true;
|
||||
dataForm.id = '';
|
||||
dataForm.projectName = '';
|
||||
dataForm.projectCode = '';
|
||||
dataForm.year = '';
|
||||
dataForm.sort = 0;
|
||||
dataForm.remarks = '';
|
||||
visible.value = true;
|
||||
dataForm.id = '';
|
||||
dataForm.projectName = '';
|
||||
dataForm.projectCode = '';
|
||||
dataForm.year = '';
|
||||
dataForm.sort = 0;
|
||||
dataForm.remarks = '';
|
||||
|
||||
nextTick(() => {
|
||||
formRef.value?.resetFields();
|
||||
if (type === 'edit' && rowData?.id) {
|
||||
loading.value = true;
|
||||
getObj(rowData.id).then((res: any) => {
|
||||
if (res.data) {
|
||||
Object.assign(dataForm, {
|
||||
id: res.data.id || '',
|
||||
projectName: res.data.projectName || '',
|
||||
projectCode: res.data.projectCode || '',
|
||||
year: res.data.year ? String(res.data.year) : '',
|
||||
sort: res.data.sort || 0,
|
||||
remarks: res.data.remarks || '',
|
||||
});
|
||||
}
|
||||
loading.value = false;
|
||||
}).catch((err: any) => {
|
||||
useMessage().error(err.msg || '获取详情失败');
|
||||
loading.value = false;
|
||||
});
|
||||
}
|
||||
});
|
||||
nextTick(() => {
|
||||
formRef.value?.resetFields();
|
||||
if (type === 'edit' && rowData?.id) {
|
||||
loading.value = true;
|
||||
getObj(rowData.id)
|
||||
.then((res: any) => {
|
||||
if (res.data) {
|
||||
Object.assign(dataForm, {
|
||||
id: res.data.id || '',
|
||||
projectName: res.data.projectName || '',
|
||||
projectCode: res.data.projectCode || '',
|
||||
year: res.data.year ? String(res.data.year) : '',
|
||||
sort: res.data.sort || 0,
|
||||
remarks: res.data.remarks || '',
|
||||
});
|
||||
}
|
||||
loading.value = false;
|
||||
})
|
||||
.catch((err: any) => {
|
||||
useMessage().error(err.msg || '获取详情失败');
|
||||
loading.value = false;
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const onSubmit = async () => {
|
||||
if (loading.value) return;
|
||||
loading.value = true;
|
||||
if (loading.value) return;
|
||||
loading.value = true;
|
||||
|
||||
try {
|
||||
const valid = await formRef.value.validate().catch(() => {});
|
||||
if (!valid) {
|
||||
loading.value = false;
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
const valid = await formRef.value.validate().catch(() => {});
|
||||
if (!valid) {
|
||||
loading.value = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
const submitData = {
|
||||
...dataForm,
|
||||
year: dataForm.year ? parseInt(dataForm.year) : null,
|
||||
};
|
||||
const submitData = {
|
||||
...dataForm,
|
||||
year: dataForm.year ? parseInt(dataForm.year) : null,
|
||||
};
|
||||
|
||||
if (dataForm.id) {
|
||||
await editObj(submitData);
|
||||
useMessage().success('编辑成功');
|
||||
} else {
|
||||
await addObj(submitData);
|
||||
useMessage().success('新增成功');
|
||||
}
|
||||
visible.value = false;
|
||||
emit('refresh');
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg || (dataForm.id ? '编辑失败' : '新增失败'));
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
if (dataForm.id) {
|
||||
await editObj(submitData);
|
||||
useMessage().success('编辑成功');
|
||||
} else {
|
||||
await addObj(submitData);
|
||||
useMessage().success('新增成功');
|
||||
}
|
||||
visible.value = false;
|
||||
emit('refresh');
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg || (dataForm.id ? '编辑失败' : '新增失败'));
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
defineExpose({ openDialog });
|
||||
</script>
|
||||
</script>
|
||||
|
||||
@@ -1,121 +1,133 @@
|
||||
<template>
|
||||
<div class="modern-page-container">
|
||||
<div class="page-wrapper">
|
||||
<el-card v-show="showSearch" class="search-card" shadow="never">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span class="card-title">
|
||||
<el-icon class="title-icon"><Search /></el-icon>
|
||||
筛选条件
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
<el-form :model="state.queryForm" ref="searchFormRef" :inline="true" @keyup.enter="getDataList" class="search-form">
|
||||
<el-form-item label="项目名称" prop="projectName">
|
||||
<el-input v-model="state.queryForm.projectName" placeholder="请输入项目名称" clearable style="width: 200px" />
|
||||
</el-form-item>
|
||||
<el-form-item label="项目代码" prop="projectCode">
|
||||
<el-input v-model="state.queryForm.projectCode" placeholder="请输入项目代码" clearable style="width: 150px" />
|
||||
</el-form-item>
|
||||
<el-form-item label="年份" prop="year">
|
||||
<el-date-picker v-model="state.queryForm.year" type="year" placeholder="选择年份" value-format="YYYY" style="width: 150px" />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="Search" @click="getDataList">查询</el-button>
|
||||
<el-button icon="Refresh" @click="handleReset">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
<div class="modern-page-container">
|
||||
<div class="page-wrapper">
|
||||
<el-card v-show="showSearch" class="search-card" shadow="never">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span class="card-title">
|
||||
<el-icon class="title-icon"><Search /></el-icon>
|
||||
筛选条件
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
<el-form :model="state.queryForm" ref="searchFormRef" :inline="true" @keyup.enter="getDataList" class="search-form">
|
||||
<el-form-item label="项目名称" prop="projectName">
|
||||
<el-input v-model="state.queryForm.projectName" placeholder="请输入项目名称" clearable style="width: 200px" />
|
||||
</el-form-item>
|
||||
<el-form-item label="项目代码" prop="projectCode">
|
||||
<el-input v-model="state.queryForm.projectCode" placeholder="请输入项目代码" clearable style="width: 150px" />
|
||||
</el-form-item>
|
||||
<el-form-item label="年份" prop="year">
|
||||
<el-date-picker v-model="state.queryForm.year" type="year" placeholder="选择年份" value-format="YYYY" style="width: 150px" />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="Search" @click="getDataList">查询</el-button>
|
||||
<el-button icon="Refresh" @click="handleReset">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
|
||||
<el-card class="content-card" shadow="never">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span class="card-title">
|
||||
<el-icon class="title-icon"><Document /></el-icon>
|
||||
收费项目管理
|
||||
</span>
|
||||
<div class="header-actions">
|
||||
<el-button icon="FolderAdd" type="primary" @click="formDialogRef.openDialog('add')" v-auth="'finance_recruit_project_add'">新增</el-button>
|
||||
<right-toolbar v-model:showSearch="showSearch" class="ml10" @queryTable="getDataList" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<el-card class="content-card" shadow="never">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span class="card-title">
|
||||
<el-icon class="title-icon"><Document /></el-icon>
|
||||
收费项目管理
|
||||
</span>
|
||||
<div class="header-actions">
|
||||
<el-button icon="FolderAdd" type="primary" @click="formDialogRef.openDialog('add')" v-auth="'finance_recruit_project_add'"
|
||||
>新增</el-button
|
||||
>
|
||||
<right-toolbar v-model:showSearch="showSearch" class="ml10" @queryTable="getDataList" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<el-table ref="tableRef" :data="state.dataList" v-loading="state.loading" stripe :cell-style="tableStyle.cellStyle" :header-cell-style="tableStyle.headerCellStyle" class="modern-table">
|
||||
<el-table-column type="index" label="序号" width="70" align="center" />
|
||||
<el-table-column prop="projectName" label="项目名称" min-width="200" show-overflow-tooltip />
|
||||
<el-table-column prop="projectCode" label="项目代码" width="150" align="center" />
|
||||
<el-table-column prop="year" label="年份" width="100" align="center" />
|
||||
<el-table-column prop="sort" label="排序" width="80" align="center" />
|
||||
<el-table-column prop="createTime" label="创建时间" width="180" align="center" />
|
||||
<el-table-column label="操作" align="center" fixed="right" width="150">
|
||||
<template #default="scope">
|
||||
<el-button icon="Edit" link type="primary" v-auth="'finance_recruit_project_edit'" @click="formDialogRef.openDialog('edit', scope.row)">编辑</el-button>
|
||||
<el-button icon="Delete" link type="danger" v-auth="'finance_recruit_project_del'" @click="handleDelete(scope.row)">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<el-table
|
||||
ref="tableRef"
|
||||
:data="state.dataList"
|
||||
v-loading="state.loading"
|
||||
stripe
|
||||
:cell-style="tableStyle.cellStyle"
|
||||
:header-cell-style="tableStyle.headerCellStyle"
|
||||
class="modern-table"
|
||||
>
|
||||
<el-table-column type="index" label="序号" width="70" align="center" />
|
||||
<el-table-column prop="projectName" label="项目名称" min-width="200" show-overflow-tooltip />
|
||||
<el-table-column prop="projectCode" label="项目代码" width="150" align="center" />
|
||||
<el-table-column prop="year" label="年份" width="100" align="center" />
|
||||
<el-table-column prop="sort" label="排序" width="80" align="center" />
|
||||
<el-table-column prop="createTime" label="创建时间" width="180" align="center" />
|
||||
<el-table-column label="操作" align="center" fixed="right" width="150">
|
||||
<template #default="scope">
|
||||
<el-button icon="Edit" link type="primary" v-auth="'finance_recruit_project_edit'" @click="formDialogRef.openDialog('edit', scope.row)"
|
||||
>编辑</el-button
|
||||
>
|
||||
<el-button icon="Delete" link type="danger" v-auth="'finance_recruit_project_del'" @click="handleDelete(scope.row)">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<pagination v-show="state.total > 0" :total="state.total" v-model:page="state.page" v-model:limit="state.limit" @pagination="getDataList" />
|
||||
</el-card>
|
||||
</div>
|
||||
<pagination v-show="state.total > 0" :total="state.total" v-model:page="state.page" v-model:limit="state.limit" @pagination="getDataList" />
|
||||
</el-card>
|
||||
</div>
|
||||
|
||||
<FormDialog ref="formDialogRef" @refresh="getDataList" />
|
||||
</div>
|
||||
<FormDialog ref="formDialogRef" @refresh="getDataList" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="FinanceRecruitProject">
|
||||
import { ref, reactive, defineAsyncComponent } from 'vue'
|
||||
import { BasicTableProps, useTable } from "/@/hooks/table";
|
||||
import { getPage, delObj } from "/@/api/finance/recruitProject";
|
||||
import { useMessage, useMessageBox } from "/@/hooks/message";
|
||||
import { Search, Document } from '@element-plus/icons-vue'
|
||||
import { ref, reactive, defineAsyncComponent } from 'vue';
|
||||
import { BasicTableProps, useTable } from '/@/hooks/table';
|
||||
import { getPage, delObj } from '/@/api/finance/recruitProject';
|
||||
import { useMessage, useMessageBox } from '/@/hooks/message';
|
||||
import { Search, Document } from '@element-plus/icons-vue';
|
||||
|
||||
const FormDialog = defineAsyncComponent(() => import('./form.vue'));
|
||||
|
||||
const tableRef = ref()
|
||||
const formDialogRef = ref()
|
||||
const searchFormRef = ref()
|
||||
const showSearch = ref(true)
|
||||
const tableRef = ref();
|
||||
const formDialogRef = ref();
|
||||
const searchFormRef = ref();
|
||||
const showSearch = ref(true);
|
||||
|
||||
const state: BasicTableProps = reactive<BasicTableProps>({
|
||||
pageList: getPage,
|
||||
queryForm: {
|
||||
projectName: '',
|
||||
projectCode: '',
|
||||
year: '',
|
||||
},
|
||||
createdIsNeed: true
|
||||
pageList: getPage,
|
||||
queryForm: {
|
||||
projectName: '',
|
||||
projectCode: '',
|
||||
year: '',
|
||||
},
|
||||
createdIsNeed: true,
|
||||
});
|
||||
|
||||
const { getDataList, tableStyle } = useTable(state);
|
||||
|
||||
const handleReset = () => {
|
||||
searchFormRef.value?.resetFields();
|
||||
getDataList();
|
||||
searchFormRef.value?.resetFields();
|
||||
getDataList();
|
||||
};
|
||||
|
||||
const handleDelete = async (row: any) => {
|
||||
try {
|
||||
await useMessageBox().confirm('确定要删除该记录吗?', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
});
|
||||
} catch {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
await useMessageBox().confirm('确定要删除该记录吗?', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
});
|
||||
} catch {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await delObj(row.id);
|
||||
useMessage().success('删除成功');
|
||||
getDataList();
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg || '删除失败');
|
||||
}
|
||||
try {
|
||||
await delObj(row.id);
|
||||
useMessage().success('删除成功');
|
||||
getDataList();
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg || '删除失败');
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import '/@/assets/styles/modern-page.scss';
|
||||
</style>
|
||||
</style>
|
||||
|
||||
@@ -1,43 +1,49 @@
|
||||
<template>
|
||||
<el-dialog :title="dataForm.id ? '编辑' : '新增'" v-model="visible" width="600px" :close-on-click-modal="false" draggable>
|
||||
<el-form ref="formRef" :model="dataForm" :rules="dataRules" label-width="100px" v-loading="loading">
|
||||
<el-form-item label="批次名称" prop="settingName">
|
||||
<el-input v-model="dataForm.settingName" placeholder="请输入批次名称" clearable />
|
||||
</el-form-item>
|
||||
<el-form-item label="类型" prop="type">
|
||||
<el-select v-model="dataForm.type" placeholder="请选择类型" style="width: 100%">
|
||||
<el-option label="普通类型" value="0" />
|
||||
<el-option label="新生收费" value="6" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="年份" prop="year">
|
||||
<el-date-picker v-model="dataForm.year" type="year" placeholder="选择年份" value-format="YYYY" style="width: 100%" />
|
||||
</el-form-item>
|
||||
<el-form-item label="截止时间" prop="lastTime">
|
||||
<el-date-picker v-model="dataForm.lastTime" type="datetime" placeholder="选择截止时间" value-format="YYYY-MM-DD HH:mm:ss" style="width: 100%" />
|
||||
</el-form-item>
|
||||
<el-form-item label="状态" prop="state">
|
||||
<el-select v-model="dataForm.state" placeholder="请选择状态" style="width: 100%">
|
||||
<el-option label="未开始" value="0" />
|
||||
<el-option label="进行中" value="30" />
|
||||
<el-option label="已结束" value="100" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="备注" prop="remarks">
|
||||
<el-input v-model="dataForm.remarks" type="textarea" :rows="3" placeholder="请输入备注" clearable />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="visible = false">取 消</el-button>
|
||||
<el-button type="primary" @click="onSubmit" :disabled="loading">确 定</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
<el-dialog :title="dataForm.id ? '编辑' : '新增'" v-model="visible" width="600px" :close-on-click-modal="false" draggable>
|
||||
<el-form ref="formRef" :model="dataForm" :rules="dataRules" label-width="100px" v-loading="loading">
|
||||
<el-form-item label="批次名称" prop="settingName">
|
||||
<el-input v-model="dataForm.settingName" placeholder="请输入批次名称" clearable />
|
||||
</el-form-item>
|
||||
<el-form-item label="类型" prop="type">
|
||||
<el-select v-model="dataForm.type" placeholder="请选择类型" style="width: 100%">
|
||||
<el-option label="普通类型" value="0" />
|
||||
<el-option label="新生收费" value="6" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="年份" prop="year">
|
||||
<el-date-picker v-model="dataForm.year" type="year" placeholder="选择年份" value-format="YYYY" style="width: 100%" />
|
||||
</el-form-item>
|
||||
<el-form-item label="截止时间" prop="lastTime">
|
||||
<el-date-picker
|
||||
v-model="dataForm.lastTime"
|
||||
type="datetime"
|
||||
placeholder="选择截止时间"
|
||||
value-format="YYYY-MM-DD HH:mm:ss"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="状态" prop="state">
|
||||
<el-select v-model="dataForm.state" placeholder="请选择状态" style="width: 100%">
|
||||
<el-option label="未开始" value="0" />
|
||||
<el-option label="进行中" value="30" />
|
||||
<el-option label="已结束" value="100" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="备注" prop="remarks">
|
||||
<el-input v-model="dataForm.remarks" type="textarea" :rows="3" placeholder="请输入备注" clearable />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="visible = false">取 消</el-button>
|
||||
<el-button type="primary" @click="onSubmit" :disabled="loading">确 定</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="FinanceRecruitSettingForm">
|
||||
import { reactive, ref, nextTick } from 'vue'
|
||||
import { reactive, ref, nextTick } from 'vue';
|
||||
import { getObj, addObj, editObj } from '/@/api/finance/recruitSetting';
|
||||
import { useMessage } from '/@/hooks/message';
|
||||
|
||||
@@ -45,91 +51,93 @@ const emit = defineEmits(['refresh']);
|
||||
|
||||
const formRef = ref();
|
||||
const dataForm = reactive({
|
||||
id: '',
|
||||
settingName: '',
|
||||
type: '6',
|
||||
year: '',
|
||||
lastTime: '',
|
||||
state: '0',
|
||||
remarks: '',
|
||||
id: '',
|
||||
settingName: '',
|
||||
type: '6',
|
||||
year: '',
|
||||
lastTime: '',
|
||||
state: '0',
|
||||
remarks: '',
|
||||
});
|
||||
const visible = ref(false);
|
||||
const loading = ref(false);
|
||||
|
||||
const dataRules = ref({
|
||||
settingName: [{ required: true, message: '请输入批次名称', trigger: 'blur' }],
|
||||
type: [{ required: true, message: '请选择类型', trigger: 'change' }],
|
||||
year: [{ required: true, message: '请选择年份', trigger: 'change' }],
|
||||
lastTime: [{ required: true, message: '请选择截止时间', trigger: 'change' }],
|
||||
state: [{ required: true, message: '请选择状态', trigger: 'change' }],
|
||||
settingName: [{ required: true, message: '请输入批次名称', trigger: 'blur' }],
|
||||
type: [{ required: true, message: '请选择类型', trigger: 'change' }],
|
||||
year: [{ required: true, message: '请选择年份', trigger: 'change' }],
|
||||
lastTime: [{ required: true, message: '请选择截止时间', trigger: 'change' }],
|
||||
state: [{ required: true, message: '请选择状态', trigger: 'change' }],
|
||||
});
|
||||
|
||||
const openDialog = async (type: string, rowData?: any) => {
|
||||
visible.value = true;
|
||||
dataForm.id = '';
|
||||
dataForm.settingName = '';
|
||||
dataForm.type = '6';
|
||||
dataForm.year = '';
|
||||
dataForm.lastTime = '';
|
||||
dataForm.state = '0';
|
||||
dataForm.remarks = '';
|
||||
visible.value = true;
|
||||
dataForm.id = '';
|
||||
dataForm.settingName = '';
|
||||
dataForm.type = '6';
|
||||
dataForm.year = '';
|
||||
dataForm.lastTime = '';
|
||||
dataForm.state = '0';
|
||||
dataForm.remarks = '';
|
||||
|
||||
nextTick(() => {
|
||||
formRef.value?.resetFields();
|
||||
if (type === 'edit' && rowData?.id) {
|
||||
loading.value = true;
|
||||
getObj(rowData.id).then((res: any) => {
|
||||
if (res.data) {
|
||||
Object.assign(dataForm, {
|
||||
id: res.data.id || '',
|
||||
settingName: res.data.settingName || '',
|
||||
type: res.data.type || '6',
|
||||
year: res.data.year ? String(res.data.year) : '',
|
||||
lastTime: res.data.lastTime || '',
|
||||
state: res.data.state || '0',
|
||||
remarks: res.data.remarks || '',
|
||||
});
|
||||
}
|
||||
loading.value = false;
|
||||
}).catch((err: any) => {
|
||||
useMessage().error(err.msg || '获取详情失败');
|
||||
loading.value = false;
|
||||
});
|
||||
}
|
||||
});
|
||||
nextTick(() => {
|
||||
formRef.value?.resetFields();
|
||||
if (type === 'edit' && rowData?.id) {
|
||||
loading.value = true;
|
||||
getObj(rowData.id)
|
||||
.then((res: any) => {
|
||||
if (res.data) {
|
||||
Object.assign(dataForm, {
|
||||
id: res.data.id || '',
|
||||
settingName: res.data.settingName || '',
|
||||
type: res.data.type || '6',
|
||||
year: res.data.year ? String(res.data.year) : '',
|
||||
lastTime: res.data.lastTime || '',
|
||||
state: res.data.state || '0',
|
||||
remarks: res.data.remarks || '',
|
||||
});
|
||||
}
|
||||
loading.value = false;
|
||||
})
|
||||
.catch((err: any) => {
|
||||
useMessage().error(err.msg || '获取详情失败');
|
||||
loading.value = false;
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const onSubmit = async () => {
|
||||
if (loading.value) return;
|
||||
loading.value = true;
|
||||
if (loading.value) return;
|
||||
loading.value = true;
|
||||
|
||||
try {
|
||||
const valid = await formRef.value.validate().catch(() => {});
|
||||
if (!valid) {
|
||||
loading.value = false;
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
const valid = await formRef.value.validate().catch(() => {});
|
||||
if (!valid) {
|
||||
loading.value = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
const submitData = {
|
||||
...dataForm,
|
||||
year: dataForm.year ? parseInt(dataForm.year) : null,
|
||||
};
|
||||
const submitData = {
|
||||
...dataForm,
|
||||
year: dataForm.year ? parseInt(dataForm.year) : null,
|
||||
};
|
||||
|
||||
if (dataForm.id) {
|
||||
await editObj(submitData);
|
||||
useMessage().success('编辑成功');
|
||||
} else {
|
||||
await addObj(submitData);
|
||||
useMessage().success('新增成功');
|
||||
}
|
||||
visible.value = false;
|
||||
emit('refresh');
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg || (dataForm.id ? '编辑失败' : '新增失败'));
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
if (dataForm.id) {
|
||||
await editObj(submitData);
|
||||
useMessage().success('编辑成功');
|
||||
} else {
|
||||
await addObj(submitData);
|
||||
useMessage().success('新增成功');
|
||||
}
|
||||
visible.value = false;
|
||||
emit('refresh');
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg || (dataForm.id ? '编辑失败' : '新增失败'));
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
defineExpose({ openDialog });
|
||||
</script>
|
||||
</script>
|
||||
|
||||
@@ -1,139 +1,151 @@
|
||||
<template>
|
||||
<div class="modern-page-container">
|
||||
<div class="page-wrapper">
|
||||
<el-card v-show="showSearch" class="search-card" shadow="never">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span class="card-title">
|
||||
<el-icon class="title-icon"><Search /></el-icon>
|
||||
筛选条件
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
<el-form :model="state.queryForm" ref="searchFormRef" :inline="true" @keyup.enter="getDataList" class="search-form">
|
||||
<el-form-item label="批次名称" prop="settingName">
|
||||
<el-input v-model="state.queryForm.settingName" placeholder="请输入批次名称" clearable style="width: 200px" />
|
||||
</el-form-item>
|
||||
<el-form-item label="年份" prop="year">
|
||||
<el-date-picker v-model="state.queryForm.year" type="year" placeholder="选择年份" value-format="YYYY" style="width: 150px" />
|
||||
</el-form-item>
|
||||
<el-form-item label="状态" prop="state">
|
||||
<el-select v-model="state.queryForm.state" placeholder="请选择状态" clearable style="width: 150px">
|
||||
<el-option label="未开始" value="0" />
|
||||
<el-option label="进行中" value="30" />
|
||||
<el-option label="已结束" value="100" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="Search" @click="getDataList">查询</el-button>
|
||||
<el-button icon="Refresh" @click="handleReset">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
<div class="modern-page-container">
|
||||
<div class="page-wrapper">
|
||||
<el-card v-show="showSearch" class="search-card" shadow="never">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span class="card-title">
|
||||
<el-icon class="title-icon"><Search /></el-icon>
|
||||
筛选条件
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
<el-form :model="state.queryForm" ref="searchFormRef" :inline="true" @keyup.enter="getDataList" class="search-form">
|
||||
<el-form-item label="批次名称" prop="settingName">
|
||||
<el-input v-model="state.queryForm.settingName" placeholder="请输入批次名称" clearable style="width: 200px" />
|
||||
</el-form-item>
|
||||
<el-form-item label="年份" prop="year">
|
||||
<el-date-picker v-model="state.queryForm.year" type="year" placeholder="选择年份" value-format="YYYY" style="width: 150px" />
|
||||
</el-form-item>
|
||||
<el-form-item label="状态" prop="state">
|
||||
<el-select v-model="state.queryForm.state" placeholder="请选择状态" clearable style="width: 150px">
|
||||
<el-option label="未开始" value="0" />
|
||||
<el-option label="进行中" value="30" />
|
||||
<el-option label="已结束" value="100" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="Search" @click="getDataList">查询</el-button>
|
||||
<el-button icon="Refresh" @click="handleReset">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
|
||||
<el-card class="content-card" shadow="never">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span class="card-title">
|
||||
<el-icon class="title-icon"><Document /></el-icon>
|
||||
收费批次设置
|
||||
</span>
|
||||
<div class="header-actions">
|
||||
<el-button icon="FolderAdd" type="primary" @click="formDialogRef.openDialog('add')" v-auth="'finance_recruit_setting_add'">新增</el-button>
|
||||
<right-toolbar v-model:showSearch="showSearch" class="ml10" @queryTable="getDataList" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<el-card class="content-card" shadow="never">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span class="card-title">
|
||||
<el-icon class="title-icon"><Document /></el-icon>
|
||||
收费批次设置
|
||||
</span>
|
||||
<div class="header-actions">
|
||||
<el-button icon="FolderAdd" type="primary" @click="formDialogRef.openDialog('add')" v-auth="'finance_recruit_setting_add'"
|
||||
>新增</el-button
|
||||
>
|
||||
<right-toolbar v-model:showSearch="showSearch" class="ml10" @queryTable="getDataList" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<el-table ref="tableRef" :data="state.dataList" v-loading="state.loading" stripe :cell-style="tableStyle.cellStyle" :header-cell-style="tableStyle.headerCellStyle" class="modern-table">
|
||||
<el-table-column type="index" label="序号" width="70" align="center" />
|
||||
<el-table-column prop="settingName" label="批次名称" min-width="200" show-overflow-tooltip />
|
||||
<el-table-column prop="type" label="类型" width="120" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-tag v-if="row.type === '0'" type="info">普通类型</el-tag>
|
||||
<el-tag v-else-if="row.type === '6'" type="success">新生收费</el-tag>
|
||||
<span v-else>{{ row.type }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="year" label="年份" width="100" align="center" />
|
||||
<el-table-column prop="lastTime" label="截止时间" width="180" align="center" />
|
||||
<el-table-column prop="state" label="状态" width="100" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-tag v-if="row.state === '0'" type="info">未开始</el-tag>
|
||||
<el-tag v-else-if="row.state === '30'" type="warning">进行中</el-tag>
|
||||
<el-tag v-else-if="row.state === '100'" type="success">已结束</el-tag>
|
||||
<span v-else>{{ row.state }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="createTime" label="创建时间" width="180" align="center" />
|
||||
<el-table-column label="操作" align="center" fixed="right" width="150">
|
||||
<template #default="scope">
|
||||
<el-button icon="Edit" link type="primary" v-auth="'finance_recruit_setting_edit'" @click="formDialogRef.openDialog('edit', scope.row)">编辑</el-button>
|
||||
<el-button icon="Delete" link type="danger" v-auth="'finance_recruit_setting_del'" @click="handleDelete(scope.row)">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<el-table
|
||||
ref="tableRef"
|
||||
:data="state.dataList"
|
||||
v-loading="state.loading"
|
||||
stripe
|
||||
:cell-style="tableStyle.cellStyle"
|
||||
:header-cell-style="tableStyle.headerCellStyle"
|
||||
class="modern-table"
|
||||
>
|
||||
<el-table-column type="index" label="序号" width="70" align="center" />
|
||||
<el-table-column prop="settingName" label="批次名称" min-width="200" show-overflow-tooltip />
|
||||
<el-table-column prop="type" label="类型" width="120" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-tag v-if="row.type === '0'" type="info">普通类型</el-tag>
|
||||
<el-tag v-else-if="row.type === '6'" type="success">新生收费</el-tag>
|
||||
<span v-else>{{ row.type }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="year" label="年份" width="100" align="center" />
|
||||
<el-table-column prop="lastTime" label="截止时间" width="180" align="center" />
|
||||
<el-table-column prop="state" label="状态" width="100" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-tag v-if="row.state === '0'" type="info">未开始</el-tag>
|
||||
<el-tag v-else-if="row.state === '30'" type="warning">进行中</el-tag>
|
||||
<el-tag v-else-if="row.state === '100'" type="success">已结束</el-tag>
|
||||
<span v-else>{{ row.state }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="createTime" label="创建时间" width="180" align="center" />
|
||||
<el-table-column label="操作" align="center" fixed="right" width="150">
|
||||
<template #default="scope">
|
||||
<el-button icon="Edit" link type="primary" v-auth="'finance_recruit_setting_edit'" @click="formDialogRef.openDialog('edit', scope.row)"
|
||||
>编辑</el-button
|
||||
>
|
||||
<el-button icon="Delete" link type="danger" v-auth="'finance_recruit_setting_del'" @click="handleDelete(scope.row)">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<pagination v-show="state.total > 0" :total="state.total" v-model:page="state.page" v-model:limit="state.limit" @pagination="getDataList" />
|
||||
</el-card>
|
||||
</div>
|
||||
<pagination v-show="state.total > 0" :total="state.total" v-model:page="state.page" v-model:limit="state.limit" @pagination="getDataList" />
|
||||
</el-card>
|
||||
</div>
|
||||
|
||||
<FormDialog ref="formDialogRef" @refresh="getDataList" />
|
||||
</div>
|
||||
<FormDialog ref="formDialogRef" @refresh="getDataList" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="FinanceRecruitSetting">
|
||||
import { ref, reactive, defineAsyncComponent } from 'vue'
|
||||
import { BasicTableProps, useTable } from "/@/hooks/table";
|
||||
import { getPage, delObj } from "/@/api/finance/recruitSetting";
|
||||
import { useMessage, useMessageBox } from "/@/hooks/message";
|
||||
import { Search, Document } from '@element-plus/icons-vue'
|
||||
import { ref, reactive, defineAsyncComponent } from 'vue';
|
||||
import { BasicTableProps, useTable } from '/@/hooks/table';
|
||||
import { getPage, delObj } from '/@/api/finance/recruitSetting';
|
||||
import { useMessage, useMessageBox } from '/@/hooks/message';
|
||||
import { Search, Document } from '@element-plus/icons-vue';
|
||||
|
||||
const FormDialog = defineAsyncComponent(() => import('./form.vue'));
|
||||
|
||||
const tableRef = ref()
|
||||
const formDialogRef = ref()
|
||||
const searchFormRef = ref()
|
||||
const showSearch = ref(true)
|
||||
const tableRef = ref();
|
||||
const formDialogRef = ref();
|
||||
const searchFormRef = ref();
|
||||
const showSearch = ref(true);
|
||||
|
||||
const state: BasicTableProps = reactive<BasicTableProps>({
|
||||
pageList: getPage,
|
||||
queryForm: {
|
||||
settingName: '',
|
||||
year: '',
|
||||
state: '',
|
||||
},
|
||||
createdIsNeed: true
|
||||
pageList: getPage,
|
||||
queryForm: {
|
||||
settingName: '',
|
||||
year: '',
|
||||
state: '',
|
||||
},
|
||||
createdIsNeed: true,
|
||||
});
|
||||
|
||||
const { getDataList, tableStyle } = useTable(state);
|
||||
|
||||
const handleReset = () => {
|
||||
searchFormRef.value?.resetFields();
|
||||
getDataList();
|
||||
searchFormRef.value?.resetFields();
|
||||
getDataList();
|
||||
};
|
||||
|
||||
const handleDelete = async (row: any) => {
|
||||
try {
|
||||
await useMessageBox().confirm('确定要删除该记录吗?', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
});
|
||||
} catch {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
await useMessageBox().confirm('确定要删除该记录吗?', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
});
|
||||
} catch {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await delObj(row.id);
|
||||
useMessage().success('删除成功');
|
||||
getDataList();
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg || '删除失败');
|
||||
}
|
||||
try {
|
||||
await delObj(row.id);
|
||||
useMessage().success('删除成功');
|
||||
getDataList();
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg || '删除失败');
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import '/@/assets/styles/modern-page.scss';
|
||||
</style>
|
||||
</style>
|
||||
|
||||
@@ -1,93 +1,93 @@
|
||||
<template>
|
||||
<el-dialog title="收费明细" v-model="visible" width="900px" :close-on-click-modal="false" draggable>
|
||||
<div class="fee-header">
|
||||
<span>学号: {{ serialNumber }}</span>
|
||||
<span style="margin-left: 20px;">姓名: {{ realName }}</span>
|
||||
<el-button type="primary" size="small" style="margin-left: 20px;" @click="handleBindProject">绑定收费项目</el-button>
|
||||
</div>
|
||||
<el-table :data="feeList" v-loading="loading" stripe border style="margin-top: 15px;">
|
||||
<el-table-column type="index" label="序号" width="60" align="center" />
|
||||
<el-table-column prop="projectCode" label="项目代码" width="120" align="center" />
|
||||
<el-table-column prop="money" label="应缴金额" width="120" align="right">
|
||||
<template #default="{ row }">
|
||||
{{ row.money ? Number(row.money).toFixed(2) : '0.00' }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="status" label="状态" width="100" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-tag v-if="row.status === '0'" type="info">未缴费</el-tag>
|
||||
<el-tag v-else-if="row.status === '10'" type="success">已缴费</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="payType" label="缴费方式" width="120" align="center">
|
||||
<template #default="{ row }">
|
||||
<span v-if="row.payType === '0'">-</span>
|
||||
<span v-else>{{ row.payType }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="paiedMoney" label="实缴金额" width="120" align="right">
|
||||
<template #default="{ row }">
|
||||
{{ row.paiedMoney ? Number(row.paiedMoney).toFixed(2) : '-' }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="payTime" label="缴费时间" width="180" align="center" />
|
||||
<el-table-column label="操作" align="center" fixed="right" width="180">
|
||||
<template #default="scope">
|
||||
<template v-if="scope.row.status === '0'">
|
||||
<el-button link type="primary" size="small" @click="handlePay(scope.row)">缴费</el-button>
|
||||
<el-button link type="danger" size="small" @click="handleDeleteFee(scope.row)">删除</el-button>
|
||||
</template>
|
||||
<template v-else>
|
||||
<el-button link type="warning" size="small" @click="handleCancelPay(scope.row)">取消缴费</el-button>
|
||||
</template>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="visible = false">关 闭</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
<el-dialog title="收费明细" v-model="visible" width="900px" :close-on-click-modal="false" draggable>
|
||||
<div class="fee-header">
|
||||
<span>学号: {{ serialNumber }}</span>
|
||||
<span style="margin-left: 20px">姓名: {{ realName }}</span>
|
||||
<el-button type="primary" size="small" style="margin-left: 20px" @click="handleBindProject">绑定收费项目</el-button>
|
||||
</div>
|
||||
<el-table :data="feeList" v-loading="loading" stripe border style="margin-top: 15px">
|
||||
<el-table-column type="index" label="序号" width="60" align="center" />
|
||||
<el-table-column prop="projectCode" label="项目代码" width="120" align="center" />
|
||||
<el-table-column prop="money" label="应缴金额" width="120" align="right">
|
||||
<template #default="{ row }">
|
||||
{{ row.money ? Number(row.money).toFixed(2) : '0.00' }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="status" label="状态" width="100" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-tag v-if="row.status === '0'" type="info">未缴费</el-tag>
|
||||
<el-tag v-else-if="row.status === '10'" type="success">已缴费</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="payType" label="缴费方式" width="120" align="center">
|
||||
<template #default="{ row }">
|
||||
<span v-if="row.payType === '0'">-</span>
|
||||
<span v-else>{{ row.payType }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="paiedMoney" label="实缴金额" width="120" align="right">
|
||||
<template #default="{ row }">
|
||||
{{ row.paiedMoney ? Number(row.paiedMoney).toFixed(2) : '-' }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="payTime" label="缴费时间" width="180" align="center" />
|
||||
<el-table-column label="操作" align="center" fixed="right" width="180">
|
||||
<template #default="scope">
|
||||
<template v-if="scope.row.status === '0'">
|
||||
<el-button link type="primary" size="small" @click="handlePay(scope.row)">缴费</el-button>
|
||||
<el-button link type="danger" size="small" @click="handleDeleteFee(scope.row)">删除</el-button>
|
||||
</template>
|
||||
<template v-else>
|
||||
<el-button link type="warning" size="small" @click="handleCancelPay(scope.row)">取消缴费</el-button>
|
||||
</template>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="visible = false">关 闭</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<el-dialog title="绑定收费项目" v-model="bindDialogVisible" width="500px">
|
||||
<el-form label-width="100px">
|
||||
<el-form-item label="选择项目">
|
||||
<el-select v-model="selectedProjectCodes" multiple placeholder="请选择收费项目" style="width: 100%">
|
||||
<el-option v-for="item in projectList" :key="item.projectCode" :label="item.projectName" :value="item.projectCode" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button @click="bindDialogVisible = false">取 消</el-button>
|
||||
<el-button type="primary" @click="submitBind">确 定</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
<el-dialog title="绑定收费项目" v-model="bindDialogVisible" width="500px">
|
||||
<el-form label-width="100px">
|
||||
<el-form-item label="选择项目">
|
||||
<el-select v-model="selectedProjectCodes" multiple placeholder="请选择收费项目" style="width: 100%">
|
||||
<el-option v-for="item in projectList" :key="item.projectCode" :label="item.projectName" :value="item.projectCode" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button @click="bindDialogVisible = false">取 消</el-button>
|
||||
<el-button type="primary" @click="submitBind">确 定</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<el-dialog title="缴费登记" v-model="payDialogVisible" width="400px">
|
||||
<el-form label-width="100px">
|
||||
<el-form-item label="缴费金额">
|
||||
<el-input-number v-model="payForm.money" :min="0" :precision="2" style="width: 100%" />
|
||||
</el-form-item>
|
||||
<el-form-item label="缴费方式">
|
||||
<el-select v-model="payForm.payType" placeholder="请选择缴费方式" style="width: 100%">
|
||||
<el-option label="现金" value="20" />
|
||||
<el-option label="银行转账" value="30" />
|
||||
<el-option label="微信" value="40" />
|
||||
<el-option label="支付宝" value="21" />
|
||||
<el-option label="其他" value="22" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button @click="payDialogVisible = false">取 消</el-button>
|
||||
<el-button type="primary" @click="submitPay">确 定</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
<el-dialog title="缴费登记" v-model="payDialogVisible" width="400px">
|
||||
<el-form label-width="100px">
|
||||
<el-form-item label="缴费金额">
|
||||
<el-input-number v-model="payForm.money" :min="0" :precision="2" style="width: 100%" />
|
||||
</el-form-item>
|
||||
<el-form-item label="缴费方式">
|
||||
<el-select v-model="payForm.payType" placeholder="请选择缴费方式" style="width: 100%">
|
||||
<el-option label="现金" value="20" />
|
||||
<el-option label="银行转账" value="30" />
|
||||
<el-option label="微信" value="40" />
|
||||
<el-option label="支付宝" value="21" />
|
||||
<el-option label="其他" value="22" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button @click="payDialogVisible = false">取 消</el-button>
|
||||
<el-button type="primary" @click="submitPay">确 定</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="FinanceRecruitStuFeeDetail">
|
||||
import { ref, reactive } from 'vue'
|
||||
import { ref, reactive } from 'vue';
|
||||
import { getBySerialNumber, bindProject, payRegister, cancelPay, delObj } from '/@/api/finance/recruitStuProject';
|
||||
import { getList } from '/@/api/finance/recruitProject';
|
||||
import { useMessage, useMessageBox } from '/@/hooks/message';
|
||||
@@ -104,99 +104,99 @@ const selectedProjectCodes = ref<string[]>([]);
|
||||
|
||||
const payDialogVisible = ref(false);
|
||||
const payForm = reactive({
|
||||
id: '',
|
||||
money: 0,
|
||||
payType: '',
|
||||
id: '',
|
||||
money: 0,
|
||||
payType: '',
|
||||
});
|
||||
|
||||
const openDialog = async (stuSerialNumber: string, stuRealName: string) => {
|
||||
serialNumber.value = stuSerialNumber;
|
||||
realName.value = stuRealName;
|
||||
visible.value = true;
|
||||
await loadFeeList();
|
||||
serialNumber.value = stuSerialNumber;
|
||||
realName.value = stuRealName;
|
||||
visible.value = true;
|
||||
await loadFeeList();
|
||||
};
|
||||
|
||||
const loadFeeList = async () => {
|
||||
loading.value = true;
|
||||
try {
|
||||
const res = await getBySerialNumber(serialNumber.value);
|
||||
feeList.value = res?.data || [];
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg || '获取收费明细失败');
|
||||
feeList.value = [];
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
loading.value = true;
|
||||
try {
|
||||
const res = await getBySerialNumber(serialNumber.value);
|
||||
feeList.value = res?.data || [];
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg || '获取收费明细失败');
|
||||
feeList.value = [];
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
const handleBindProject = async () => {
|
||||
try {
|
||||
const res = await getList({});
|
||||
projectList.value = res?.data || [];
|
||||
selectedProjectCodes.value = [];
|
||||
bindDialogVisible.value = true;
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg || '获取收费项目失败');
|
||||
}
|
||||
try {
|
||||
const res = await getList({});
|
||||
projectList.value = res?.data || [];
|
||||
selectedProjectCodes.value = [];
|
||||
bindDialogVisible.value = true;
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg || '获取收费项目失败');
|
||||
}
|
||||
};
|
||||
|
||||
const submitBind = async () => {
|
||||
if (selectedProjectCodes.value.length === 0) {
|
||||
useMessage().warning('请选择收费项目');
|
||||
return;
|
||||
}
|
||||
try {
|
||||
await bindProject(serialNumber.value, selectedProjectCodes.value);
|
||||
useMessage().success('绑定成功');
|
||||
bindDialogVisible.value = false;
|
||||
await loadFeeList();
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg || '绑定失败');
|
||||
}
|
||||
if (selectedProjectCodes.value.length === 0) {
|
||||
useMessage().warning('请选择收费项目');
|
||||
return;
|
||||
}
|
||||
try {
|
||||
await bindProject(serialNumber.value, selectedProjectCodes.value);
|
||||
useMessage().success('绑定成功');
|
||||
bindDialogVisible.value = false;
|
||||
await loadFeeList();
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg || '绑定失败');
|
||||
}
|
||||
};
|
||||
|
||||
const handlePay = (row: any) => {
|
||||
payForm.id = row.id;
|
||||
payForm.money = Number(row.money) || 0;
|
||||
payForm.payType = '';
|
||||
payDialogVisible.value = true;
|
||||
payForm.id = row.id;
|
||||
payForm.money = Number(row.money) || 0;
|
||||
payForm.payType = '';
|
||||
payDialogVisible.value = true;
|
||||
};
|
||||
|
||||
const submitPay = async () => {
|
||||
if (!payForm.payType) {
|
||||
useMessage().warning('请选择缴费方式');
|
||||
return;
|
||||
}
|
||||
try {
|
||||
await payRegister(payForm.id, payForm.payType);
|
||||
useMessage().success('缴费成功');
|
||||
payDialogVisible.value = false;
|
||||
await loadFeeList();
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg || '缴费失败');
|
||||
}
|
||||
if (!payForm.payType) {
|
||||
useMessage().warning('请选择缴费方式');
|
||||
return;
|
||||
}
|
||||
try {
|
||||
await payRegister(payForm.id, payForm.payType);
|
||||
useMessage().success('缴费成功');
|
||||
payDialogVisible.value = false;
|
||||
await loadFeeList();
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg || '缴费失败');
|
||||
}
|
||||
};
|
||||
|
||||
const handleCancelPay = async (row: any) => {
|
||||
try {
|
||||
await useMessageBox().confirm('确定要取消该缴费记录吗?', '提示', { type: 'warning' });
|
||||
await cancelPay(row.id);
|
||||
useMessage().success('取消成功');
|
||||
await loadFeeList();
|
||||
} catch {
|
||||
// 用户取消操作
|
||||
}
|
||||
try {
|
||||
await useMessageBox().confirm('确定要取消该缴费记录吗?', '提示', { type: 'warning' });
|
||||
await cancelPay(row.id);
|
||||
useMessage().success('取消成功');
|
||||
await loadFeeList();
|
||||
} catch {
|
||||
// 用户取消操作
|
||||
}
|
||||
};
|
||||
|
||||
const handleDeleteFee = async (row: any) => {
|
||||
try {
|
||||
await useMessageBox().confirm('确定要删除该收费项目吗?', '提示', { type: 'warning' });
|
||||
await delObj(row.id);
|
||||
useMessage().success('删除成功');
|
||||
await loadFeeList();
|
||||
} catch {
|
||||
// 用户取消操作
|
||||
}
|
||||
try {
|
||||
await useMessageBox().confirm('确定要删除该收费项目吗?', '提示', { type: 'warning' });
|
||||
await delObj(row.id);
|
||||
useMessage().success('删除成功');
|
||||
await loadFeeList();
|
||||
} catch {
|
||||
// 用户取消操作
|
||||
}
|
||||
};
|
||||
|
||||
defineExpose({ openDialog });
|
||||
@@ -204,8 +204,8 @@ defineExpose({ openDialog });
|
||||
|
||||
<style scoped>
|
||||
.fee-header {
|
||||
padding: 10px 0;
|
||||
font-size: 14px;
|
||||
color: #606266;
|
||||
padding: 10px 0;
|
||||
font-size: 14px;
|
||||
color: #606266;
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
||||
@@ -1,49 +1,49 @@
|
||||
<template>
|
||||
<el-dialog :title="dataForm.id ? '编辑' : '新增'" v-model="visible" width="600px" :close-on-click-modal="false" draggable>
|
||||
<el-form ref="formRef" :model="dataForm" :rules="dataRules" label-width="100px" v-loading="loading">
|
||||
<el-form-item label="学号" prop="serialNumber">
|
||||
<el-input v-model="dataForm.serialNumber" placeholder="请输入学号" clearable />
|
||||
</el-form-item>
|
||||
<el-form-item label="姓名" prop="realName">
|
||||
<el-input v-model="dataForm.realName" placeholder="请输入姓名" clearable />
|
||||
</el-form-item>
|
||||
<el-form-item label="学生来源" prop="stuSource">
|
||||
<el-select v-model="dataForm.stuSource" placeholder="请选择学生来源" style="width: 100%">
|
||||
<el-option label="本地" value="1" />
|
||||
<el-option label="外地" value="2" />
|
||||
<el-option label="其他" value="3" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="年份" prop="year">
|
||||
<el-date-picker v-model="dataForm.year" type="year" placeholder="选择年份" value-format="YYYY" style="width: 100%" />
|
||||
</el-form-item>
|
||||
<el-form-item label="手机号" prop="phone">
|
||||
<el-input v-model="dataForm.phone" placeholder="请输入手机号" clearable />
|
||||
</el-form-item>
|
||||
<el-form-item label="缴费码" prop="payCode">
|
||||
<el-input v-model="dataForm.payCode" placeholder="请输入缴费码" clearable />
|
||||
</el-form-item>
|
||||
<el-form-item label="是否取消" prop="isCancal">
|
||||
<el-radio-group v-model="dataForm.isCancal">
|
||||
<el-radio label="0">正常</el-radio>
|
||||
<el-radio label="1">已取消</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="备注" prop="remarks">
|
||||
<el-input v-model="dataForm.remarks" type="textarea" :rows="3" placeholder="请输入备注" clearable />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="visible = false">取 消</el-button>
|
||||
<el-button type="primary" @click="onSubmit" :disabled="loading">确 定</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
<el-dialog :title="dataForm.id ? '编辑' : '新增'" v-model="visible" width="600px" :close-on-click-modal="false" draggable>
|
||||
<el-form ref="formRef" :model="dataForm" :rules="dataRules" label-width="100px" v-loading="loading">
|
||||
<el-form-item label="学号" prop="serialNumber">
|
||||
<el-input v-model="dataForm.serialNumber" placeholder="请输入学号" clearable />
|
||||
</el-form-item>
|
||||
<el-form-item label="姓名" prop="realName">
|
||||
<el-input v-model="dataForm.realName" placeholder="请输入姓名" clearable />
|
||||
</el-form-item>
|
||||
<el-form-item label="学生来源" prop="stuSource">
|
||||
<el-select v-model="dataForm.stuSource" placeholder="请选择学生来源" style="width: 100%">
|
||||
<el-option label="本地" value="1" />
|
||||
<el-option label="外地" value="2" />
|
||||
<el-option label="其他" value="3" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="年份" prop="year">
|
||||
<el-date-picker v-model="dataForm.year" type="year" placeholder="选择年份" value-format="YYYY" style="width: 100%" />
|
||||
</el-form-item>
|
||||
<el-form-item label="手机号" prop="phone">
|
||||
<el-input v-model="dataForm.phone" placeholder="请输入手机号" clearable />
|
||||
</el-form-item>
|
||||
<el-form-item label="缴费码" prop="payCode">
|
||||
<el-input v-model="dataForm.payCode" placeholder="请输入缴费码" clearable />
|
||||
</el-form-item>
|
||||
<el-form-item label="是否取消" prop="isCancal">
|
||||
<el-radio-group v-model="dataForm.isCancal">
|
||||
<el-radio label="0">正常</el-radio>
|
||||
<el-radio label="1">已取消</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="备注" prop="remarks">
|
||||
<el-input v-model="dataForm.remarks" type="textarea" :rows="3" placeholder="请输入备注" clearable />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="visible = false">取 消</el-button>
|
||||
<el-button type="primary" @click="onSubmit" :disabled="loading">确 定</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="FinanceRecruitStuForm">
|
||||
import { reactive, ref, nextTick } from 'vue'
|
||||
import { reactive, ref, nextTick } from 'vue';
|
||||
import { getObj, addObj, editObj } from '/@/api/finance/recruitStu';
|
||||
import { useMessage } from '/@/hooks/message';
|
||||
|
||||
@@ -51,97 +51,99 @@ const emit = defineEmits(['refresh']);
|
||||
|
||||
const formRef = ref();
|
||||
const dataForm = reactive({
|
||||
id: '',
|
||||
serialNumber: '',
|
||||
realName: '',
|
||||
stuSource: '1',
|
||||
year: '',
|
||||
phone: '',
|
||||
payCode: '',
|
||||
isCancal: '0',
|
||||
remarks: '',
|
||||
id: '',
|
||||
serialNumber: '',
|
||||
realName: '',
|
||||
stuSource: '1',
|
||||
year: '',
|
||||
phone: '',
|
||||
payCode: '',
|
||||
isCancal: '0',
|
||||
remarks: '',
|
||||
});
|
||||
const visible = ref(false);
|
||||
const loading = ref(false);
|
||||
|
||||
const dataRules = ref({
|
||||
serialNumber: [{ required: true, message: '请输入学号', trigger: 'blur' }],
|
||||
realName: [{ required: true, message: '请输入姓名', trigger: 'blur' }],
|
||||
stuSource: [{ required: true, message: '请选择学生来源', trigger: 'change' }],
|
||||
year: [{ required: true, message: '请选择年份', trigger: 'change' }],
|
||||
phone: [{ required: true, message: '请输入手机号', trigger: 'blur' }],
|
||||
serialNumber: [{ required: true, message: '请输入学号', trigger: 'blur' }],
|
||||
realName: [{ required: true, message: '请输入姓名', trigger: 'blur' }],
|
||||
stuSource: [{ required: true, message: '请选择学生来源', trigger: 'change' }],
|
||||
year: [{ required: true, message: '请选择年份', trigger: 'change' }],
|
||||
phone: [{ required: true, message: '请输入手机号', trigger: 'blur' }],
|
||||
});
|
||||
|
||||
const openDialog = async (type: string, rowData?: any) => {
|
||||
visible.value = true;
|
||||
dataForm.id = '';
|
||||
dataForm.serialNumber = '';
|
||||
dataForm.realName = '';
|
||||
dataForm.stuSource = '1';
|
||||
dataForm.year = '';
|
||||
dataForm.phone = '';
|
||||
dataForm.payCode = '';
|
||||
dataForm.isCancal = '0';
|
||||
dataForm.remarks = '';
|
||||
visible.value = true;
|
||||
dataForm.id = '';
|
||||
dataForm.serialNumber = '';
|
||||
dataForm.realName = '';
|
||||
dataForm.stuSource = '1';
|
||||
dataForm.year = '';
|
||||
dataForm.phone = '';
|
||||
dataForm.payCode = '';
|
||||
dataForm.isCancal = '0';
|
||||
dataForm.remarks = '';
|
||||
|
||||
nextTick(() => {
|
||||
formRef.value?.resetFields();
|
||||
if (type === 'edit' && rowData?.id) {
|
||||
loading.value = true;
|
||||
getObj(rowData.id).then((res: any) => {
|
||||
if (res.data) {
|
||||
Object.assign(dataForm, {
|
||||
id: res.data.id || '',
|
||||
serialNumber: res.data.serialNumber || '',
|
||||
realName: res.data.realName || '',
|
||||
stuSource: res.data.stuSource || '1',
|
||||
year: res.data.year ? String(res.data.year) : '',
|
||||
phone: res.data.phone || '',
|
||||
payCode: res.data.payCode || '',
|
||||
isCancal: res.data.isCancal || '0',
|
||||
remarks: res.data.remarks || '',
|
||||
});
|
||||
}
|
||||
loading.value = false;
|
||||
}).catch((err: any) => {
|
||||
useMessage().error(err.msg || '获取详情失败');
|
||||
loading.value = false;
|
||||
});
|
||||
}
|
||||
});
|
||||
nextTick(() => {
|
||||
formRef.value?.resetFields();
|
||||
if (type === 'edit' && rowData?.id) {
|
||||
loading.value = true;
|
||||
getObj(rowData.id)
|
||||
.then((res: any) => {
|
||||
if (res.data) {
|
||||
Object.assign(dataForm, {
|
||||
id: res.data.id || '',
|
||||
serialNumber: res.data.serialNumber || '',
|
||||
realName: res.data.realName || '',
|
||||
stuSource: res.data.stuSource || '1',
|
||||
year: res.data.year ? String(res.data.year) : '',
|
||||
phone: res.data.phone || '',
|
||||
payCode: res.data.payCode || '',
|
||||
isCancal: res.data.isCancal || '0',
|
||||
remarks: res.data.remarks || '',
|
||||
});
|
||||
}
|
||||
loading.value = false;
|
||||
})
|
||||
.catch((err: any) => {
|
||||
useMessage().error(err.msg || '获取详情失败');
|
||||
loading.value = false;
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const onSubmit = async () => {
|
||||
if (loading.value) return;
|
||||
loading.value = true;
|
||||
if (loading.value) return;
|
||||
loading.value = true;
|
||||
|
||||
try {
|
||||
const valid = await formRef.value.validate().catch(() => {});
|
||||
if (!valid) {
|
||||
loading.value = false;
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
const valid = await formRef.value.validate().catch(() => {});
|
||||
if (!valid) {
|
||||
loading.value = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
const submitData = {
|
||||
...dataForm,
|
||||
year: dataForm.year ? parseInt(dataForm.year) : null,
|
||||
};
|
||||
const submitData = {
|
||||
...dataForm,
|
||||
year: dataForm.year ? parseInt(dataForm.year) : null,
|
||||
};
|
||||
|
||||
if (dataForm.id) {
|
||||
await editObj(submitData);
|
||||
useMessage().success('编辑成功');
|
||||
} else {
|
||||
await addObj(submitData);
|
||||
useMessage().success('新增成功');
|
||||
}
|
||||
visible.value = false;
|
||||
emit('refresh');
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg || (dataForm.id ? '编辑失败' : '新增失败'));
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
if (dataForm.id) {
|
||||
await editObj(submitData);
|
||||
useMessage().success('编辑成功');
|
||||
} else {
|
||||
await addObj(submitData);
|
||||
useMessage().success('新增成功');
|
||||
}
|
||||
visible.value = false;
|
||||
emit('refresh');
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg || (dataForm.id ? '编辑失败' : '新增失败'));
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
defineExpose({ openDialog });
|
||||
</script>
|
||||
</script>
|
||||
|
||||
@@ -1,148 +1,160 @@
|
||||
<template>
|
||||
<div class="modern-page-container">
|
||||
<div class="page-wrapper">
|
||||
<el-card v-show="showSearch" class="search-card" shadow="never">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span class="card-title">
|
||||
<el-icon class="title-icon"><Search /></el-icon>
|
||||
筛选条件
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
<el-form :model="state.queryForm" ref="searchFormRef" :inline="true" @keyup.enter="getDataList" class="search-form">
|
||||
<el-form-item label="学号" prop="serialNumber">
|
||||
<el-input v-model="state.queryForm.serialNumber" placeholder="请输入学号" clearable style="width: 150px" />
|
||||
</el-form-item>
|
||||
<el-form-item label="姓名" prop="realName">
|
||||
<el-input v-model="state.queryForm.realName" placeholder="请输入姓名" clearable style="width: 150px" />
|
||||
</el-form-item>
|
||||
<el-form-item label="年份" prop="year">
|
||||
<el-date-picker v-model="state.queryForm.year" type="year" placeholder="选择年份" value-format="YYYY" style="width: 150px" />
|
||||
</el-form-item>
|
||||
<el-form-item label="手机号" prop="phone">
|
||||
<el-input v-model="state.queryForm.phone" placeholder="请输入手机号" clearable style="width: 150px" />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="Search" @click="getDataList">查询</el-button>
|
||||
<el-button icon="Refresh" @click="handleReset">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
<div class="modern-page-container">
|
||||
<div class="page-wrapper">
|
||||
<el-card v-show="showSearch" class="search-card" shadow="never">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span class="card-title">
|
||||
<el-icon class="title-icon"><Search /></el-icon>
|
||||
筛选条件
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
<el-form :model="state.queryForm" ref="searchFormRef" :inline="true" @keyup.enter="getDataList" class="search-form">
|
||||
<el-form-item label="学号" prop="serialNumber">
|
||||
<el-input v-model="state.queryForm.serialNumber" placeholder="请输入学号" clearable style="width: 150px" />
|
||||
</el-form-item>
|
||||
<el-form-item label="姓名" prop="realName">
|
||||
<el-input v-model="state.queryForm.realName" placeholder="请输入姓名" clearable style="width: 150px" />
|
||||
</el-form-item>
|
||||
<el-form-item label="年份" prop="year">
|
||||
<el-date-picker v-model="state.queryForm.year" type="year" placeholder="选择年份" value-format="YYYY" style="width: 150px" />
|
||||
</el-form-item>
|
||||
<el-form-item label="手机号" prop="phone">
|
||||
<el-input v-model="state.queryForm.phone" placeholder="请输入手机号" clearable style="width: 150px" />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="Search" @click="getDataList">查询</el-button>
|
||||
<el-button icon="Refresh" @click="handleReset">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
|
||||
<el-card class="content-card" shadow="never">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span class="card-title">
|
||||
<el-icon class="title-icon"><User /></el-icon>
|
||||
新生信息管理
|
||||
</span>
|
||||
<div class="header-actions">
|
||||
<el-button icon="FolderAdd" type="primary" @click="formDialogRef.openDialog('add')" v-auth="'finance_recruit_stu_add'">新增</el-button>
|
||||
<right-toolbar v-model:showSearch="showSearch" class="ml10" @queryTable="getDataList" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<el-card class="content-card" shadow="never">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span class="card-title">
|
||||
<el-icon class="title-icon"><User /></el-icon>
|
||||
新生信息管理
|
||||
</span>
|
||||
<div class="header-actions">
|
||||
<el-button icon="FolderAdd" type="primary" @click="formDialogRef.openDialog('add')" v-auth="'finance_recruit_stu_add'">新增</el-button>
|
||||
<right-toolbar v-model:showSearch="showSearch" class="ml10" @queryTable="getDataList" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<el-table ref="tableRef" :data="state.dataList" v-loading="state.loading" stripe :cell-style="tableStyle.cellStyle" :header-cell-style="tableStyle.headerCellStyle" class="modern-table">
|
||||
<el-table-column type="index" label="序号" width="70" align="center" />
|
||||
<el-table-column prop="serialNumber" label="学号" width="120" align="center" />
|
||||
<el-table-column prop="realName" label="姓名" width="100" align="center" />
|
||||
<el-table-column prop="stuSource" label="学生来源" width="100" align="center">
|
||||
<template #default="{ row }">
|
||||
<span v-if="row.stuSource === '1'">本地</span>
|
||||
<span v-else-if="row.stuSource === '2'">外地</span>
|
||||
<span v-else-if="row.stuSource === '3'">其他</span>
|
||||
<span v-else>{{ row.stuSource }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="year" label="年份" width="100" align="center" />
|
||||
<el-table-column prop="phone" label="手机号" width="140" align="center" />
|
||||
<el-table-column prop="payCode" label="缴费码" width="150" show-overflow-tooltip />
|
||||
<el-table-column prop="isCancal" label="是否取消" width="100" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-tag v-if="row.isCancal === '1'" type="danger">已取消</el-tag>
|
||||
<el-tag v-else type="success">正常</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="createTime" label="创建时间" width="180" align="center" />
|
||||
<el-table-column label="操作" align="center" fixed="right" width="200">
|
||||
<template #default="scope">
|
||||
<el-button icon="View" link type="primary" v-auth="'finance_recruit_stu_project_look'" @click="viewFeeDetail(scope.row)">收费明细</el-button>
|
||||
<el-button icon="Edit" link type="primary" v-auth="'finance_recruit_stu_edit'" @click="formDialogRef.openDialog('edit', scope.row)">编辑</el-button>
|
||||
<el-button icon="Delete" link type="danger" v-auth="'finance_recruit_stu_del'" @click="handleDelete(scope.row)">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<el-table
|
||||
ref="tableRef"
|
||||
:data="state.dataList"
|
||||
v-loading="state.loading"
|
||||
stripe
|
||||
:cell-style="tableStyle.cellStyle"
|
||||
:header-cell-style="tableStyle.headerCellStyle"
|
||||
class="modern-table"
|
||||
>
|
||||
<el-table-column type="index" label="序号" width="70" align="center" />
|
||||
<el-table-column prop="serialNumber" label="学号" width="120" align="center" />
|
||||
<el-table-column prop="realName" label="姓名" width="100" align="center" />
|
||||
<el-table-column prop="stuSource" label="学生来源" width="100" align="center">
|
||||
<template #default="{ row }">
|
||||
<span v-if="row.stuSource === '1'">本地</span>
|
||||
<span v-else-if="row.stuSource === '2'">外地</span>
|
||||
<span v-else-if="row.stuSource === '3'">其他</span>
|
||||
<span v-else>{{ row.stuSource }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="year" label="年份" width="100" align="center" />
|
||||
<el-table-column prop="phone" label="手机号" width="140" align="center" />
|
||||
<el-table-column prop="payCode" label="缴费码" width="150" show-overflow-tooltip />
|
||||
<el-table-column prop="isCancal" label="是否取消" width="100" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-tag v-if="row.isCancal === '1'" type="danger">已取消</el-tag>
|
||||
<el-tag v-else type="success">正常</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="createTime" label="创建时间" width="180" align="center" />
|
||||
<el-table-column label="操作" align="center" fixed="right" width="200">
|
||||
<template #default="scope">
|
||||
<el-button icon="View" link type="primary" v-auth="'finance_recruit_stu_project_look'" @click="viewFeeDetail(scope.row)"
|
||||
>收费明细</el-button
|
||||
>
|
||||
<el-button icon="Edit" link type="primary" v-auth="'finance_recruit_stu_edit'" @click="formDialogRef.openDialog('edit', scope.row)"
|
||||
>编辑</el-button
|
||||
>
|
||||
<el-button icon="Delete" link type="danger" v-auth="'finance_recruit_stu_del'" @click="handleDelete(scope.row)">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<pagination v-show="state.total > 0" :total="state.total" v-model:page="state.page" v-model:limit="state.limit" @pagination="getDataList" />
|
||||
</el-card>
|
||||
</div>
|
||||
<pagination v-show="state.total > 0" :total="state.total" v-model:page="state.page" v-model:limit="state.limit" @pagination="getDataList" />
|
||||
</el-card>
|
||||
</div>
|
||||
|
||||
<FormDialog ref="formDialogRef" @refresh="getDataList" />
|
||||
<FeeDetailDialog ref="feeDetailDialogRef" />
|
||||
</div>
|
||||
<FormDialog ref="formDialogRef" @refresh="getDataList" />
|
||||
<FeeDetailDialog ref="feeDetailDialogRef" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="FinanceRecruitStu">
|
||||
import { ref, reactive, defineAsyncComponent } from 'vue'
|
||||
import { BasicTableProps, useTable } from "/@/hooks/table";
|
||||
import { getPage, delObj } from "/@/api/finance/recruitStu";
|
||||
import { useMessage, useMessageBox } from "/@/hooks/message";
|
||||
import { Search, User } from '@element-plus/icons-vue'
|
||||
import { ref, reactive, defineAsyncComponent } from 'vue';
|
||||
import { BasicTableProps, useTable } from '/@/hooks/table';
|
||||
import { getPage, delObj } from '/@/api/finance/recruitStu';
|
||||
import { useMessage, useMessageBox } from '/@/hooks/message';
|
||||
import { Search, User } from '@element-plus/icons-vue';
|
||||
|
||||
const FormDialog = defineAsyncComponent(() => import('./form.vue'));
|
||||
const FeeDetailDialog = defineAsyncComponent(() => import('./feeDetail.vue'));
|
||||
|
||||
const tableRef = ref()
|
||||
const formDialogRef = ref()
|
||||
const feeDetailDialogRef = ref()
|
||||
const searchFormRef = ref()
|
||||
const showSearch = ref(true)
|
||||
const tableRef = ref();
|
||||
const formDialogRef = ref();
|
||||
const feeDetailDialogRef = ref();
|
||||
const searchFormRef = ref();
|
||||
const showSearch = ref(true);
|
||||
|
||||
const state: BasicTableProps = reactive<BasicTableProps>({
|
||||
pageList: getPage,
|
||||
queryForm: {
|
||||
serialNumber: '',
|
||||
realName: '',
|
||||
year: '',
|
||||
phone: '',
|
||||
},
|
||||
createdIsNeed: true
|
||||
pageList: getPage,
|
||||
queryForm: {
|
||||
serialNumber: '',
|
||||
realName: '',
|
||||
year: '',
|
||||
phone: '',
|
||||
},
|
||||
createdIsNeed: true,
|
||||
});
|
||||
|
||||
const { getDataList, tableStyle } = useTable(state);
|
||||
|
||||
const handleReset = () => {
|
||||
searchFormRef.value?.resetFields();
|
||||
getDataList();
|
||||
searchFormRef.value?.resetFields();
|
||||
getDataList();
|
||||
};
|
||||
|
||||
const handleDelete = async (row: any) => {
|
||||
try {
|
||||
await useMessageBox().confirm('确定要删除该记录吗?', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
});
|
||||
} catch {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
await useMessageBox().confirm('确定要删除该记录吗?', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
});
|
||||
} catch {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await delObj(row.id);
|
||||
useMessage().success('删除成功');
|
||||
getDataList();
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg || '删除失败');
|
||||
}
|
||||
try {
|
||||
await delObj(row.id);
|
||||
useMessage().success('删除成功');
|
||||
getDataList();
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg || '删除失败');
|
||||
}
|
||||
};
|
||||
|
||||
const viewFeeDetail = (row: any) => {
|
||||
feeDetailDialogRef.value.openDialog(row.serialNumber, row.realName);
|
||||
feeDetailDialogRef.value.openDialog(row.serialNumber, row.realName);
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import '/@/assets/styles/modern-page.scss';
|
||||
</style>
|
||||
</style>
|
||||
|
||||
@@ -1,205 +1,213 @@
|
||||
<template>
|
||||
<div class="modern-page-container">
|
||||
<div class="page-wrapper">
|
||||
<el-card v-show="showSearch" class="search-card" shadow="never">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span class="card-title">
|
||||
<el-icon class="title-icon"><Search /></el-icon>
|
||||
筛选条件
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
<el-form :model="state.queryForm" ref="searchFormRef" :inline="true" @keyup.enter="getDataList" class="search-form">
|
||||
<el-form-item label="学号" prop="serialNumber">
|
||||
<el-input v-model="state.queryForm.serialNumber" placeholder="请输入学号" clearable style="width: 150px" />
|
||||
</el-form-item>
|
||||
<el-form-item label="项目代码" prop="projectCode">
|
||||
<el-input v-model="state.queryForm.projectCode" placeholder="请输入项目代码" clearable style="width: 150px" />
|
||||
</el-form-item>
|
||||
<el-form-item label="状态" prop="status">
|
||||
<el-select v-model="state.queryForm.status" placeholder="请选择状态" clearable style="width: 150px">
|
||||
<el-option label="未缴费" value="0" />
|
||||
<el-option label="已缴费" value="10" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="Search" @click="getDataList">查询</el-button>
|
||||
<el-button icon="Refresh" @click="handleReset">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
<div class="modern-page-container">
|
||||
<div class="page-wrapper">
|
||||
<el-card v-show="showSearch" class="search-card" shadow="never">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span class="card-title">
|
||||
<el-icon class="title-icon"><Search /></el-icon>
|
||||
筛选条件
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
<el-form :model="state.queryForm" ref="searchFormRef" :inline="true" @keyup.enter="getDataList" class="search-form">
|
||||
<el-form-item label="学号" prop="serialNumber">
|
||||
<el-input v-model="state.queryForm.serialNumber" placeholder="请输入学号" clearable style="width: 150px" />
|
||||
</el-form-item>
|
||||
<el-form-item label="项目代码" prop="projectCode">
|
||||
<el-input v-model="state.queryForm.projectCode" placeholder="请输入项目代码" clearable style="width: 150px" />
|
||||
</el-form-item>
|
||||
<el-form-item label="状态" prop="status">
|
||||
<el-select v-model="state.queryForm.status" placeholder="请选择状态" clearable style="width: 150px">
|
||||
<el-option label="未缴费" value="0" />
|
||||
<el-option label="已缴费" value="10" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="Search" @click="getDataList">查询</el-button>
|
||||
<el-button icon="Refresh" @click="handleReset">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
|
||||
<el-card class="content-card" shadow="never">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span class="card-title">
|
||||
<el-icon class="title-icon"><Money /></el-icon>
|
||||
学生收费管理
|
||||
</span>
|
||||
<div class="header-actions">
|
||||
<right-toolbar v-model:showSearch="showSearch" class="ml10" @queryTable="getDataList" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<el-card class="content-card" shadow="never">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span class="card-title">
|
||||
<el-icon class="title-icon"><Money /></el-icon>
|
||||
学生收费管理
|
||||
</span>
|
||||
<div class="header-actions">
|
||||
<right-toolbar v-model:showSearch="showSearch" class="ml10" @queryTable="getDataList" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<el-table ref="tableRef" :data="state.dataList" v-loading="state.loading" stripe :cell-style="tableStyle.cellStyle" :header-cell-style="tableStyle.headerCellStyle" class="modern-table">
|
||||
<el-table-column type="index" label="序号" width="70" align="center" />
|
||||
<el-table-column prop="serialNumber" label="学号" width="120" align="center" />
|
||||
<el-table-column prop="projectCode" label="项目代码" width="150" align="center" />
|
||||
<el-table-column prop="money" label="应缴金额" width="120" align="right">
|
||||
<template #default="{ row }">
|
||||
{{ row.money ? Number(row.money).toFixed(2) : '0.00' }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="status" label="状态" width="100" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-tag v-if="row.status === '0'" type="info">未缴费</el-tag>
|
||||
<el-tag v-else-if="row.status === '10'" type="success">已缴费</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="payType" label="缴费方式" width="120" align="center">
|
||||
<template #default="{ row }">
|
||||
<span v-if="row.payType === '0'">-</span>
|
||||
<span v-else>{{ row.payType }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="paiedMoney" label="实缴金额" width="120" align="right">
|
||||
<template #default="{ row }">
|
||||
{{ row.paiedMoney ? Number(row.paiedMoney).toFixed(2) : '-' }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="payTime" label="缴费时间" width="180" align="center" />
|
||||
<el-table-column prop="createTime" label="创建时间" width="180" align="center" />
|
||||
<el-table-column label="操作" align="center" fixed="right" width="200">
|
||||
<template #default="scope">
|
||||
<template v-if="scope.row.status === '0'">
|
||||
<el-button link type="primary" v-auth="'finance_recruit_stu_project_edit'" @click="handlePay(scope.row)">缴费</el-button>
|
||||
<el-button link type="danger" v-auth="'finance_recruit_stu_project_del'" @click="handleDelete(scope.row)">删除</el-button>
|
||||
</template>
|
||||
<template v-else>
|
||||
<el-button link type="warning" v-auth="'finance_recruit_stu_project_edit'" @click="handleCancelPay(scope.row)">取消缴费</el-button>
|
||||
</template>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<el-table
|
||||
ref="tableRef"
|
||||
:data="state.dataList"
|
||||
v-loading="state.loading"
|
||||
stripe
|
||||
:cell-style="tableStyle.cellStyle"
|
||||
:header-cell-style="tableStyle.headerCellStyle"
|
||||
class="modern-table"
|
||||
>
|
||||
<el-table-column type="index" label="序号" width="70" align="center" />
|
||||
<el-table-column prop="serialNumber" label="学号" width="120" align="center" />
|
||||
<el-table-column prop="projectCode" label="项目代码" width="150" align="center" />
|
||||
<el-table-column prop="money" label="应缴金额" width="120" align="right">
|
||||
<template #default="{ row }">
|
||||
{{ row.money ? Number(row.money).toFixed(2) : '0.00' }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="status" label="状态" width="100" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-tag v-if="row.status === '0'" type="info">未缴费</el-tag>
|
||||
<el-tag v-else-if="row.status === '10'" type="success">已缴费</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="payType" label="缴费方式" width="120" align="center">
|
||||
<template #default="{ row }">
|
||||
<span v-if="row.payType === '0'">-</span>
|
||||
<span v-else>{{ row.payType }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="paiedMoney" label="实缴金额" width="120" align="right">
|
||||
<template #default="{ row }">
|
||||
{{ row.paiedMoney ? Number(row.paiedMoney).toFixed(2) : '-' }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="payTime" label="缴费时间" width="180" align="center" />
|
||||
<el-table-column prop="createTime" label="创建时间" width="180" align="center" />
|
||||
<el-table-column label="操作" align="center" fixed="right" width="200">
|
||||
<template #default="scope">
|
||||
<template v-if="scope.row.status === '0'">
|
||||
<el-button link type="primary" v-auth="'finance_recruit_stu_project_edit'" @click="handlePay(scope.row)">缴费</el-button>
|
||||
<el-button link type="danger" v-auth="'finance_recruit_stu_project_del'" @click="handleDelete(scope.row)">删除</el-button>
|
||||
</template>
|
||||
<template v-else>
|
||||
<el-button link type="warning" v-auth="'finance_recruit_stu_project_edit'" @click="handleCancelPay(scope.row)">取消缴费</el-button>
|
||||
</template>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<pagination v-show="state.total > 0" :total="state.total" v-model:page="state.page" v-model:limit="state.limit" @pagination="getDataList" />
|
||||
</el-card>
|
||||
</div>
|
||||
<pagination v-show="state.total > 0" :total="state.total" v-model:page="state.page" v-model:limit="state.limit" @pagination="getDataList" />
|
||||
</el-card>
|
||||
</div>
|
||||
|
||||
<el-dialog title="缴费登记" v-model="payDialogVisible" width="400px">
|
||||
<el-form label-width="100px">
|
||||
<el-form-item label="缴费金额">
|
||||
<el-input-number v-model="payForm.money" :min="0" :precision="2" style="width: 100%" />
|
||||
</el-form-item>
|
||||
<el-form-item label="缴费方式">
|
||||
<el-select v-model="payForm.payType" placeholder="请选择缴费方式" style="width: 100%">
|
||||
<el-option label="现金" value="20" />
|
||||
<el-option label="银行转账" value="30" />
|
||||
<el-option label="微信" value="40" />
|
||||
<el-option label="支付宝" value="21" />
|
||||
<el-option label="其他" value="22" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button @click="payDialogVisible = false">取 消</el-button>
|
||||
<el-button type="primary" @click="submitPay">确 定</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
<el-dialog title="缴费登记" v-model="payDialogVisible" width="400px">
|
||||
<el-form label-width="100px">
|
||||
<el-form-item label="缴费金额">
|
||||
<el-input-number v-model="payForm.money" :min="0" :precision="2" style="width: 100%" />
|
||||
</el-form-item>
|
||||
<el-form-item label="缴费方式">
|
||||
<el-select v-model="payForm.payType" placeholder="请选择缴费方式" style="width: 100%">
|
||||
<el-option label="现金" value="20" />
|
||||
<el-option label="银行转账" value="30" />
|
||||
<el-option label="微信" value="40" />
|
||||
<el-option label="支付宝" value="21" />
|
||||
<el-option label="其他" value="22" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button @click="payDialogVisible = false">取 消</el-button>
|
||||
<el-button type="primary" @click="submitPay">确 定</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="FinanceRecruitStuProject">
|
||||
import { ref, reactive } from 'vue'
|
||||
import { BasicTableProps, useTable } from "/@/hooks/table";
|
||||
import { getPage, delObj, payRegister, cancelPay } from "/@/api/finance/recruitStuProject";
|
||||
import { useMessage, useMessageBox } from "/@/hooks/message";
|
||||
import { Search, Money } from '@element-plus/icons-vue'
|
||||
import { ref, reactive } from 'vue';
|
||||
import { BasicTableProps, useTable } from '/@/hooks/table';
|
||||
import { getPage, delObj, payRegister, cancelPay } from '/@/api/finance/recruitStuProject';
|
||||
import { useMessage, useMessageBox } from '/@/hooks/message';
|
||||
import { Search, Money } from '@element-plus/icons-vue';
|
||||
|
||||
const tableRef = ref()
|
||||
const searchFormRef = ref()
|
||||
const showSearch = ref(true)
|
||||
const tableRef = ref();
|
||||
const searchFormRef = ref();
|
||||
const showSearch = ref(true);
|
||||
|
||||
const state: BasicTableProps = reactive<BasicTableProps>({
|
||||
pageList: getPage,
|
||||
queryForm: {
|
||||
serialNumber: '',
|
||||
projectCode: '',
|
||||
status: '',
|
||||
},
|
||||
createdIsNeed: true
|
||||
pageList: getPage,
|
||||
queryForm: {
|
||||
serialNumber: '',
|
||||
projectCode: '',
|
||||
status: '',
|
||||
},
|
||||
createdIsNeed: true,
|
||||
});
|
||||
|
||||
const { getDataList, tableStyle } = useTable(state);
|
||||
|
||||
const handleReset = () => {
|
||||
searchFormRef.value?.resetFields();
|
||||
getDataList();
|
||||
searchFormRef.value?.resetFields();
|
||||
getDataList();
|
||||
};
|
||||
|
||||
const handleDelete = async (row: any) => {
|
||||
try {
|
||||
await useMessageBox().confirm('确定要删除该记录吗?', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
});
|
||||
} catch {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
await useMessageBox().confirm('确定要删除该记录吗?', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
});
|
||||
} catch {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await delObj(row.id);
|
||||
useMessage().success('删除成功');
|
||||
getDataList();
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg || '删除失败');
|
||||
}
|
||||
try {
|
||||
await delObj(row.id);
|
||||
useMessage().success('删除成功');
|
||||
getDataList();
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg || '删除失败');
|
||||
}
|
||||
};
|
||||
|
||||
const payDialogVisible = ref(false);
|
||||
const payForm = reactive({
|
||||
id: '',
|
||||
money: 0,
|
||||
payType: '',
|
||||
id: '',
|
||||
money: 0,
|
||||
payType: '',
|
||||
});
|
||||
|
||||
const handlePay = (row: any) => {
|
||||
payForm.id = row.id;
|
||||
payForm.money = Number(row.money) || 0;
|
||||
payForm.payType = '';
|
||||
payDialogVisible.value = true;
|
||||
payForm.id = row.id;
|
||||
payForm.money = Number(row.money) || 0;
|
||||
payForm.payType = '';
|
||||
payDialogVisible.value = true;
|
||||
};
|
||||
|
||||
const submitPay = async () => {
|
||||
if (!payForm.payType) {
|
||||
useMessage().warning('请选择缴费方式');
|
||||
return;
|
||||
}
|
||||
try {
|
||||
await payRegister(payForm.id, payForm.payType);
|
||||
useMessage().success('缴费成功');
|
||||
payDialogVisible.value = false;
|
||||
getDataList();
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg || '缴费失败');
|
||||
}
|
||||
if (!payForm.payType) {
|
||||
useMessage().warning('请选择缴费方式');
|
||||
return;
|
||||
}
|
||||
try {
|
||||
await payRegister(payForm.id, payForm.payType);
|
||||
useMessage().success('缴费成功');
|
||||
payDialogVisible.value = false;
|
||||
getDataList();
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg || '缴费失败');
|
||||
}
|
||||
};
|
||||
|
||||
const handleCancelPay = async (row: any) => {
|
||||
try {
|
||||
await useMessageBox().confirm('确定要取消该缴费记录吗?', '提示', { type: 'warning' });
|
||||
await cancelPay(row.id);
|
||||
useMessage().success('取消成功');
|
||||
getDataList();
|
||||
} catch {
|
||||
// 用户取消操作
|
||||
}
|
||||
try {
|
||||
await useMessageBox().confirm('确定要取消该缴费记录吗?', '提示', { type: 'warning' });
|
||||
await cancelPay(row.id);
|
||||
useMessage().success('取消成功');
|
||||
getDataList();
|
||||
} catch {
|
||||
// 用户取消操作
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import '/@/assets/styles/modern-page.scss';
|
||||
</style>
|
||||
</style>
|
||||
|
||||
@@ -1,118 +1,112 @@
|
||||
<template>
|
||||
<el-dialog :title="title" v-model="visible" width="90%"
|
||||
:close-on-click-modal="false" draggable>
|
||||
<el-form ref="dataFormRef" :model="form" :rules="dataRules" label-width="150px" v-loading="loading"
|
||||
:disabled="operType === 'view'">
|
||||
<el-row :gutter="24">
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item :label="t('createTable.tableName')" prop="tableName">
|
||||
<el-input v-model="form.tableName" :placeholder="t('createTable.inputTableNameTip')"/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-dialog :title="title" v-model="visible" width="90%" :close-on-click-modal="false" draggable>
|
||||
<el-form ref="dataFormRef" :model="form" :rules="dataRules" label-width="150px" v-loading="loading" :disabled="operType === 'view'">
|
||||
<el-row :gutter="24">
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item :label="t('createTable.tableName')" prop="tableName">
|
||||
<el-input v-model="form.tableName" :placeholder="t('createTable.inputTableNameTip')" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item :label="t('createTable.comments')" prop="comments">
|
||||
<el-input v-model="form.comments" :placeholder="t('createTable.inputCommentsTip')"/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item :label="t('createTable.comments')" prop="comments">
|
||||
<el-input v-model="form.comments" :placeholder="t('createTable.inputCommentsTip')" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="24" class="mb20">
|
||||
<el-form-item :label="t('createTable.columnInfo')" prop="columns">
|
||||
<el-table :data="form.columns" border style="width: 100%" max-height="500">
|
||||
<el-table-column type="index" :label="t('createTable.index')" width="80">
|
||||
<template #header>
|
||||
<el-button icon="Plus" size="small" type="primary" circle @click="onAddItem"></el-button>
|
||||
</template>
|
||||
<template #default="scope">
|
||||
<el-button icon="Minus" size="small" type="danger" circle
|
||||
@click="handleDelete(scope.$index, scope.row)"></el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="name" :label="t('createTable.name')" show-overflow-tooltip>
|
||||
<template #default="scope">
|
||||
<el-input v-model="scope.row.name" :placeholder="t('createTable.name')"
|
||||
@blur="suggestedFieldType(scope.row)"/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="comment" :label="t('createTable.comment')" show-overflow-tooltip>
|
||||
<template #default="scope">
|
||||
<el-input v-model="scope.row.comment" :placeholder="t('createTable.comment')"/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="typeName" :label="t('createTable.typeName')" show-overflow-tooltip>
|
||||
<template #default="scope">
|
||||
<el-select v-model="scope.row.typeName" :placeholder="t('createTable.typeName')" clearable filterable>
|
||||
<el-option v-for="item in typeList" :key="item.value" :label="item.label" :value="item.value"/>
|
||||
</el-select>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="precision" :label="t('createTable.precision')" show-overflow-tooltip>
|
||||
<template #default="scope">
|
||||
<el-input-number :min="0" :max="10000" v-model="scope.row.precision"
|
||||
:placeholder="t('createTable.precision')"></el-input-number>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="scale" :label="t('createTable.scale')" show-overflow-tooltip>
|
||||
<template #default="scope">
|
||||
<el-input-number :min="0" :max="10000" v-model="scope.row.scale"
|
||||
:placeholder="t('createTable.scale')"></el-input-number>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="defaultValue" :label="t('createTable.defaultValue')" show-overflow-tooltip>
|
||||
<template #default="scope">
|
||||
<el-input v-model="scope.row.defaultValue" :placeholder="t('createTable.defaultValue')"/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="primary" :label="t('createTable.primary')" show-overflow-tooltip>
|
||||
<template #default="scope">
|
||||
<el-radio-group v-model="scope.row.primary">
|
||||
<el-radio v-for="(item, index) in tableDict" :key="index" :label="item.value" class="w-5">
|
||||
{{ item.label }}
|
||||
</el-radio>
|
||||
</el-radio-group>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="nullable" :label="t('createTable.nullable')" show-overflow-tooltip>
|
||||
<template #default="scope">
|
||||
<el-radio-group v-model="scope.row.nullable">
|
||||
<el-radio v-for="(item, index) in tableDict" :key="index" :label="item.value" class="w-5">
|
||||
{{ item.label }}
|
||||
</el-radio>
|
||||
</el-radio-group>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
</el-row>
|
||||
</el-form>
|
||||
<template #footer v-if="operType !== 'view'">
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="visible = false">{{ $t('common.cancelButtonText') }}</el-button>
|
||||
<el-button type="primary" @click="onSubmit" :disabled="loading">{{
|
||||
$t('common.confirmButtonText')
|
||||
}}</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
<el-col :span="24" class="mb20">
|
||||
<el-form-item :label="t('createTable.columnInfo')" prop="columns">
|
||||
<el-table :data="form.columns" border style="width: 100%" max-height="500">
|
||||
<el-table-column type="index" :label="t('createTable.index')" width="80">
|
||||
<template #header>
|
||||
<el-button icon="Plus" size="small" type="primary" circle @click="onAddItem"></el-button>
|
||||
</template>
|
||||
<template #default="scope">
|
||||
<el-button icon="Minus" size="small" type="danger" circle @click="handleDelete(scope.$index, scope.row)"></el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="name" :label="t('createTable.name')" show-overflow-tooltip>
|
||||
<template #default="scope">
|
||||
<el-input v-model="scope.row.name" :placeholder="t('createTable.name')" @blur="suggestedFieldType(scope.row)" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="comment" :label="t('createTable.comment')" show-overflow-tooltip>
|
||||
<template #default="scope">
|
||||
<el-input v-model="scope.row.comment" :placeholder="t('createTable.comment')" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="typeName" :label="t('createTable.typeName')" show-overflow-tooltip>
|
||||
<template #default="scope">
|
||||
<el-select v-model="scope.row.typeName" :placeholder="t('createTable.typeName')" clearable filterable>
|
||||
<el-option v-for="item in typeList" :key="item.value" :label="item.label" :value="item.value" />
|
||||
</el-select>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="precision" :label="t('createTable.precision')" show-overflow-tooltip>
|
||||
<template #default="scope">
|
||||
<el-input-number :min="0" :max="10000" v-model="scope.row.precision" :placeholder="t('createTable.precision')"></el-input-number>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="scale" :label="t('createTable.scale')" show-overflow-tooltip>
|
||||
<template #default="scope">
|
||||
<el-input-number :min="0" :max="10000" v-model="scope.row.scale" :placeholder="t('createTable.scale')"></el-input-number>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="defaultValue" :label="t('createTable.defaultValue')" show-overflow-tooltip>
|
||||
<template #default="scope">
|
||||
<el-input v-model="scope.row.defaultValue" :placeholder="t('createTable.defaultValue')" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="primary" :label="t('createTable.primary')" show-overflow-tooltip>
|
||||
<template #default="scope">
|
||||
<el-radio-group v-model="scope.row.primary">
|
||||
<el-radio v-for="(item, index) in tableDict" :key="index" :label="item.value" class="w-5">
|
||||
{{ item.label }}
|
||||
</el-radio>
|
||||
</el-radio-group>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="nullable" :label="t('createTable.nullable')" show-overflow-tooltip>
|
||||
<template #default="scope">
|
||||
<el-radio-group v-model="scope.row.nullable">
|
||||
<el-radio v-for="(item, index) in tableDict" :key="index" :label="item.value" class="w-5">
|
||||
{{ item.label }}
|
||||
</el-radio>
|
||||
</el-radio-group>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
<template #footer v-if="operType !== 'view'">
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="visible = false">{{ $t('common.cancelButtonText') }}</el-button>
|
||||
<el-button type="primary" @click="onSubmit" :disabled="loading">{{ $t('common.confirmButtonText') }}</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="CreateTableDialog">
|
||||
import {useMessage, useMessageBox} from "/@/hooks/message";
|
||||
import {getObj, addObj, putObj} from '/@/api/gen/create-table'
|
||||
import {useI18n} from "vue-i18n"
|
||||
import {rule, validateNull} from '/@/utils/validate';
|
||||
import {useDict} from "/@/hooks/dict";
|
||||
import {list} from "/@/api/gen/fieldtype";
|
||||
import {fetchList} from '/@/api/gen/table';
|
||||
import { useMessage, useMessageBox } from '/@/hooks/message';
|
||||
import { getObj, addObj, putObj } from '/@/api/gen/create-table';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { rule, validateNull } from '/@/utils/validate';
|
||||
import { useDict } from '/@/hooks/dict';
|
||||
import { list } from '/@/api/gen/fieldtype';
|
||||
import { fetchList } from '/@/api/gen/table';
|
||||
|
||||
const emit = defineEmits(['refresh']);
|
||||
|
||||
const {t} = useI18n();
|
||||
const {yes_no_type} = useDict('yes_no_type');
|
||||
const { t } = useI18n();
|
||||
const { yes_no_type } = useDict('yes_no_type');
|
||||
|
||||
const tableDict = [{value: -1, label: '否'}, {value: 1, label: '是'}]
|
||||
const tableDict = [
|
||||
{ value: -1, label: '否' },
|
||||
{ value: 1, label: '是' },
|
||||
];
|
||||
|
||||
// 定义变量内容
|
||||
const dataFormRef = ref();
|
||||
@@ -124,16 +118,16 @@ const typeList = ref([]) as any;
|
||||
|
||||
// 提交表单数据
|
||||
const form = reactive({
|
||||
id: '',
|
||||
tableName: '',
|
||||
dsName: '',
|
||||
comments: '',
|
||||
databaseType: '',
|
||||
pkPolicy: '',
|
||||
primary: '',
|
||||
columnsInfo: '',
|
||||
columnInfo: '',
|
||||
columns: [] as any
|
||||
id: '',
|
||||
tableName: '',
|
||||
dsName: '',
|
||||
comments: '',
|
||||
databaseType: '',
|
||||
pkPolicy: '',
|
||||
primary: '',
|
||||
columnsInfo: '',
|
||||
columnInfo: '',
|
||||
columns: [] as any,
|
||||
});
|
||||
|
||||
/**
|
||||
@@ -143,249 +137,253 @@ const form = reactive({
|
||||
* @param {*} callback
|
||||
*/
|
||||
let validateTableName = async (rule, value, callback) => {
|
||||
const {data} = await fetchList({tableName: value})
|
||||
if (data.total === 0) {
|
||||
callback()
|
||||
} else {
|
||||
callback(new Error('表名已存在'))
|
||||
}
|
||||
}
|
||||
const { data } = await fetchList({ tableName: value });
|
||||
if (data.total === 0) {
|
||||
callback();
|
||||
} else {
|
||||
callback(new Error('表名已存在'));
|
||||
}
|
||||
};
|
||||
|
||||
// 定义校验规则
|
||||
const dataRules = ref({
|
||||
tableName: [
|
||||
{required: true, message: '表名称不能为空', trigger: 'blur'},
|
||||
{max: 32, message: '长度在 32 个字符', trigger: 'blur'},
|
||||
{validator: rule.validatorLowercase, trigger: 'blur'},
|
||||
{validator: validateTableName, trigger: 'blur'}
|
||||
],
|
||||
comments: [{validator: rule.overLength, trigger: 'blur'}, {
|
||||
required: true,
|
||||
message: '表注释不能为空',
|
||||
trigger: 'blur'
|
||||
}],
|
||||
databaseType: [{required: true, message: '数据库类型不能为空', trigger: 'blur'}],
|
||||
pkPolicy: [{required: true, message: '主键策略不能为空', trigger: 'blur'}],
|
||||
columns: [{required: true, message: '字段信息不能为空', trigger: 'blur'}],
|
||||
})
|
||||
tableName: [
|
||||
{ required: true, message: '表名称不能为空', trigger: 'blur' },
|
||||
{ max: 32, message: '长度在 32 个字符', trigger: 'blur' },
|
||||
{ validator: rule.validatorLowercase, trigger: 'blur' },
|
||||
{ validator: validateTableName, trigger: 'blur' },
|
||||
],
|
||||
comments: [
|
||||
{ validator: rule.overLength, trigger: 'blur' },
|
||||
{
|
||||
required: true,
|
||||
message: '表注释不能为空',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
databaseType: [{ required: true, message: '数据库类型不能为空', trigger: 'blur' }],
|
||||
pkPolicy: [{ required: true, message: '主键策略不能为空', trigger: 'blur' }],
|
||||
columns: [{ required: true, message: '字段信息不能为空', trigger: 'blur' }],
|
||||
});
|
||||
|
||||
// 打开弹窗
|
||||
const openDialog = (type: string, id: string, dsName: string) => {
|
||||
visible.value = true
|
||||
operType.value = type;
|
||||
form.id = ''
|
||||
form.dsName = dsName
|
||||
index = 1
|
||||
if (type === 'add') {
|
||||
title.value = t('common.addBtn');
|
||||
} else if (type === 'edit') {
|
||||
title.value = t('common.editBtn');
|
||||
} else if (type === 'view') {
|
||||
title.value = t('common.viewBtn');
|
||||
}
|
||||
// 获取字典值
|
||||
getFieldTypeList()
|
||||
// 重置表单数据
|
||||
nextTick(() => {
|
||||
dataFormRef.value?.resetFields();
|
||||
if (!id) onAddItem()
|
||||
});
|
||||
visible.value = true;
|
||||
operType.value = type;
|
||||
form.id = '';
|
||||
form.dsName = dsName;
|
||||
index = 1;
|
||||
if (type === 'add') {
|
||||
title.value = t('common.addBtn');
|
||||
} else if (type === 'edit') {
|
||||
title.value = t('common.editBtn');
|
||||
} else if (type === 'view') {
|
||||
title.value = t('common.viewBtn');
|
||||
}
|
||||
// 获取字典值
|
||||
getFieldTypeList();
|
||||
// 重置表单数据
|
||||
nextTick(() => {
|
||||
dataFormRef.value?.resetFields();
|
||||
if (!id) onAddItem();
|
||||
});
|
||||
|
||||
// 获取CreateTable信息
|
||||
if (id) {
|
||||
form.id = id
|
||||
getCreateTableData(id)
|
||||
}
|
||||
// 获取CreateTable信息
|
||||
if (id) {
|
||||
form.id = id;
|
||||
getCreateTableData(id);
|
||||
}
|
||||
};
|
||||
|
||||
// 提交
|
||||
const onSubmit = async () => {
|
||||
const valid = await dataFormRef.value.validate().catch(() => {
|
||||
});
|
||||
if (!valid) return false;
|
||||
const valid = await dataFormRef.value.validate().catch(() => {});
|
||||
if (!valid) return false;
|
||||
|
||||
try {
|
||||
if (form.id) {
|
||||
await useMessageBox().confirm("注意:目前修改会重新建表" + form.tableName);
|
||||
}
|
||||
} catch {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
if (form.id) {
|
||||
await useMessageBox().confirm('注意:目前修改会重新建表' + form.tableName);
|
||||
}
|
||||
} catch {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
loading.value = true;
|
||||
form.columnInfo = JSON.stringify(form.columns)
|
||||
let columns = {} as any
|
||||
form.columns.forEach(each => {
|
||||
if (validateNull(each.defaultValue)) each.defaultValue = null
|
||||
columns[each.name] = each
|
||||
})
|
||||
form.columnsInfo = JSON.stringify(columns)
|
||||
await addObj(form);
|
||||
useMessage().success(t(form.id ? 'common.editSuccessText' : 'common.addSuccessText'));
|
||||
visible.value = false;
|
||||
emit('refresh');
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg);
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
try {
|
||||
loading.value = true;
|
||||
form.columnInfo = JSON.stringify(form.columns);
|
||||
let columns = {} as any;
|
||||
form.columns.forEach((each) => {
|
||||
if (validateNull(each.defaultValue)) each.defaultValue = null;
|
||||
columns[each.name] = each;
|
||||
});
|
||||
form.columnsInfo = JSON.stringify(columns);
|
||||
await addObj(form);
|
||||
useMessage().success(t(form.id ? 'common.editSuccessText' : 'common.addSuccessText'));
|
||||
visible.value = false;
|
||||
emit('refresh');
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg);
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
// 初始化表单数据
|
||||
const getCreateTableData = (id: string) => {
|
||||
// 获取数据
|
||||
loading.value = true
|
||||
getObj(id).then((res: any) => {
|
||||
let columnInfo = res.data.columnInfo;
|
||||
res.data.columns = validateNull(columnInfo) ? [] : JSON.parse(columnInfo);
|
||||
Object.assign(form, res.data)
|
||||
}).finally(() => {
|
||||
loading.value = false
|
||||
})
|
||||
// 获取数据
|
||||
loading.value = true;
|
||||
getObj(id)
|
||||
.then((res: any) => {
|
||||
let columnInfo = res.data.columnInfo;
|
||||
res.data.columns = validateNull(columnInfo) ? [] : JSON.parse(columnInfo);
|
||||
Object.assign(form, res.data);
|
||||
})
|
||||
.finally(() => {
|
||||
loading.value = false;
|
||||
});
|
||||
};
|
||||
|
||||
let index = 1;
|
||||
const onAddItem = () => {
|
||||
let find = form.columns.find(f => f.name === 'id');
|
||||
if (find) {
|
||||
let obj = {
|
||||
name: '',
|
||||
comment: '',
|
||||
typeName: 'varchar',
|
||||
precision: 255,
|
||||
scale: 0,
|
||||
defaultValue: null,
|
||||
primary: -1,
|
||||
nullable: 1
|
||||
};
|
||||
let find = form.columns.find((f) => f.name === 'id');
|
||||
if (find) {
|
||||
let obj = {
|
||||
name: '',
|
||||
comment: '',
|
||||
typeName: 'varchar',
|
||||
precision: 255,
|
||||
scale: 0,
|
||||
defaultValue: null,
|
||||
primary: -1,
|
||||
nullable: 1,
|
||||
};
|
||||
|
||||
// 从 index为 1 的位置开始添加, 并且新增的字段要依次向后
|
||||
form.columns.splice(index++, 0, obj)
|
||||
return
|
||||
}
|
||||
let id = {
|
||||
name: 'id',
|
||||
comment: '主键',
|
||||
typeName: 'bigint',
|
||||
precision: 20,
|
||||
scale: 0,
|
||||
defaultValue: null,
|
||||
primary: 1,
|
||||
nullable: -1
|
||||
};
|
||||
let create_user = {
|
||||
name: 'create_by',
|
||||
comment: '创建人',
|
||||
typeName: 'varchar',
|
||||
precision: 64,
|
||||
scale: 0,
|
||||
defaultValue: null,
|
||||
primary: -1,
|
||||
nullable: 1
|
||||
};
|
||||
let create_time = {
|
||||
name: 'create_time',
|
||||
comment: '创建时间',
|
||||
typeName: 'datetime',
|
||||
precision: 0,
|
||||
scale: 0,
|
||||
defaultValue: null,
|
||||
primary: -1,
|
||||
nullable: 1
|
||||
};
|
||||
// 从 index为 1 的位置开始添加, 并且新增的字段要依次向后
|
||||
form.columns.splice(index++, 0, obj);
|
||||
return;
|
||||
}
|
||||
let id = {
|
||||
name: 'id',
|
||||
comment: '主键',
|
||||
typeName: 'bigint',
|
||||
precision: 20,
|
||||
scale: 0,
|
||||
defaultValue: null,
|
||||
primary: 1,
|
||||
nullable: -1,
|
||||
};
|
||||
let create_user = {
|
||||
name: 'create_by',
|
||||
comment: '创建人',
|
||||
typeName: 'varchar',
|
||||
precision: 64,
|
||||
scale: 0,
|
||||
defaultValue: null,
|
||||
primary: -1,
|
||||
nullable: 1,
|
||||
};
|
||||
let create_time = {
|
||||
name: 'create_time',
|
||||
comment: '创建时间',
|
||||
typeName: 'datetime',
|
||||
precision: 0,
|
||||
scale: 0,
|
||||
defaultValue: null,
|
||||
primary: -1,
|
||||
nullable: 1,
|
||||
};
|
||||
|
||||
let update_user = {
|
||||
name: 'update_by',
|
||||
comment: '修改人',
|
||||
typeName: 'varchar',
|
||||
precision: 64,
|
||||
scale: 0,
|
||||
defaultValue: null,
|
||||
primary: -1,
|
||||
nullable: 1
|
||||
};
|
||||
let update_user = {
|
||||
name: 'update_by',
|
||||
comment: '修改人',
|
||||
typeName: 'varchar',
|
||||
precision: 64,
|
||||
scale: 0,
|
||||
defaultValue: null,
|
||||
primary: -1,
|
||||
nullable: 1,
|
||||
};
|
||||
|
||||
let update_time = {
|
||||
name: 'update_time',
|
||||
comment: '修改时间',
|
||||
typeName: 'datetime',
|
||||
precision: 0,
|
||||
scale: 0,
|
||||
defaultValue: null,
|
||||
primary: -1,
|
||||
nullable: 1
|
||||
};
|
||||
let update_time = {
|
||||
name: 'update_time',
|
||||
comment: '修改时间',
|
||||
typeName: 'datetime',
|
||||
precision: 0,
|
||||
scale: 0,
|
||||
defaultValue: null,
|
||||
primary: -1,
|
||||
nullable: 1,
|
||||
};
|
||||
|
||||
let del_flag = {
|
||||
name: 'del_flag',
|
||||
comment: '删除标记',
|
||||
typeName: 'char',
|
||||
precision: 1,
|
||||
scale: 0,
|
||||
defaultValue: '0',
|
||||
primary: -1,
|
||||
nullable: -1
|
||||
};
|
||||
let del_flag = {
|
||||
name: 'del_flag',
|
||||
comment: '删除标记',
|
||||
typeName: 'char',
|
||||
precision: 1,
|
||||
scale: 0,
|
||||
defaultValue: '0',
|
||||
primary: -1,
|
||||
nullable: -1,
|
||||
};
|
||||
|
||||
let tenant_id = {
|
||||
name: 'tenant_id',
|
||||
comment: '租户ID',
|
||||
typeName: 'bigint',
|
||||
precision: 0,
|
||||
scale: 0,
|
||||
primary: -1,
|
||||
nullable: -1
|
||||
};
|
||||
let tenant_id = {
|
||||
name: 'tenant_id',
|
||||
comment: '租户ID',
|
||||
typeName: 'bigint',
|
||||
precision: 0,
|
||||
scale: 0,
|
||||
primary: -1,
|
||||
nullable: -1,
|
||||
};
|
||||
|
||||
form.columns.push(id);
|
||||
form.columns.push(create_user);
|
||||
form.columns.push(create_time);
|
||||
form.columns.push(update_user);
|
||||
form.columns.push(update_time);
|
||||
form.columns.push(del_flag);
|
||||
form.columns.push(tenant_id);
|
||||
}
|
||||
form.columns.push(id);
|
||||
form.columns.push(create_user);
|
||||
form.columns.push(create_time);
|
||||
form.columns.push(update_user);
|
||||
form.columns.push(update_time);
|
||||
form.columns.push(del_flag);
|
||||
form.columns.push(tenant_id);
|
||||
};
|
||||
|
||||
const getFieldTypeList = async () => {
|
||||
typeList.value = [];
|
||||
// 获取数据
|
||||
const {data} = await list();
|
||||
// 设置属性类型值
|
||||
const typeMap = new Map();
|
||||
data.forEach((item: any) => {
|
||||
const {attrType, columnType} = item;
|
||||
if (!typeMap.has(attrType)) {
|
||||
typeMap.set(columnType, attrType);
|
||||
typeList.value.push({label: columnType, value: columnType});
|
||||
}
|
||||
});
|
||||
typeList.value = [];
|
||||
// 获取数据
|
||||
const { data } = await list();
|
||||
// 设置属性类型值
|
||||
const typeMap = new Map();
|
||||
data.forEach((item: any) => {
|
||||
const { attrType, columnType } = item;
|
||||
if (!typeMap.has(attrType)) {
|
||||
typeMap.set(columnType, attrType);
|
||||
typeList.value.push({ label: columnType, value: columnType });
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const handleDelete = (index: number, row: any) => {
|
||||
form.columns.splice(index, 1)
|
||||
}
|
||||
form.columns.splice(index, 1);
|
||||
};
|
||||
|
||||
// 字段建议
|
||||
const suggestedFieldType = (row: { name: string, typeName: string, precision: number }) => {
|
||||
// 如果fieldName 包含 time,date ,则默认为时间类型, 如果包含id ,则默认是 bigint
|
||||
if (row.name.includes('time') || row.name.includes('date')) {
|
||||
row.typeName = 'datetime'
|
||||
row.precision = 0
|
||||
} else if (row.name.includes('id')) {
|
||||
row.typeName = 'bigint'
|
||||
row.precision = 20
|
||||
} else if(row.name.includes('flag') || row.name.includes('status')){
|
||||
row.typeName = 'char'
|
||||
row.precision = 1
|
||||
} else {
|
||||
row.typeName = 'varchar'
|
||||
row.precision = 255
|
||||
}
|
||||
}
|
||||
const suggestedFieldType = (row: { name: string; typeName: string; precision: number }) => {
|
||||
// 如果fieldName 包含 time,date ,则默认为时间类型, 如果包含id ,则默认是 bigint
|
||||
if (row.name.includes('time') || row.name.includes('date')) {
|
||||
row.typeName = 'datetime';
|
||||
row.precision = 0;
|
||||
} else if (row.name.includes('id')) {
|
||||
row.typeName = 'bigint';
|
||||
row.precision = 20;
|
||||
} else if (row.name.includes('flag') || row.name.includes('status')) {
|
||||
row.typeName = 'char';
|
||||
row.precision = 1;
|
||||
} else {
|
||||
row.typeName = 'varchar';
|
||||
row.precision = 255;
|
||||
}
|
||||
};
|
||||
|
||||
// 暴露变量
|
||||
defineExpose({
|
||||
openDialog
|
||||
openDialog,
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -1,33 +1,33 @@
|
||||
export default {
|
||||
createTable: {
|
||||
index: '#',
|
||||
importcreateTableTip: 'import CreateTable',
|
||||
id: 'id',
|
||||
tableName: 'tableName',
|
||||
comments: 'comments',
|
||||
comment: 'comment',
|
||||
databaseType: 'databaseType',
|
||||
pkPolicy: 'pkPolicy',
|
||||
createUser: 'createUser',
|
||||
createTime: 'createTime',
|
||||
columnInfo: 'columnInfo',
|
||||
tenantId: 'tenantId',
|
||||
inputIdTip: 'input id',
|
||||
inputTableNameTip: 'input tableName',
|
||||
inputCommentsTip: 'input comments',
|
||||
inputCommentTip: 'input comment',
|
||||
inputDatabaseTypeTip: 'input databaseType',
|
||||
inputPkPolicyTip: 'input pkPolicy',
|
||||
inputCreateUserTip: 'input createUser',
|
||||
inputCreateTimeTip: 'input createTime',
|
||||
inputColumnInfoTip: 'input columnInfo',
|
||||
inputTenantIdTip: 'input tenantId',
|
||||
name: 'name',
|
||||
typeName: 'typeName',
|
||||
precision: 'precision',
|
||||
scale: 'scale',
|
||||
defaultValue: 'defaultValue',
|
||||
primary: 'primary',
|
||||
nullable: 'nullable',
|
||||
}
|
||||
}
|
||||
createTable: {
|
||||
index: '#',
|
||||
importcreateTableTip: 'import CreateTable',
|
||||
id: 'id',
|
||||
tableName: 'tableName',
|
||||
comments: 'comments',
|
||||
comment: 'comment',
|
||||
databaseType: 'databaseType',
|
||||
pkPolicy: 'pkPolicy',
|
||||
createUser: 'createUser',
|
||||
createTime: 'createTime',
|
||||
columnInfo: 'columnInfo',
|
||||
tenantId: 'tenantId',
|
||||
inputIdTip: 'input id',
|
||||
inputTableNameTip: 'input tableName',
|
||||
inputCommentsTip: 'input comments',
|
||||
inputCommentTip: 'input comment',
|
||||
inputDatabaseTypeTip: 'input databaseType',
|
||||
inputPkPolicyTip: 'input pkPolicy',
|
||||
inputCreateUserTip: 'input createUser',
|
||||
inputCreateTimeTip: 'input createTime',
|
||||
inputColumnInfoTip: 'input columnInfo',
|
||||
inputTenantIdTip: 'input tenantId',
|
||||
name: 'name',
|
||||
typeName: 'typeName',
|
||||
precision: 'precision',
|
||||
scale: 'scale',
|
||||
defaultValue: 'defaultValue',
|
||||
primary: 'primary',
|
||||
nullable: 'nullable',
|
||||
},
|
||||
};
|
||||
|
||||
@@ -1,33 +1,33 @@
|
||||
export default {
|
||||
createTable: {
|
||||
index: '#',
|
||||
importcreateTableTip: '导入自动创建表管理',
|
||||
id: '主键ID',
|
||||
tableName: '表名称',
|
||||
comments: '表注释',
|
||||
comment: '字段注释',
|
||||
databaseType: '数据库类型',
|
||||
pkPolicy: '主键策略',
|
||||
createUser: '创建人',
|
||||
createTime: '创建时间',
|
||||
columnInfo: '字段信息',
|
||||
tenantId: '租户ID',
|
||||
inputIdTip: '请输入主键ID',
|
||||
inputTableNameTip: '请输入表名称',
|
||||
inputCommentsTip: '请输入表注释',
|
||||
inputCommentTip: '请输入字段注释',
|
||||
inputDatabaseTypeTip: '请输入数据库引擎',
|
||||
inputPkPolicyTip: '请输入主键策略',
|
||||
inputCreateUserTip: '请输入创建人',
|
||||
inputCreateTimeTip: '请输入创建时间',
|
||||
inputColumnInfoTip: '请输入字段信息',
|
||||
inputTenantIdTip: '请输入租户ID',
|
||||
name: '字段名称',
|
||||
typeName: '字段类型',
|
||||
precision: '字段长度',
|
||||
scale: '小数位数',
|
||||
defaultValue: '默认值',
|
||||
primary: '主键',
|
||||
nullable: 'NULL',
|
||||
}
|
||||
}
|
||||
createTable: {
|
||||
index: '#',
|
||||
importcreateTableTip: '导入自动创建表管理',
|
||||
id: '主键ID',
|
||||
tableName: '表名称',
|
||||
comments: '表注释',
|
||||
comment: '字段注释',
|
||||
databaseType: '数据库类型',
|
||||
pkPolicy: '主键策略',
|
||||
createUser: '创建人',
|
||||
createTime: '创建时间',
|
||||
columnInfo: '字段信息',
|
||||
tenantId: '租户ID',
|
||||
inputIdTip: '请输入主键ID',
|
||||
inputTableNameTip: '请输入表名称',
|
||||
inputCommentsTip: '请输入表注释',
|
||||
inputCommentTip: '请输入字段注释',
|
||||
inputDatabaseTypeTip: '请输入数据库引擎',
|
||||
inputPkPolicyTip: '请输入主键策略',
|
||||
inputCreateUserTip: '请输入创建人',
|
||||
inputCreateTimeTip: '请输入创建时间',
|
||||
inputColumnInfoTip: '请输入字段信息',
|
||||
inputTenantIdTip: '请输入租户ID',
|
||||
name: '字段名称',
|
||||
typeName: '字段类型',
|
||||
precision: '字段长度',
|
||||
scale: '小数位数',
|
||||
defaultValue: '默认值',
|
||||
primary: '主键',
|
||||
nullable: 'NULL',
|
||||
},
|
||||
};
|
||||
|
||||
@@ -1,160 +1,168 @@
|
||||
<template>
|
||||
<div class="layout-padding">
|
||||
<div class="layout-padding-auto layout-padding-view">
|
||||
<el-row v-show="showSearch">
|
||||
<el-form :model="state.queryForm" ref="queryRef" :inline="true" @keyup.enter="getDataList">
|
||||
<el-form-item label="数据源" prop="name">
|
||||
<el-select @change="getDataList" placeholder="请选择数据源" v-model="state.queryForm.dsName">
|
||||
<el-option label="默认数据源" value="master"></el-option>
|
||||
<el-option :key="ds.id" :label="ds.name" :value="ds.name" v-for="ds in datasourceList"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('createTable.tableName')" prop="tableName">
|
||||
<el-input :placeholder="t('createTable.inputTableNameTip')" v-model="state.queryForm.tableName"/>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button icon="search" type="primary" @click="getDataList">
|
||||
{{ $t('common.queryBtn') }}
|
||||
</el-button>
|
||||
<el-button icon="Refresh" @click="resetQuery">{{ $t('common.resetBtn') }}</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<div class="mb8" style="width: 100%">
|
||||
<el-button icon="folder-add" type="primary" class="ml10" v-auth="'codegen_table_add'"
|
||||
@click="formDialogRef.openDialog('add',null,state.queryForm.dsName)">
|
||||
{{ $t('common.addBtn') }}
|
||||
</el-button>
|
||||
<el-button plain :disabled="multiple" v-auth="'codegen_table_add'" icon="Delete" type="primary" class="ml10"
|
||||
@click="handleDelete(selectObjs)">
|
||||
{{ $t('common.delBtn') }}
|
||||
</el-button>
|
||||
<right-toolbar v-model:showSearch="showSearch" :export="'order_createtable_export'"
|
||||
@exportExcel="exportExcel" class="ml10" style="float: right;margin-right: 20px"
|
||||
@queryTable="getDataList"></right-toolbar>
|
||||
</div>
|
||||
</el-row>
|
||||
<el-table :data="state.dataList" v-loading="state.loading" style="width: 100%"
|
||||
:cell-style="tableStyle.cellStyle"
|
||||
border
|
||||
:header-cell-style="tableStyle.headerCellStyle"
|
||||
@selection-change="handleSelectionChange" @sort-change="sortChangeHandle">
|
||||
<el-table-column type="selection" width="40" align="center"/>
|
||||
<el-table-column type="index" fixed="left" :label="t('createTable.index')" width="40"/>
|
||||
<el-table-column prop="tableName" :label="t('createTable.tableName')" show-overflow-tooltip/>
|
||||
<el-table-column prop="comments" :label="t('createTable.comments')" show-overflow-tooltip/>
|
||||
<el-table-column prop="primary" :label="t('createTable.primary')" show-overflow-tooltip>
|
||||
<template #default="scope">
|
||||
<!-- 获取主键列名称-->
|
||||
{{ JSON.parse(scope.row.columnInfo).find(col => col.primary === 1)?.name }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="createTime" :label="t('createTable.createTime')" show-overflow-tooltip/>
|
||||
<el-table-column :label="$t('common.action')" fixed="right" width="200">
|
||||
<template #default="scope">
|
||||
<el-button text type="primary" icon="view" @click="formDialogRef.openDialog('view', scope.row.id)">
|
||||
{{ $t('common.viewBtn') }}
|
||||
</el-button>
|
||||
<el-button icon="FolderOpened" @click="openGen(scope.row)" text type="primary">{{
|
||||
$t('gen.genBtn')
|
||||
}}
|
||||
</el-button>
|
||||
<el-button icon="edit-pen" text type="primary" v-auth="'order_createtable_edit'"
|
||||
@click="formDialogRef.openDialog('edit', scope.row.id)">{{ $t('common.editBtn') }}
|
||||
</el-button>
|
||||
<el-button icon="delete" text type="primary" @click="handleDelete([scope.row.id])">{{
|
||||
$t('common.delBtn')
|
||||
}}
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<pagination @size-change="sizeChangeHandle" @current-change="currentChangeHandle" v-bind="state.pagination"/>
|
||||
</div>
|
||||
<div class="layout-padding">
|
||||
<div class="layout-padding-auto layout-padding-view">
|
||||
<el-row v-show="showSearch">
|
||||
<el-form :model="state.queryForm" ref="queryRef" :inline="true" @keyup.enter="getDataList">
|
||||
<el-form-item label="数据源" prop="name">
|
||||
<el-select @change="getDataList" placeholder="请选择数据源" v-model="state.queryForm.dsName">
|
||||
<el-option label="默认数据源" value="master"></el-option>
|
||||
<el-option :key="ds.id" :label="ds.name" :value="ds.name" v-for="ds in datasourceList"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('createTable.tableName')" prop="tableName">
|
||||
<el-input :placeholder="t('createTable.inputTableNameTip')" v-model="state.queryForm.tableName" />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button icon="search" type="primary" @click="getDataList">
|
||||
{{ $t('common.queryBtn') }}
|
||||
</el-button>
|
||||
<el-button icon="Refresh" @click="resetQuery">{{ $t('common.resetBtn') }}</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<div class="mb8" style="width: 100%">
|
||||
<el-button
|
||||
icon="folder-add"
|
||||
type="primary"
|
||||
class="ml10"
|
||||
v-auth="'codegen_table_add'"
|
||||
@click="formDialogRef.openDialog('add', null, state.queryForm.dsName)"
|
||||
>
|
||||
{{ $t('common.addBtn') }}
|
||||
</el-button>
|
||||
<el-button
|
||||
plain
|
||||
:disabled="multiple"
|
||||
v-auth="'codegen_table_add'"
|
||||
icon="Delete"
|
||||
type="primary"
|
||||
class="ml10"
|
||||
@click="handleDelete(selectObjs)"
|
||||
>
|
||||
{{ $t('common.delBtn') }}
|
||||
</el-button>
|
||||
<right-toolbar
|
||||
v-model:showSearch="showSearch"
|
||||
:export="'order_createtable_export'"
|
||||
@exportExcel="exportExcel"
|
||||
class="ml10"
|
||||
style="float: right; margin-right: 20px"
|
||||
@queryTable="getDataList"
|
||||
></right-toolbar>
|
||||
</div>
|
||||
</el-row>
|
||||
<el-table
|
||||
:data="state.dataList"
|
||||
v-loading="state.loading"
|
||||
style="width: 100%"
|
||||
:cell-style="tableStyle.cellStyle"
|
||||
border
|
||||
:header-cell-style="tableStyle.headerCellStyle"
|
||||
@selection-change="handleSelectionChange"
|
||||
@sort-change="sortChangeHandle"
|
||||
>
|
||||
<el-table-column type="selection" width="40" align="center" />
|
||||
<el-table-column type="index" fixed="left" :label="t('createTable.index')" width="40" />
|
||||
<el-table-column prop="tableName" :label="t('createTable.tableName')" show-overflow-tooltip />
|
||||
<el-table-column prop="comments" :label="t('createTable.comments')" show-overflow-tooltip />
|
||||
<el-table-column prop="primary" :label="t('createTable.primary')" show-overflow-tooltip>
|
||||
<template #default="scope">
|
||||
<!-- 获取主键列名称-->
|
||||
{{ JSON.parse(scope.row.columnInfo).find((col) => col.primary === 1)?.name }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="createTime" :label="t('createTable.createTime')" show-overflow-tooltip />
|
||||
<el-table-column :label="$t('common.action')" fixed="right" width="200">
|
||||
<template #default="scope">
|
||||
<el-button text type="primary" icon="view" @click="formDialogRef.openDialog('view', scope.row.id)">
|
||||
{{ $t('common.viewBtn') }}
|
||||
</el-button>
|
||||
<el-button icon="FolderOpened" @click="openGen(scope.row)" text type="primary">{{ $t('gen.genBtn') }} </el-button>
|
||||
<el-button icon="edit-pen" text type="primary" v-auth="'order_createtable_edit'" @click="formDialogRef.openDialog('edit', scope.row.id)"
|
||||
>{{ $t('common.editBtn') }}
|
||||
</el-button>
|
||||
<el-button icon="delete" text type="primary" @click="handleDelete([scope.row.id])">{{ $t('common.delBtn') }} </el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<pagination @size-change="sizeChangeHandle" @current-change="currentChangeHandle" v-bind="state.pagination" />
|
||||
</div>
|
||||
|
||||
<!-- 编辑、新增 -->
|
||||
<form-dialog ref="formDialogRef" @refresh="getDataList(false)"/>
|
||||
</div>
|
||||
<!-- 编辑、新增 -->
|
||||
<form-dialog ref="formDialogRef" @refresh="getDataList(false)" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="systemCreateTable">
|
||||
import {BasicTableProps, useTable} from "/@/hooks/table";
|
||||
import {fetchList, delObjs} from "/@/api/gen/create-table";
|
||||
import {useMessage, useMessageBox} from "/@/hooks/message";
|
||||
import { BasicTableProps, useTable } from '/@/hooks/table';
|
||||
import { fetchList, delObjs } from '/@/api/gen/create-table';
|
||||
import { useMessage, useMessageBox } from '/@/hooks/message';
|
||||
|
||||
import {useI18n} from "vue-i18n";
|
||||
import {list} from "/@/api/gen/datasource";
|
||||
import {useSyncTableApi, useTableApi} from "/@/api/gen/table";
|
||||
import {validateNull} from "/@/utils/validate";
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { list } from '/@/api/gen/datasource';
|
||||
import { useSyncTableApi, useTableApi } from '/@/api/gen/table';
|
||||
import { validateNull } from '/@/utils/validate';
|
||||
|
||||
// 引入组件
|
||||
const FormDialog = defineAsyncComponent(() => import('./form.vue'));
|
||||
const {t} = useI18n()
|
||||
const { t } = useI18n();
|
||||
// 定义变量内容
|
||||
const formDialogRef = ref()
|
||||
const formDialogRef = ref();
|
||||
const datasourceList = ref();
|
||||
const router = useRouter();
|
||||
|
||||
// 搜索变量
|
||||
const queryRef = ref()
|
||||
const showSearch = ref(true)
|
||||
const queryRef = ref();
|
||||
const showSearch = ref(true);
|
||||
// 多选变量
|
||||
const selectObjs = ref([]) as any
|
||||
const multiple = ref(true)
|
||||
const selectObjs = ref([]) as any;
|
||||
const multiple = ref(true);
|
||||
|
||||
const state: BasicTableProps = reactive<BasicTableProps>({
|
||||
queryForm: {
|
||||
},
|
||||
pageList: fetchList,
|
||||
descs: ["create_time"]
|
||||
})
|
||||
queryForm: {},
|
||||
pageList: fetchList,
|
||||
descs: ['create_time'],
|
||||
});
|
||||
|
||||
// table hook
|
||||
const {
|
||||
getDataList,
|
||||
currentChangeHandle,
|
||||
sizeChangeHandle,
|
||||
sortChangeHandle,
|
||||
downBlobFile,
|
||||
tableStyle
|
||||
} = useTable(state)
|
||||
const { getDataList, currentChangeHandle, sizeChangeHandle, sortChangeHandle, downBlobFile, tableStyle } = useTable(state);
|
||||
|
||||
// 清空搜索条件
|
||||
const resetQuery = () => {
|
||||
// 清空搜索条件
|
||||
queryRef.value?.resetFields()
|
||||
// 清空多选
|
||||
selectObjs.value = []
|
||||
getDataList()
|
||||
}
|
||||
// 清空搜索条件
|
||||
queryRef.value?.resetFields();
|
||||
// 清空多选
|
||||
selectObjs.value = [];
|
||||
getDataList();
|
||||
};
|
||||
|
||||
// 导出excel
|
||||
const exportExcel = () => {
|
||||
downBlobFile('/order/create-table/export', state.queryForm, 'create-table.xlsx')
|
||||
}
|
||||
downBlobFile('/order/create-table/export', state.queryForm, 'create-table.xlsx');
|
||||
};
|
||||
|
||||
// 多选事件
|
||||
const handleSelectionChange = (objs: any) => {
|
||||
selectObjs.value = objs.map(({id}) => id);
|
||||
multiple.value = !objs.length;
|
||||
selectObjs.value = objs.map(({ id }) => id);
|
||||
multiple.value = !objs.length;
|
||||
};
|
||||
|
||||
// 删除操作
|
||||
const handleDelete = async (ids: string[]) => {
|
||||
try {
|
||||
await useMessageBox().confirm(t('common.delConfirmText'));
|
||||
} catch {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
await useMessageBox().confirm(t('common.delConfirmText'));
|
||||
} catch {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await delObjs(ids);
|
||||
getDataList();
|
||||
useMessage().success(t('common.delSuccessText'));
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg);
|
||||
}
|
||||
try {
|
||||
await delObjs(ids);
|
||||
getDataList();
|
||||
useMessage().success(t('common.delSuccessText'));
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -162,30 +170,30 @@ const handleDelete = async (ids: string[]) => {
|
||||
* @param row
|
||||
*/
|
||||
const openGen = (row: { tableName: string }) => {
|
||||
useTableApi(state.queryForm.dsName, row.tableName)
|
||||
.then((res) => {
|
||||
if (validateNull(res.data.fieldList)) {
|
||||
useSyncTableApi(state.queryForm.dsName, row.tableName);
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
router.push({
|
||||
path: '/gen/gener/index',
|
||||
query: {
|
||||
tableName: row.tableName,
|
||||
dsName: state.queryForm.dsName,
|
||||
},
|
||||
});
|
||||
});
|
||||
useTableApi(state.queryForm.dsName, row.tableName)
|
||||
.then((res) => {
|
||||
if (validateNull(res.data.fieldList)) {
|
||||
useSyncTableApi(state.queryForm.dsName, row.tableName);
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
router.push({
|
||||
path: '/gen/gener/index',
|
||||
query: {
|
||||
tableName: row.tableName,
|
||||
dsName: state.queryForm.dsName,
|
||||
},
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
// 初始化数据
|
||||
onMounted(() => {
|
||||
list().then((res) => {
|
||||
datasourceList.value = res.data;
|
||||
// 默认去第一个数据源
|
||||
state.queryForm.dsName = datasourceList.value[0]?.name || 'master';
|
||||
getDataList();
|
||||
});
|
||||
list().then((res) => {
|
||||
datasourceList.value = res.data;
|
||||
// 默认去第一个数据源
|
||||
state.queryForm.dsName = datasourceList.value[0]?.name || 'master';
|
||||
getDataList();
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -1,85 +1,84 @@
|
||||
<template>
|
||||
<el-dialog :title="form.id ? $t('common.editBtn') : $t('common.addBtn')" v-model="visible"
|
||||
:close-on-click-modal="false" draggable>
|
||||
<el-form ref="dataFormRef" :model="form" :rules="dataRules" formDialogRef label-width="90px" v-loading="loading">
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item :label="t('datasourceconf.dsType')" prop="dsType">
|
||||
<el-select v-model="form.dsType" :placeholder="t('datasourceconf.inputdsTypeTip')">
|
||||
<el-option :key="item.value" :label="item.label" :value="item.value" v-for="item in ds_type"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item :label="t('datasourceconf.name')" prop="name">
|
||||
<el-input v-model="form.name" :placeholder="t('datasourceconf.inputnameTip')"/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item :label="t('datasourceconf.username')" prop="username">
|
||||
<el-input v-model="form.username" :placeholder="t('datasourceconf.inputusernameTip')"/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item :label="t('datasourceconf.password')" prop="password">
|
||||
<el-input v-model="form.password" :placeholder="t('datasourceconf.inputpasswordTip')"/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item :label="t('datasourceconf.confType')" prop="confType">
|
||||
<el-radio-group v-model="form.confType">
|
||||
<el-radio :label="Number(item.value)" v-for="(item, index) in ds_config_type" border :key="index">
|
||||
{{ item.label }}
|
||||
</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12" class="mb20" v-if="form.confType === 0 && form.dsType === 'mssql'">
|
||||
<el-form-item :label="t('datasourceconf.instance')" prop="instance">
|
||||
<el-input v-model="form.instance" :placeholder="t('datasourceconf.inputinstanceTip')"/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12" class="mb20" v-if="form.confType === 0">
|
||||
<el-form-item :label="t('datasourceconf.port')" prop="port">
|
||||
<el-input-number v-model="form.port" :placeholder="t('datasourceconf.inputportTip')"/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12" class="mb20" v-if="form.confType === 0">
|
||||
<el-form-item :label="t('datasourceconf.host')" prop="host">
|
||||
<el-input v-model="form.host" :placeholder="t('datasourceconf.inputhostTip')"/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12" class="mb20" v-if="form.confType === 0">
|
||||
<el-form-item :label="t('datasourceconf.dsName')" prop="dsName">
|
||||
<el-input v-model="form.dsName" :placeholder="t('datasourceconf.inputdsNameTip')"/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24" class="mb20" v-if="form.confType === 1">
|
||||
<el-form-item :label="t('datasourceconf.url')" prop="url">
|
||||
<el-input v-model="form.url" type="textarea" :placeholder="t('datasourceconf.inputurlTip')"/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-dialog :title="form.id ? $t('common.editBtn') : $t('common.addBtn')" v-model="visible" :close-on-click-modal="false" draggable>
|
||||
<el-form ref="dataFormRef" :model="form" :rules="dataRules" formDialogRef label-width="90px" v-loading="loading">
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item :label="t('datasourceconf.dsType')" prop="dsType">
|
||||
<el-select v-model="form.dsType" :placeholder="t('datasourceconf.inputdsTypeTip')">
|
||||
<el-option :key="item.value" :label="item.label" :value="item.value" v-for="item in ds_type"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item :label="t('datasourceconf.name')" prop="name">
|
||||
<el-input v-model="form.name" :placeholder="t('datasourceconf.inputnameTip')" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item :label="t('datasourceconf.username')" prop="username">
|
||||
<el-input v-model="form.username" :placeholder="t('datasourceconf.inputusernameTip')" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item :label="t('datasourceconf.password')" prop="password">
|
||||
<el-input v-model="form.password" :placeholder="t('datasourceconf.inputpasswordTip')" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item :label="t('datasourceconf.confType')" prop="confType">
|
||||
<el-radio-group v-model="form.confType">
|
||||
<el-radio :label="Number(item.value)" v-for="(item, index) in ds_config_type" border :key="index">
|
||||
{{ item.label }}
|
||||
</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12" class="mb20" v-if="form.confType === 0 && form.dsType === 'mssql'">
|
||||
<el-form-item :label="t('datasourceconf.instance')" prop="instance">
|
||||
<el-input v-model="form.instance" :placeholder="t('datasourceconf.inputinstanceTip')" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12" class="mb20" v-if="form.confType === 0">
|
||||
<el-form-item :label="t('datasourceconf.port')" prop="port">
|
||||
<el-input-number v-model="form.port" :placeholder="t('datasourceconf.inputportTip')" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12" class="mb20" v-if="form.confType === 0">
|
||||
<el-form-item :label="t('datasourceconf.host')" prop="host">
|
||||
<el-input v-model="form.host" :placeholder="t('datasourceconf.inputhostTip')" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12" class="mb20" v-if="form.confType === 0">
|
||||
<el-form-item :label="t('datasourceconf.dsName')" prop="dsName">
|
||||
<el-input v-model="form.dsName" :placeholder="t('datasourceconf.inputdsNameTip')" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24" class="mb20" v-if="form.confType === 1">
|
||||
<el-form-item :label="t('datasourceconf.url')" prop="url">
|
||||
<el-input v-model="form.url" type="textarea" :placeholder="t('datasourceconf.inputurlTip')" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="visible = false">{{ $t('common.cancelButtonText') }}</el-button>
|
||||
<el-button type="primary" @click="onSubmit" :disabled="loading">{{ $t('common.confirmButtonText') }}</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="systemDatasourceConfDialog">
|
||||
import {useMessage} from '/@/hooks/message';
|
||||
import {getObj, addObj, putObj} from '/@/api/gen/datasource';
|
||||
import {useI18n} from 'vue-i18n';
|
||||
import {useDict} from '/@/hooks/dict';
|
||||
import {rule} from "/@/utils/validate";
|
||||
import { useMessage } from '/@/hooks/message';
|
||||
import { getObj, addObj, putObj } from '/@/api/gen/datasource';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { useDict } from '/@/hooks/dict';
|
||||
import { rule } from '/@/utils/validate';
|
||||
|
||||
// 定义子组件向父组件传值/事件
|
||||
const emit = defineEmits(['refresh']);
|
||||
const {t} = useI18n();
|
||||
const { t } = useI18n();
|
||||
|
||||
// 定义变量内容
|
||||
const dataFormRef = ref();
|
||||
@@ -87,23 +86,23 @@ const visible = ref(false);
|
||||
const loading = ref(false);
|
||||
|
||||
// 定义字典处理
|
||||
const {ds_config_type, ds_type} = useDict('ds_config_type', 'ds_type');
|
||||
const { ds_config_type, ds_type } = useDict('ds_config_type', 'ds_type');
|
||||
|
||||
// 提交表单数据
|
||||
const form = reactive({
|
||||
id: '',
|
||||
name: '',
|
||||
url: '',
|
||||
username: '',
|
||||
password: ('' as string) || undefined,
|
||||
createTime: '',
|
||||
updateTime: '',
|
||||
dsType: '',
|
||||
confType: 0,
|
||||
dsName: '',
|
||||
instance: '',
|
||||
port: 3306,
|
||||
host: '',
|
||||
id: '',
|
||||
name: '',
|
||||
url: '',
|
||||
username: '',
|
||||
password: ('' as string) || undefined,
|
||||
createTime: '',
|
||||
updateTime: '',
|
||||
dsType: '',
|
||||
confType: 0,
|
||||
dsName: '',
|
||||
instance: '',
|
||||
port: 3306,
|
||||
host: '',
|
||||
});
|
||||
|
||||
/**
|
||||
@@ -113,86 +112,103 @@ const form = reactive({
|
||||
* @param {*} callback
|
||||
*/
|
||||
const validateDsName = (_rule, value, callback) => {
|
||||
var re = /(?=.*[a-z])(?=.*_)/;
|
||||
if (value && !re.test(value)) {
|
||||
callback(new Error('数据源名称不合法, 组名_数据源名形式'));
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
var re = /(?=.*[a-z])(?=.*_)/;
|
||||
if (value && !re.test(value)) {
|
||||
callback(new Error('数据源名称不合法, 组名_数据源名形式'));
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
};
|
||||
|
||||
// 定义校验规则
|
||||
const dataRules = ref({
|
||||
name: [
|
||||
{required: true, message: '别名不能为空', trigger: 'blur'},
|
||||
{validator: validateDsName, trigger: 'blur'},
|
||||
],
|
||||
url: [{required: true, message: 'jdbcurl不能为空', trigger: 'blur'}, {
|
||||
min: 10,
|
||||
max: 500,
|
||||
message: 'URL长度必须介于 10 和 500 字符之间',
|
||||
trigger: 'blur'
|
||||
},],
|
||||
username: [{ validator: rule.overLength, trigger: 'blur' },{required: true, message: '用户名不能为空', trigger: 'blur'}],
|
||||
password: [{ validator: rule.overLength, trigger: 'blur' },{required: true, message: '密码不能为空', trigger: 'blur'}],
|
||||
dsType: [{required: true, message: '数据库类型不能为空', trigger: 'blur'}],
|
||||
confType: [{required: true, message: '配置类型不能为空', trigger: 'blur'}],
|
||||
dsName: [{ validator: rule.overLength, trigger: 'blur' },{required: true, message: '数据库名称不能为空', trigger: 'blur'}],
|
||||
instance: [{ validator: rule.overLength, trigger: 'blur' },{required: true, message: '实例不能为空', trigger: 'blur'}],
|
||||
port: [{required: true, message: '端口不能为空', trigger: 'blur'}],
|
||||
host: [{ validator: rule.overLength, trigger: 'blur' },{required: true, message: '主机不能为空', trigger: 'blur'}],
|
||||
name: [
|
||||
{ required: true, message: '别名不能为空', trigger: 'blur' },
|
||||
{ validator: validateDsName, trigger: 'blur' },
|
||||
],
|
||||
url: [
|
||||
{ required: true, message: 'jdbcurl不能为空', trigger: 'blur' },
|
||||
{
|
||||
min: 10,
|
||||
max: 500,
|
||||
message: 'URL长度必须介于 10 和 500 字符之间',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
username: [
|
||||
{ validator: rule.overLength, trigger: 'blur' },
|
||||
{ required: true, message: '用户名不能为空', trigger: 'blur' },
|
||||
],
|
||||
password: [
|
||||
{ validator: rule.overLength, trigger: 'blur' },
|
||||
{ required: true, message: '密码不能为空', trigger: 'blur' },
|
||||
],
|
||||
dsType: [{ required: true, message: '数据库类型不能为空', trigger: 'blur' }],
|
||||
confType: [{ required: true, message: '配置类型不能为空', trigger: 'blur' }],
|
||||
dsName: [
|
||||
{ validator: rule.overLength, trigger: 'blur' },
|
||||
{ required: true, message: '数据库名称不能为空', trigger: 'blur' },
|
||||
],
|
||||
instance: [
|
||||
{ validator: rule.overLength, trigger: 'blur' },
|
||||
{ required: true, message: '实例不能为空', trigger: 'blur' },
|
||||
],
|
||||
port: [{ required: true, message: '端口不能为空', trigger: 'blur' }],
|
||||
host: [
|
||||
{ validator: rule.overLength, trigger: 'blur' },
|
||||
{ required: true, message: '主机不能为空', trigger: 'blur' },
|
||||
],
|
||||
});
|
||||
|
||||
// 打开弹窗
|
||||
const openDialog = async (id: string) => {
|
||||
visible.value = true;
|
||||
form.id = '';
|
||||
visible.value = true;
|
||||
form.id = '';
|
||||
|
||||
// 重置表单数据
|
||||
nextTick(() => {
|
||||
dataFormRef.value?.resetFields();
|
||||
});
|
||||
// 重置表单数据
|
||||
nextTick(() => {
|
||||
dataFormRef.value?.resetFields();
|
||||
});
|
||||
|
||||
// 获取DatasourceConf信息
|
||||
if (id) {
|
||||
form.id = id;
|
||||
await getDatasourceConfData(id);
|
||||
// 修改密码时候,原密码打码
|
||||
form.password = '********';
|
||||
}
|
||||
// 获取DatasourceConf信息
|
||||
if (id) {
|
||||
form.id = id;
|
||||
await getDatasourceConfData(id);
|
||||
// 修改密码时候,原密码打码
|
||||
form.password = '********';
|
||||
}
|
||||
};
|
||||
|
||||
// 提交
|
||||
const onSubmit = async () => {
|
||||
const valid = await dataFormRef.value.validate().catch(() => {
|
||||
});
|
||||
if (!valid) return false;
|
||||
const valid = await dataFormRef.value.validate().catch(() => {});
|
||||
if (!valid) return false;
|
||||
|
||||
form.password = form.password?.includes('******') ? undefined : form.password;
|
||||
form.password = form.password?.includes('******') ? undefined : form.password;
|
||||
|
||||
try {
|
||||
loading.value = true;
|
||||
form.id ? await putObj(form) : await addObj(form);
|
||||
useMessage().success(t(form.id ? 'common.editSuccessText' : 'common.addSuccessText'));
|
||||
visible.value = false;
|
||||
emit('refresh');
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg);
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
try {
|
||||
loading.value = true;
|
||||
form.id ? await putObj(form) : await addObj(form);
|
||||
useMessage().success(t(form.id ? 'common.editSuccessText' : 'common.addSuccessText'));
|
||||
visible.value = false;
|
||||
emit('refresh');
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg);
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
// 初始化表单数据
|
||||
const getDatasourceConfData = (id: string) => {
|
||||
// 获取数据
|
||||
return getObj(id).then((res: any) => {
|
||||
Object.assign(form, res.data);
|
||||
});
|
||||
// 获取数据
|
||||
return getObj(id).then((res: any) => {
|
||||
Object.assign(form, res.data);
|
||||
});
|
||||
};
|
||||
|
||||
// 暴露变量
|
||||
defineExpose({
|
||||
openDialog,
|
||||
openDialog,
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
<template>
|
||||
<el-dialog :title="form.id ? $t('common.editBtn') : $t('common.addBtn')" v-model="visible" width="600" :close-on-click-modal="false" draggable>
|
||||
<el-form ref="dataFormRef" :model="form" :rules="dataRules" formDialogRef label-width="90px" v-loading="loading">
|
||||
<el-form-item :label="t('fieldtype.columnType')" prop="columnType">
|
||||
<el-input v-model="form.columnType" :placeholder="t('fieldtype.inputcolumnTypeTip')" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('fieldtype.attrType')" prop="attrType">
|
||||
<el-input v-model="form.attrType" :placeholder="t('fieldtype.inputattrTypeTip')" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('fieldtype.packageName')" prop="packageName">
|
||||
<el-input v-model="form.packageName" :placeholder="t('fieldtype.inputpackageNameTip')" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('fieldtype.columnType')" prop="columnType">
|
||||
<el-input v-model="form.columnType" :placeholder="t('fieldtype.inputcolumnTypeTip')" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('fieldtype.attrType')" prop="attrType">
|
||||
<el-input v-model="form.attrType" :placeholder="t('fieldtype.inputattrTypeTip')" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('fieldtype.packageName')" prop="packageName">
|
||||
<el-input v-model="form.packageName" :placeholder="t('fieldtype.inputpackageNameTip')" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
|
||||
@@ -37,8 +37,8 @@
|
||||
</el-dialog>
|
||||
</template>
|
||||
<script setup lang="ts" name="child">
|
||||
import {useListTableApi, useListTableColumnApi, useSyncTableApi} from '/@/api/gen/table';
|
||||
import {useMessage} from "/@/hooks/message";
|
||||
import { useListTableApi, useListTableColumnApi, useSyncTableApi } from '/@/api/gen/table';
|
||||
import { useMessage } from '/@/hooks/message';
|
||||
|
||||
const emit = defineEmits(['update:modelValue']);
|
||||
|
||||
@@ -109,10 +109,10 @@ const getChildTableColumnList = (val: string) => {
|
||||
const onSubmit = async () => {
|
||||
const valid = await dataFormRef.value.validate().catch(() => {});
|
||||
if (!valid) return false;
|
||||
// 同步子表数据
|
||||
useSyncTableApi(currentDsName.value,form.childTableName).then(() => {
|
||||
useMessage().success('子表信息同步成功')
|
||||
});
|
||||
// 同步子表数据
|
||||
useSyncTableApi(currentDsName.value, form.childTableName).then(() => {
|
||||
useMessage().success('子表信息同步成功');
|
||||
});
|
||||
|
||||
visible.value = false;
|
||||
};
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
import { useMessage } from '/@/hooks/message';
|
||||
import { addObj, getObj, putObj } from '/@/api/gen/template';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import {rule} from "/@/utils/validate";
|
||||
import { rule } from '/@/utils/validate';
|
||||
|
||||
const CodeEditor = defineAsyncComponent(() => import('/@/components/CodeEditor/index.vue'));
|
||||
const emit = defineEmits(['refresh']);
|
||||
@@ -60,9 +60,18 @@ const form = reactive({
|
||||
|
||||
// 定义校验规则
|
||||
const dataRules = ref({
|
||||
templateName: [{ validator: rule.overLength, trigger: 'blur' },{ required: true, message: '模板名称不能为空', trigger: 'blur' }],
|
||||
generatorPath: [{ validator: rule.overLength, trigger: 'blur' },{ required: true, message: '模板路径不能为空', trigger: 'blur' }],
|
||||
templateDesc: [{ validator: rule.overLength, trigger: 'blur' },{ required: true, message: '模板描述不能为空', trigger: 'blur' }],
|
||||
templateName: [
|
||||
{ validator: rule.overLength, trigger: 'blur' },
|
||||
{ required: true, message: '模板名称不能为空', trigger: 'blur' },
|
||||
],
|
||||
generatorPath: [
|
||||
{ validator: rule.overLength, trigger: 'blur' },
|
||||
{ required: true, message: '模板路径不能为空', trigger: 'blur' },
|
||||
],
|
||||
templateDesc: [
|
||||
{ validator: rule.overLength, trigger: 'blur' },
|
||||
{ required: true, message: '模板描述不能为空', trigger: 'blur' },
|
||||
],
|
||||
});
|
||||
|
||||
// 打开弹窗
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user