foreign-admin-ui/src/views/system/worder/index.vue

286 lines
6.8 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="system table_form-container">
<!-- 搜索 -->
<WorkerSearch
:search-form="searchForm"
:buttonLoading="loading"
:search-options="searchOptions"
@search="handleSearch"
@reset="handleReset"
>
<template #button>
<el-button type="primary" @click="handleAdd" v-auth="'worker_addWorker'">新增员工</el-button>
</template>
</WorkerSearch>
<!-- 表格 -->
<WorkerTable
:table-data="workerList"
:columns="tableColumnsOptions"
row-key="id"
:loading="loading"
>
<template #status="{ row }">
<el-tag :type="row.status === 1 ? 'success' : 'danger'">
{{ row.status === 1 ? '正常' : '封禁' }}
</el-tag>
</template>
<template #action="{ row }">
<el-button link type="primary" size="small" @click="handleEdit(row)" v-auth="'worker_editWorker'">
编辑
</el-button>
</template>
</WorkerTable>
<!-- 新增/编辑弹窗 -->
<WorkerDialog
:visible="dialogVisible"
:title="dialogTitle"
:type="dialogType"
:button-loading="submitLoading"
@confirm="handleSubmit"
@cancel="handleCancel"
@close="handleClose"
>
<WorkerForm
:form-data="workerForm"
:form-rules="workerFormRules"
:form-items="workerFormItemOptions"
:options-map="workerFormOptionsMap"
ref="workerFormRef"
:key="formKey"
/>
</WorkerDialog>
</div>
</template>
<script setup lang="ts">
defineOptions({
name: 'Worder'
})
import type { FormInstance } from 'element-plus'
import { usePageLoading, useButtonLoading } from '@/composables/useLoading'
const { loading, startLoading, stopLoading } = usePageLoading()
const { buttonLoading: submitLoading, startButtonLoading: startSubmitLoading, stopButtonLoading: stopSubmitLoading } = useButtonLoading()
// 组件
import WorkerSearch from '@/components/common/Search.vue'
import WorkerTable from '@/components/common/Table.vue'
import WorkerDialog from '@/components/common/Dialog.vue'
import WorkerForm from '@/components/common/Form.vue'
// 配置以及表单验证
import { search, tableColumns, addFormItem, editFormItem } from './options'
import { addRules, editRules } from './rules'
// 接口
import {
getWorkerListApi,
getWorkerRoleIdOptionApi,
addWorkerApi,
editWorkerApi,
} from '@/api/modules/system/worker'
/**
* @description: 定义搜索数据
*/
const searchForm = ref({
username: '',
})
const searchOptions = ref(search)
/**
* @description: 定义表格数据
*/
const workerList = ref<any[]>([])
const tableColumnsOptions = ref(tableColumns)
/**
* @description: 定义弹窗数据
*/
const dialogVisible = ref(false)
const dialogTitle = ref('')
const dialogType = ref<'add' | 'edit'>('add')
// 切换弹窗类型时强制刷新表单组件,避免表单字段切换时旧值残留
const formKey = ref(0)
/**
* @description: 定义表单数据
*/
const workerForm = ref<any>({
user_id: 0,
username: '',
email: '',
role_id: null as number | null,
status: 1,
})
const workerFormRef = ref<FormInstance>()
const workerFormRules = ref<any>({})
const workerFormItemOptions = ref<any[]>([])
// 表单下拉选项映射(角色 / 状态)
const workerFormOptionsMap = ref<Record<string, { label: string; value: number }[]>>({
role_id: [],
status: [
{ label: '正常', value: 1 },
{ label: '封禁', value: 2 },
],
})
/**
* @description: 角色下拉数据加载
*/
const fetchRoleOptions = async () => {
try {
const data: any = await getWorkerRoleIdOptionApi()
const list = Array.isArray(data) ? data : (data?.data || [])
workerFormOptionsMap.value.role_id = list.map((item: any) => ({
label: item.title,
value: item.id,
}))
} catch (err) {
console.error('获取员工角色选项失败', err)
}
}
/**
* @description: 获取员工列表
*/
const fetchWorkerList = async () => {
startLoading()
try {
const params: any = {
username: searchForm.value.username || undefined,
}
const data: any = await getWorkerListApi(params)
const list = Array.isArray(data) ? data : (data?.data || [])
workerList.value = list.map((item: any) => ({
...item,
roleTitle: item.role?.title || '-',
}))
} catch (err) {
console.error('获取员工列表失败', err)
} finally {
stopLoading()
}
}
/**
* @description: 页面挂载
*/
onMounted(async () => {
await Promise.all([fetchRoleOptions(), fetchWorkerList()])
})
/**
* @description: 搜索 / 重置
*/
const handleSearch = () => {
fetchWorkerList()
}
const handleReset = () => {
searchForm.value = { username: '' }
fetchWorkerList()
}
/**
* @description: 新增
* 入参字段email、role_id
*/
const handleAdd = () => {
dialogVisible.value = true
dialogTitle.value = '新增员工'
dialogType.value = 'add'
workerFormItemOptions.value = addFormItem as any
workerFormRules.value = addRules()
formKey.value++
workerForm.value = {
user_id: 0,
email: '',
role_id: null,
}
}
/**
* @description: 编辑
* 入参字段username、email、status
*/
const handleEdit = (row: any) => {
dialogVisible.value = true
dialogTitle.value = '编辑员工'
dialogType.value = 'edit'
workerFormItemOptions.value = editFormItem as any
workerFormRules.value = editRules()
formKey.value++
workerForm.value = {
user_id: row.id,
username: row.username,
email: row.email,
status: row.status,
}
}
/**
* @description: 提交表单
*/
const handleSubmit = async () => {
startSubmitLoading()
try {
await workerFormRef.value?.validate()
if (dialogType.value === 'add') {
const params = {
email: workerForm.value.email,
role_id: workerForm.value.role_id,
}
await addWorkerApi(params)
ElNotification({
message: '新增成功',
type: 'success',
duration: 2000,
customClass: 'global-notification',
})
} else {
const params = {
user_id: workerForm.value.user_id,
username: workerForm.value.username,
email: workerForm.value.email,
status: workerForm.value.status,
}
await editWorkerApi(params)
ElNotification({
message: '编辑成功',
type: 'success',
duration: 2000,
customClass: 'global-notification',
})
}
dialogVisible.value = false
await fetchWorkerList()
} catch (err: any) {
if (err?.message) {
ElNotification({
message: err.message || '操作失败',
type: 'error',
duration: 2000,
customClass: 'global-notification',
})
}
} finally {
stopSubmitLoading()
}
}
/**
* @description: 取消 / 关闭弹窗
*/
const handleCancel = () => {
dialogVisible.value = false
}
const handleClose = () => {
dialogVisible.value = false
}
</script>
<style scoped lang="scss"></style>