v1.0.2 更新内容

This commit is contained in:
浅念
2025-08-15 16:31:55 +08:00
parent f5deb7b8f7
commit 0e84bedb67
21 changed files with 2977 additions and 319 deletions
+47 -18
View File
@@ -4,7 +4,7 @@
<ElRow>
<div style="width: 12px"></div>
<ElCol :xs="24" :sm="12" :lg="6" class="el-col2">
<ElButton @click="showDialog('add')" v-ripple>新增</ElButton>
<ElButton @click="showDialog('add')" v-ripple v-if="hasAuth('system@company_add')">新增</ElButton>
</ElCol>
</ElRow>
<ArtTable
@@ -19,6 +19,7 @@
<template #default>
<ElTableColumn label="ID" prop="id" />
<ElTableColumn label="公司名称" prop="name" />
<ElTableColumn label="公司标识" prop="abbr" />
<ElTableColumn label="状态" prop="status">
<template #default="scope">
<ElTag :type="scope.row.status ? 'primary' : 'info'">
@@ -30,8 +31,21 @@
<ElTableColumn fixed="right" label="操作" width="200px">
<template #default="scope">
<ElRow>
<el-button link @click="showDialog('edit', scope.row)"> 编辑 </el-button>
<el-button link @click="deleteRole(scope.row)"> 删除 </el-button>
<el-button
link
@click="showDialog('edit', scope.row)"
v-if="hasAuth('system@company_update')"
>
编辑
</el-button>
<el-button
type="danger"
link
@click="deleteRole(scope.row)"
v-if="hasAuth('system@company_destroy')"
>
删除
</el-button>
</ElRow>
</template>
</ElTableColumn>
@@ -43,10 +57,19 @@
width="40%"
align-center
>
<ElForm ref="formRef" :model="form" :rules="rules" label-width="160px">
<ElForm ref="formRef" :model="form" :rules="rules" label-width="80px" class="form">
<ElFormItem label="公司名称" prop="name">
<ElInput v-model="form.name" />
</ElFormItem>
<ElFormItem label="公司标识" prop="abbr">
<ElInput v-model="form.abbr" />
</ElFormItem>
<!-- <ElFormItem label="飞书标识" prop="tenant_key">
<ElInput v-model="form.tenant_key" />
</ElFormItem> -->
<ElFormItem label="状态">
<ElSwitch v-model="form.status" :active-value="1" :inactive-value="0" />
</ElFormItem>
</ElForm>
<template #footer>
<div class="dialog-footer">
@@ -65,22 +88,26 @@
<script setup lang="ts">
import { ElMessage, ElMessageBox } from 'element-plus'
import type { FormInstance, FormRules } from 'element-plus'
import { Ordertype} from '@/mock/temp/formData'
import { systemService } from '@/api/systemApi'
import { useAuth } from '@/composables/useAuth'
const { hasAuth } = useAuth()
defineOptions({ name: 'Type ' })
const loading = ref(false)
const dialogVisible = ref(false)
const typeList = ref<any[]>([])
const formRef = ref<FormInstance>()
const { width } = useWindowSize()
const isMobile = computed(() => width.value < 500)
const rules = reactive<FormRules>({
name: [{ required: true, message: '请输入公司名称', trigger: 'blur' }]
name: [{ required: true, message: '请输入公司名称', trigger: 'blur' }],
abbr: [{ required: true, message: '请输入公司简称', trigger: 'blur' }]
// tenant_key: [{ required: true, message: '请输入飞书标识', trigger: 'blur' }]
})
const form = reactive<Ordertype>({
const form = reactive<any>({
name: '',
id:''
id: '',
abbr: '',
status: 1
})
const pagination = reactive({
currentPage: 1,
@@ -127,18 +154,25 @@
if (type === 'edit' && row) {
form.name = row.name
form.id = row.id
form.status = row.status
form.abbr = row.abbr
// form.tenant_key = row.tenant_key
} else {
form.name = ''
form.id = ''
form.status = 1
form.abbr = ''
// form.tenant_key = ''
}
}
const deleteRole = (row?: any) => {
ElMessageBox.confirm('确定删除该分类吗?', '删除确认', {
ElMessageBox.confirm('确定删除吗?', '删除确认', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'error'
}).then(async () => {
const { message } = await systemService.companyDelete({
id: row.id,
id: row.id
})
ElMessage.success(message)
getWorkList()
@@ -148,17 +182,12 @@
const handleSubmit = async (formEl: FormInstance | undefined) => {
if (!formEl) return
if (dialogType.value === 'add') {
const { message } = await systemService.companyAdd({
name: form.name
})
const { message } = await systemService.companyAdd(form)
ElMessage.success(message)
dialogVisible.value = false
getWorkList()
} else {
const { message } = await systemService.companyEdit({
name: form.name,
id: form.id
})
const { message } = await systemService.companyEdit(form)
ElMessage.success(message)
dialogVisible.value = false
getWorkList()
-194
View File
@@ -1,194 +0,0 @@
<template>
<div class="page-content">
<div v-if="!isMobile">
<ElRow>
<!-- <ElCol :xs="24" :sm="12" :lg="6">
<ElInput placeholder="名称"></ElInput>
</ElCol> -->
<div style="width: 12px"></div>
<ElCol :xs="24" :sm="12" :lg="6" class="el-col2">
<!-- <ElButton v-ripple>搜索</ElButton> -->
<ElButton @click="showDialog('add')" v-ripple>新增</ElButton>
</ElCol>
</ElRow>
<ArtTable
ref="tableRef"
row-key="id"
:loading="loading"
:data="tableData"
:currentPage="pagination.currentPage"
:pageSize="pagination.pageSize"
:total="pagination.total"
>
<template #default>
<ElTableColumn label="ID" prop="id" />
<ElTableColumn label="分类名称" prop="name" />
<ElTableColumn label="状态" prop="status">
<template #default="scope">
<ElTag :type="scope.row.status ? 'primary' : 'info'">
{{ scope.row.status ? '启用' : '禁用' }}
</ElTag>
</template>
</ElTableColumn>
<ElTableColumn label="创建时间" prop="created_at" />
<ElTableColumn fixed="right" label="操作" width="200px">
<template #default="scope">
<ElRow>
<el-button link @click="showDialog('edit', scope.row)"> 编辑 </el-button>
<el-button link @click="deleteRole(scope.row)"> 删除 </el-button>
</ElRow>
</template>
</ElTableColumn>
</template>
</ArtTable>
<ElDialog
v-model="dialogVisible"
:title="dialogType === 'add' ? '新增' : '编辑'"
width="40%"
align-center
>
<ElForm ref="formRef" :model="form" :rules="rules" label-width="160px">
<ElFormItem label="分类名称" prop="name">
<ElInput v-model="form.name" />
</ElFormItem>
</ElForm>
<template #footer>
<div class="dialog-footer">
<ElButton @click="dialogVisible = false">取消</ElButton>
<ElButton type="primary" @click="handleSubmit(formRef)">提交</ElButton>
</div>
</template>
</ElDialog>
</div>
<div v-else class="mobile-hide-tip">
<p>该页面暂不支持移动端访问</p>
</div>
</div>
</template>
<script setup lang="ts">
import { ElMessage, ElMessageBox } from 'element-plus'
import type { FormInstance, FormRules } from 'element-plus'
import { Ordertype} from '@/mock/temp/formData'
import { systemService } from '@/api/systemApi'
defineOptions({ name: 'Type ' })
const loading = ref(false)
const dialogVisible = ref(false)
const typeList = ref<any[]>([])
const formRef = ref<FormInstance>()
const { width } = useWindowSize()
const isMobile = computed(() => width.value < 500)
const rules = reactive<FormRules>({
name: [
{ required: true, message: '请输入分类名称', trigger: 'blur' }
]
})
const form = reactive<Ordertype>({
name: '',
id:''
})
const pagination = reactive({
currentPage: 1,
pageSize: 10,
total: 0
})
// 表格数据
const tableData = ref<any[]>([])
// 表格实例引用
const tableRef = ref()
onMounted(() => {
getWorkList()
})
// 获取列表数据
const getWorkList = async () => {
loading.value = true
try {
const { currentPage, pageSize } = pagination
const { records, current, size, total } = await systemService.getFeishuAppList({
current: currentPage,
size: pageSize
})
tableData.value = records.map((item: any, index: number) => ({
...item
}))
Object.assign(pagination, { currentPage: current, pageSize: size, total })
} catch (error) {
console.error('获取列表失败:', error)
} finally {
loading.value = false
}
}
const dialogType = ref('add')
const showDialog = (type: string, row?: any) => {
dialogVisible.value = true
dialogType.value = type
if (type === 'edit' && row) {
form.name = row.name
form.id = row.id
} else {
form.name = ''
}
}
const deleteRole = (row?: any) => {
ElMessageBox.confirm('确定删除该分类吗?', '删除确认', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'error'
}).then(async () => {
const { message } = await systemService.feishuAppDelete({
id: row.id,
})
ElMessage.success(message)
getWorkList()
})
}
const handleSubmit = async (formEl: FormInstance | undefined) => {
if (!formEl) return
if (dialogType.value === 'add') {
const { message } = await systemService.feishuAppAdd({
name: form.name
})
ElMessage.success(message)
dialogVisible.value = false
getWorkList()
} else {
const { message } = await systemService.feishuAppEdit({
name: form.name,
id: form.id
})
ElMessage.success(message)
dialogVisible.value = false
getWorkList()
}
}
</script>
<style lang="scss" scoped>
:deep(.el-table__empty-block) {
height: 100% !important;
min-height: 200px;
display: flex;
align-items: center;
justify-content: center;
}
.page-content {
.svg-icon {
width: 1.8em;
height: 1.8em;
overflow: hidden;
vertical-align: -8px;
fill: currentcolor;
}
}
</style>
+350
View File
@@ -0,0 +1,350 @@
<template>
<div class="page-content">
<div v-if="!isMobile">
<ElRow>
<!-- <ElCol :xs="24" :sm="12" :lg="6">
<ElInput placeholder="名称"></ElInput>
</ElCol> -->
<div style="width: 12px"></div>
<ElCol :xs="24" :sm="12" :lg="6" class="el-col2">
<!-- <ElButton v-ripple>搜索</ElButton> -->
<ElButton @click="showDialog('add')" v-if="hasAuth('system@feishu_app_add')" v-ripple
>新增</ElButton
>
</ElCol>
</ElRow>
<ArtTable
ref="tableRef"
row-key="id"
:loading="loading"
:data="tableData"
:currentPage="pagination.currentPage"
:pageSize="pagination.pageSize"
:total="pagination.total"
>
<template #default>
<ElTableColumn label="ID" prop="id" width="80" />
<ElTableColumn label="公司" prop="corp_id" width="140">
<template #default="scope">
{{ scope.row.corpInfo.name }}
</template>
</ElTableColumn>
<ElTableColumn label="系统" prop="system_id" width="140">
<template #default="scope">
{{ scope.row.systemInfo.name }}
</template>
</ElTableColumn>
<ElTableColumn label="名称" prop="name" width="160" />
<ElTableColumn label="应用ID" prop="app_id" width="180" show-overflow-tooltip />
<ElTableColumn label="基础域" prop="base_uri" width="220" show-overflow-tooltip />
<ElTableColumn label="授权地址" prop="r_url" width="260" show-overflow-tooltip />
<ElTableColumn label="授权范围" prop="scopes" width="240" show-overflow-tooltip />
<ElTableColumn label="携带参数" prop="state" width="140" show-overflow-tooltip />
<ElTableColumn label="排序" prop="sort" width="90" />
<ElTableColumn label="状态" prop="status" width="100">
<template #default="scope">
<ElTag :type="scope.row.status ? 'primary' : 'info'">
{{ scope.row.status ? '启用' : '禁用' }}
</ElTag>
</template>
</ElTableColumn>
<ElTableColumn label="创建时间" prop="created_at" width="180" />
<ElTableColumn fixed="right" label="操作" width="180px">
<template #default="scope">
<ElRow>
<el-button
link
@click="showDialog('edit', scope.row)"
v-if="hasAuth('system@feishu_app_update')"
>
编辑
</el-button>
<el-button
type="danger"
link
@click="deleteRole(scope.row)"
v-if="hasAuth('system@feishu_app_destroy')"
>
删除
</el-button>
</ElRow>
</template>
</ElTableColumn>
</template>
</ArtTable>
<ElDialog
v-model="dialogVisible"
:title="dialogType === 'add' ? '新增' : '编辑'"
align-center
>
<ElForm
ref="formRef"
:model="form"
:rules="rules"
style="padding: 5px 20px"
label-width="100px"
>
<ElFormItem label="公司" prop="corp_id">
<ElSelect v-model="form.corp_id" placeholder="请选择公司" filterable style="width: 100%">
<ElOption v-for="item in companyList" :key="item.id" :label="item.name" :value="item.id" />
</ElSelect>
</ElFormItem>
<ElFormItem label="系统" prop="system_id">
<ElSelect v-model="form.system_id" placeholder="请选择系统" filterable style="width: 100%">
<ElOption v-for="item in systemsList" :key="item.id" :label="item.name" :value="item.id" />
</ElSelect>
</ElFormItem>
<ElFormItem label="名称" prop="name">
<ElInput v-model="form.name" placeholder="请输入名称" />
</ElFormItem>
<!-- <ElFormItem label="企业标识" prop="tenant_key">
<ElInput v-model="form.tenant_key" placeholder="请输入企业标识" />
</ElFormItem> -->
<ElFormItem label="应用ID" prop="app_id">
<ElInput v-model="form.app_id" placeholder="请输入应用ID" />
</ElFormItem>
<ElFormItem label="应用秘钥" prop="app_secret">
<ElInput v-model="form.app_secret" placeholder="请输入应用秘钥" show-password />
</ElFormItem>
<ElFormItem label="基础域" prop="base_uri">
<ElInput v-model="form.base_uri" placeholder="请输入基础域" />
</ElFormItem>
<ElFormItem label="授权地址" prop="r_url">
<ElInput v-model="form.r_url" placeholder="请输入授权地址" />
</ElFormItem>
<ElFormItem label="授权范围" prop="scopes">
<ElInput v-model="form.scopes" type="textarea" :rows="3" placeholder="请输入授权范围" />
</ElFormItem>
<ElFormItem label="携带参数" prop="state">
<ElInput v-model="form.state" placeholder="请输入携带参数" />
</ElFormItem>
<ElFormItem label="排序" prop="sort">
<ElInputNumber v-model="form.sort" :min="0" placeholder="请输入排序" />
</ElFormItem>
<ElFormItem label="状态" prop="status">
<ElSwitch v-model="form.status" :active-value="1" :inactive-value="0" />
</ElFormItem>
</ElForm>
<template #footer>
<div class="dialog-footer">
<ElButton @click="dialogVisible = false">取消</ElButton>
<ElButton type="primary" @click="handleSubmit(formRef)">提交</ElButton>
</div>
</template>
</ElDialog>
</div>
<div v-else class="mobile-hide-tip">
<p>该页面暂不支持移动端访问</p>
</div>
</div>
</template>
<script setup lang="ts">
import { ElMessage, ElMessageBox } from 'element-plus'
import type { FormInstance, FormRules } from 'element-plus'
import { systemService } from '@/api/systemApi'
import { UserService } from '@/api/usersApi'
import { useAuth } from '@/composables/useAuth'
const { hasAuth } = useAuth()
defineOptions({ name: 'Type ' })
const loading = ref(false)
const dialogVisible = ref(false)
const formRef = ref<FormInstance>()
const { width } = useWindowSize()
const isMobile = computed(() => width.value < 500)
const rules = reactive<FormRules>({
corp_id: [{ required: true, message: '请选择公司', trigger: 'change' }],
system_id: [{ required: true, message: '请选择系统', trigger: 'change' }],
name: [{ required: true, message: '请输入名称', trigger: 'blur' }],
// app_id: [{ required: true, message: '请输入应用ID', trigger: 'blur' }],
// app_secret: [{ required: true, message: '请输入应用秘钥', trigger: 'blur' }],
// base_uri: [{ required: true, message: '请输入基础域', trigger: 'blur' }],
// r_url: [{ required: true, message: '请输入授权地址', trigger: 'blur' }],
// scopes: [{ required: true, message: '请输入授权范围', trigger: 'blur' }],
// state: [{ required: true, message: '请输入携带参数', trigger: 'blur' }],
// sort: [{ required: true, message: '请输入排序', trigger: 'blur' }],
// status: [{ required: true, message: '请选择状态', trigger: 'change' }]
})
const form = reactive({
corp_id: '',
system_id: '',
name: '',
// tenant_key: '',
app_id: '',
app_secret: '',
base_uri: '',
r_url: '',
scopes: '',
state: '',
sort: 0,
status: 1,
id: ''
})
const pagination = reactive({
currentPage: 1,
pageSize: 10,
total: 0
})
const companyList = ref<any[]>([])
const systemsList = ref<any[]>([])
const getcompanyList = async () => {
const response = await UserService.getCompanyList()
const list = (response as any)?.data ?? (response as any)?.records ?? response
companyList.value = Array.isArray(list) ? list : []
}
const getsystemsList = async () => {
const response = await UserService.getsystemsList()
const list = (response as any)?.data ?? (response as any)?.records ?? response
systemsList.value = Array.isArray(list) ? list : []
}
// 表格数据
const tableData = ref<any[]>([])
// 表格实例引用
const tableRef = ref()
onMounted(() => {
getWorkList()
getcompanyList()
getsystemsList()
})
// 获取列表数据
const getWorkList = async () => {
loading.value = true
try {
const { currentPage, pageSize } = pagination
const { records, current, size, total } = await systemService.getFeishuAppList({
current: currentPage,
size: pageSize
})
tableData.value = records.map((item: any, index: number) => ({
...item
}))
Object.assign(pagination, { currentPage: current, pageSize: size, total })
} catch (error) {
console.error('获取列表失败:', error)
} finally {
loading.value = false
}
}
const dialogType = ref('add')
const showDialog = (type: string, row?: any) => {
dialogVisible.value = true
dialogType.value = type
if (type === 'edit' && row) {
// 编辑模式,填充所有字段
Object.assign(form, {
corp_id: row.corp_id || '',
system_id: row.system_id || '',
name: row.name || '',
// tenant_key: row.tenant_key || '',
app_id: row.app_id || '',
app_secret: row.app_secret || '',
base_uri: row.base_uri || '',
r_url: row.r_url || '',
scopes: row.scopes || '',
state: row.state || '',
sort: row.sort || 0,
status: row.status !== undefined ? row.status : 1,
id: row.id || ''
})
} else {
// 新增模式,重置所有字段
Object.assign(form, {
corp_id: '',
system_id: '',
name: '',
// tenant_key: '',
app_id: '',
app_secret: '',
base_uri: '',
r_url: '',
scopes: '',
state: '',
sort: 0,
status: 1,
id: ''
})
}
}
const deleteRole = (row?: any) => {
ElMessageBox.confirm('确定删除吗?', '删除确认', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'error'
}).then(async () => {
const { message } = await systemService.feishuAppDelete({
id: row.id
})
ElMessage.success(message)
getWorkList()
})
}
const handleSubmit = async (formEl: FormInstance | undefined) => {
if (!formEl) return
await formEl.validate(async (valid) => {
if (valid) {
if (dialogType.value === 'add') {
const { message } = await systemService.feishuAppAdd({
corp_id: form.corp_id,
system_id: form.system_id,
name: form.name,
app_id: form.app_id,
app_secret: form.app_secret,
base_uri: form.base_uri,
r_url: form.r_url,
scopes: form.scopes,
state: form.state,
sort: form.sort,
status: form.status
})
ElMessage.success(message)
} else {
const { message } = await systemService.feishuAppEdit({
id: form.id,
corp_id: form.corp_id,
system_id: form.system_id,
name: form.name,
app_id: form.app_id,
app_secret: form.app_secret,
base_uri: form.base_uri,
r_url: form.r_url,
scopes: form.scopes,
state: form.state,
sort: form.sort,
status: form.status
})
ElMessage.success(message)
}
dialogVisible.value = false
getWorkList()
}
})
}
</script>
<style lang="scss" scoped>
:deep(.el-table__empty-block) {
height: 100% !important;
min-height: 200px;
display: flex;
align-items: center;
justify-content: center;
}
.page-content {
.svg-icon {
width: 1.8em;
height: 1.8em;
overflow: hidden;
vertical-align: -8px;
fill: currentcolor;
}
}
</style>
+63 -8
View File
@@ -14,8 +14,25 @@
<!-- 表格头部 -->
<ArtTableHeader :showZebra="false" v-model:columns="columnChecks" @refresh="handleRefresh">
<template #left>
<el-segmented
v-model="yearVal"
size="large"
:options="segmentedOptions"
@change="searchArticleByYear"
>
<!-- <template #default="scope">
<div class="flex flex-col items-center gap-2 p-2">
<div>{{ scope.item.label }}</div>
</div>
</template> -->
</el-segmented>
<!-- 按钮权限:后端控制模式,使用自定义指令 -->
<ElButton v-auth="'system@menu_add'" @click="showModel('menu', null)" v-ripple>
<ElButton
v-auth="'system@menu_add'"
@click="showModel('menu', null)"
v-ripple
style="margin-left: 20px"
>
添加菜单
</ElButton>
<ElButton @click="toggleExpand" v-ripple>
@@ -224,7 +241,7 @@
import { SearchFormItem } from '@/types'
import { systemService } from '@/api/systemApi'
import { UserService } from '@/api/usersApi'
const yearVal = ref<any>('')
defineOptions({ name: 'Menus' })
const { hasAuth } = useAuth()
@@ -233,6 +250,20 @@
const menuList = ref<any[]>([])
const loading = ref(false)
const systemsListtab = ref<any>([])
const segmentedOptions = computed(() =>
Array.isArray(systemsListtab.value)
? systemsListtab.value.map((item: any) => ({ label: item.name, value: item.id }))
: []
)
const getsystemsListtab = async () => {
const response = await UserService.getsystemsList()
const list = (response as any)?.data?.records ?? (response as any)?.records ?? response ?? []
systemsListtab.value = Array.isArray(list) ? list : []
if (!yearVal.value && systemsListtab.value.length > 0) {
yearVal.value = systemsListtab.value[0].id
}
}
//系统
const systemsList = ref<any>()
const getsystemsList = async () => {
@@ -467,16 +498,37 @@
const tableData = ref<AppRouteRecord[]>([])
onMounted(() => {
getsystemsListtab()
getTableData()
})
const searchArticleByYear = () => {
getTableData()
}
// const handleSegmentedClick = (item: any) => {
// // 若点击的是当前项也强制刷新
// yearVal.value = item?.value ?? yearVal.value
// getTableData()
// }
const getTableData = async () => {
loading.value = true
// const { res } = await systemService.getMenutreeList()
await systemService.getMenutreeList().then((res) => {
console.log(res)
menuList.value = res
})
// 清空旧数据,避免视觉上出现追加
menuList.value = []
tableData.value = []
// 并发安全:本次请求标识
requestCounter += 1
const reqId = requestCounter
const params: any = {
system_id: yearVal.value || '1'
}
try {
const res = await systemService.getMenutreeList(params)
// 若在等待过程中又发起了新请求,则丢弃本次结果
if (reqId !== requestCounter) return
menuList.value = Array.isArray(res) ? res : []
} catch (e) {
console.error(e)
menuList.value = []
}
// console.log(res)
// menuList.value = data
@@ -660,6 +712,9 @@
const isExpanded = ref(false)
const tableRef = ref()
// 数据请求并发保护计数器
let requestCounter = 0
const toggleExpand = () => {
isExpanded.value = !isExpanded.value
nextTick(() => {
+25 -4
View File
@@ -7,7 +7,7 @@
<div style="width: 12px"></div>
<ElCol :xs="24" :sm="12" :lg="6" class="el-col2">
<ElButton v-ripple>搜索</ElButton>
<ElButton @click="showDialog('add')" v-ripple>新增角色</ElButton>
<ElButton @click="showDialog('add')" v-ripple v-if="hasAuth('system@role_add')">新增角色</ElButton>
</ElCol>
</ElRow>
@@ -36,9 +36,28 @@
<ElTableColumn fixed="right" label="操作" width="200px">
<template #default="scope">
<ElRow>
<el-button link @click="showPermissionDialog(scope.row)"> 菜单权限 </el-button>
<el-button link @click="showDialog('edit', scope.row)"> 编辑 </el-button>
<el-button link @click="deleteRole(scope.row)"> 删除 </el-button>
<el-button
link
@click="showPermissionDialog(scope.row)"
v-if="hasAuth('system@role_perm')"
>
菜单权限
</el-button>
<el-button
type="success"
link
@click="showDialog('edit', scope.row)"
v-if="hasAuth('system@role_update')"
>
编辑
</el-button>
<el-button
type="danger"
link
@click="deleteRole(scope.row)"
v-if="hasAuth('system@role_destroy')"
>删除
</el-button>
</ElRow>
</template>
</ElTableColumn>
@@ -118,6 +137,8 @@
import type { FormInstance, FormRules } from 'element-plus'
import { formatMenuTitle } from '@/router/utils/utils'
import { systemService } from '@/api/systemApi'
import { useAuth } from '@/composables/useAuth'
const { hasAuth } = useAuth()
// import { ButtonMoreItem } from '@/components/core/forms/ArtButtonMore.vue'
// import { Role, ROLE_LIST_DATA } from '@/mock/temp/formData'
const loading = ref(false)
+330 -53
View File
@@ -8,7 +8,7 @@
<div style="width: 12px"></div>
<ElCol :xs="24" :sm="12" :lg="6" class="el-col2">
<!-- <ElButton v-ripple>搜索</ElButton> -->
<ElButton @click="showDialog('add')" v-ripple>新增</ElButton>
<ElButton @click="showDialog('add')" v-ripple v-if="hasAuth('system@systems_add')">新增</ElButton>
</ElCol>
</ElRow>
@@ -22,36 +22,114 @@
:total="pagination.total"
>
<template #default>
<ElTableColumn label="ID" prop="id" />
<ElTableColumn label="分类名称" prop="name" />
<ElTableColumn label="ID" prop="id" width="80" />
<ElTableColumn label="系统编码" prop="code" />
<ElTableColumn label="系统名称" prop="name" />
<ElTableColumn label="系统类型" prop="type">
<template #default="scope">
<ElTag :type="getTypeTagType(scope.row.type)">
{{ getTypeText(scope.row.type) }}
</ElTag>
</template>
</ElTableColumn>
<ElTableColumn label="系统描述" prop="desc" show-overflow-tooltip />
<ElTableColumn label="域名URL" prop="domain_url" show-overflow-tooltip />
<ElTableColumn label="区分角色" prop="is_role">
<template #default="scope">
<ElTag :type="scope.row.is_role ? 'success' : 'info'">
{{ scope.row.is_role ? '是' : '否' }}
</ElTag>
</template>
</ElTableColumn>
<!-- <ElTableColumn label="排序" prop="sort" width="80" /> -->
<ElTableColumn label="状态" prop="status">
<template #default="scope">
<ElTag :type="scope.row.status ? 'primary' : 'info'">
{{ scope.row.status ? '启用' : '禁用' }}
</ElTag>
</template>
</ElTableColumn>
<template #default="scope">
<ElTag :type="scope.row.status ? 'primary' : 'info'">
{{ scope.row.status ? '启用' : '禁用' }}
</ElTag>
</template>
</ElTableColumn>
<ElTableColumn label="创建时间" prop="created_at" />
<ElTableColumn fixed="right" label="操作" width="200px">
<ElTableColumn fixed="right" label="操作">
<template #default="scope">
<ElRow>
<el-button link @click="showDialog('edit', scope.row)"> 编辑 </el-button>
<el-button link @click="deleteRole(scope.row)"> 删除 </el-button>
<el-button
link
@click="showDialog('edit', scope.row)"
v-if="hasAuth('system@systems_update')"
>
编辑
</el-button>
<el-button
type="danger"
link
@click="deleteRole(scope.row)"
v-if="hasAuth('system@systems_destroy')"
>
删除
</el-button>
</ElRow>
</template>
</ElTableColumn>
</template>
</ArtTable>
<ElDialog
v-model="dialogVisible"
:title="dialogType === 'add' ? '新增' : '编辑'"
width="40%"
width="60%"
align-center
>
<ElForm ref="formRef" :model="form" :rules="rules" label-width="160px">
<ElFormItem label="分类名称" prop="name">
<ElInput v-model="form.name" />
<ElFormItem label="系统编码" prop="code">
<ElInput v-model="form.code" placeholder="请输入系统编码" />
</ElFormItem>
<ElFormItem label="系统名称" prop="name">
<ElInput v-model="form.name" placeholder="请输入系统名称" />
</ElFormItem>
<ElFormItem label="系统类型" prop="type">
<ElSelect v-model="form.type" placeholder="请选择系统类型" style="width: 100%">
<ElOption label="管理后台" value="admin" />
<ElOption label="Web端" value="web" />
<ElOption label="小程序" value="miniapp" />
<ElOption label="工具" value="tool" />
<ElOption label="其他" value="other" />
</ElSelect>
</ElFormItem>
<ElFormItem label="系统描述" prop="desc">
<ElInput v-model="form.desc" type="textarea" :rows="3" placeholder="请输入系统描述" />
</ElFormItem>
<ElFormItem label="系统图标" prop="icon">
<ElUpload
v-model:file-list="iconFileList"
:show-file-list="false"
:headers="uploadHeaders"
:action="actionImageUplode"
:before-upload="beforeIconUpload"
:on-success="handleIconSuccess"
:on-error="handleIconError"
accept="image/*"
class="icon-uploader"
>
<div v-if="form.icon" class="icon-preview">
<img :src="file_url" alt="系统图标" class="icon-image" />
<div class="icon-overlay">
<el-icon><Plus /></el-icon>
</div>
</div>
<el-icon v-else class="icon-uploader-icon"><Plus /></el-icon>
</ElUpload>
</ElFormItem>
<ElFormItem label="域名URL" prop="domain_url">
<ElInput v-model="form.domain_url" placeholder="请输入域名URL" />
</ElFormItem>
<ElFormItem label="排序" prop="sort">
<ElInputNumber v-model="form.sort" :min="0" placeholder="请输入排序" />
</ElFormItem>
<ElFormItem label="是否区分角色权限" prop="is_role">
<ElSwitch v-model="form.is_role" :active-value="1" :inactive-value="0" />
</ElFormItem>
<ElFormItem label="状态" prop="status">
<ElSwitch v-model="form.status" :active-value="1" :inactive-value="0" />
</ElFormItem>
</ElForm>
<template #footer>
@@ -70,25 +148,58 @@
<script setup lang="ts">
import { ElMessage, ElMessageBox } from 'element-plus'
import { Plus } from '@element-plus/icons-vue'
import type { FormInstance, FormRules } from 'element-plus'
import { Ordertype} from '@/mock/temp/formData'
import { systemService } from '@/api/systemApi'
import { useAuth } from '@/composables/useAuth'
const { hasAuth } = useAuth()
defineOptions({ name: 'Type ' })
const loading = ref(false)
const dialogVisible = ref(false)
const typeList = ref<any[]>([])
const dialogType = ref<'add' | 'edit'>('add')
const formRef = ref<FormInstance>()
const iconFileList = ref<any[]>([])
const typeList = ref<any[]>([])
const { width } = useWindowSize()
const isMobile = computed(() => width.value < 500)
import { useUploadHeaders } from '@/composables/useUploadHeaders'
const { uploadHeaders } = useUploadHeaders()
let actionImageUplode = `${import.meta.env.VITE_API_URL}/ticket/upload`
const rules = reactive<FormRules>({
name: [
{ required: true, message: '请输入分类名称', trigger: 'blur' }
]
code: [{ required: true, message: '请输入系统编码', trigger: 'blur' }],
name: [{ required: true, message: '请输入系统名称', trigger: 'blur' }],
type: [{ required: true, message: '请选择系统类型', trigger: 'change' }]
// desc: [
// { required: true, message: '请输入系统描述', trigger: 'blur' }
// ],
// icon: [
// { required: true, message: '请输入系统图标', trigger: 'blur' }
// ],
// domain_url: [
// { required: true, message: '请输入域名URL', trigger: 'blur' }
// ],
// is_role: [
// { required: true, message: '请选择是否区分角色权限', trigger: 'change' }
// ],
// sort: [
// { required: true, message: '请输入排序', trigger: 'blur' }
// ],
// status: [
// { required: true, message: '请选择状态', trigger: 'change' }
// ]
})
const form = reactive<Ordertype>({
const file_url = ref('')
const form = reactive({
code: '',
name: '',
id:''
type: '',
desc: '',
icon: '',
domain_url: '',
is_role: false,
sort: 0,
status: true,
id: ''
})
const pagination = reactive({
currentPage: 1,
@@ -107,40 +218,86 @@
// 获取列表数据
const getWorkList = async () => {
loading.value = true
try {
loading.value = true
try {
const { currentPage, pageSize } = pagination
const { records, current, size, total } = await systemService.getSystemList({
current: currentPage,
size: pageSize
current: currentPage,
size: pageSize
})
tableData.value = records.map((item: any, index: number) => ({
...item
...item
}))
Object.assign(pagination, { currentPage: current, pageSize: size, total })
} catch (error) {
} catch (error) {
console.error('获取列表失败:', error)
} finally {
} finally {
loading.value = false
}
}
}
const dialogType = ref('add')
// 系统类型相关辅助函数
const getTypeText = (type: string) => {
const typeMap: { [key: string]: string } = {
'admin': '管理后台',
'web': 'Web端',
'miniapp': '小程序',
'tool': '工具',
'other': '其他'
}
return typeMap[type] || type
}
const getTypeTagType = (type: string) => {
const typeMap: { [key: string]: 'primary' | 'success' | 'warning' | 'info' | 'danger' } = {
'admin': 'danger',
'web': 'primary',
'miniapp': 'success',
'tool': 'warning',
'other': 'info'
}
return typeMap[type] || 'info'
}
const showDialog = (type: string, row?: any) => {
dialogVisible.value = true
dialogType.value = type
dialogType.value = type as 'add' | 'edit'
if (type === 'edit' && row) {
form.name = row.name
form.id = row.id
file_url.value = row.icon
// 编辑模式,填充所有字段
Object.assign(form, {
code: row.code || '',
name: row.name || '',
type: row.type || 'web',
desc: row.desc || '',
icon: row.icon || row.icon_url || '', // 优先使用 icon,其次 icon_url
domain_url: row.domain_url || '',
is_role: row.is_role !== undefined ? row.is_role : 0,
sort: row.sort || 0,
status: row.status !== undefined ? row.status : 1,
id: row.id || '' // 编辑时填充文件名,如果没有则使用 icon
})
} else {
form.name = ''
file_url.value = ''
// 新增模式,重置所有字段
Object.assign(form, {
code: '',
name: '',
type: 'web',
desc: '',
icon: '',
domain_url: '',
is_role: 0,
sort: 0,
status: 1,
id: ''
})
}
}
const deleteRole = (row?: any) => {
ElMessageBox.confirm('确定删除该分类吗?', '删除确认', {
ElMessageBox.confirm('确定删除吗?', '删除确认', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'error'
@@ -155,22 +312,72 @@
const handleSubmit = async (formEl: FormInstance | undefined) => {
if (!formEl) return
if (dialogType.value === 'add') {
const { message } = await systemService.systemAdd({
name: form.name
})
ElMessage.success(message)
dialogVisible.value = false
getWorkList()
} else {
const { message } = await systemService.systemEdit({
name: form.name,
id:form.id
})
ElMessage.success(message)
dialogVisible.value = false
getWorkList()
await formEl.validate(async (valid) => {
if (valid) {
if (dialogType.value === 'add') {
const { message } = await systemService.systemAdd({
code: form.code,
name: form.name,
type: form.type,
desc: form.desc,
icon: form.icon,
domain_url: form.domain_url,
is_role: form.is_role,
sort: form.sort,
status: form.status
})
ElMessage.success(message)
} else {
const { message } = await systemService.systemEdit({
id: form.id,
code: form.code,
name: form.name,
type: form.type,
desc: form.desc,
icon: form.icon,
domain_url: form.domain_url,
is_role: form.is_role,
sort: form.sort,
status: form.status
})
ElMessage.success(message)
}
dialogVisible.value = false
getWorkList()
}
})
}
// 图标上传相关函数
const beforeIconUpload = (file: File) => {
const isImage = file.type.startsWith('image/')
const isLt2M = file.size / 1024 / 1024 < 2
if (!isImage) {
ElMessage.error('只能上传图片文件!')
return false
}
if (!isLt2M) {
ElMessage.error('图片大小不能超过 2MB!')
return false
}
return true
}
const handleIconSuccess = (response: any, file: any) => {
// 接口返回 file_url 用于回显,file_name 用于传参
if (response.data) {
form.icon = response.data.file_url || response.data.file_name // 回显用 file_url
file_url.value = response.data.file_url
} else {
form.icon = response.file_url || response.file_name
file_url.value = response.file_url
}
ElMessage.success('图标上传成功')
}
const handleIconError = () => {
ElMessage.error('图标上传失败')
}
</script>
@@ -191,4 +398,74 @@
fill: currentcolor;
}
}
.el-table {
margin-top: 20px;
}
.icon-uploader {
text-align: center;
}
.icon-uploader-icon {
font-size: 28px;
color: #8c939d;
width: 64px;
height: 64px;
line-height: 64px;
text-align: center;
border: 1px dashed #d9d9d9;
border-radius: 6px;
cursor: pointer;
transition: border-color 0.3s;
}
.icon-uploader-icon:hover {
border-color: #409eff;
}
.icon-preview {
position: relative;
width: 64px;
height: 64px;
border: 1px dashed #d9d9d9;
border-radius: 6px;
cursor: pointer;
overflow: hidden;
}
.icon-image {
width: 100%;
height: 100%;
object-fit: cover;
}
.icon-overlay {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.5);
display: flex;
align-items: center;
justify-content: center;
opacity: 0;
transition: opacity 0.3s;
}
.icon-overlay .el-icon {
color: white;
font-size: 20px;
}
.icon-preview:hover .icon-overlay {
opacity: 1;
}
.icon-tip {
font-size: 12px;
color: #999;
margin-top: 8px;
text-align: center;
}
</style>