提交 503f411b authored 作者: xiejiang's avatar xiejiang

feat: 新增权限克隆 以及优化菜单,表单等多个优化项

上级 450cbfe6
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* @Author: xiejiang * @Author: xiejiang
* @Date: 2024-12-02 14:56:33 * @Date: 2024-12-02 14:56:33
* @LastEditors: xiejiang * @LastEditors: xiejiang
* @LastEditTime: 2024-12-06 16:50:46 * @LastEditTime: 2024-12-08 14:51:30
* @Description: * @Description:
* Copyright(c)2024 by 好老师教育科技有限公司 All right Reserved. * Copyright(c)2024 by 好老师教育科技有限公司 All right Reserved.
*/ */
...@@ -46,9 +46,9 @@ export interface ReqSaveDictionary { ...@@ -46,9 +46,9 @@ export interface ReqSaveDictionary {
dictCode: string // 字典编码 dictCode: string // 字典编码
dictId: number | string // 字典ID dictId: number | string // 字典ID
dictName: string // 字典名称 dictName: string // 字典名称
isAllowAddsub: number // 是否允许添加子集:1允许,0不允许 isAllowAddsub: number | undefined // 是否允许添加子集:1允许,0不允许
isAllowDelete: number // 是否允许删除:1允许,0不允许 isAllowDelete: number | undefined // 是否允许删除:1允许,0不允许
isAllowEdit: number // 是否允许编辑:1允许,0不允许 isAllowEdit: number | undefined // 是否允许编辑:1允许,0不允许
remark: string // 字典说明 remark: string // 字典说明
} }
......
差异被折叠。
...@@ -14,8 +14,10 @@ const hanldleClick = () => { ...@@ -14,8 +14,10 @@ const hanldleClick = () => {
.back { .back {
width: 40px; width: 40px;
height: 24px; height: 24px;
position: absolute;
text-align: center; text-align: center;
border-radius: 12px; border-radius: 12px;
z-index: 999;
border: 1px solid var(--td-gray-color-2); border: 1px solid var(--td-gray-color-2);
color: var(--td-font-gray-2); color: var(--td-font-gray-2);
font-size: 12px; font-size: 12px;
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* @Author: xiejiang * @Author: xiejiang
* @Date: 2024-11-28 09:24:26 * @Date: 2024-11-28 09:24:26
* @LastEditors: xiejiang * @LastEditors: xiejiang
* @LastEditTime: 2024-11-29 09:35:06 * @LastEditTime: 2024-12-08 15:47:14
* @Description: table操作按钮 * @Description: table操作按钮
* Copyright(c)2024 by 好老师教育科技有限公司 All right Reserved. * Copyright(c)2024 by 好老师教育科技有限公司 All right Reserved.
--> -->
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
@click="handleClick" @click="handleClick"
:disabled="props.disabled" :disabled="props.disabled"
:loading="props.loading" :loading="props.loading"
v-bind="$attrs"
> >
<template #icon> <slot></slot></template> <template #icon> <slot></slot></template>
{{ props.content }} {{ props.content }}
......
...@@ -167,4 +167,11 @@ const onPageChange = (pageInfo: { current: number; pageSize: number }) => { ...@@ -167,4 +167,11 @@ const onPageChange = (pageInfo: { current: number; pageSize: number }) => {
text-align: right; text-align: right;
padding-right: 20px; padding-right: 20px;
} }
.cell-content {
width: 100%;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
</style> </style>
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* @Author: xiejiang * @Author: xiejiang
* @Date: 2024-11-29 16:08:58 * @Date: 2024-11-29 16:08:58
* @LastEditors: xiejiang * @LastEditors: xiejiang
* @LastEditTime: 2024-11-29 16:23:47 * @LastEditTime: 2024-12-08 15:08:34
* @Description: * @Description:
* Copyright(c)2024 by 好老师教育科技有限公司 All right Reserved. * Copyright(c)2024 by 好老师教育科技有限公司 All right Reserved.
--> -->
...@@ -34,7 +34,7 @@ const props = defineProps({ ...@@ -34,7 +34,7 @@ const props = defineProps({
display: inline-block; display: inline-block;
width: 4px; width: 4px;
height: 16px; height: 16px;
border-radius: 2px; border-radius: 0 3px;
background: var(--td-brand-color); background: var(--td-brand-color);
} }
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* @Author: xiejiang * @Author: xiejiang
* @Date: 2024-11-11 09:38:40 * @Date: 2024-11-11 09:38:40
* @LastEditors: xiejiang * @LastEditors: xiejiang
* @LastEditTime: 2024-12-02 11:04:03 * @LastEditTime: 2024-12-08 11:40:59
* @Description: * @Description:
* Copyright(c)2024 by 好老师教育科技有限公司 All right Reserved. * Copyright(c)2024 by 好老师教育科技有限公司 All right Reserved.
--> -->
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
alt="logo" alt="logo"
:width="isCollapse ? 64 : 208" :width="isCollapse ? 64 : 208"
:height="isCollapse ? 64 : 64" :height="isCollapse ? 64 : 64"
:class="[isCollapse ? 'ml-[28px]' : 'ml-[10px]']" class="ml-[0px] logo-transition"
@click="$router.push('/')" @click="$router.push('/')"
/> />
<Icon <Icon
...@@ -50,4 +50,10 @@ const changeCollapse = () => globalStore.setGlobalState('isCollapse', !globalSto ...@@ -50,4 +50,10 @@ const changeCollapse = () => globalStore.setGlobalState('isCollapse', !globalSto
height: 60px; height: 60px;
color: var(--td-font-gray-1); color: var(--td-font-gray-1);
} }
.logo-transition {
transition:
width 0.2s ease,
height 0.2s ease;
}
</style> </style>
...@@ -11,6 +11,11 @@ ...@@ -11,6 +11,11 @@
max-height: calc(100% - 52px); max-height: calc(100% - 52px);
max-width: calc(100% - 24px); max-width: calc(100% - 24px);
overflow: auto; overflow: auto;
> div {
min-width: 1200px;
overflow: auto;
}
} }
.t-footer { .t-footer {
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* @Author: xiejiang * @Author: xiejiang
* @Date: 2024-11-11 09:38:40 * @Date: 2024-11-11 09:38:40
* @LastEditors: xiejiang * @LastEditors: xiejiang
* @LastEditTime: 2024-11-13 18:01:45 * @LastEditTime: 2024-12-08 16:25:46
* @Description: * @Description:
* Copyright(c)2024 by 好老师教育科技有限公司 All right Reserved. * Copyright(c)2024 by 好老师教育科技有限公司 All right Reserved.
--> -->
...@@ -11,11 +11,32 @@ ...@@ -11,11 +11,32 @@
<div <div
v-show="isCollapse" v-show="isCollapse"
class="w-[32px] h-[32px] flex justify-center items-center bg-gray-1 rounded-[4px] cursor-pointer" class="w-[32px] h-[32px] flex justify-center items-center bg-gray-1 rounded-[4px] cursor-pointer"
@click="handleCollapse"
> >
<t-icon name="search" size="24" /> <t-tooltip placement="right" theme="light" overlay-class-name="custom-tooltip">
<template #content>
<div class="p-[16px]">
<t-auto-complete
ref="menuInputRef"
style="width: 240px"
v-model="searchMenu"
:options="options"
highlight-keyword
:filterable="false"
placeholder="请输入关键词搜索"
clearable
@change="onChange"
:on-select="handleClickMenu"
/>
</div>
</template>
<template #default>
<t-icon name="search" size="24" />
</template>
</t-tooltip>
</div> </div>
<!-- <t-tooltip placement="top" theme="light" overlay-class-name="custom-tooltip"> </t-tooltip> -->
<t-auto-complete <t-auto-complete
ref="menuInputRef" ref="menuInputRef"
v-show="!isCollapse" v-show="!isCollapse"
...@@ -68,9 +89,9 @@ const handleClickMenu = (label: string) => { ...@@ -68,9 +89,9 @@ const handleClickMenu = (label: string) => {
} }
} }
function handleCollapse() { // function handleCollapse() {
globalStore.setGlobalState('isCollapse', !globalStore.isCollapse) // globalStore.setGlobalState('isCollapse', !globalStore.isCollapse)
} // }
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>
...@@ -88,5 +109,9 @@ function handleCollapse() { ...@@ -88,5 +109,9 @@ function handleCollapse() {
color: var(--font-gray-4); color: var(--font-gray-4);
} }
} }
:deep(.t-icon) {
color: var(--td-font-gray-6);
}
} }
</style> </style>
...@@ -2,12 +2,20 @@ ...@@ -2,12 +2,20 @@
* @Author: xiejiang * @Author: xiejiang
* @Date: 2024-11-11 09:38:40 * @Date: 2024-11-11 09:38:40
* @LastEditors: xiejiang * @LastEditors: xiejiang
* @LastEditTime: 2024-12-02 14:24:20 * @LastEditTime: 2024-12-08 11:25:18
* @Description: * @Description:
* Copyright(c)2024 by 好老师教育科技有限公司 All right Reserved. * Copyright(c)2024 by 好老师教育科技有限公司 All right Reserved.
--> -->
<template> <template>
<t-menu :collapsed="isCollapse" :value="activeMenu" expand-mutex v-model:expanded="expanded"> <t-menu
:collapsed="isCollapse"
width="208px"
:class="'collapse' + isCollapse ? 'active' : ''"
:value="activeMenu"
expand-mutex
:default-value="defaultMenu"
v-model:expanded="expanded"
>
<SubMenu :menu-list="menuList" /> <SubMenu :menu-list="menuList" />
</t-menu> </t-menu>
</template> </template>
...@@ -25,10 +33,13 @@ const menuList = computed(() => authStore.authMenuListGet) ...@@ -25,10 +33,13 @@ const menuList = computed(() => authStore.authMenuListGet)
const activeMenu = computed(() => authStore.menuSign) const activeMenu = computed(() => authStore.menuSign)
const isCollapse = computed(() => globalStore.isCollapse) const isCollapse = computed(() => globalStore.isCollapse)
const expanded = ref<string[]>([]) const expanded = ref<string[]>([])
const defaultMenu = ref('')
// 设置展开菜单 // 设置展开菜单
const expandedFunc = (name: string) => { const expandedFunc = (name: string) => {
expanded.value = [menuList.value.find(item => item.children?.some(em => em.menuSign === name))?.menuSign] as string[] expanded.value = [menuList.value.find(item => item.children?.some(em => em.menuSign === name))?.menuSign] as string[]
console.log(expanded.value)
} }
watch(activeMenu, val => { watch(activeMenu, val => {
...@@ -38,10 +49,57 @@ watch(activeMenu, val => { ...@@ -38,10 +49,57 @@ watch(activeMenu, val => {
onMounted(() => { onMounted(() => {
const name = route.name as string const name = route.name as string
expandedFunc(name) expandedFunc(name)
defaultMenu.value = expanded.value[0]
}) })
</script> </script>
<style lang="less"> <style lang="less">
.t-default-menu { .t-default-menu {
height: calc(100% - 112px) !important; height: calc(100% - 112px) !important;
} }
.t-default-menu.t-is-collapsed {
width: 52px !important;
}
.t-default-menu__inner .t-menu {
padding: var(--td-comp-paddingTB-l) 0;
}
.t-default-menu .t-menu__item.t-is-opened {
color: var(--td-brand-color) !important;
font-weight: 700;
.t-icon {
color: var(--td-brand-color);
}
}
.t-is-collapsed {
.t-menu__item {
border-radius: 0 8px 8px 0;
}
.t-is-opened {
color: var(--td-white);
background-color: var(--td-brand-color) !important;
border-radius: 0 8px 8px 0;
.t-icon {
color: var(--td-white) !important;
}
}
.t-menu__item.t-is-opened .t-icon {
color: var(--td-brand-color);
}
.t-menu__item.t-is-active:not(.t-is-opened) {
color: var(--td-white);
background-color: var(--td-brand-color) !important;
.t-icon {
color: var(--td-white) !important;
}
}
}
</style> </style>
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* @Author: xiejiang * @Author: xiejiang
* @Date: 2024-11-11 09:38:40 * @Date: 2024-11-11 09:38:40
* @LastEditors: xiejiang * @LastEditors: xiejiang
* @LastEditTime: 2024-11-28 18:59:10 * @LastEditTime: 2024-12-08 10:41:05
* @Description: * @Description:
* Copyright(c)2024 by 好老师教育科技有限公司 All right Reserved. * Copyright(c)2024 by 好老师教育科技有限公司 All right Reserved.
--> -->
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
<t-layout class="layout-container"> <t-layout class="layout-container">
<Header class="layout-header" /> <Header class="layout-header" />
<t-layout class="layout-content"> <t-layout class="layout-content">
<t-aside :class="[isCollapse ? 'w-[96px]' : 'w-[232px]']"> <t-aside :class="[isCollapse ? 'w-[52px]' : 'w-[208px]']">
<MenuSearch /> <MenuSearch />
<Menu /> <Menu />
<!-- <MiddleBtn /> --> <!-- <MiddleBtn /> -->
...@@ -30,7 +30,7 @@ import Menu from '@/layouts/components/Menu/index.vue' ...@@ -30,7 +30,7 @@ import Menu from '@/layouts/components/Menu/index.vue'
const globalStore = useGlobalStore() const globalStore = useGlobalStore()
const isCollapse = computed(() => globalStore.isCollapse) const isCollapse = computed(() => globalStore.isCollapse)
const tabWidth = isCollapse.value ? 'width: calc(100% - 96px)' : 'width: calc(100% - 232px)' const tabWidth = isCollapse.value ? 'width: calc(100% - 52px)' : 'width: calc(100% - 208px)'
</script> </script>
<style scoped lang="less"> <style scoped lang="less">
......
...@@ -24,7 +24,8 @@ export interface UserInfo { ...@@ -24,7 +24,8 @@ export interface UserInfo {
loginInfo: { loginInfo: {
device: string device: string
ip: string ip: string
location: string location?: string
loginAddress?: string
time: string time: string
} }
status: string status: string
......
...@@ -84,6 +84,7 @@ ...@@ -84,6 +84,7 @@
--td-font-gray-3: rgb(0 0 0 / 40%); --td-font-gray-3: rgb(0 0 0 / 40%);
--td-font-gray-4: rgb(0 0 0 / 20%); --td-font-gray-4: rgb(0 0 0 / 20%);
--td-font-gray-5: rgb(0 0 0 / 6%); --td-font-gray-5: rgb(0 0 0 / 6%);
--td-font-gray-6: rgb(0 0 0 / 26%);
--td-white: #fff; --td-white: #fff;
--td-border: var(--td-gray-color-2); --td-border: var(--td-gray-color-2);
--td-text-color-primary: var(--td-font-gray-1); --td-text-color-primary: var(--td-font-gray-1);
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
<Back /> <Back />
<main class="m-auto max-w-[1012px]"> <main class="m-auto max-w-[1012px]">
<!-- 基本信息 --> <!-- 基本信息 -->
<PageTitle title="基本信息" class="mb-[24px]" /> <PageTitle title="基本信息" class="mb-[24px] mt-[12px]" />
<div class="flex flex-wrap"> <div class="flex flex-wrap">
<DetailTable label="机构名称" :value="state?.companyName" /> <DetailTable label="机构名称" :value="state?.companyName" />
<DetailTable label="机构类型" :value="state?.companyType" /> <DetailTable label="机构类型" :value="state?.companyType" />
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* @Author: xiejiang * @Author: xiejiang
* @Date: 2024-11-28 15:01:02 * @Date: 2024-11-28 15:01:02
* @LastEditors: xiejiang * @LastEditors: xiejiang
* @LastEditTime: 2024-12-05 10:51:58 * @LastEditTime: 2024-12-08 14:43:35
* @Description: 机构管理 * @Description: 机构管理
* Copyright(c)2024 by 好老师教育科技有限公司 All right Reserved. * Copyright(c)2024 by 好老师教育科技有限公司 All right Reserved.
--> -->
...@@ -18,7 +18,11 @@ ...@@ -18,7 +18,11 @@
@page-change="handlePage" @page-change="handlePage"
> >
<template #header-left> <template #header-left>
<SearchWithButton :loading="loading" placeholder="机构名称" v-model="condRoleName" @on-search="handleSearch" <SearchWithButton
:loading="loading"
placeholder="机构名称"
v-model="companyName"
@on-search="handleSearch(searchParams)"
/></template> /></template>
<template #header-right> <template #header-right>
...@@ -43,7 +47,7 @@ ...@@ -43,7 +47,7 @@
<script setup lang="tsx" name="institution"> <script setup lang="tsx" name="institution">
import { useRouter } from 'vue-router' import { useRouter } from 'vue-router'
import { PrimaryTableCol } from 'tdesign-vue-next' import { PrimaryTableCol, MessagePlugin } from 'tdesign-vue-next'
import type { filterItemProp } from '@/components/PageFilters/interface/index' import type { filterItemProp } from '@/components/PageFilters/interface/index'
import type { Pagination } from '@/components/PageContainer/interface/index' import type { Pagination } from '@/components/PageContainer/interface/index'
import { statusTxt } from '@/utils/status' import { statusTxt } from '@/utils/status'
...@@ -86,7 +90,7 @@ const pagination = ref({ ...@@ -86,7 +90,7 @@ const pagination = ref({
total: 0 total: 0
}) })
const condRoleName = ref('') const companyName = ref('')
// 筛选项配置,type类型参考pageFilters组件下的ts定义 // 筛选项配置,type类型参考pageFilters组件下的ts定义
const filterConditions = ref<filterItemProp[]>([ const filterConditions = ref<filterItemProp[]>([
...@@ -122,10 +126,11 @@ const getDictData = () => { ...@@ -122,10 +126,11 @@ const getDictData = () => {
// 表格columns配置 // 表格columns配置
const columns: PrimaryTableCol[] = [ const columns: PrimaryTableCol[] = [
{ {
title: '序号',
colKey: 'serial-number', colKey: 'serial-number',
width: 50 width: 70
}, },
{ title: '机构名称', colKey: 'companyName', ellipsis: true }, { title: '机构名称', colKey: 'companyName' },
{ {
title: '机构类型', title: '机构类型',
colKey: 'companyTypeName' colKey: 'companyTypeName'
...@@ -171,7 +176,7 @@ const getData = () => { ...@@ -171,7 +176,7 @@ const getData = () => {
const postData = { const postData = {
...pagination.value, ...pagination.value,
...searchParams.value, ...searchParams.value,
condRoleName: condRoleName.value condRoleName: companyName.value
} }
getCompanyList(postData) getCompanyList(postData)
.then(res => { .then(res => {
...@@ -182,7 +187,7 @@ const getData = () => { ...@@ -182,7 +187,7 @@ const getData = () => {
loading.value = false loading.value = false
}) })
} }
const searchParams = ref<Record<string, any>>({}) // 搜索筛选 const searchParams = ref<Record<string, any>>({}) // 搜索筛选
// 处理搜索条件 // 处理搜索条件
const handleSearch = (params: Record<string, any>) => { const handleSearch = (params: Record<string, any>) => {
...@@ -228,8 +233,12 @@ const handelStatus = (row: ResCompany, status: number) => { ...@@ -228,8 +233,12 @@ const handelStatus = (row: ResCompany, status: number) => {
}) })
.then(() => { .then(() => {
getData() getData()
MessagePlugin.success('操作成功')
dialog.hide() dialog.hide()
}) })
.catch(() => {
MessagePlugin.error('操作失败')
})
.finally(() => { .finally(() => {
dialog.update({ confirmBtn: { content: '确定', loading: false } }) dialog.update({ confirmBtn: { content: '确定', loading: false } })
}) })
...@@ -247,9 +256,13 @@ const handelDel = (row: ResCompany) => { ...@@ -247,9 +256,13 @@ const handelDel = (row: ResCompany) => {
companyId: row?.companyId companyId: row?.companyId
}) })
.then(() => { .then(() => {
MessagePlugin.success('操作成功')
getData() getData()
dialog.hide() dialog.hide()
}) })
.catch(() => {
MessagePlugin.error('操作失败')
})
.finally(() => { .finally(() => {
dialog.update({ confirmBtn: { content: '确定', loading: false } }) dialog.update({ confirmBtn: { content: '确定', loading: false } })
}) })
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* @Author: xiejiang * @Author: xiejiang
* @Date: 2024-11-05 10:14:56 * @Date: 2024-11-05 10:14:56
* @LastEditors: xiejiang * @LastEditors: xiejiang
* @LastEditTime: 2024-12-02 11:08:02 * @LastEditTime: 2024-12-08 14:49:30
* @Description: 首页 * @Description: 首页
* Copyright(c)2024 by 好老师教育科技有限公司 All right Reserved. * Copyright(c)2024 by 好老师教育科技有限公司 All right Reserved.
--> -->
...@@ -14,22 +14,25 @@ ...@@ -14,22 +14,25 @@
<div class="home-avatar flex items-center justify-center"> <div class="home-avatar flex items-center justify-center">
<div> <div>
<p class="text-20 bold">{{ userInfo && userInfo.userName }},您好!</p> <p class="text-20 bold">{{ userInfo && userInfo.userName }},您好!</p>
<p class="text-14">欢迎使用好老师考研后台管理系统</p> <p class="text-14">欢迎使用智慧教育平台</p>
</div> </div>
</div> </div>
<div class="home-line w-full"></div> <div class="home-line w-full"></div>
<div class="home-user flex flex-col items-center justify-center"> <div class="home-user flex flex-col items-center justify-center">
<p> <p>
<span>部门:</span> <span>角色:</span>
<span>{{ userInfo?.department }}</span> <span class="max-w-[calc(100%-90px)]">
</p> <span v-for="v in userInfo?.roleNames || []" :key="v"> {{ v }}</span></span
<p> >
<span>岗位:</span> <span v-if="!userInfo?.roleNames.length">-</span>
<span>{{ userInfo?.position }}</span>
</p> </p>
<p> <p>
<span>角色:</span> <span>上次登录:</span>
<span>{{ userInfo?.roleName }}</span> <span class="max-w-[calc(100%-90px)]"
>{{ userInfo?.loginInfo.loginAddress || '-' }}{{ userInfo?.loginInfo.time || '-' }}{{
userInfo?.loginInfo.device || '-'
}}</span
>
</p> </p>
</div> </div>
<img :src="homeImg" class="mt-[80px]" width="502" alt="" /> <img :src="homeImg" class="mt-[80px]" width="502" alt="" />
...@@ -90,7 +93,6 @@ onMounted(() => { ...@@ -90,7 +93,6 @@ onMounted(() => {
> p { > p {
width: 100%; width: 100%;
display: flex; display: flex;
align-items: center;
justify-content: space-between; justify-content: space-between;
font-weight: 400; font-weight: 400;
font-size: 14px; font-size: 14px;
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* @Author: xiejiang * @Author: xiejiang
* @Date: 2024-11-05 10:14:56 * @Date: 2024-11-05 10:14:56
* @LastEditors: xiejiang * @LastEditors: xiejiang
* @LastEditTime: 2024-12-05 16:40:21 * @LastEditTime: 2024-12-08 14:31:01
* @Description: 登录 * @Description: 登录
* Copyright(c)2024 by 好老师教育科技有限公司 All right Reserved. * Copyright(c)2024 by 好老师教育科技有限公司 All right Reserved.
--> -->
...@@ -21,7 +21,12 @@ ...@@ -21,7 +21,12 @@
<t-form-item name="mobile" :required-mark="false"> <t-form-item name="mobile" :required-mark="false">
<t-input <t-input
v-model="formData.mobile" v-model="formData.mobile"
@input="v => (formData.mobile = v.replace(/[^0-9]/g, ''))" maxlength="11"
@input="
v => {
formData.mobile = v.target.value.replace(/[^0-9]/g, '')
}
"
placeholder="请输入手机号" placeholder="请输入手机号"
> >
<template #prefix-icon> <template #prefix-icon>
...@@ -30,7 +35,16 @@ ...@@ -30,7 +35,16 @@
</t-input> </t-input>
</t-form-item> </t-form-item>
<t-form-item name="code" :required-mark="false"> <t-form-item name="code" :required-mark="false">
<t-input v-model="formData.code" placeholder="请输入验证码"> <t-input
v-model="formData.code"
maxlength="4"
@input="
v => {
formData.code = v.target.value.replace(/[^0-9]/g, '')
}
"
placeholder="请输入验证码"
>
<template #prefix-icon> <template #prefix-icon>
<ShieldErrorIcon /> <ShieldErrorIcon />
</template> </template>
...@@ -141,6 +155,9 @@ const isShowPuzzleVcode = ref(false) ...@@ -141,6 +155,9 @@ const isShowPuzzleVcode = ref(false)
const sliderVerify = ref() const sliderVerify = ref()
// 发送短信验证码 // 发送短信验证码
const getCode = function () { const getCode = function () {
if (!isPhoneNumber(formData.mobile) || codeBtnDisabled.value) {
return
}
isShowPuzzleVcode.value = true isShowPuzzleVcode.value = true
} }
...@@ -168,7 +185,7 @@ const onPuzzleVcodeClose = () => { ...@@ -168,7 +185,7 @@ const onPuzzleVcodeClose = () => {
telephone: formData.mobile telephone: formData.mobile
}) })
.then(() => { .then(() => {
MessagePlugin.success('已发送短信验证码!') MessagePlugin.success('验证成功!')
// 重置密码的验证码 // 重置密码的验证码
codeBtnTxt.value = '<span class="text-primary">60s</span>后重新获取' codeBtnTxt.value = '<span class="text-primary">60s</span>后重新获取'
codeBtnDisabled.value = true codeBtnDisabled.value = true
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* @Author: xiejiang * @Author: xiejiang
* @Date: 2024-11-11 09:38:40 * @Date: 2024-11-11 09:38:40
* @LastEditors: xiejiang * @LastEditors: xiejiang
* @LastEditTime: 2024-12-05 16:55:50 * @LastEditTime: 2024-12-08 15:49:03
* @Description: 系统字典-管理子集 * @Description: 系统字典-管理子集
* Copyright(c)2024 by 好老师教育科技有限公司 All right Reserved. * Copyright(c)2024 by 好老师教育科技有限公司 All right Reserved.
--> -->
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
<Back /> <Back />
<main class="m-auto max-w-[1012px]"> <main class="m-auto max-w-[1012px]">
<!-- 基本信息 --> <!-- 基本信息 -->
<PageTitle title="基本信息" class="my-[24px]" /> <PageTitle title="基本信息" class="mb-[24px] mt-[12px]" />
<div class="flex flex-wrap" v-loading="detailLoading"> <div class="flex flex-wrap" v-loading="detailLoading">
<DetailTable label="字典大类" :value="dataInfo.categoryName" /> <DetailTable label="字典大类" :value="dataInfo.categoryName" />
<DetailTable label="字典名称" :value="dataInfo.dictName" /> <DetailTable label="字典名称" :value="dataInfo.dictName" />
...@@ -40,6 +40,11 @@ ...@@ -40,6 +40,11 @@
<template v-for="(_, name) in $slots" #[name]="scope"> <template v-for="(_, name) in $slots" #[name]="scope">
<slot :name="name" v-bind="scope" /> <slot :name="name" v-bind="scope" />
</template> </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> </t-table>
<div class="table-add"> <div class="table-add">
<span class="cursor-pointer text-[var(--td-brand-color)]" @click="handleAdd">+ 新增 </span> <span class="cursor-pointer text-[var(--td-brand-color)]" @click="handleAdd">+ 新增 </span>
...@@ -75,7 +80,7 @@ const dataInfo = ref<ResDictionary>({ ...@@ -75,7 +80,7 @@ const dataInfo = ref<ResDictionary>({
dictName: '', dictName: '',
dictCode: '', dictCode: '',
remark: '', remark: '',
dictId: 0, dictId: '',
isAllowAddsub: 0, isAllowAddsub: 0,
isAllowDelete: 0 isAllowDelete: 0
}) })
...@@ -118,21 +123,36 @@ const pagination = ref({ ...@@ -118,21 +123,36 @@ const pagination = ref({
// 表格columns配置 // 表格columns配置
const columns: PrimaryTableCol[] = [ const columns: PrimaryTableCol[] = [
{ {
title: '序号',
colKey: 'serial-number', colKey: 'serial-number',
width: 50 width: 70
}, },
{ title: '值名称', colKey: 'valueName', ellipsis: true }, { title: '值名称', colKey: 'valueName' },
{ title: '值编码', colKey: 'dataCode', ellipsis: true }, { title: '值编码', colKey: 'dataCode' },
{ title: '备注', colKey: 'remark', ellipsis: true }, { title: '备注', colKey: 'remark' },
{ {
title: '快速排序', title: '快速排序',
colKey: 'sort', colKey: 'sort',
width: 88, width: 88,
cell: (h, { row }: { row: any }) => { cell: (h, { row, rowIndex }: { row: any; rowIndex: number }) => {
return ( return (
<div class='flex items-center text-[var(--td-brand-color)]'> <div class='flex items-center text-[var(--td-brand-color)]'>
<ArrowDownIcon class='mr-[8px] cursor-pointer' onClick={handleSort(row, true)} /> <operate-btn
<ArrowUpIcon class='cursor-pointer' onClick={handleSort(row, false)} /> content=''
class='ico-btn'
disabled={rowIndex == 0 ? 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)}
>
<ArrowDownIcon />
</operate-btn>
</div> </div>
) )
} }
...@@ -186,8 +206,12 @@ const handleDel = (row: ResDictionary) => () => { ...@@ -186,8 +206,12 @@ const handleDel = (row: ResDictionary) => () => {
}) })
.then(() => { .then(() => {
GetDictDataList() GetDictDataList()
MessagePlugin.success('操作成功')
dialog.hide() dialog.hide()
}) })
.catch(() => {
MessagePlugin.error('操作失败')
})
.finally(() => { .finally(() => {
dialog.update({ confirmBtn: { content: '确定', loading: false } }) dialog.update({ confirmBtn: { content: '确定', loading: false } })
}) })
...@@ -220,7 +244,7 @@ const GetDictDataList = () => { ...@@ -220,7 +244,7 @@ const GetDictDataList = () => {
onMounted(() => { onMounted(() => {
setBreadcrumb([ setBreadcrumb([
{ {
title: '系统权限' title: '系统配置'
}, },
{ {
title: '系统字典', title: '系统字典',
...@@ -236,8 +260,6 @@ onMounted(() => { ...@@ -236,8 +260,6 @@ onMounted(() => {
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>
@import './comm.less';
.table-add { .table-add {
width: 100%; width: 100%;
padding: 13px; padding: 13px;
...@@ -245,4 +267,8 @@ onMounted(() => { ...@@ -245,4 +267,8 @@ onMounted(() => {
box-sizing: border-box; box-sizing: border-box;
background: var(--td-brand-color-1); background: var(--td-brand-color-1);
} }
:deep(.ico-btn) {
padding: 0;
}
</style> </style>
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* @Author: xiejiang * @Author: xiejiang
* @Date: 2024-11-11 09:38:40 * @Date: 2024-11-11 09:38:40
* @LastEditors: xiejiang * @LastEditors: xiejiang
* @LastEditTime: 2024-12-05 15:03:49 * @LastEditTime: 2024-12-08 11:34:20
* @Description: 系统字典 * @Description: 系统字典
* Copyright(c)2024 by 好老师教育科技有限公司 All right Reserved. * Copyright(c)2024 by 好老师教育科技有限公司 All right Reserved.
--> -->
...@@ -50,7 +50,7 @@ ...@@ -50,7 +50,7 @@
<script setup lang="tsx" name="dictionary"> <script setup lang="tsx" name="dictionary">
import { useRouter } from 'vue-router' import { useRouter } from 'vue-router'
import { PrimaryTableCol } from 'tdesign-vue-next' import { PrimaryTableCol, MessagePlugin } from 'tdesign-vue-next'
import type { filterItemProp } from '@/components/PageFilters/interface/index' import type { filterItemProp } from '@/components/PageFilters/interface/index'
import type { Pagination } from '@/components/PageContainer/interface/index' import type { Pagination } from '@/components/PageContainer/interface/index'
import { statusTxt, dictionaryAttributes, dictionaryAttributeTxt } from '@/utils/status' import { statusTxt, dictionaryAttributes, dictionaryAttributeTxt } from '@/utils/status'
...@@ -72,7 +72,7 @@ const router = useRouter() ...@@ -72,7 +72,7 @@ const router = useRouter()
onMounted(() => { onMounted(() => {
setBreadcrumb([ setBreadcrumb([
{ {
title: '系统权限' title: '系统配置'
}, },
{ {
title: '系统字典' title: '系统字典'
...@@ -117,11 +117,12 @@ const filterConditions = computed<filterItemProp[]>(() => [ ...@@ -117,11 +117,12 @@ const filterConditions = computed<filterItemProp[]>(() => [
// 表格columns配置 // 表格columns配置
const columns: PrimaryTableCol[] = [ const columns: PrimaryTableCol[] = [
{ {
title: '序号',
colKey: 'serial-number', colKey: 'serial-number',
width: 50 width: 70
}, },
{ title: '字典大类', colKey: 'categoryId', ellipsis: true }, { title: '字典大类', colKey: 'categoryId' },
{ title: '字典名称', colKey: 'dictName', ellipsis: true }, { title: '字典名称', colKey: 'dictName' },
{ title: '字典编码', colKey: 'dictCode' }, { title: '字典编码', colKey: 'dictCode' },
{ title: '字典说明', colKey: 'remark' }, { title: '字典说明', colKey: 'remark' },
{ {
...@@ -236,8 +237,12 @@ const handelStatus = (row: ResDictionary, status: number) => { ...@@ -236,8 +237,12 @@ const handelStatus = (row: ResDictionary, status: number) => {
}) })
.then(() => { .then(() => {
getData() getData()
MessagePlugin.success('操作成功')
dialog.hide() dialog.hide()
}) })
.catch(() => {
MessagePlugin.error('操作失败')
})
.finally(() => { .finally(() => {
dialog.update({ confirmBtn: { content: '确定', loading: false } }) dialog.update({ confirmBtn: { content: '确定', loading: false } })
}) })
...@@ -258,8 +263,12 @@ const handelDel = (row: ResDictionary) => { ...@@ -258,8 +263,12 @@ const handelDel = (row: ResDictionary) => {
}) })
.then(() => { .then(() => {
getData() getData()
MessagePlugin.success('操作成功')
dialog.hide() dialog.hide()
}) })
.catch(() => {
MessagePlugin.error('操作失败')
})
.finally(() => { .finally(() => {
dialog.update({ confirmBtn: { content: '确定删除', loading: false } }) dialog.update({ confirmBtn: { content: '确定删除', loading: false } })
}) })
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* @Author: xiejiang * @Author: xiejiang
* @Date: 2024-11-11 09:38:40 * @Date: 2024-11-11 09:38:40
* @LastEditors: xiejiang * @LastEditors: xiejiang
* @LastEditTime: 2024-12-03 11:44:08 * @LastEditTime: 2024-12-08 14:54:41
* @Description: 系统字典-新增编辑字典 * @Description: 系统字典-新增编辑字典
* Copyright(c)2024 by 好老师教育科技有限公司 All right Reserved. * Copyright(c)2024 by 好老师教育科技有限公司 All right Reserved.
--> -->
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* @Author: xiejiang * @Author: xiejiang
* @Date: 2024-11-11 09:38:40 * @Date: 2024-11-11 09:38:40
* @LastEditors: xiejiang * @LastEditors: xiejiang
* @LastEditTime: 2024-12-05 14:03:49 * @LastEditTime: 2024-12-08 15:05:16
* @Description: 菜单管理 * @Description: 菜单管理
* Copyright(c)2024 by 好老师教育科技有限公司 All right Reserved. * Copyright(c)2024 by 好老师教育科技有限公司 All right Reserved.
--> -->
...@@ -77,7 +77,7 @@ ...@@ -77,7 +77,7 @@
</template> </template>
<script setup lang="tsx" name="sys-menu"> <script setup lang="tsx" name="sys-menu">
import { PrimaryTableCol } from 'tdesign-vue-next' import { PrimaryTableCol, MessagePlugin } from 'tdesign-vue-next'
import type { filterItemProp } from 'src/components/PageFilters/interface/index' import type { filterItemProp } from 'src/components/PageFilters/interface/index'
import type { Pagination } from 'src/components/PageContainer/interface/index' import type { Pagination } from 'src/components/PageContainer/interface/index'
import { useBasic } from '@/hooks/useBasic' import { useBasic } from '@/hooks/useBasic'
...@@ -104,7 +104,7 @@ const onTabChange = () => { ...@@ -104,7 +104,7 @@ const onTabChange = () => {
onMounted(() => { onMounted(() => {
setBreadcrumb([ setBreadcrumb([
{ {
title: '系统权限' title: '系统配置'
}, },
{ {
title: '菜单管理' title: '菜单管理'
...@@ -187,12 +187,16 @@ const handleStatus = (row: ResMenu, status: number) => { ...@@ -187,12 +187,16 @@ const handleStatus = (row: ResMenu, status: number) => {
// 请求成功后,销毁弹框 // 请求成功后,销毁弹框
dialog.update({ confirmBtn: { content: '确定', loading: true } }) dialog.update({ confirmBtn: { content: '确定', loading: true } })
submit({ submit({
menuId: row?.menuId as number menuId: row?.menuId as string
}) })
.then(() => { .then(() => {
MessagePlugin.success('操作成功')
getData() getData()
dialog.hide() dialog.hide()
}) })
.catch(() => {
MessagePlugin.error('操作失败')
})
.finally(() => { .finally(() => {
dialog.update({ confirmBtn: { content: '确定', loading: false } }) dialog.update({ confirmBtn: { content: '确定', loading: false } })
}) })
...@@ -207,7 +211,7 @@ const handleDel = (row: ResMenu) => { ...@@ -207,7 +211,7 @@ const handleDel = (row: ResMenu) => {
// 请求成功后,销毁弹框 // 请求成功后,销毁弹框
dialog.update({ confirmBtn: { content: '确定', loading: true } }) dialog.update({ confirmBtn: { content: '确定', loading: true } })
postMenuRemove({ postMenuRemove({
menuId: row?.menuId as number menuId: row?.menuId as string
}) })
.then(() => { .then(() => {
getData() getData()
......
...@@ -151,6 +151,7 @@ const open = (val: ResMenu | null) => { ...@@ -151,6 +151,7 @@ const open = (val: ResMenu | null) => {
for (const key in formData) { for (const key in formData) {
if (Object.prototype.hasOwnProperty.call(val, key)) { if (Object.prototype.hasOwnProperty.call(val, key)) {
;(formData as any)[key] = val[key] // 使用类型断言 ;(formData as any)[key] = val[key] // 使用类型断言
console.log(formData.isButton)
} }
} }
getLevelMenu() getLevelMenu()
......
<template> <template>
<Drawer :drawer-visible="drawerVisible" width="480" title="操作日志" :show-footer="false" @close="close"> <Drawer :drawer-visible="drawerVisible" width="480" title="操作日志" :footer="false" @close="close">
<SearchWithButton <SearchWithButton
:loading="loading" :loading="loading"
placeholder="操作人姓名" placeholder="操作人姓名"
...@@ -19,6 +19,11 @@ ...@@ -19,6 +19,11 @@
<template v-for="(_, name) in $slots" #[name]="scope"> <template v-for="(_, name) in $slots" #[name]="scope">
<slot :name="name" v-bind="scope" /> <slot :name="name" v-bind="scope" />
</template> </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> </t-table>
</Drawer> </Drawer>
</template> </template>
...@@ -34,15 +39,17 @@ const drawerVisible = ref(false) ...@@ -34,15 +39,17 @@ const drawerVisible = ref(false)
const condInputUserName = ref('') const condInputUserName = ref('')
const loading = ref(false) const loading = ref(false)
const tableData = ref<ResMenu[]>([]) const tableData = ref<ResMenu[]>([])
const pagination = ref({
page: 1, const pagination = ref<PaginationProps>({
limit: 10, current: 1,
pageSize: 10,
size: 'small',
total: 0 total: 0
}) })
// 表格columns配置 // 表格columns配置
const columns: PrimaryTableCol[] = [ const columns: PrimaryTableCol[] = [
{ title: '操作人', colKey: 'inputUserName', ellipsis: true }, { title: '操作人', colKey: 'inputUserName' },
{ title: '操作时间', colKey: 'inputTime', ellipsis: true }, { title: '操作时间', colKey: 'inputTime' },
{ {
title: '操作内容', title: '操作内容',
colKey: 'content', colKey: 'content',
...@@ -62,7 +69,8 @@ const columns: PrimaryTableCol[] = [ ...@@ -62,7 +69,8 @@ const columns: PrimaryTableCol[] = [
const getData = () => { const getData = () => {
getOperations({ getOperations({
...pagination.value, page: pagination.value.current as number,
limit: pagination.value.pageSize as number,
condInputUserName: condInputUserName.value condInputUserName: condInputUserName.value
}) })
.then(res => { .then(res => {
...@@ -81,8 +89,8 @@ const operateTypeTxt = (key: number) => { ...@@ -81,8 +89,8 @@ const operateTypeTxt = (key: number) => {
// 表格分页 // 表格分页
const onPageChange = (val: PaginationProps) => { const onPageChange = (val: PaginationProps) => {
pagination.value.page = val.current as number pagination.value.current = val.current as number
pagination.value.limit = val.pageSize as number pagination.value.pageSize = val.pageSize as number
getData() getData()
} }
...@@ -91,13 +99,13 @@ const open = () => { ...@@ -91,13 +99,13 @@ const open = () => {
getData() getData()
} }
const close = () => { const close = () => {
pagination.value.page = 1 pagination.value.current = 1
pagination.value.limit = 10 pagination.value.pageSize = 10
drawerVisible.value = false drawerVisible.value = false
} }
const handleSearch = () => { const handleSearch = () => {
pagination.value.page = 1 pagination.value.current = 1
getData() getData()
} }
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* @Author: xiejiang * @Author: xiejiang
* @Date: 2024-12-04 14:06:18 * @Date: 2024-12-04 14:06:18
* @LastEditors: xiejiang * @LastEditors: xiejiang
* @LastEditTime: 2024-12-05 15:25:28 * @LastEditTime: 2024-12-08 10:39:51
* @Description: 菜单排序 * @Description: 菜单排序
* Copyright(c)2024 by 好老师教育科技有限公司 All right Reserved. * Copyright(c)2024 by 好老师教育科技有限公司 All right Reserved.
--> -->
...@@ -29,7 +29,7 @@ ...@@ -29,7 +29,7 @@
</template> </template>
<script setup lang="ts" name="menu-sort"> <script setup lang="ts" name="menu-sort">
import { TypDragEventState, TreeProps } from 'tdesign-vue-next' import { TreeProps } from 'tdesign-vue-next'
import { ResMenuTree } from '@/api/interface/menu/index' import { ResMenuTree } from '@/api/interface/menu/index'
import { getMenuTree, postMenuSort } from '@/api/modules/menu/index' import { getMenuTree, postMenuSort } from '@/api/modules/menu/index'
...@@ -84,13 +84,16 @@ function findChildrenByParentId(tree: ResMenuTree[], parentId: string): ResMenuT ...@@ -84,13 +84,16 @@ function findChildrenByParentId(tree: ResMenuTree[], parentId: string): ResMenuT
return result return result
} }
const handleAllowDrop = (options: TypDragEventState) => { const handleAllowDrop: TreeProps['allowDrop'] = ctx => {
const { dropPosition } = options const { dropPosition, dropNode, dragNode } = ctx
console.log(dropPosition)
// 只允许同级拖动 // 只允许同级拖动
if (dropPosition === 1) { if (dropPosition === 1) {
return true // 允许同级拖动
if (dragNode?.data?.parentId === dropNode?.data?.parentId) {
return true
} else {
return false
}
} else { } else {
return false return false
} }
......
...@@ -65,7 +65,7 @@ ...@@ -65,7 +65,7 @@
</template> </template>
<script setup lang="tsx" name="version"> <script setup lang="tsx" name="version">
import { PrimaryTableCol } from 'tdesign-vue-next' import { PrimaryTableCol, MessagePlugin } from 'tdesign-vue-next'
import type { filterItemProp } from 'src/components/PageFilters/interface/index' import type { filterItemProp } from 'src/components/PageFilters/interface/index'
import type { Pagination } from 'src/components/PageContainer/interface/index' import type { Pagination } from 'src/components/PageContainer/interface/index'
import { useBasic } from '@/hooks/useBasic' import { useBasic } from '@/hooks/useBasic'
...@@ -89,7 +89,7 @@ const onTabChange = () => { ...@@ -89,7 +89,7 @@ const onTabChange = () => {
onMounted(() => { onMounted(() => {
setBreadcrumb([ setBreadcrumb([
{ {
title: '系统权限' title: '系统配置'
}, },
{ {
title: '版本管理' title: '版本管理'
...@@ -178,8 +178,12 @@ const handleStatus = (row: ResVersion, status: number) => { ...@@ -178,8 +178,12 @@ const handleStatus = (row: ResVersion, status: number) => {
}) })
.then(() => { .then(() => {
getData() getData()
MessagePlugin.success('操作成功')
dialog.hide() dialog.hide()
}) })
.catch(() => {
MessagePlugin.error('操作失败')
})
.finally(() => { .finally(() => {
dialog.update({ confirmBtn: { content: '确定', loading: false } }) dialog.update({ confirmBtn: { content: '确定', loading: false } })
}) })
...@@ -204,8 +208,12 @@ const handleDel = (row: ResVersion) => { ...@@ -204,8 +208,12 @@ const handleDel = (row: ResVersion) => {
}) })
.then(() => { .then(() => {
getData() getData()
MessagePlugin.success('操作成功')
dialog.hide() dialog.hide()
}) })
.catch(() => {
MessagePlugin.error('操作失败')
})
.finally(() => { .finally(() => {
dialog.update({ confirmBtn: { content: '确定', loading: false } }) dialog.update({ confirmBtn: { content: '确定', loading: false } })
}) })
......
...@@ -12,6 +12,11 @@ ...@@ -12,6 +12,11 @@
<template v-for="(_, name) in $slots" #[name]="scope"> <template v-for="(_, name) in $slots" #[name]="scope">
<slot :name="name" v-bind="scope" /> <slot :name="name" v-bind="scope" />
</template> </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> </t-table>
</Drawer> </Drawer>
</template> </template>
...@@ -32,8 +37,9 @@ const tableData = ref<any[]>([]) ...@@ -32,8 +37,9 @@ const tableData = ref<any[]>([])
// 表格columns配置 // 表格columns配置
const columns: PrimaryTableCol[] = [ const columns: PrimaryTableCol[] = [
{ {
title: '序号',
colKey: 'serial-number', colKey: 'serial-number',
width: 50 width: 70
}, },
{ {
title: '变更前状态', title: '变更前状态',
...@@ -49,8 +55,8 @@ const columns: PrimaryTableCol[] = [ ...@@ -49,8 +55,8 @@ const columns: PrimaryTableCol[] = [
return <span>{statusVersionTxt(row.afterStatus)?.title}</span> return <span>{statusVersionTxt(row.afterStatus)?.title}</span>
} }
}, },
{ title: '操作人', colKey: 'inputUserName', ellipsis: true }, { title: '操作人', colKey: 'inputUserName' },
{ title: '操作时间', colKey: 'inputTime', ellipsis: true } { title: '操作时间', colKey: 'inputTime' }
] ]
const open = (val: ResVersion) => { const open = (val: ResVersion) => {
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* @Author: xiejiang * @Author: xiejiang
* @Date: 2024-11-11 09:38:40 * @Date: 2024-11-11 09:38:40
* @LastEditors: xiejiang * @LastEditors: xiejiang
* @LastEditTime: 2024-12-06 16:35:08 * @LastEditTime: 2024-12-08 10:28:35
* @Description: 权限配置 * @Description: 权限配置
* Copyright(c)2024 by 好老师教育科技有限公司 All right Reserved. * Copyright(c)2024 by 好老师教育科技有限公司 All right Reserved.
--> -->
...@@ -58,10 +58,17 @@ ...@@ -58,10 +58,17 @@
submitLoading = val submitLoading = val
} }
" "
@updateMenuId="
val => {
sourceMenuId = val
}
"
v-show="tabValue === 2" v-show="tabValue === 2"
/> />
</div> </div>
<CopyPermissions ref="copyPermissionsRef" />
<!-- 添加角色 --> <!-- 添加角色 -->
<!-- <Dialog :dialog-visible="dialogVisible" width="480px" title="添加角色" :footer="true" @close="close"> <!-- <Dialog :dialog-visible="dialogVisible" width="480px" title="添加角色" :footer="true" @close="close">
<template #body> <template #body>
...@@ -95,18 +102,23 @@ ...@@ -95,18 +102,23 @@
</template> </template>
<script setup lang="ts" name="authority"> <script setup lang="ts" name="authority">
import { useRoute } from 'vue-router'
import { ResRoleList } from '@/api/interface/user-roles/index' import { ResRoleList } from '@/api/interface/user-roles/index'
import { getRoleList } from '@/api/modules/user-roles/index' import { getRoleList } from '@/api/modules/user-roles/index'
import Capabilities from './page/capabilities.vue' import Capabilities from './page/capabilities.vue'
import DataPermissions from './page/data-permissions.vue' import DataPermissions from './page/data-permissions.vue'
import CopyPermissions from './page/copy-permissions.vue'
import { useBasic } from '@/hooks/useBasic' import { useBasic } from '@/hooks/useBasic'
const { setBreadcrumb } = useBasic() const { setBreadcrumb } = useBasic()
// 左边角色相关 // 左边角色相关
const roleName = ref('') const roleName = ref('')
const roleId = ref() const roleId = ref()
const sourceMenuId = ref('')
const loading = ref(false) const loading = ref(false)
const roles = ref<ResRoleList[]>([]) const roles = ref<ResRoleList[]>([])
const route = useRoute()
const handleSearch = () => { const handleSearch = () => {
loading.value = true loading.value = true
getRoleList({ getRoleList({
...@@ -115,7 +127,12 @@ const handleSearch = () => { ...@@ -115,7 +127,12 @@ const handleSearch = () => {
}) })
.then(res => { .then(res => {
roles.value = res.data roles.value = res.data
roleId.value = res.data[0]?.roleId // 区分是否有默认值
if (route.query.roleId) {
roleId.value = route.query.roleId
} else {
roleId.value = res.data[0]?.roleId
}
}) })
.catch(() => { .catch(() => {
roles.value = [] roles.value = []
...@@ -164,13 +181,14 @@ const handleSearch = () => { ...@@ -164,13 +181,14 @@ const handleSearch = () => {
// } // }
// 右边相关 // 右边相关
const tabValue = ref(2) const tabValue = ref(1)
const condMenuName = ref('') const condMenuName = ref('')
const submitLoading = ref(false) const submitLoading = ref(false)
const capabilitiesRef = ref() const capabilitiesRef = ref()
const dataPermissionsRef = ref() const dataPermissionsRef = ref()
const copyPermissionsRef = ref()
const handleSearchTree = () => { const handleSearchTree = () => {
if (tabValue.value == 1) { if (tabValue.value == 1) {
capabilitiesRef.value?.getData() capabilitiesRef.value?.getData()
...@@ -189,6 +207,11 @@ const handleConfirm = () => { ...@@ -189,6 +207,11 @@ const handleConfirm = () => {
const handleClear = () => { const handleClear = () => {
if (tabValue.value == 1) { if (tabValue.value == 1) {
capabilitiesRef.value?.clear() capabilitiesRef.value?.clear()
} else {
if (!sourceMenuId.value) {
return MessagePlugin.error('请选择菜单')
}
copyPermissionsRef.value?.open(roleId.value, sourceMenuId.value)
} }
} }
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* @Author: xiejiang * @Author: xiejiang
* @Date: 2024-12-06 17:31:56 * @Date: 2024-12-06 17:31:56
* @LastEditors: xiejiang * @LastEditors: xiejiang
* @LastEditTime: 2024-12-06 17:39:48 * @LastEditTime: 2024-12-08 10:25:04
* @Description: * @Description:
* Copyright(c)2024 by 好老师教育科技有限公司 All right Reserved. * Copyright(c)2024 by 好老师教育科技有限公司 All right Reserved.
--> -->
...@@ -17,18 +17,33 @@ ...@@ -17,18 +17,33 @@
@confirm="handleConfirm" @confirm="handleConfirm"
@close="close" @close="close"
> >
<t-tree :data="menuTree" activable expand-mutex hover transition> </t-tree> <t-tree
:data="menuTree"
:checkable="true"
v-model="allChecked"
expand-all
value-mode="all"
activable
hover
transition
>
</t-tree>
</Drawer> </Drawer>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { MessagePlugin } from 'tdesign-vue-next'
import { ResMenuTree } from '@/api/interface/menu/index' import { ResMenuTree } from '@/api/interface/menu/index'
import { getMenuTree } from '@/api/modules/menu/index' import { getMenuTree, postDataRangeClone } from '@/api/modules/menu/index'
const menuTree = ref<ResMenuTree[]>([]) const menuTree = ref<ResMenuTree[]>([])
const drawerVisible = ref(false) const drawerVisible = ref(false)
const submitLoading = 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[] { function newParamToTree(tree: ResMenuTree[]): ResMenuTree[] {
...@@ -57,10 +72,30 @@ const getData = () => { ...@@ -57,10 +72,30 @@ const getData = () => {
}) })
} }
// 保存权限
const handleConfirm = () => { const handleConfirm = () => {
if (allChecked.value.length == 0) {
MessagePlugin.error('请选择需要克隆的权限!')
return
}
submitLoading.value = true submitLoading.value = true
postDataRangeClone({
roleId: roleId.value,
targetMenuId: allChecked.value,
sourceMenuId: sourceMenuId.value
}).finally(() => {
submitLoading.value = false
close()
})
}
const open = (roleID: string, sourceMenuID: string) => {
roleId.value = roleID
sourceMenuId.value = sourceMenuID
drawerVisible.value = true
} }
// 关闭抽屉
const close = () => { const close = () => {
drawerVisible.value = false drawerVisible.value = false
} }
...@@ -68,6 +103,10 @@ const close = () => { ...@@ -68,6 +103,10 @@ const close = () => {
onMounted(() => { onMounted(() => {
getData() getData()
}) })
defineExpose({
open
})
</script> </script>
<style lang="less" scoped></style> <style lang="less" scoped></style>
...@@ -103,6 +103,12 @@ watch(toRef(props, 'tabValue'), (val: number) => { ...@@ -103,6 +103,12 @@ watch(toRef(props, 'tabValue'), (val: number) => {
} }
}) })
watch(menuId, () => {
console.log(995)
emit('updateMenuId', menuId.value)
})
// 为树形结构的每个节点添加新参数且删除没有选择数据 // 为树形结构的每个节点添加新参数且删除没有选择数据
function newParamToTree(tree: ResMenuTree[]): ResMenuTree[] { function newParamToTree(tree: ResMenuTree[]): ResMenuTree[] {
return tree return tree
...@@ -222,7 +228,7 @@ onMounted(() => { ...@@ -222,7 +228,7 @@ onMounted(() => {
GetRoleList() GetRoleList()
}) })
const emit = defineEmits(['loading']) const emit = defineEmits(['loading', 'updateMenuId'])
defineExpose({ defineExpose({
getData, getData,
submit submit
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* @Author: xiejiang * @Author: xiejiang
* @Date: 2024-12-01 10:37:37 * @Date: 2024-12-01 10:37:37
* @LastEditors: xiejiang * @LastEditors: xiejiang
* @LastEditTime: 2024-12-08 09:13:14 * @LastEditTime: 2024-12-08 15:11:47
* @Description: * @Description:
* Copyright(c)2024 by 好老师教育科技有限公司 All right Reserved. * Copyright(c)2024 by 好老师教育科技有限公司 All right Reserved.
--> -->
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
<Back /> <Back />
<main class="m-auto max-w-[1012px]"> <main class="m-auto max-w-[1012px]">
<!-- 基本信息 --> <!-- 基本信息 -->
<PageTitle title="基本信息" class="mb-[24px]" /> <PageTitle title="基本信息" class="mb-[24px] mt-[12px]" />
<div class="flex flex-wrap"> <div class="flex flex-wrap">
<DetailTable label="角色名称" :value="state?.roleName" /> <DetailTable label="角色名称" :value="state?.roleName" />
<DetailTable label="状态"> <DetailTable label="状态">
...@@ -36,6 +36,11 @@ ...@@ -36,6 +36,11 @@
<template v-for="(_, name) in $slots" #[name]="scope"> <template v-for="(_, name) in $slots" #[name]="scope">
<slot :name="name" v-bind="scope" /> <slot :name="name" v-bind="scope" />
</template> </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> </t-table>
</main> </main>
</div> </div>
...@@ -78,10 +83,11 @@ const pagination = ref({ ...@@ -78,10 +83,11 @@ const pagination = ref({
// 表格columns配置 // 表格columns配置
const columns: PrimaryTableCol[] = [ const columns: PrimaryTableCol[] = [
{ {
title: '序号',
colKey: 'serial-number', colKey: 'serial-number',
width: 50 width: 70
}, },
{ title: '用户姓名', colKey: 'userName', ellipsis: true }, { title: '用户姓名', colKey: 'userName' },
{ title: '手机号码', colKey: 'mobile' }, { title: '手机号码', colKey: 'mobile' },
{ title: '最近登录时间', colKey: 'role' }, { title: '最近登录时间', colKey: 'role' },
{ title: '最近登录IP', colKey: 'role' }, { title: '最近登录IP', colKey: 'role' },
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* @Author: xiejiang * @Author: xiejiang
* @Date: 2024-11-28 15:01:02 * @Date: 2024-11-28 15:01:02
* @LastEditors: xiejiang * @LastEditors: xiejiang
* @LastEditTime: 2024-12-05 15:03:23 * @LastEditTime: 2024-12-08 14:05:30
* @Description: 角色管理 * @Description: 角色管理
* Copyright(c)2024 by 好老师教育科技有限公司 All right Reserved. * Copyright(c)2024 by 好老师教育科技有限公司 All right Reserved.
--> -->
...@@ -49,7 +49,7 @@ ...@@ -49,7 +49,7 @@
<script setup lang="tsx" name="users"> <script setup lang="tsx" name="users">
import { useRouter } from 'vue-router' import { useRouter } from 'vue-router'
import { PrimaryTableCol } from 'tdesign-vue-next' import { PrimaryTableCol, MessagePlugin } from 'tdesign-vue-next'
import type { filterItemProp } from '@/components/PageFilters/interface/index' import type { filterItemProp } from '@/components/PageFilters/interface/index'
import type { Pagination } from '@/components/PageContainer/interface/index' import type { Pagination } from '@/components/PageContainer/interface/index'
import { statusTxt } from '@/utils/status' import { statusTxt } from '@/utils/status'
...@@ -104,10 +104,11 @@ const filterConditions = ref<filterItemProp[]>([ ...@@ -104,10 +104,11 @@ const filterConditions = ref<filterItemProp[]>([
// 表格columns配置 // 表格columns配置
const columns: PrimaryTableCol[] = [ const columns: PrimaryTableCol[] = [
{ {
title: '序号',
colKey: 'serial-number', colKey: 'serial-number',
width: 50 width: 70
}, },
{ title: '角色名称', colKey: 'roleName', ellipsis: true }, { title: '角色名称', colKey: 'roleName' },
{ title: '角色描述', colKey: 'description' }, { title: '角色描述', colKey: 'description' },
{ {
title: '角色状态', title: '角色状态',
...@@ -188,8 +189,12 @@ const handelStatus = (row: ResRoleList, status: number) => { ...@@ -188,8 +189,12 @@ const handelStatus = (row: ResRoleList, status: number) => {
}) })
.then(() => { .then(() => {
getData() getData()
MessagePlugin.success('操作成功')
dialog.hide() dialog.hide()
}) })
.catch(() => {
MessagePlugin.error('操作失败')
})
.finally(() => { .finally(() => {
dialog.update({ confirmBtn: { content: '确定', loading: false } }) dialog.update({ confirmBtn: { content: '确定', loading: false } })
}) })
...@@ -209,8 +214,12 @@ const handelDel = (row: ResRoleList) => { ...@@ -209,8 +214,12 @@ const handelDel = (row: ResRoleList) => {
}) })
.then(() => { .then(() => {
getData() getData()
MessagePlugin.success('操作成功')
dialog.hide() dialog.hide()
}) })
.catch(() => {
MessagePlugin.error('操作失败')
})
.finally(() => { .finally(() => {
dialog.update({ confirmBtn: { content: '确定', loading: false } }) dialog.update({ confirmBtn: { content: '确定', loading: false } })
}) })
...@@ -219,7 +228,12 @@ const handelDel = (row: ResRoleList) => { ...@@ -219,7 +228,12 @@ const handelDel = (row: ResRoleList) => {
} }
// 权限 // 权限
const handelPermissions = (row: any) => { const handelPermissions = (row: ResRoleList) => {
console.log('权限配置', row) router.push({
name: 'authority',
query: {
roleId: row.roleId
}
})
} }
</script> </script>
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
<Back /> <Back />
<main class="m-auto max-w-[1012px]"> <main class="m-auto max-w-[1012px]">
<!-- 基本信息 --> <!-- 基本信息 -->
<PageTitle title="基本信息" class="my-[24px]" /> <PageTitle title="基本信息" class="mb-[24px] mt-[12px]" />
<div class="flex flex-wrap"> <div class="flex flex-wrap">
<DetailTable :label="'用户名'" :value="detailData?.userName" /> <DetailTable :label="'用户名'" :value="detailData?.userName" />
<DetailTable :label="'手机号码'" :value="detailData?.mobile" /> <DetailTable :label="'手机号码'" :value="detailData?.mobile" />
...@@ -31,6 +31,11 @@ ...@@ -31,6 +31,11 @@
<template v-for="(_, name) in $slots" #[name]="scope"> <template v-for="(_, name) in $slots" #[name]="scope">
<slot :name="name" v-bind="scope" /> <slot :name="name" v-bind="scope" />
</template> </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> </t-table>
<!-- 登录日志 --> <!-- 登录日志 -->
...@@ -47,6 +52,11 @@ ...@@ -47,6 +52,11 @@
<template v-for="(_, name) in $slots" #[name]="scope"> <template v-for="(_, name) in $slots" #[name]="scope">
<slot :name="name" v-bind="scope" /> <slot :name="name" v-bind="scope" />
</template> </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> </t-table>
</main> </main>
</div> </div>
...@@ -79,8 +89,8 @@ const getData = () => { ...@@ -79,8 +89,8 @@ const getData = () => {
tableData.value = list.map( tableData.value = list.map(
(e: { (e: {
menuPermission: { menuPermission: {
menuName: any menuName: string
buttonNames: any[] buttonNames: string[]
areaPermissions: { areaName: string }[] areaPermissions: { areaName: string }[]
rolePermissions: { roleName: string }[] rolePermissions: { roleName: string }[]
}[] }[]
...@@ -90,8 +100,8 @@ const getData = () => { ...@@ -90,8 +100,8 @@ const getData = () => {
let dataPermission: string[] = [] let dataPermission: string[] = []
e.menuPermission.map( e.menuPermission.map(
(em: { (em: {
menuName: any menuName: string
buttonNames: any[] buttonNames: string[]
areaPermissions: { areaName: string }[] areaPermissions: { areaName: string }[]
rolePermissions: { roleName: string }[] rolePermissions: { roleName: string }[]
}) => { }) => {
...@@ -143,12 +153,13 @@ const pagination = ref({ ...@@ -143,12 +153,13 @@ const pagination = ref({
// 表格columns配置 // 表格columns配置
const columns: PrimaryTableCol[] = [ const columns: PrimaryTableCol[] = [
{ {
title: '序号',
colKey: 'serial-number', colKey: 'serial-number',
width: 50 width: 70
}, },
{ title: '角色名称', colKey: 'userName', ellipsis: true }, { title: '角色名称', colKey: 'userName' },
{ title: '功能权限', colKey: 'functionPermission', ellipsis: true }, { title: '功能权限', colKey: 'functionPermission' },
{ title: '数据权限', colKey: 'dataPermission', ellipsis: true } { title: '数据权限', colKey: 'dataPermission' }
] ]
// 日志 // 日志
...@@ -160,8 +171,9 @@ const paginationLog = ref({ ...@@ -160,8 +171,9 @@ const paginationLog = ref({
}) })
const columnsLog: PrimaryTableCol[] = [ const columnsLog: PrimaryTableCol[] = [
{ {
title: '序号',
colKey: 'serial-number', colKey: 'serial-number',
width: 50 width: 70
}, },
{ title: '登录时间', colKey: 'loginTime' }, { title: '登录时间', colKey: 'loginTime' },
{ title: '登录地点', colKey: 'loginAddress' }, { title: '登录地点', colKey: 'loginAddress' },
......
...@@ -52,7 +52,7 @@ ...@@ -52,7 +52,7 @@
<script setup lang="tsx" name="users"> <script setup lang="tsx" name="users">
import { useRouter } from 'vue-router' import { useRouter } from 'vue-router'
import { PrimaryTableCol } from 'tdesign-vue-next' import { PrimaryTableCol, MessagePlugin } from 'tdesign-vue-next'
import type { filterItemProp } from 'src/components/PageFilters/interface/index' import type { filterItemProp } from 'src/components/PageFilters/interface/index'
import type { Pagination } from 'src/components/PageContainer/interface/index' import type { Pagination } from 'src/components/PageContainer/interface/index'
import { statusTxt } from '@/utils/status' import { statusTxt } from '@/utils/status'
...@@ -106,10 +106,11 @@ const filterConditions = computed<filterItemProp[]>(() => [ ...@@ -106,10 +106,11 @@ const filterConditions = computed<filterItemProp[]>(() => [
// 表格columns配置 // 表格columns配置
const columns: PrimaryTableCol[] = [ const columns: PrimaryTableCol[] = [
{ {
title: '序号',
colKey: 'serial-number', colKey: 'serial-number',
width: 50 width: 70
}, },
{ title: '用户姓名', colKey: 'userName', ellipsis: true }, { title: '用户姓名', colKey: 'userName' },
{ title: '手机号码', colKey: 'mobile' }, { title: '手机号码', colKey: 'mobile' },
{ title: '用户角色', width: 220, colKey: 'roleNames' }, { title: '用户角色', width: 220, colKey: 'roleNames' },
{ {
...@@ -190,8 +191,12 @@ const handelStatus = (row: ResUserList, status: number) => { ...@@ -190,8 +191,12 @@ const handelStatus = (row: ResUserList, status: number) => {
}) })
.then(() => { .then(() => {
getData() getData()
MessagePlugin.success('操作成功')
dialog.hide() dialog.hide()
}) })
.catch(() => {
MessagePlugin.error('操作失败')
})
.finally(() => { .finally(() => {
dialog.update({ confirmBtn: { content: '确定', loading: false } }) dialog.update({ confirmBtn: { content: '确定', loading: false } })
}) })
...@@ -211,8 +216,12 @@ const handelDel = (row: ResUserList) => { ...@@ -211,8 +216,12 @@ const handelDel = (row: ResUserList) => {
}) })
.then(() => { .then(() => {
getData() getData()
MessagePlugin.success('操作成功')
dialog.hide() dialog.hide()
}) })
.catch(() => {
MessagePlugin.error('操作失败')
})
.finally(() => { .finally(() => {
dialog.update({ confirmBtn: { content: '确定', loading: false } }) dialog.update({ confirmBtn: { content: '确定', loading: false } })
}) })
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论