提交 a9ae07d6 authored 作者: xiejiang's avatar xiejiang

fix: 修复菜单,等测试出的bug

上级 503f411b
......@@ -2,7 +2,7 @@
* @Author: xiejiang
* @Date: 2024-12-03 10:43:24
* @LastEditors: xiejiang
* @LastEditTime: 2024-12-06 15:22:47
* @LastEditTime: 2024-12-09 09:54:16
* @Description:
* Copyright(c)2024 by 好老师教育科技有限公司 All right Reserved.
*/
......@@ -24,7 +24,7 @@ export interface ResMenu extends KeyAny {
inputTime?: string //创建时间
inputUserId?: number //创建人ID
inputUserName?: string //创建人姓名
menuId?: number | string //菜单编号
menuId?: string //菜单编号
menuLevel: number | string //菜单层级
menuName: string //菜单名称
menuSign: string //菜单标识(路由名称)
......
......@@ -2,7 +2,7 @@
* @Author: xiejiang
* @Date: 2024-12-05 09:20:12
* @LastEditors: xiejiang
* @LastEditTime: 2024-12-05 15:07:43
* @LastEditTime: 2024-12-09 17:52:26
* @Description:
* Copyright(c)2024 by 好老师教育科技有限公司 All right Reserved.
*/
......@@ -47,6 +47,6 @@ export interface ResVersionPage {
publishedNum: number // 已发布数量 [必填]
pageInfo: {
list: ResVersion[]
total: number // 总数 [必填]
}
total: number // 总数 [必填]
}
......@@ -2,13 +2,18 @@
* @Author: xiejiang
* @Date: 2024-11-07 11:19:31
* @LastEditors: xiejiang
* @LastEditTime: 2024-12-05 09:27:39
* @LastEditTime: 2024-12-09 12:00:01
* @Description: 表格页面容器组件
-->
<template>
<div class="h-full flex flex-col">
<!-- 筛选区域 -->
<PageFilters :filter-conditions="props.filterConditions" v-bind="filtersProps" @on-filter="handleSeach" />
<PageFilters
:filter-conditions="props.filterConditions"
v-bind="filtersProps"
@on-filter="handleSeach"
@clear="handleClear"
/>
<div class="mt-[12px] p-[16px] bg-white flex-1 max-h-[calc(100%-64px)] overflow-auto">
<!-- 表格头部操作区 -->
<div class="flex justify-between items-center">
......@@ -108,9 +113,15 @@ const emit = defineEmits<{
'search-change': [params: Record<string, any>]
'sort-change': [sort: Record<string, any>]
'page-change': [pageInfo: Pagination]
clear: []
change: [changeParams: any]
}>()
// 清空
const handleClear = () => {
emit('clear')
}
// 列配置项
const columnControllerVisible = ref(false)
const columnControllerConfig = computed<TableProps['columnController']>(() => ({
......
......@@ -7,6 +7,7 @@
<t-input
v-model="item.str"
clearable
v-bind="item.$attrs"
:placeholder="item.label"
:style="{ width: (item.width || 160) + 'px' }"
v-if="item.type === 'input'"
......@@ -19,6 +20,7 @@
v-model="item.str"
:placeholder="item.label"
clearable
v-bind="item.$attrs"
:style="{ width: (item.width || 160) + 'px' }"
v-if="item.type === 'select' && item.selectData"
>
......@@ -26,6 +28,7 @@
</t-select>
<t-select
v-model="item.values"
v-bind="item.$attrs"
:placeholder="item.label"
clearable
multiple
......@@ -41,6 +44,7 @@
allow-input
clearable
:placeholder="item.label"
v-bind="item.$attrs"
:style="{ width: (item.width || 160) + 'px' }"
v-if="item.type === 'date'"
/>
......@@ -96,17 +100,6 @@ const props = withDefaults(defineProps<PageFiltersProps>(), {
const filterData = ref<filterItemProp[]>([])
const minCollapsedNum: SelectProps['minCollapsedNum'] = 1
watch(
() => props.filterConditions,
(val: filterItemProp[]) => {
filterData.value = val
},
{
deep: true,
immediate: true
}
)
// 判断是否显示筛选结果区域
const isShowFilterResult = computed(() => filterData.value.find((v: filterItemProp) => v.str || v.values?.length))
......@@ -120,7 +113,7 @@ const handleClear = () => {
item.str = ''
item.values = []
})
handleFilterSearch()
emit('clear')
}
// 展示筛选内容的结果(select、input)
......@@ -151,6 +144,7 @@ const filterParams: DynamicType = reactive({})
const emit = defineEmits<{
'on-filter': [filter: DynamicType['filter']]
clear: []
}>()
const handleFilterSearch = () => {
......@@ -166,6 +160,29 @@ const resetFilterConditions = () => {
})
return filterParams
}
watch(
() => props.filterConditions,
(val: filterItemProp[]) => {
filterData.value = val
},
{
deep: true,
immediate: true
}
)
watch(
() => filterData,
() => {
handleFilterSearch()
},
{
deep: true,
immediate: true
}
)
defineExpose<DynamicType>({
resetFilterConditions
})
......
/*
* @Author: xiejiang
* @Date: 2024-12-08 09:25:35
* @LastEditors: xiejiang
* @LastEditTime: 2024-12-09 18:10:59
* @Description:
* Copyright(c)2024 by 好老师教育科技有限公司 All right Reserved.
*/
// 下拉选项数据结构
export interface SelectOption {
label: string // 显示文本
......@@ -22,6 +30,7 @@ export interface filterItemProp {
closable?: boolean
placeholder?: string // 占位文本
disabled?: boolean // 是否禁用
$attrs?: any
}
// 筛选组件Props
export interface PageFiltersProps {
......
......@@ -2,7 +2,7 @@
* @Author: xiejiang
* @Date: 2023-07-13 10:27:58
* @LastEditors: xiejiang
* @LastEditTime: 2024-12-06 14:33:05
* @LastEditTime: 2024-12-09 17:36:28
* @Description: 搜索组件
-->
<template>
......@@ -13,7 +13,7 @@
:placeholder="placeholder"
borderless
@enter="handleFullySearch"
@clear="handleClearSearch"
:on-clear="handleClearSearch"
>
<template #prefix-icon>
<SearchIcon />
......@@ -24,7 +24,7 @@
</template>
<script setup name="SearchWithButton" lang="ts">
const emit = defineEmits(['update:modelValue', 'onSearch', 'onClear'])
const emit = defineEmits(['update:modelValue', 'onSearch', 'clear'])
const props = defineProps({
modelValue: {
type: String,
......@@ -49,7 +49,8 @@ const props = defineProps({
})
const searchKey = ref('')
const handleClearSearch = () => {
emit('onClear')
emit('update:modelValue', searchKey.value)
emit('clear')
}
const handleFullySearch = () => {
emit('onSearch', searchKey.value)
......
......@@ -71,6 +71,14 @@ const props = defineProps({
disabled: {
type: Boolean,
default: false
},
maxlength: {
type: Number,
default: 9999
},
placeholder: {
type: String,
default: '请输入内容'
}
})
......
......@@ -116,7 +116,10 @@ router.beforeEach(async (to, from, next) => {
// 存储当前激活菜单,如果当前不需要tab,则激活activeMenu
authStore.setMenuSign(to.meta?.activeMenu ? (to.meta.activeMenu as string) : (to.name as string))
const activeMenuId = findMenuByName(authStore.authMenuListGet, to.name as string)?.menuId ?? ''
authStore.setActiveMenuId(activeMenuId)
if (activeMenuId) {
authStore.setActiveMenuId(activeMenuId)
}
next()
return
// }
......
......@@ -2,7 +2,7 @@
* @Author: xiejiang
* @Date: 2024-12-01 10:37:37
* @LastEditors: xiejiang
* @LastEditTime: 2024-12-05 15:14:43
* @LastEditTime: 2024-12-09 15:48:06
* @Description: 机构详情
* Copyright(c)2024 by 好老师教育科技有限公司 All right Reserved.
-->
......@@ -11,10 +11,17 @@
<Back />
<main class="m-auto max-w-[1012px]">
<!-- 基本信息 -->
<PageTitle title="基本信息" class="mb-[24px] mt-[12px]" />
<PageTitle class="mb-[24px] mt-[12px]">
<div class="flex items-center">
<span>基本信息</span>
<t-button shape="round" class="ml-[12px]" theme="primary" size="small" variant="outline" @click="handelEdit">
编辑机构</t-button
>
</div>
</PageTitle>
<div class="flex flex-wrap">
<DetailTable label="机构名称" :value="state?.companyName" />
<DetailTable label="机构类型" :value="state?.companyType" />
<DetailTable label="机构类型" :value="state?.companyTypeName" />
<DetailTable label="机构状态"
><span>
{{ statusTxt(state?.companyStatus as number)?.title }}
......@@ -36,13 +43,15 @@
</template>
<script setup lang="ts" name="institution-detail">
import { useRoute } from 'vue-router'
import { useRoute, useRouter } from 'vue-router'
import { useBasic } from '@/hooks/useBasic'
import { statusTxt } from '@/utils/status'
import { ResCompany } from '@/api/interface/institution/index'
import { getDetail } from '@/api/modules/institution/index'
const { setBreadcrumb } = useBasic()
const route = useRoute()
const router = useRouter()
const state = ref<ResCompany>()
......@@ -52,7 +61,15 @@ const getData = () => {
})
}
const { setBreadcrumb } = useBasic()
// 编辑新增
const handelEdit = () => {
router.push({
name: 'institution-edit',
query: {
companyId: route.query.companyId
}
})
}
onMounted(() => {
setBreadcrumb([
......
......@@ -2,7 +2,7 @@
* @Author: xiejiang
* @Date: 2024-12-01 10:26:11
* @LastEditors: xiejiang
* @LastEditTime: 2024-12-05 10:59:59
* @LastEditTime: 2024-12-09 17:44:36
* @Description: 新增编辑角色
* Copyright(c)2024 by 好老师教育科技有限公司 All right Reserved.
-->
......@@ -26,7 +26,11 @@
<t-form-item label="管理员手机号码" name="adminUserMobile">
<t-input
maxlength="11"
@input="v => (formData.adminUserMobile = v.replace(/[^0-9]/g, ''))"
@input="
v => {
formData.adminUserMobile = v.target.value.replace(/[^0-9]/g, '')
}
"
v-model="formData.adminUserMobile"
placeholder="请输入管理员手机号码"
>
......@@ -40,14 +44,14 @@
v-model="formData.serviceTerminationTime"
clearable
type="date"
:disable-date="{ before: '2023-12-31' }"
:disable-date="{ before: dayjs().subtract(1, 'day').format('YYYY-MM-DD') }"
placeholder="请选择时间"
/>
<p class="text-[var(--td-warning-color-6)] text-[12px] m-0 times">机构服务的结束时间为该日期当日23:59:59</p>
</t-form-item>
<t-form-item label="机构备注" name="remark">
<t-textarea maxlength="200" v-model="formData.remark" placeholder="请输入内容"> </t-textarea>
<t-textarea :maxlength="200" v-model="formData.remark" placeholder="请输入内容"> </t-textarea>
</t-form-item>
</t-form>
......@@ -64,6 +68,7 @@
<script setup lang="ts" name="institution-edit">
import { useRoute, useRouter } from 'vue-router'
import { FormProps, FormInstanceFunctions, CustomValidator } from 'tdesign-vue-next'
import dayjs from 'dayjs'
import { useBasic } from '@/hooks/useBasic'
import { isPhoneNumber } from '@/utils'
import { ReqCompany } from '@/api/interface/institution/index'
......@@ -207,7 +212,7 @@ onMounted(() => {
name: 'institution'
},
{
title: route.query.companyId ? '添加机构' : '修改机构'
title: route.query.companyId ? '修改机构' : '添加机构'
}
])
getDictData()
......
......@@ -2,7 +2,7 @@
* @Author: xiejiang
* @Date: 2024-11-28 15:01:02
* @LastEditors: xiejiang
* @LastEditTime: 2024-12-08 14:43:35
* @LastEditTime: 2024-12-09 16:35:49
* @Description: 机构管理
* Copyright(c)2024 by 好老师教育科技有限公司 All right Reserved.
-->
......@@ -22,6 +22,7 @@
:loading="loading"
placeholder="机构名称"
v-model="companyName"
@clear="handleClear"
@on-search="handleSearch(searchParams)"
/></template>
......@@ -78,7 +79,6 @@ onMounted(() => {
}
])
getDictData()
getData()
})
// 加载状态
......@@ -135,7 +135,20 @@ const columns: PrimaryTableCol[] = [
title: '机构类型',
colKey: 'companyTypeName'
},
{ title: '机构管理员', colKey: 'adminUserName' },
{
title: '机构管理员',
colKey: 'adminUserName',
ellipsis: true,
cell: (h, { row }) => {
return (
<div class='flex items-center'>
<span>
{row.adminUserName}({row.adminUserMobile})
</span>
</div>
)
}
},
{ title: '服务到期时间', colKey: 'serviceTerminationTime' },
{
title: '机构状态',
......@@ -176,7 +189,7 @@ const getData = () => {
const postData = {
...pagination.value,
...searchParams.value,
condRoleName: companyName.value
companyName: companyName.value
}
getCompanyList(postData)
.then(res => {
......@@ -196,6 +209,12 @@ const handleSearch = (params: Record<string, any>) => {
getData()
}
const handleClear = () => {
companyName.value = ''
pagination.value.page = 1
getData()
}
// 处理分页
const handlePage = (pageInfo: Pagination) => {
pagination.value = { ...pagination.value, ...pageInfo }
......
......@@ -2,7 +2,7 @@
* @Author: xiejiang
* @Date: 2024-11-05 10:14:56
* @LastEditors: xiejiang
* @LastEditTime: 2024-12-08 14:31:01
* @LastEditTime: 2024-12-09 09:17:08
* @Description: 登录
* Copyright(c)2024 by 好老师教育科技有限公司 All right Reserved.
-->
......@@ -22,6 +22,7 @@
<t-input
v-model="formData.mobile"
maxlength="11"
clearable
@input="
v => {
formData.mobile = v.target.value.replace(/[^0-9]/g, '')
......
......@@ -2,7 +2,7 @@
* @Author: xiejiang
* @Date: 2024-11-11 09:38:40
* @LastEditors: xiejiang
* @LastEditTime: 2024-12-08 15:49:03
* @LastEditTime: 2024-12-09 15:15:33
* @Description: 系统字典-管理子集
* Copyright(c)2024 by 好老师教育科技有限公司 All right Reserved.
-->
......@@ -134,23 +134,18 @@ const columns: PrimaryTableCol[] = [
title: '快速排序',
colKey: 'sort',
width: 88,
cell: (h, { row, rowIndex }: { row: any; rowIndex: number }) => {
cell: (h, { row }: { row: any }) => {
return (
<div class='flex items-center text-[var(--td-brand-color)]'>
<operate-btn
content=''
class='ico-btn'
disabled={rowIndex == 0 ? true : false}
disabled={row.isFirst ? true : false}
onClick={handleSort(row, false)}
>
<ArrowUpIcon />
</operate-btn>
<operate-btn
content=''
class='ico-btn'
disabled={rowIndex == tableData.value.length - 1 ? true : false}
onClick={handleSort(row, true)}
>
<operate-btn content='' class='ico-btn' disabled={row.isLast ? true : false} onClick={handleSort(row, true)}>
<ArrowDownIcon />
</operate-btn>
</div>
......@@ -233,7 +228,7 @@ const GetDictDataList = () => {
loading.value = true
getGetDictDataList({ dictId: route.query.dictId as string })
.then(res => {
tableData.value = res.data
tableData.value = res.data || []
pagination.value.total = res?.recordsFiltered as number
})
.finally(() => {
......
......@@ -2,7 +2,7 @@
* @Author: xiejiang
* @Date: 2024-11-11 09:38:40
* @LastEditors: xiejiang
* @LastEditTime: 2024-12-08 11:34:20
* @LastEditTime: 2024-12-09 16:36:11
* @Description: 系统字典
* Copyright(c)2024 by 好老师教育科技有限公司 All right Reserved.
-->
......@@ -23,6 +23,7 @@
placeholder="搜索字典大类,字典名称"
v-model="categoryNameOrDictName"
@on-search="handleSearch(searchParams)"
@clear="handleClear"
/></template>
<template #header-right>
......@@ -36,10 +37,10 @@
<template #operation="{ row }">
<operate-btn v-if="row.status != '2'" content="启用" @click="handelStatus(row, 2)"> </operate-btn>
<operate-btn content="编辑" @click="handelEdit(row)"> </operate-btn>
<operate-btn content="管理子集" @click="handelSubset(row)"> </operate-btn>
<operate-btn v-if="row.isAllowEdit" content="编辑" @click="handelEdit(row)"> </operate-btn>
<operate-btn v-if="row.isAllowAddsub" content="管理子集" @click="handelSubset(row)"> </operate-btn>
<operate-btn v-if="row.status == '2'" content="停用" @click="handelStatus(row, 1)"> </operate-btn>
<operate-btn v-if="row.status != '2'" content="删除" @click="handelDel(row)"></operate-btn>
<operate-btn v-if="row.isAllowDelete" content="删除" @click="handelDel(row)"></operate-btn>
</template>
</PageContainer>
......@@ -78,7 +79,6 @@ onMounted(() => {
title: '系统字典'
}
])
getData()
})
const dictionaryEditRef = ref()
......@@ -121,7 +121,7 @@ const columns: PrimaryTableCol[] = [
colKey: 'serial-number',
width: 70
},
{ title: '字典大类', colKey: 'categoryId' },
{ title: '字典大类', colKey: 'categoryName' },
{ title: '字典名称', colKey: 'dictName' },
{ title: '字典编码', colKey: 'dictCode' },
{ title: '字典说明', colKey: 'remark' },
......@@ -154,8 +154,8 @@ const columns: PrimaryTableCol[] = [
)
}
},
{ title: '创建人', colKey: 'inputUserName' },
{ title: '创建时间', colKey: 'inputTime' },
{ title: '添加人', colKey: 'inputUserName' },
{ title: '添加 时间', colKey: 'inputTime' },
{ title: '操作', colKey: 'operation', fixed: 'right', width: 260 }
]
......@@ -205,6 +205,13 @@ const handleSearch = (params: Record<string, any>) => {
getData()
}
// 清空搜索条件
const handleClear = () => {
categoryNameOrDictName.value = ''
pagination.value.page = 1
getData()
}
// 处理分页
const handlePage = (pageInfo: Pagination) => {
pagination.value = { ...pagination.value, ...pageInfo }
......
......@@ -56,7 +56,7 @@
</t-form-item>
<t-form-item label="字典说明" name="remark">
<t-textarea maxlength="200" v-model="formData.remark" placeholder="请输入字典说明"> </t-textarea>
<t-textarea :maxlength="200" v-model="formData.remark" placeholder="请输入字典说明"> </t-textarea>
</t-form-item>
</t-form>
</Drawer>
......@@ -170,10 +170,6 @@ defineExpose({
</script>
<style lang="less" scoped>
:deep(.t-textarea__limit) {
display: none;
}
:deep(.t-radio__label) {
color: var(--td-font-gray-2);
}
......
......@@ -22,10 +22,10 @@
<t-input maxlength="20" v-model="formData.valueName" placeholder="请输入内容"> </t-input>
</t-form-item>
<t-form-item label="值编码" name="dataCode">
<t-input v-model="formData.dataCode" placeholder="请输入内容"> </t-input>
<t-input v-model="formData.dataCode" maxlength="50" placeholder="请输入内容"> </t-input>
</t-form-item>
<t-form-item label="值备注" name="remark">
<t-textarea maxlength="200" v-model="formData.remark" placeholder="请输入内容"> </t-textarea>
<t-textarea :maxlength="200" v-model="formData.remark" placeholder="请输入内容"> </t-textarea>
</t-form-item>
</t-form>
</Drawer>
......@@ -111,9 +111,3 @@ defineExpose({
close
})
</script>
<style lang="less" scoped>
:deep(.t-textarea__limit) {
display: none;
}
</style>
......@@ -2,7 +2,7 @@
* @Author: xiejiang
* @Date: 2024-11-11 09:38:40
* @LastEditors: xiejiang
* @LastEditTime: 2024-12-08 15:05:16
* @LastEditTime: 2024-12-09 16:40:03
* @Description: 菜单管理
* Copyright(c)2024 by 好老师教育科技有限公司 All right Reserved.
-->
......@@ -10,7 +10,7 @@
<div class="h-full overflow-auto">
<t-tabs class="px-[16px]" v-model="tabValue" :on-change="onTabChange">
<t-tab-panel :value="0" label="平台菜单" :destroy-on-hide="false" />
<t-tab-panel :value="1" label="机构菜单" :destroy-on-hide="false" />
<t-tab-panel :value="1" :disabled="true" label="机构菜单" :destroy-on-hide="false" />
</t-tabs>
<PageContainer
......@@ -31,6 +31,7 @@
:loading="loading"
placeholder="搜索菜单名称"
v-model="condMenuName"
@clear="handleClear"
@on-search="handleSearch(searchParams)"
/></template>
<template #header-right>
......@@ -110,13 +111,17 @@ onMounted(() => {
title: '菜单管理'
}
])
getData()
GetAllMenuGroup()
})
// 搜索参数类型
const filterConditions = ref<filterItemProp[]>([])
// 表格列配置
const columns: PrimaryTableCol[] = [
{
title: '序号',
colKey: 'serial-number',
width: 70
},
{
title: '菜单层级',
colKey: 'menuLevel',
......@@ -167,6 +172,13 @@ const handleSearch = (params: Record<string, any>) => {
getData()
}
// 清空搜索条件
const handleClear = () => {
condMenuName.value = ''
pagination.value.page = 1
getData()
}
// 分页变更
const handlePage = (pageInfo: { page: number; limit: number }) => {
pagination.value = { ...pagination.value, ...pageInfo }
......
......@@ -44,7 +44,7 @@
<t-form-item v-if="formData.menuLevel === 3" label="是否为按钮" name="isButton">
<t-radio-group v-model="formData.isButton">
<t-radio :value="1"></t-radio>
<t-radio :value="2"></t-radio>
<t-radio :value="0"></t-radio>
</t-radio-group>
</t-form-item>
<t-form-item label="父级菜单" name="parentId" v-if="formData.menuLevel !== 1">
......@@ -211,10 +211,6 @@ defineExpose({
</script>
<style lang="less" scoped>
:deep(.t-textarea__limit) {
display: none;
}
:deep(.t-radio__label) {
color: var(--td-font-gray-2);
}
......
......@@ -19,11 +19,6 @@
<template v-for="(_, name) in $slots" #[name]="scope">
<slot :name="name" v-bind="scope" />
</template>
<template v-for="col in columns" #[col.colKey]="{ row }" :key="col.colKey">
<template v-if="col.colKey != 'operation'">
<div class="cell-content">{{ row[col.colKey] || '-' }}</div>
</template>
</template>
</t-table>
</Drawer>
</template>
......@@ -59,7 +54,7 @@ const columns: PrimaryTableCol[] = [
<div class='text-[var(--td-brand-color)]'>
<p>操作:{operateTypeTxt(row.operateType)}</p>
<p>菜单名称:{row.menuName}</p>
<p>路由名称:{row.menuSign}</p>
<p>路由名称:{row.router}</p>
<p>菜单层级:{menuLevelTxt(row.menuLevel)}</p>
</div>
)
......
......@@ -2,12 +2,12 @@
* @Author: xiejiang
* @Date: 2024-12-04 14:06:18
* @LastEditors: xiejiang
* @LastEditTime: 2024-12-08 10:39:51
* @LastEditTime: 2024-12-09 16:51:19
* @Description: 菜单排序
* Copyright(c)2024 by 好老师教育科技有限公司 All right Reserved.
-->
<template>
<Drawer :drawer-visible="drawerVisible" width="480" title="菜单排序" :show-footer="false" @close="close">
<Drawer :drawer-visible="drawerVisible" width="480" title="菜单排序" :footer="false" @close="close">
<t-tree
:data="menuTree"
activable
......
......@@ -2,7 +2,7 @@
* @Author: xiejiang
* @Date: 2024-11-11 09:38:40
* @LastEditors: xiejiang
* @LastEditTime: 2024-12-05 15:19:07
* @LastEditTime: 2024-12-09 18:22:42
* @Description: 版本管理
* Copyright(c)2024 by 好老师教育科技有限公司 All right Reserved.
-->
......@@ -65,6 +65,7 @@
</template>
<script setup lang="tsx" name="version">
import dayjs from 'dayjs'
import { PrimaryTableCol, MessagePlugin } from 'tdesign-vue-next'
import type { filterItemProp } from 'src/components/PageFilters/interface/index'
import type { Pagination } from 'src/components/PageContainer/interface/index'
......@@ -95,14 +96,19 @@ onMounted(() => {
title: '版本管理'
}
])
getData()
// getData()
})
// 搜索参数类型
const filterConditions = ref<filterItemProp[]>([
{
label: '上线时间',
prop: 'onlineTime',
type: 'date'
type: 'date',
$attrs: {
'disable-date': (date: string) => {
return dayjs(date).isBefore(dayjs().format('YYYY-MM')) || dayjs(date).isAfter(dayjs().format('YYYY-MM-DD'))
}
}
},
{
label: '版本状态',
......@@ -117,6 +123,11 @@ const filterConditions = ref<filterItemProp[]>([
])
// 表格列配置
const columns: PrimaryTableCol[] = [
{
title: '序号',
colKey: 'serial-number',
width: 70
},
{ title: '版本号', colKey: 'version' },
{
title: '版本状态',
......@@ -233,7 +244,7 @@ const getData = () => {
.then(res => {
tableData.value = res.data.pageInfo.list
publishedNum.value = res.data?.publishedNum
pagination.value.total = res.data?.total
pagination.value.total = res.data?.pageInfo?.total
})
.catch(() => {
tableData.value = []
......
<!--
* @Author: xiejiang
* @Date: 2024-12-08 09:25:35
* @LastEditors: xiejiang
* @LastEditTime: 2024-12-09 18:01:54
* @Description:
* Copyright(c)2024 by 好老师教育科技有限公司 All right Reserved.
-->
<template>
<Drawer :drawer-visible="drawerVisible" width="480px" title="版本详情" @close="close" :show-footer="false">
<Drawer :drawer-visible="drawerVisible" width="480px" title="版本详情" @close="close" :footer="false">
<InfoLable class="mb-[16px]" label="当前终端" :value="props.tabType == 1 ? '平台端' : '机构端'" />
<InfoLable class="mb-[16px]" label="版本号" :value="state.version" />
<InfoLable class="mb-[16px]" label="更新说明"><div v-html="state.description || '-'"></div> </InfoLable>
......
......@@ -17,6 +17,10 @@
<t-form-item label="更新说明" name="description">
<WangEditor
height="300px"
:editor-config="{
placeholder: '请输入版本更新说明',
maxLength: 200
}"
:toolbar-config="{
excludeKeys: ['uploadImage', 'uploadVideo'] // 添加这两项以排除图片和视频上传选项
}"
......@@ -24,7 +28,7 @@
/>
</t-form-item>
<t-form-item label="版本备注" name="remark">
<t-textarea maxlength="200" v-model="formData.remark" placeholder="请输入版本备注"> </t-textarea>
<t-textarea :maxlength="200" v-model="formData.remark" placeholder="请输入版本备注"> </t-textarea>
</t-form-item>
</t-form>
</Drawer>
......@@ -134,10 +138,6 @@ defineExpose({
</script>
<style lang="less" scoped>
:deep(.t-textarea__limit) {
display: none;
}
.form {
border-top: 1px solid var(--td-font-gray-4);
}
......
......@@ -2,7 +2,7 @@
* @Author: xiejiang
* @Date: 2024-11-11 09:38:40
* @LastEditors: xiejiang
* @LastEditTime: 2024-12-08 10:28:35
* @LastEditTime: 2024-12-09 17:44:49
* @Description: 权限配置
* Copyright(c)2024 by 好老师教育科技有限公司 All right Reserved.
-->
......@@ -15,10 +15,13 @@
<li
v-for="v in roles"
:key="v.roleId"
:class="v.roleId === roleId ? 'li-active' : ''"
:class="
v.roleId === roleId ? 'li-active flex justify-between items-center' : ' flex justify-between items-center'
"
@click="roleId = v.roleId"
>
{{ v.roleName }}
<span>{{ v.roleName }}</span>
<span>{{ v.userNumber }}</span>
</li>
</ul>
</div>
......@@ -63,12 +66,9 @@
sourceMenuId = val
}
"
v-show="tabValue === 2"
v-if="tabValue === 2"
/>
</div>
<CopyPermissions ref="copyPermissionsRef" />
<!-- 添加角色 -->
<!-- <Dialog :dialog-visible="dialogVisible" width="480px" title="添加角色" :footer="true" @close="close">
<template #body>
......@@ -107,7 +107,6 @@ import { ResRoleList } from '@/api/interface/user-roles/index'
import { getRoleList } from '@/api/modules/user-roles/index'
import Capabilities from './page/capabilities.vue'
import DataPermissions from './page/data-permissions.vue'
import CopyPermissions from './page/copy-permissions.vue'
import { useBasic } from '@/hooks/useBasic'
const { setBreadcrumb } = useBasic()
......@@ -188,7 +187,7 @@ const submitLoading = ref(false)
const capabilitiesRef = ref()
const dataPermissionsRef = ref()
const copyPermissionsRef = ref()
// const copyPermissionsRef = ref()
const handleSearchTree = () => {
if (tabValue.value == 1) {
capabilitiesRef.value?.getData()
......@@ -208,10 +207,11 @@ const handleClear = () => {
if (tabValue.value == 1) {
capabilitiesRef.value?.clear()
} else {
// 应用其他菜单
if (!sourceMenuId.value) {
return MessagePlugin.error('请选择菜单')
}
copyPermissionsRef.value?.open(roleId.value, sourceMenuId.value)
dataPermissionsRef.value?.copyPermissions(roleId.value, sourceMenuId.value)
}
}
......
......@@ -2,7 +2,7 @@
* @Author: xiejiang
* @Date: 2024-12-05 17:16:22
* @LastEditors: xiejiang
* @LastEditTime: 2024-12-06 15:17:15
* @LastEditTime: 2024-12-09 10:15:38
* @Description: 功能权限
* Copyright(c)2024 by 好老师教育科技有限公司 All right Reserved.
-->
......@@ -55,17 +55,13 @@ const props = defineProps({
})
watch([toRef(props, 'roleId')], () => {
try {
getData()
} catch {
MessagePlugin.error('获取菜单树失败')
}
getData()
})
const loading = ref(false)
const menuTree = ref<ResMenuTree[]>([])
// 勾选
function findNodeById(tree: ResMenuTree[], id: number) {
function findNodeById(tree: ResMenuTree[], id: string) {
tree.forEach(it => {
if (it.menuId == id) {
it.selected = true
......@@ -84,16 +80,16 @@ const handleSelectAll = (itx: ResMenuTree) => {
// 勾选则需要勾选父级
if (itx.selected) {
if (itx.parentId) {
findNodeById(menuTree.value, itx.parentId as number)
findNodeById(menuTree.value, itx.parentId as string)
}
} else {
// 取消后面所有子集
if (itx.children) {
itx.children.forEach((v: ResMenuTree) => {
v.selected = itx.selected
v.selected = false
if (v.children) {
v.children.forEach((val: ResMenuTree) => {
val.selected = itx.selected
val.selected = false
})
}
})
......
......@@ -2,7 +2,7 @@
* @Author: xiejiang
* @Date: 2024-12-06 17:31:56
* @LastEditors: xiejiang
* @LastEditTime: 2024-12-08 10:25:04
* @LastEditTime: 2024-12-09 17:31:06
* @Description:
* Copyright(c)2024 by 好老师教育科技有限公司 All right Reserved.
-->
......@@ -10,7 +10,7 @@
<Drawer
:drawer-visible="drawerVisible"
width="480px"
title="权限克隆"
title="应用至其他菜单"
:loading="submitLoading"
confirm-btn-text="保存"
:cancel-btn="false"
......@@ -18,11 +18,11 @@
@close="close"
>
<t-tree
:data="menuTree"
:data="props.menuTree"
:checkable="true"
v-model="allChecked"
expand-all
value-mode="all"
value-mode="parentFirst"
activable
hover
transition
......@@ -34,48 +34,57 @@
<script setup lang="ts">
import { MessagePlugin } from 'tdesign-vue-next'
import { ResMenuTree } from '@/api/interface/menu/index'
import { getMenuTree, postDataRangeClone } from '@/api/modules/menu/index'
import { postDataRangeClone } from '@/api/modules/menu/index'
const menuTree = ref<ResMenuTree[]>([])
const props = withDefaults(
defineProps<{
menuTree: ResMenuTree[]
}>(),
{
menuTree: () => [] as ResMenuTree[]
}
)
// const menuTree = ref<ResMenuTree[]>([])
const drawerVisible = ref(false)
const submitLoading = ref(false)
const loading = ref(false)
// const loading = ref(false)
const roleId = ref('')
const sourceMenuId = ref('')
const allChecked = ref([])
// 为树形结构的每个节点添加新参数
function newParamToTree(tree: ResMenuTree[]): ResMenuTree[] {
return tree.map(node => {
const newNode = {
...node,
children: node?.children || [],
label: node?.menuName || '-',
value: node?.menuId
}
if (newNode.children && newNode.children.length > 0) {
newNode.children = newParamToTree(newNode.children)
}
return newNode
})
}
// // 为树形结构的每个节点添加新参数
// function newParamToTree(tree: ResMenuTree[]): ResMenuTree[] {
// return tree.map(node => {
// const newNode = {
// ...node,
// children: node?.children || [],
// label: node?.menuName || '-',
// value: node?.menuId
// }
// if (newNode.children && newNode.children.length > 0) {
// newNode.children = newParamToTree(newNode.children)
// }
// return newNode
// })
// }
const getData = () => {
loading.value = true
getMenuTree({})
.then(res => {
menuTree.value = newParamToTree(res.data)
})
.finally(() => {
loading.value = false
})
}
// const getData = () => {
// loading.value = true
// getMenuTree({})
// .then(res => {
// menuTree.value = newParamToTree(res.data)
// })
// .finally(() => {
// loading.value = false
// })
// }
// 保存权限
const handleConfirm = () => {
if (allChecked.value.length == 0) {
MessagePlugin.error('请选择需要克隆的权限!')
MessagePlugin.error('请选择需要应用到其他的菜单!')
return
}
submitLoading.value = true
......@@ -97,12 +106,13 @@ const open = (roleID: string, sourceMenuID: string) => {
// 关闭抽屉
const close = () => {
allChecked.value = []
drawerVisible.value = false
}
onMounted(() => {
getData()
})
// onMounted(() => {
// getData()
// })
defineExpose({
open
......
......@@ -9,6 +9,7 @@
placeholder="搜索菜单功能名称"
v-model="condMenuName"
@on-search="getData"
@clear="getData"
/>
<t-tree :data="menuTree" :actived="[menuId]" @active="onTreeAcitve" activable hover transition> </t-tree>
......@@ -28,7 +29,21 @@
<t-radio-button value="2">地区</t-radio-button>
</t-radio-group>
<div class="permissions-main">
<t-input
<SearchWithButton
v-if="type == '1'"
class="max-w-[384px] mb-[20px]"
placeholder="搜索角色名称"
v-model="roleName"
@on-search="GetRoleList"
@clear="
() => {
roleName = ''
GetRoleList()
}
"
/>
<!-- <t-input
v-if="type == '1'"
class="max-w-[384px] mb-[20px]"
v-model="roleName"
......@@ -39,10 +54,10 @@
<template #suffixIcon>
<search-icon :style="{ cursor: 'pointer' }" />
</template>
</t-input>
</t-input> -->
<!-- 地区 -->
<t-checkbox-group v-model="areas" v-show="type == '2'">
<t-checkbox-group :disabled="!menuId" v-model="areas" v-show="type == '2'">
<t-checkbox
v-for="item in areaList"
:value="item.dictDataId"
......@@ -51,13 +66,15 @@
/>
</t-checkbox-group>
<!-- 角色 -->
<t-checkbox-group v-model="roles" v-show="type == '1'">
<t-checkbox-group v-model="roles" :disabled="!menuId" v-show="type == '1'">
<t-checkbox v-for="item in roleList" :value="item.roleId" :key="item.roleId" :label="item.roleName" />
</t-checkbox-group>
</div>
</div>
</div>
</div>
<CopyPermissions ref="copyPermissionsRef" :menu-tree="menuTree" />
</div>
</template>
......@@ -69,6 +86,9 @@ import { ResDictionary } from '@/api/interface/dectionory/index'
import { getGetDictDataByName } from '@/api/modules/dectionory/index'
import { ResRoleList } from '@/api/interface/user-roles/index'
import { getRoleList } from '@/api/modules/user-roles/index'
import CopyPermissions from './copy-permissions.vue'
const copyPermissionsRef = ref()
const condMenuName = ref('')
const loading = ref(false)
......@@ -86,26 +106,16 @@ const props = defineProps({
})
watch([toRef(props, 'roleId')], () => {
try {
getData()
} catch {
MessagePlugin.error('获取菜单树失败')
}
getData()
})
watch(toRef(props, 'tabValue'), (val: number) => {
try {
if (val == 2) {
getData()
}
} catch {
MessagePlugin.error('获取菜单树失败')
if (val == 2) {
getData()
}
})
watch(menuId, () => {
console.log(995)
emit('updateMenuId', menuId.value)
})
......@@ -136,8 +146,13 @@ const getData = () => {
if (Array.isArray(res.data)) {
// 检查 res.data 是否为数组
menuTree.value = newParamToTree(res.data)
menuId.value = (menuTree.value[0]?.menuId || '') as string
GetDataRange()
menuId.value = menuTree.value[0]?.menuId || ''
if (menuId.value) {
GetDataRange()
} else {
areas.value = []
roles.value = []
}
} else {
menuId.value = '' // 如果不是数组,设置为空字符串
menuTree.value = [] // 如果不是数组,设置为空数组
......@@ -172,7 +187,7 @@ const roleName = ref('')
const roleList = ref<ResRoleList[]>([])
const GetRoleList = () => {
getRoleList({ status: 1, roleName: roleName.value }).then(res => {
getRoleList({ status: 2, roleName: roleName.value }).then(res => {
roleList.value = res.data
})
}
......@@ -183,11 +198,9 @@ const GetDataRange = () => {
getDataRange({ roleId: props.roleId, menuId: menuId.value })
.then(res => {
if (res.data) {
if (res.data) {
const data = res.data as ResDataRange
areas.value = data.areas?.map((item: { id: string }) => item.id) || []
roles.value = data.roles?.map((item: { id: string }) => item.id) || []
}
const data = res.data as ResDataRange
areas.value = data.areas?.map((item: { id: string }) => item.id) || []
roles.value = data.roles?.map((item: { id: string }) => item.id) || []
}
})
.finally(() => {
......@@ -196,6 +209,10 @@ const GetDataRange = () => {
}
const submit = () => {
if (!menuId.value) {
return MessagePlugin.error('请选择菜单')
}
emit('loading', true)
// 组装地区数据
const areaLists: AreasRole[] =
......@@ -223,15 +240,22 @@ const submit = () => {
})
}
// 调用权限克隆
const copyPermissions = (roleID: string, sourceMenuID: string) => {
copyPermissionsRef.value.open(roleID, sourceMenuID)
}
onMounted(() => {
getAreaList()
GetRoleList()
getData()
})
const emit = defineEmits(['loading', 'updateMenuId'])
defineExpose({
getData,
submit
submit,
copyPermissions
})
</script>
......
......@@ -2,7 +2,7 @@
* @Author: xiejiang
* @Date: 2024-11-28 15:01:02
* @LastEditors: xiejiang
* @LastEditTime: 2024-12-08 14:05:30
* @LastEditTime: 2024-12-09 16:33:42
* @Description: 角色管理
* Copyright(c)2024 by 好老师教育科技有限公司 All right Reserved.
-->
......@@ -22,10 +22,11 @@
:loading="loading"
placeholder="搜索角色名称"
v-model="roleName"
@clear="handleClear"
@on-search="handleSearch(searchParams)"
/></template>
<template #header-right>
<div class="flex items-center justify-end gap-2">
<div class="flex items-center justify-end gap-2" v-if="buttonPms('role-add-btn')">
<t-button shape="round" theme="primary" @click="handelEdit(null)">
<template #icon><AddIcon /></template>
添加角色</t-button
......@@ -37,7 +38,7 @@
<operate-btn v-if="row.status != 2" content="启用" @click="handelStatus(row, 2)"> </operate-btn>
<operate-btn v-if="row.status != 1" content="详情" @click="handelDetail(row)"> </operate-btn>
<operate-btn v-if="row.status == 2" content="权限配置" @click="handelPermissions(row)"> </operate-btn>
<operate-btn content="编辑" @click="handelEdit(row)"> </operate-btn>
<operate-btn content="编辑" v-if="buttonPms('role-edit-btn')" @click="handelEdit(row)"> </operate-btn>
<operate-btn v-if="row.status == 2" content="停用" @click="handelStatus(row, 1)"> </operate-btn>
<operate-btn v-if="row.status != 2" content="删除" @click="handelDel(row)"></operate-btn>
</template>
......@@ -53,6 +54,7 @@ import { PrimaryTableCol, MessagePlugin } from 'tdesign-vue-next'
import type { filterItemProp } from '@/components/PageFilters/interface/index'
import type { Pagination } from '@/components/PageContainer/interface/index'
import { statusTxt } from '@/utils/status'
import { buttonPms } from '@/utils'
import { useBasic } from '@/hooks/useBasic'
import MessageBox from '@/utils/messageBox'
import RoleEdit from './page/role-edit.vue'
......@@ -73,7 +75,7 @@ onMounted(() => {
name: 'role'
}
])
getData()
// getData()
})
// 加载状态
......@@ -139,6 +141,13 @@ const handleSearch = (params: Record<string, any>) => {
getData()
}
// 清空搜索条件
const handleClear = () => {
roleName.value = ''
pagination.value.page = 1
getData()
}
// 处理分页
const handlePage = (pageInfo: Pagination) => {
pagination.value = { ...pagination.value, ...pageInfo }
......@@ -167,7 +176,7 @@ const handelDetail = (row: ResRoleList) => {
router.push({
name: 'role-detail',
query: {
id: row.roleId
roleId: row.roleId
}
})
}
......
......@@ -22,7 +22,7 @@
<t-input maxlength="20" v-model="formData.roleName" placeholder="请输入角色姓名"> </t-input>
</t-form-item>
<t-form-item label="角色描述" name="description">
<t-textarea maxlength="200" v-model="formData.description" placeholder="请输入角色备注"> </t-textarea>
<t-textarea :maxlength="200" v-model="formData.description" placeholder="请输入角色备注"> </t-textarea>
</t-form-item>
</t-form>
</Drawer>
......@@ -96,9 +96,3 @@ defineExpose({
close
})
</script>
<style lang="less" scoped>
:deep(.t-textarea__limit) {
display: none;
}
</style>
<template>
<div class="bg-white p-[12px] h-full overflow-auto">
<Back />
<main class="m-auto max-w-[1012px]">
<main class="m-auto max-w-[1012px]" v-loading="loading">
<!-- 基本信息 -->
<PageTitle title="基本信息" class="mb-[24px] mt-[12px]" />
<div class="flex flex-wrap">
......@@ -9,7 +9,7 @@
<DetailTable :label="'手机号码'" :value="detailData?.mobile" />
<DetailTable label="状态">
<span>
{{ statusTxt(detailData?.status as number)?.title }}
{{ statusTxt(detailData?.status as number)?.title||'-' }}
</span>
</DetailTable>
<DetailTable :label="'添加时间'" :value="detailData?.inputTime" />
......@@ -24,17 +24,19 @@
:columns="columns"
:loading="loading"
@page-change="onPageChange"
row-key="ids"
:rowspan-and-colspan="rowspanAndColspan"
max-height="400px"
:pagination="pagination.total > 10 ? pagination : undefined"
>
<!-- 保留自定义列插槽 -->
<template v-for="(_, name) in $slots" #[name]="scope">
<slot :name="name" v-bind="scope" />
</template>
<template v-for="col in columns" #[col.colKey]="{ row }" :key="col.colKey">
<template v-if="col.colKey != 'operation'">
<div class="cell-content">{{ row[col.colKey] || '-' }}</div>
<template v-if="col.colKey == 'dataPermission'">
<div class="cell-content">{{ dataPermissions(row) || '-' }}</div>
</template>
<template v-else-if="col.colKey == 'functionPermission'">
<div class="cell-content">{{ functionPermission(row) || '-' }}</div>
</template>
<template v-else> {{ row[col.colKey] || '-' }} </template>
</template>
</t-table>
......@@ -48,15 +50,6 @@
@page-change="onLogsPageChange"
:pagination="paginationLog.total > 10 ? paginationLog : undefined"
>
<!-- 保留自定义列插槽 -->
<template v-for="(_, name) in $slots" #[name]="scope">
<slot :name="name" v-bind="scope" />
</template>
<template v-for="col in columns" #[col.colKey]="{ row }" :key="col.colKey">
<template v-if="col.colKey != 'operation'">
<div class="cell-content">{{ row[col.colKey] || '-' }}</div>
</template>
</template>
</t-table>
</main>
</div>
......@@ -64,7 +57,7 @@
<script setup lang="tsx" name="users-detail">
import { useRoute } from 'vue-router'
import { PrimaryTableCol, PaginationProps } from 'tdesign-vue-next'
import { PrimaryTableCol, PaginationProps, TableProps } from 'tdesign-vue-next'
import { useBasic } from '@/hooks/useBasic'
import { statusTxt } from '@/utils/status'
import { getUserDetail, getLogs } from '@/api/modules/user-roles/index'
......@@ -79,45 +72,91 @@ const detailData = ref<ResUserList>()
// 获取用户详情
const getData = () => {
loading.value = true
getUserDetail({
userId: route.query.userId as string,
...pagination.value
}).then(res => {
detailData.value = res.data
pagination.value.total = res.data?.roleNames?.total as number
const list = res.data?.roleNames?.list || []
tableData.value = list.map(
(e: {
menuPermission: {
menuName: string
buttonNames: string[]
areaPermissions: { areaName: string }[]
rolePermissions: { roleName: string }[]
}[]
}) => {
// 匹配对应格式
let functionPermission: string[] = []
let dataPermission: string[] = []
e.menuPermission.map(
(em: {
menuName: string
buttonNames: string[]
areaPermissions: { areaName: string }[]
rolePermissions: { roleName: string }[]
}) => {
functionPermission.push(em.menuName + em.buttonNames.join(','))
dataPermission.push(
em.areaPermissions.map((val: { areaName: string }) => val.areaName).join(',') +
'-' +
em.rolePermissions.map((val: { roleName: string }) => val.roleName).join(',')
)
}
)
return { ...e, functionPermission: functionPermission.join(';'), dataPermission: dataPermission.join(';') }
}
)
})
.then(res => {
detailData.value = res.data
pagination.value.total = res.data?.roleNames?.total as number
const list = res.data?.roleNames?.list || []
const tableDatas = list.map(
(
e: {
menuPermission: {
menuName: string
buttonNames: string[]
areaPermissions: { name: string }[]
rolePermissions: { name: string }[]
}[]
},
index: number
) => {
const lists = e.menuPermission.map((em, i: number) => {
return { ...e, ...em, ids: `${index}-${i}`, rowspan: !i ? e.menuPermission.length : 0, serial: index + 1 }
})
return [...lists]
// 匹配对应格式
// let functionPermission: string[] = []
// let dataPermission: string[] = []
// e.menuPermission.map(
// (em: {
// menuName: string
// buttonNames: string[]
// areaPermissions: { name: string }[]
// rolePermissions: { name: string }[]
// }) => {
// const buttonNames = em.buttonNames || []
// const areaPermissions = em.areaPermissions || []
// const rolePermissions = em.rolePermissions || []
// functionPermission.push(em.menuName + buttonNames.join(','))
// dataPermission.push(
// areaPermissions.map((val: { name: string }) => val.name).join(',') +
// '-' +
// rolePermissions.map((val: { name: string }) => val.name).join(',')
// )
// }
// )
// return { ...e, functionPermission: functionPermission.join(';'), dataPermission: dataPermission.join(';') }
}
)
tableData.value = tableDatas.flat()
})
.finally(() => {
loading.value = false
})
}
const dataPermissions = (row: ResUserList) => {
const areaPermissions = row.areaPermissions || []
const rolePermissions = row.rolePermissions || []
const txt =
areaPermissions.map((val: { name: string }) => val.name).join(',') +
'-' +
rolePermissions.map((val: { name: string }) => val.name).join(',')
return txt
}
const functionPermission = (row: ResUserList) => {
const buttonNames = row.buttonNames || []
return row.menuName + (buttonNames.length ? '-' + buttonNames.join(',') : '')
}
// 合并单元格
const rowspanAndColspan: TableProps['rowspanAndColspan'] = ({ row, colIndex }) => {
if (colIndex === 1 || colIndex === 0) {
return {
colspan: 1,
rowspan: row?.rowspan
}
} else {
return {
colspan: 1,
rowspan: 1
}
}
}
const onPageChange = (val: PaginationProps) => {
......@@ -154,10 +193,10 @@ const pagination = ref({
const columns: PrimaryTableCol[] = [
{
title: '序号',
colKey: 'serial-number',
colKey: 'serial',
width: 70
},
{ title: '角色名称', colKey: 'userName' },
{ title: '角色名称', colKey: 'roleName' },
{ title: '功能权限', colKey: 'functionPermission' },
{ title: '数据权限', colKey: 'dataPermission' }
]
......@@ -187,7 +226,7 @@ onMounted(() => {
title: '系统权限'
},
{
title: '用户管理',
title: '用户列表',
name: 'users'
},
{
......
......@@ -2,7 +2,7 @@
* @Author: xiejiang
* @Date: 2024-11-28 15:01:02
* @LastEditors: xiejiang
* @LastEditTime: 2024-12-05 15:03:09
* @LastEditTime: 2024-12-09 17:26:42
* @Description: 用户管理
* Copyright(c)2024 by 好老师教育科技有限公司 All right Reserved.
-->
......@@ -22,10 +22,11 @@
:loading="loading"
placeholder="用户姓名/手机号码"
v-model="mobileOrName"
@clear="handleClear"
@on-search="handleSearch(searchParams)"
/></template>
<template #header-right>
<div class="flex items-center justify-end gap-2">
<div class="flex items-center justify-end gap-2" v-if="buttonPms('user-add-btn')">
<t-button shape="round" theme="primary" @click="handelEdit(null)">
<template #icon><AddIcon /></template>
添加用户</t-button
......@@ -38,8 +39,8 @@
<template v-else
><operate-btn v-if="row.status != 2" content="启用" @click="handelStatus(row, 2)"> </operate-btn>
<operate-btn v-if="row.status != 1" content="详情" @click="handelDetail(row)"> </operate-btn>
<operate-btn content="编辑" @click="handelEdit(row)"> </operate-btn>
<operate-btn v-if="row.status == 2" content="停用" @click="handelStatus(row, 1)"> </operate-btn>
<operate-btn v-if="buttonPms('user-edit-btn')" content="编辑" @click="handelEdit(row)"> </operate-btn>
<operate-btn v-if="row.status == 2" content="停用" @click="handelStatus(row, 3)"> </operate-btn>
<operate-btn v-if="row.status != 2" content="删除" @click="handelDel(row)"></operate-btn
></template>
</template>
......@@ -56,6 +57,7 @@ import { PrimaryTableCol, MessagePlugin } from 'tdesign-vue-next'
import type { filterItemProp } from 'src/components/PageFilters/interface/index'
import type { Pagination } from 'src/components/PageContainer/interface/index'
import { statusTxt } from '@/utils/status'
import { buttonPms } from '@/utils'
import { useBasic } from '@/hooks/useBasic'
import MessageBox from '@/utils/messageBox'
import UserEdit from './page/user-edit.vue'
......@@ -75,7 +77,7 @@ onMounted(() => {
title: '用户管理'
}
])
getData()
// getData()
})
// 加载状态
......@@ -112,7 +114,20 @@ const columns: PrimaryTableCol[] = [
},
{ title: '用户姓名', colKey: 'userName' },
{ title: '手机号码', colKey: 'mobile' },
{ title: '用户角色', width: 220, colKey: 'roleNames' },
{
title: '用户角色',
width: 220,
colKey: 'roles',
ellipsis: true,
cell: (h, { row }) => {
const roles = row.roles || []
return (
<p class='ellipsis w-full'>
<span>{roles.map((e: { name: string }) => e.name).join(';') || '-'}</span>
</p>
)
}
},
{
title: '状态',
colKey: 'status',
......@@ -126,7 +141,7 @@ const columns: PrimaryTableCol[] = [
}
},
{ title: '添加时间', colKey: 'inputTime' },
{ title: '添加人', colKey: 'imputUserName' },
{ title: '添加人', colKey: 'inputUserName' },
{ title: '操作', colKey: 'operation', fixed: 'right', width: 220 }
]
......@@ -158,6 +173,13 @@ const handleSearch = (params: Record<string, any>) => {
getData()
}
// 清空搜索条件
const handleClear = () => {
mobileOrName.value = ''
pagination.value.page = 1
getData()
}
// 处理分页
const handlePage = (pageInfo: Pagination) => {
pagination.value = { ...pagination.value, ...pageInfo }
......@@ -212,7 +234,7 @@ const handelDel = (row: ResUserList) => {
dialog.update({ confirmBtn: { content: '确定', loading: true } })
getUserOperate({
userId: row?.userId,
operateType: 3
operateType: 1
})
.then(() => {
getData()
......
......@@ -16,6 +16,7 @@
<t-form-item label="手机号码" name="mobile">
<t-input
v-model="formData.mobile"
maxlength="11"
@input="v => (formData.mobile = v.replace(/[^0-9]/g, ''))"
placeholder="请输入手机号码"
>
......@@ -27,7 +28,7 @@
</t-select>
</t-form-item>
<t-form-item label="用户备注" name="remark">
<t-textarea maxlength="200" v-model="formData.remark" placeholder="请输入用户备注"> </t-textarea>
<t-textarea :maxlength="200" v-model="formData.remark" placeholder="请输入用户备注"> </t-textarea>
</t-form-item>
</t-form>
</Drawer>
......@@ -97,11 +98,10 @@ const rules: FormProps['rules'] = {
],
mobile: [
{
required: true,
validator: validateTelePhone
}
],
role: [
roleIds: [
{
required: true,
message: '请选择用户角色!',
......@@ -119,10 +119,13 @@ const open = (val: ResUserList | null) => {
if (Object.prototype.hasOwnProperty.call(val, key)) {
;(formData as any)[key] = val[key]
}
const roleIds = val.roles || []
formData.roleIds = roleIds.map((item: { id: string }) => item.id)
}
} else {
title.value = '新增用户'
}
getRoleListData()
}
const close = () => {
formRef.value?.reset()
......@@ -155,18 +158,12 @@ const handleConfirm = () => {
const emit = defineEmits(['success'])
onMounted(() => {
getRoleListData()
})
// onMounted(() => {
// getRoleListData()
// })
defineExpose({
open,
close
})
</script>
<style lang="less" scoped>
:deep(.t-textarea__limit) {
display: none;
}
</style>
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论