This commit is contained in:
陈红丽 2024-08-24 09:57:13 +08:00
parent 0c9cb50548
commit bfa6f73975
13 changed files with 331 additions and 191 deletions

View File

@ -62,7 +62,18 @@ export function changePassword(data) {
} }
); );
} }
/**
* @description:
*/
export function sendSms(data) {
return http.request(
{
url: `/sms/sendSms`,
method: 'POST',
data
}
);
}
/** /**
* @description: * @description:
*/ */
@ -142,6 +153,16 @@ export function userBatchDelete(data:any) {
data data
}); });
} }
/**
* @description:
*/
export function userImport(data) {
return http.request({
url: '/user/import',
method: 'POST',
data
});
}
/** /**
* @description: * @description:
*/ */
@ -153,6 +174,16 @@ export function userExport() {
isTransformResponse: false, isTransformResponse: false,
}); });
} }
/**
* @description:
*/
export function getTemplateByCode(code:any) {
return http.request({
url: '/file/template/getTemplateByCode/'+code,
method: 'GET'
});
}
/** /**
* @description: * @description:
*/ */

View File

@ -8,6 +8,7 @@
:layout="layout" :layout="layout"
:total="pager.count" :total="pager.count"
:hide-on-single-page="false" :hide-on-single-page="false"
background
@size-change="sizeChange" @size-change="sizeChange"
@current-change="pageChange" @current-change="pageChange"
></el-pagination> ></el-pagination>

View File

@ -1,7 +1,7 @@
<template> <template>
<PageWrapper> <PageWrapper>
<el-row :gutter="10" class="mt-3"> <el-row :gutter="10" class="mt-3">
<el-col :xs="24" :sm="24" :md="8" :lg="8" :xl="8" class="mb-4"> <el-col :xs="24" :sm="24" :md="7" :lg="7" :xl="7" class="mb-4">
<el-card shadow="hover" class="border-0"> <el-card shadow="hover" class="border-0">
<template #header> <template #header>
<el-row> <el-row>
@ -15,36 +15,40 @@
</el-input> </el-input>
</el-col> </el-col>
<el-col :span="4" style="text-align: right;"> <el-col :span="4" style="text-align: right;">
<el-button type="primary" @click="reloadTable"> 查询 </el-button> <el-button type="primary" @click="pager.page=1;loadDataTable()"> 查询 </el-button>
</el-col> </el-col>
</el-row> </el-row>
<div style="margin-top:15px;"> <div style="margin-top:15px;">
<el-button type="primary" @click="addConfig">新建</el-button> <el-button type="primary" icon="Plus" @click="addConfig" v-perm="['sys:config:add']">新建</el-button>
<el-button type="danger" :disabled="!selectionData.length" @click="handleDelete()">删除</el-button> <el-button type="warning" icon="Edit" @click="handleEdit" v-perm="['sys:config:edit']">编辑</el-button>
<el-button type="danger" icon="Delete" @click="handleDelete()" v-perm="['sys:config:delete']">删除</el-button>
</div> </div>
</template> </template>
<BasicTable :columns="columns" :showTableSetting="false" :request="loadDataTable" :row-key="(row) => row.id" <div :style="{ height: fwbHeight + 'px' }" class="dict-list-box">
ref="tableRef" :actionColumn="actionColumn" @selection-change="onSelectionChange" highlight-current-row <div v-for="(item, index) in configDataList" :key="index" @click="onCheckedRow(item)" class="dict-item"
@row-click="onCheckedRow" /> :class="item.id == configId ? 'active' : ''">
<span class="t1">{{ item.name }}</span>
</div>
</div>
<pagination style="justify-content: flex-end" class="mt-10 flex" @change="loadDataTable" v-model="pager" layout="total, jumper">
</pagination>
</el-card> </el-card>
</el-col> </el-col>
<el-col :xs="24" :sm="24" :md="16" :lg="16" :xl="16" class="mb-4"> <el-col :xs="24" :sm="24" :md="17" :lg="17" :xl="17" class="mb-4">
<el-card shadow="hover" class="mb-4 border-0 proCard"> <el-card shadow="hover" class="mb-4 border-0 proCard">
<configItem :configId="configId" v-if="configItemShow"></configItem> <configItem :configId="configId" v-if="configItemShow"></configItem>
</el-card> </el-card>
</el-col> </el-col>
</el-row> </el-row>
<editDialog v-if="editVisible" :configId="configId" v-model:visible="editVisible" @success="reloadTable"> <editDialog v-if="editVisible" :configId="configId" v-model:visible="editVisible" @success="loadDataTable()">
</editDialog> </editDialog>
</PageWrapper> </PageWrapper>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { ref, reactive, h, nextTick, defineAsyncComponent } from 'vue'; import { ref,nextTick, defineAsyncComponent,onMounted } from 'vue';
import { SearchOutlined } from '@vicons/antd'; import { SearchOutlined } from '@vicons/antd';
import { TableAction } from '@/components/Table'; import { getConfigList, configDelete } from '@/api/data/config';
import { getConfigList, configDelete, configBatchDelete } from '@/api/data/config';
import { columns } from './columns';
import configItem from './configItem.vue'; import configItem from './configItem.vue';
import { message, confirm } from "@/utils/auth"; import { message, confirm } from "@/utils/auth";
const editDialog = defineAsyncComponent(() => const editDialog = defineAsyncComponent(() =>
@ -54,86 +58,52 @@ const configId = ref(0)
const configItemShow = ref(false) const configItemShow = ref(false)
const tableRef = ref(); const tableRef = ref();
const editVisible = ref(false) const editVisible = ref(false)
const selectionData = ref([])
const params = ref({ const params = ref({
name: '', name: '',
}); });
const configDataList = ref([])
const actionColumn = reactive({ const pager = ref({
lable: 150, page: 1,
title: '操作', size: 10,
prop: 'action', count: configDataList.value.length
fixed: 'right',
render(record) {
return h(TableAction as any, {
style: 'text',
actions: [
{
label: '编辑',
icon:'Edit',
type: 'warning',
onClick: handleEdit.bind(null, record),
},
{
label: '删除',
icon:'Delete',
type: 'danger',
onClick: handleDelete.bind(null, record),
}
],
});
},
}); });
const fwbHeight = document.body.clientHeight - 390
//
const addConfig = async () => { const addConfig = async () => {
configId.value=0 configId.value=0
await nextTick(); await nextTick();
editVisible.value=true editVisible.value=true
}; };
//
const handleEdit = async (record: Recordable) => { const handleEdit = () => {
configId.value=record.row.id
await nextTick();
editVisible.value=true editVisible.value=true
}; };
//
function onCheckedRow(row) { function onCheckedRow(row) {
configId.value = row.id configId.value = row.id
} }
//
function reloadTable() {
tableRef.value.reload({ pageNo: 1 });
}
//; const loadDataTable = async () => {
const loadDataTable = async (res) => { const result = await getConfigList({ ...params.value, pageNo:pager.value.page,pageSize:pager.value.size });
const result = await getConfigList({ ...params.value, ...res });
configId.value = result?.records[0]?.id configId.value = result?.records[0]?.id
configItemShow.value = true configItemShow.value = true
nextTick(() => { configDataList.value = result.records
const tables = tableRef.value.getTableRef(); pager.value.count = result.total
tables.setCurrentRow(result?.records[0])
})
return result;
}; };
// async function handleDelete() {
async function handleDelete(record: Recordable) {
let ids = []
if (!record) {
ids = selectionData.value.map(({ id }) => id);
}
await confirm('确定要删除?'); await confirm('确定要删除?');
record ? await configDelete(record.row.id) : await configBatchDelete(ids); await configDelete(configId.value);
message("删除成功"); message("删除成功");
reloadTable() pager.value.page = 1
} loadDataTable()
function onSelectionChange(value) {
selectionData.value = value
} }
onMounted(() => {
loadDataTable()
})
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.card-header { .card-header {
@ -141,4 +111,42 @@ function onSelectionChange(value) {
justify-content: space-between; justify-content: space-between;
align-items: center; align-items: center;
} }
.dict-list-box {
.dict-item {
height: 40px;
line-height: 40px;
padding: 0 6px;
cursor: pointer;
display: flex;
justify-content: space-between;
.t1 {
font-size: 14px;
display: block;
font-weight: 700;
.t2 {
font-size: 12px;
font-weight: normal;
}
}
&.active {
background-color: #e8f1ff;
border-radius: 3px;
.t1 {
color: #1677ff;
}
.t2 {
color:rgb(22, 119, 255,.8)
}
}
.el-badge__content.is-fixed {
top: 20px;
right: calc(-10px + var(--el-badge-size)/ 2);
}
}
}
</style> </style>

View File

@ -1,7 +1,7 @@
<template> <template>
<PageWrapper> <PageWrapper>
<el-row :gutter="10" class="mt-3"> <el-row :gutter="10" class="mt-3">
<el-col :xs="24" :sm="24" :md="8" :lg="8" :xl="8" class="mb-4"> <el-col :xs="24" :sm="24" :md="7" :lg="7" :xl="7" class="mb-4">
<el-card shadow="hover" class="border-0"> <el-card shadow="hover" class="border-0">
<template #header> <template #header>
<el-row> <el-row>
@ -15,37 +15,43 @@
</el-input> </el-input>
</el-col> </el-col>
<el-col :span="4" style="text-align: right;"> <el-col :span="4" style="text-align: right;">
<el-button type="primary" @click="reloadTable"> 查询 </el-button> <el-button type="primary" @click="pager.page=1;loadDataTable()"> 查询 </el-button>
</el-col> </el-col>
</el-row> </el-row>
<el-button type="primary" icon="RefreshRight" @click="dictRefresh" style="margin-top:15px;"
v-perm="['sys:dict:cache']">刷新缓存</el-button>
<div style="margin-top:15px;"> <div style="margin-top:15px;">
<el-button type="primary" @click="dictRefresh" v-perm="['sys:dict:cache']">刷新缓存</el-button> <el-button type="primary" icon="Plus" @click="addDict" v-perm="['sys:dict:add']">新建</el-button>
<el-button type="primary" @click="addDict" v-perm="['sys:dict:add']">新建</el-button> <el-button type="warning" icon="Edit" @click="handleEdit" v-perm="['sys:dict:edit']">编辑</el-button>
<el-button type="danger" v-perm="['sys:dict:delete']" :disabled="!selectionData.length" @click="handleDelete()">删除</el-button> <el-button type="danger" icon="Delete" v-perm="['sys:dict:delete']"
@click="handleDelete()">删除</el-button>
</div> </div>
</template> </template>
<BasicTable :columns="columns" :showTableSetting="false" :request="loadDataTable" :row-key="(row) => row.id" <div :style="{ height: fwbHeight + 'px' }" class="dict-list-box">
ref="tableRef" :actionColumn="actionColumn" @selection-change="onSelectionChange" highlight-current-row <div v-for="(item, index) in dictDataList" :key="index" @click="onCheckedRow(item)" class="dict-item"
@row-click="onCheckedRow" /> :class="item.id == dictId ? 'active' : ''">
<span class="t1">{{ item.name }}<span class="t2">({{ item.code }})</span></span>
</div>
</div>
<pagination style="justify-content: flex-end" class="mt-10 flex" @change="loadDataTable" v-model="pager" layout="total, jumper">
</pagination>
</el-card> </el-card>
</el-col> </el-col>
<el-col :xs="24" :sm="24" :md="16" :lg="16" :xl="16" class="mb-4"> <el-col :xs="24" :sm="24" :md="17" :lg="17" :xl="17" class="mb-4">
<el-card shadow="hover" class="mb-4 border-0 proCard"> <el-card shadow="hover" class="mb-4 border-0 proCard">
<dictItem :dictId="dictId" v-if="dictItemShow"></dictItem> <dictItem :dictId="dictId" v-if="dictItemShow"></dictItem>
</el-card> </el-card>
</el-col> </el-col>
</el-row> </el-row>
<editDialog v-if="editVisible" :dictId="dictId" v-model:visible="editVisible" @success="reloadTable"> <editDialog v-if="editVisible" :dictId="dictId" v-model:visible="editVisible" @success="loadDataTable()">
</editDialog> </editDialog>
</PageWrapper> </PageWrapper>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { ref, reactive, h, nextTick, defineAsyncComponent } from 'vue'; import { onMounted, ref, nextTick, defineAsyncComponent } from 'vue';
import { SearchOutlined } from '@vicons/antd'; import { SearchOutlined } from '@vicons/antd';
import { TableAction } from '@/components/Table'; import { getDictList, refreshCache, dictDelete } from '@/api/data/dictionary';
import { getDictList, refreshCache, dictDelete, dictBatchDelete } from '@/api/data/dictionary';
import { columns } from './columns';
import dictItem from './dictItem.vue'; import dictItem from './dictItem.vue';
import { message, confirm } from "@/utils/auth"; import { message, confirm } from "@/utils/auth";
const editDialog = defineAsyncComponent(() => const editDialog = defineAsyncComponent(() =>
@ -53,75 +59,40 @@ const editDialog = defineAsyncComponent(() =>
) )
const dictId = ref(0) const dictId = ref(0)
const dictItemShow = ref(false) const dictItemShow = ref(false)
const tableRef = ref(); const dictDataList = ref([])
const selectedKey = ref('');
const rowKeysName = ref('');
const currentRow = ref();
const editVisible = ref(false) const editVisible = ref(false)
const selectionData = ref([])
const params = ref({ const params = ref({
name: '', name: '',
}); });
const pager = ref({
const actionColumn = reactive({ page: 1,
lable: 150, size: 10,
title: '操作', count: dictDataList.value.length
prop: 'action',
fixed: 'right',
render(record) {
return h(TableAction as any, {
style: 'text',
actions: [
{
label: '编辑',
icon:'Edit',
type: 'warning',
onClick: handleEdit.bind(null, record),
},
{
label: '删除',
icon:'Delete',
type: 'danger',
onClick: handleDelete.bind(null, record),
}
],
});
},
}); });
const fwbHeight = document.body.clientHeight - 440
// //
const addDict = async () => { const addDict = async () => {
dictId.value=0 dictId.value = 0
await nextTick(); await nextTick();
editVisible.value=true editVisible.value = true
}; };
// //
const handleEdit = async (record: Recordable) => { const handleEdit = () => {
dictId.value=record.row.id editVisible.value = true
await nextTick();
editVisible.value=true
}; };
// //
function onCheckedRow(row) { function onCheckedRow(row) {
dictId.value = row.id dictId.value = row.id
} }
//
function reloadTable() {
tableRef.value.reload({ pageNo: 1 });
}
//; //;
const loadDataTable = async (res) => { const loadDataTable = async () => {
const result = await getDictList({ ...params.value, ...res }); const result = await getDictList({ ...params.value, pageNo:pager.value.page,pageSize:pager.value.size });
dictId.value = result?.records[0]?.id dictId.value = result?.records[0]?.id
dictItemShow.value = true dictItemShow.value = true
nextTick(() => { dictDataList.value = result.records
const tables = tableRef.value.getTableRef(); pager.value.count = result.total
tables.setCurrentRow(result?.records[0])
})
return result;
}; };
// //
@ -130,19 +101,17 @@ async function dictRefresh() {
message("刷新成功"); message("刷新成功");
} }
// //
async function handleDelete(record: Recordable) { async function handleDelete() {
let ids = []
if (!record) {
ids = selectionData.value.map(({ id }) => id);
}
await confirm('确定要删除?'); await confirm('确定要删除?');
record ? await dictDelete(record.row.id) : await dictBatchDelete(ids); await dictDelete(dictId.value);
message("删除成功"); message("删除成功");
reloadTable() pager.value.page = 1
} loadDataTable()
function onSelectionChange(value) {
selectionData.value = value
} }
onMounted(() => {
loadDataTable()
})
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.card-header { .card-header {
@ -150,4 +119,42 @@ function onSelectionChange(value) {
justify-content: space-between; justify-content: space-between;
align-items: center; align-items: center;
} }
.dict-list-box {
.dict-item {
height: 40px;
line-height: 40px;
padding: 0 6px;
cursor: pointer;
display: flex;
justify-content: space-between;
.t1 {
font-size: 14px;
display: block;
font-weight: 700;
.t2 {
font-size: 12px;
font-weight: normal;
}
}
&.active {
background-color: #e8f1ff;
border-radius: 3px;
.t1 {
color: #1677ff;
}
.t2 {
color:rgb(22, 119, 255,.8)
}
}
.el-badge__content.is-fixed {
top: 20px;
right: calc(-10px + var(--el-badge-size)/ 2);
}
}
}
</style> </style>

View File

@ -1,5 +1,5 @@
<template> <template>
<el-dialog v-model="props.visible" :title="dialogTitle" :append-to-body="true" width="600" :close-on-click-modal="false" <el-dialog v-model="props.visible" :title="dialogTitle" width="600" :close-on-click-modal="false"
:before-close="dialogClose"> :before-close="dialogClose">
<el-form ref="formRef" :model="formData" label-width="90px"> <el-form ref="formRef" :model="formData" label-width="90px">
<el-form-item <el-form-item

View File

@ -1,5 +1,5 @@
<template> <template>
<el-dialog v-model="props.visible" :title="dialogTitle" :append-to-body="true" width="600" :close-on-click-modal="false" <el-dialog v-model="props.visible" :title="dialogTitle" width="600" :close-on-click-modal="false"
:before-close="dialogClose"> :before-close="dialogClose">
<el-form ref="formRef" :model="formData" label-width="90px"> <el-form ref="formRef" :model="formData" label-width="90px">
<el-form-item <el-form-item

View File

@ -1,5 +1,5 @@
<template> <template>
<el-dialog v-model="props.visible" :title="dialogTitle" :append-to-body="true" width="600" :close-on-click-modal="false" <el-dialog v-model="props.visible" :title="dialogTitle" width="600" :close-on-click-modal="false"
:before-close="dialogClose"> :before-close="dialogClose">
<el-form ref="formRef" :model="formData" label-width="90px"> <el-form ref="formRef" :model="formData" label-width="90px">
<el-form-item <el-form-item

View File

@ -1,5 +1,5 @@
<template> <template>
<el-dialog v-model="props.visible" :title="dialogTitle" :append-to-body="true" width="600" :close-on-click-modal="false" <el-dialog v-model="props.visible" :title="dialogTitle" width="600" :close-on-click-modal="false"
:before-close="dialogClose"> :before-close="dialogClose">
<el-form ref="formRef" :model="formData" label-width="90px"> <el-form ref="formRef" :model="formData" label-width="90px">
<el-form-item <el-form-item

View File

@ -42,11 +42,11 @@ export const columns = [
}, },
{ {
label: '模板编号', label: '模板编号',
prop: 'number', prop: 'code',
}, },
{ {
label: '接收人手机', label: '接收人邮箱',
prop: 'receiveMobile', prop: 'receiveEmail',
}, },
{ {
label: '接收人类型', label: '接收人类型',

View File

@ -10,12 +10,22 @@
<el-descriptions column="2" border> <el-descriptions column="2" border>
<el-descriptions-item label="日志标题:" label-class-name="des-width">{{formData.title}}</el-descriptions-item> <el-descriptions-item label="日志标题:" label-class-name="des-width">{{formData.title}}</el-descriptions-item>
<el-descriptions-item label="日志类型:" label-class-name="des-width">{{getTyepText(formData.type)}}</el-descriptions-item> <el-descriptions-item label="日志类型:" label-class-name="des-width">{{getTyepText(formData.type)}}</el-descriptions-item>
<el-descriptions-item label="模板编号:">{{formData.number}}</el-descriptions-item> <el-descriptions-item label="模板编号:">{{formData.code}}</el-descriptions-item>
<el-descriptions-item label="接收人手机:">{{formData.receiveMobile}}</el-descriptions-item> <el-descriptions-item label="接收人邮箱:">{{formData.receiveEmail}}</el-descriptions-item>
<el-descriptions-item label="接收人类型:">{{getReviceType(formData.receiveType)}}</el-descriptions-item> <el-descriptions-item label="接收人类型:">{{getReviceType(formData.receiveType)}}</el-descriptions-item>
<el-descriptions-item label="请求耗时:">{{formData.consumeTime}}s</el-descriptions-item> <el-descriptions-item label="请求耗时:">{{formData.consumeTime}}s</el-descriptions-item>
<el-descriptions-item label="日志状态:">{{formData.status==1?'已读':'未读'}}</el-descriptions-item> <el-descriptions-item label="日志状态:">{{formData.status==1?'已读':'未读'}}</el-descriptions-item>
</el-descriptions> </el-descriptions>
<el-descriptions class="margin-top" :column="1" border>
<el-descriptions-item label="请求参数" label-class-name="des-width">
{{formData.param}}
</el-descriptions-item>
</el-descriptions>
<el-descriptions class="margin-top" :column="1" border>
<el-descriptions-item label="返回结果" label-class-name="des-width">
{{formData.result}}
</el-descriptions-item>
</el-descriptions>
<template #footer> <template #footer>
<span class="dialog-footer"> <span class="dialog-footer">
<el-button @click="dialogClose">关闭</el-button> <el-button @click="dialogClose">关闭</el-button>

View File

@ -37,7 +37,7 @@ import { useRoute, useRouter } from 'vue-router';
import { useUserStore } from '@/store/modules/user'; import { useUserStore } from '@/store/modules/user';
import { ElMessage } from 'element-plus'; import { ElMessage } from 'element-plus';
import { ResultEnum } from '@/enums/httpEnum'; import { ResultEnum } from '@/enums/httpEnum';
import { getInfoCaptcha } from '@/api/system/user'; import { getInfoCaptcha,sendSms } from '@/api/system/user';
import { PageEnum } from '@/enums/pageEnum'; import { PageEnum } from '@/enums/pageEnum';
import { SafetyCertificateOutlined } from '@vicons/antd'; import { SafetyCertificateOutlined } from '@vicons/antd';
const captchaImg = ref('') const captchaImg = ref('')
@ -56,7 +56,6 @@ const loading = ref(false);
const codeMsg: any = ref('获取验证码'); const codeMsg: any = ref('获取验证码');
const isGetCode = ref(false); const isGetCode = ref(false);
const autoLogin = ref(true);
const LOGIN_NAME = PageEnum.BASE_LOGIN_NAME; const LOGIN_NAME = PageEnum.BASE_LOGIN_NAME;
const formInline = reactive({ const formInline = reactive({
@ -73,11 +72,12 @@ const userStore = useUserStore();
const router = useRouter(); const router = useRouter();
const route = useRoute(); const route = useRoute();
function getCode() { async function getCode() {
if (!formInline.mobile) { if (!formInline.mobile) {
formRef.value.validateField('mobile') formRef.value.validateField('mobile')
return return
} }
await sendSms({mobile:formInline.mobile})
codeMsg.value = 60; codeMsg.value = 60;
isGetCode.value = true; isGetCode.value = true;
let time = setInterval(() => { let time = setInterval(() => {

View File

@ -37,7 +37,15 @@
</template> </template>
删除 删除
</el-button> </el-button>
<el-upload <el-button type="primary" @click="importVisible=true" v-perm="['sys:user:import']">
<template #icon>
<el-icon class="el-input__icon">
<Upload />
</el-icon>
</template>
导入
</el-button>
<!-- <el-upload
ref="upload" ref="upload"
action="/api/user/import" action="/api/user/import"
:headers="uploadHeaders" :headers="uploadHeaders"
@ -56,7 +64,7 @@
</template> </template>
导入 导入
</el-button> </el-button>
</el-upload> </el-upload> -->
<el-button type="primary" @click="handleExport" :loading="exportLoading" :disabled="exportLoading" v-perm="['sys:user:export']"> <el-button type="primary" @click="handleExport" :loading="exportLoading" :disabled="exportLoading" v-perm="['sys:user:export']">
<template #icon> <template #icon>
<el-icon class="el-input__icon"> <el-icon class="el-input__icon">
@ -76,31 +84,30 @@
@success="reloadTable('noRefresh')" @success="reloadTable('noRefresh')"
> >
</editDialog> </editDialog>
<userUpload v-if="importVisible" v-model:visible="importVisible" @success="reloadTable()"/>
</PageWrapper> </PageWrapper>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { h, nextTick, reactive, ref ,defineAsyncComponent} from 'vue'; import { h, nextTick, reactive, ref ,defineAsyncComponent} from 'vue';
import { ColProps, UploadInstance } from 'element-plus'; import { ColProps } from 'element-plus';
import { TableAction } from '@/components/Table'; import { TableAction } from '@/components/Table';
import { useForm } from '@/components/Form/index'; import { useForm } from '@/components/Form/index';
import { getUserList,userDelete,userBatchDelete,userExport,resetPwd } from '@/api/system/user'; import { getUserList,userDelete,userBatchDelete,userExport,resetPwd } from '@/api/system/user';
import {message,confirm,loading, closeLoading} from "@/utils/auth"; import {message,confirm} from "@/utils/auth";
import { columns } from './columns'; import { columns } from './columns';
import { schemas } from './querySchemas'; import { schemas } from './querySchemas';
import { useUserStore } from '@/store/modules/user';
import {downloadByData} from '@/utils/file/download'; import {downloadByData} from '@/utils/file/download';
const userId = ref(0); const userId = ref(0);
const tableRef = ref(); const tableRef = ref();
const editVisible = ref(false) const editVisible = ref(false)
const importVisible = ref(false)
const selectionData = ref([]) const selectionData = ref([])
const upload = ref<UploadInstance>();
const exportLoading=ref(false) const exportLoading=ref(false)
const editDialog = defineAsyncComponent(() => const editDialog = defineAsyncComponent(() =>
import('./edit.vue')) import('./edit.vue'))
const uploadHeaders = reactive({ const userUpload = defineAsyncComponent(() =>
authorization:useUserStore().getToken import('./userUpload.vue'))
});
const formParams = reactive({ const formParams = reactive({
realname: '', realname: '',
role:'', role:'',
@ -216,34 +223,7 @@
userId.value =0 userId.value =0
editVisible.value = true editVisible.value = true
} }
const beforeUpload = (file: UploadFile) => {
const isLt2M = file.size / 1024 / 1024 < 200;
if (!isLt2M) {
message("大小不能超过200MB!", "error");
return false;
}
if (!/\.(xlsx|xls|XLSX|XLS)$/.test(file.name)) {
message("请上传.xlsx .xls", "error");
return false;
}
loading("上传中");
return true;
};
const onSuccess = (file: UploadFile) => {
upload.value!.clearFiles();
closeLoading();
if (file.code == 0) {
message("导入成功");
reloadTable()
} else {
message(file.msg ? file.msg : "导入失败", "error");
}
};
const onError = () => {
upload.value!.clearFiles();
closeLoading();
message("导入失败", "error");
};
// //
const handleExport = async()=>{ const handleExport = async()=>{
exportLoading.value=true exportLoading.value=true

View File

@ -0,0 +1,103 @@
<template>
<el-dialog v-model="props.visible" :title="dialogTitle" width="450" :close-on-click-modal="false"
:before-close="dialogClose">
<el-upload
style="width:400px"
drag
ref="upload"
action="/api/user/import"
:headers="uploadHeaders"
:on-error="onError"
:on-success="onSuccess"
:before-upload="beforeUpload"
:show-file-list="false"
:limit="1"
v-perm="['sys:user:import']"
>
<el-icon class="el-icon--upload" style="color:#165DFF;"><upload-filled /></el-icon>
<div class="el-upload__text">
点击或将文件拖拽到这里上传
</div>
</el-upload>
<div style="margin-top:20px;">
<span>只能上传 xlsxlsx 文件,</span>
<el-button type="primary" link @click="handleDownload">下载模板
</el-button>
</div>
</el-dialog>
</template>
<script lang="ts" setup>
import { getTemplateByCode } from '@/api/system/user';
import { computed,shallowRef,ref,reactive } from "vue";
import { UploadInstance } from 'element-plus';
import { FormInstance } from "element-plus";
import { message,loading,closeLoading } from "@/utils/auth";
const formRef = shallowRef<FormInstance>();
import { useUserStore } from '@/store/modules/user';
const props = defineProps({
visible: {
type: Boolean,
required: true,
default: false
},
id: {
type: Number,
required: true,
default: 0
}
});
const upload = ref<UploadInstance>();
const uploadHeaders = reactive({
authorization:useUserStore().getToken
});
const emit = defineEmits(["success", "update:visible"]);
const dialogTitle = computed(() => {
return '导入用户';
});
const dialogClose = () => {
emit("update:visible", false);
};
const beforeUpload = (file: UploadFile) => {
const isLt2M = file.size / 1024 / 1024 < 200;
if (!isLt2M) {
message("大小不能超过200MB!", "error");
return false;
}
if (!/\.(xlsx|xls|XLSX|XLS)$/.test(file.name)) {
message("请上传.xlsx .xls", "error");
return false;
}
loading("上传中");
return true;
};
const onSuccess = (file: UploadFile) => {
upload.value!.clearFiles();
closeLoading();
if (file.code == 0) {
message("导入成功");
emit("update:visible", false);
emit("success");
} else {
message(file.msg ? file.msg : "导入失败", "error");
}
};
const onError = () => {
upload.value!.clearFiles();
closeLoading();
message("导入失败", "error");
};
const handleDownload = async()=>{
const res =await getTemplateByCode('user_import')
window.open(res.filePath)
}
</script>