lzq 2025-12-02 23:49:36 +08:00
parent 04618447dc
commit ad0fd2ab96
16 changed files with 321 additions and 226 deletions

19
package-lock.json generated
View File

@ -80,7 +80,6 @@
"integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==", "integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"@babel/code-frame": "^7.27.1", "@babel/code-frame": "^7.27.1",
"@babel/generator": "^7.28.5", "@babel/generator": "^7.28.5",
@ -1063,7 +1062,6 @@
"integrity": "sha512-lLt8KLHyl7IClc3RqRpRikz15eCfTRlAWL9leVzPyg5N87FfKE/7EWgWvpiL/z4Tf3dQCIqQb88TmHE0JTIDvA==", "integrity": "sha512-lLt8KLHyl7IClc3RqRpRikz15eCfTRlAWL9leVzPyg5N87FfKE/7EWgWvpiL/z4Tf3dQCIqQb88TmHE0JTIDvA==",
"devOptional": true, "devOptional": true,
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"c12": "^3.3.1", "c12": "^3.3.1",
"consola": "^3.4.2", "consola": "^3.4.2",
@ -1775,7 +1773,6 @@
"resolved": "https://registry.npmjs.org/@types/lodash-es/-/lodash-es-4.17.12.tgz", "resolved": "https://registry.npmjs.org/@types/lodash-es/-/lodash-es-4.17.12.tgz",
"integrity": "sha512-0NgftHUcV4v34VhXm8QBSftKVXtbkBG3ViCjs6+eJ5a6y6Mi/jiFGPc1sC7QK+9BFhWrURE3EOggmWaSxL9OzQ==", "integrity": "sha512-0NgftHUcV4v34VhXm8QBSftKVXtbkBG3ViCjs6+eJ5a6y6Mi/jiFGPc1sC7QK+9BFhWrURE3EOggmWaSxL9OzQ==",
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"@types/lodash": "*" "@types/lodash": "*"
} }
@ -1793,7 +1790,6 @@
"integrity": "sha512-GNWcUTRBgIRJD5zj+Tq0fKOJ5XZajIiBroOF0yvj2bSU1WvNdYS/dn9UxwsujGW4JX06dnHyjV2y9rRaybH0iQ==", "integrity": "sha512-GNWcUTRBgIRJD5zj+Tq0fKOJ5XZajIiBroOF0yvj2bSU1WvNdYS/dn9UxwsujGW4JX06dnHyjV2y9rRaybH0iQ==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"undici-types": "~7.16.0" "undici-types": "~7.16.0"
} }
@ -2447,7 +2443,6 @@
} }
], ],
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"baseline-browser-mapping": "^2.8.25", "baseline-browser-mapping": "^2.8.25",
"caniuse-lite": "^1.0.30001754", "caniuse-lite": "^1.0.30001754",
@ -3745,15 +3740,13 @@
"version": "4.17.21", "version": "4.17.21",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
"license": "MIT", "license": "MIT"
"peer": true
}, },
"node_modules/lodash-es": { "node_modules/lodash-es": {
"version": "4.17.21", "version": "4.17.21",
"resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz",
"integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==", "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==",
"license": "MIT", "license": "MIT"
"peer": true
}, },
"node_modules/lodash-unified": { "node_modules/lodash-unified": {
"version": "1.0.3", "version": "1.0.3",
@ -4250,7 +4243,6 @@
"resolved": "https://registry.npmjs.org/pinia/-/pinia-3.0.4.tgz", "resolved": "https://registry.npmjs.org/pinia/-/pinia-3.0.4.tgz",
"integrity": "sha512-l7pqLUFTI/+ESXn6k3nu30ZIzW5E2WZF/LaHJEpoq6ElcLD+wduZoB2kBN19du6K/4FDpPMazY2wJr+IndBtQw==", "integrity": "sha512-l7pqLUFTI/+ESXn6k3nu30ZIzW5E2WZF/LaHJEpoq6ElcLD+wduZoB2kBN19du6K/4FDpPMazY2wJr+IndBtQw==",
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"@vue/devtools-api": "^7.7.7" "@vue/devtools-api": "^7.7.7"
}, },
@ -4323,7 +4315,6 @@
} }
], ],
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"nanoid": "^3.3.11", "nanoid": "^3.3.11",
"picocolors": "^1.1.1", "picocolors": "^1.1.1",
@ -4942,7 +4933,6 @@
"integrity": "sha512-ZIdT8eUv8tegmqy1tTIdJv9We2DumkNZFdCF5mz/Kpq3OcTaxSuCAYZge6HKK2CmNC02G1eJig2RV7XTw5hQrA==", "integrity": "sha512-ZIdT8eUv8tegmqy1tTIdJv9We2DumkNZFdCF5mz/Kpq3OcTaxSuCAYZge6HKK2CmNC02G1eJig2RV7XTw5hQrA==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"@adobe/css-tools": "~4.3.3", "@adobe/css-tools": "~4.3.3",
"debug": "^4.3.2", "debug": "^4.3.2",
@ -5023,7 +5013,6 @@
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
"devOptional": true, "devOptional": true,
"license": "MIT", "license": "MIT",
"peer": true,
"engines": { "engines": {
"node": ">=12" "node": ">=12"
}, },
@ -5081,7 +5070,6 @@
"integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==", "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==",
"devOptional": true, "devOptional": true,
"license": "Apache-2.0", "license": "Apache-2.0",
"peer": true,
"bin": { "bin": {
"tsc": "bin/tsc", "tsc": "bin/tsc",
"tsserver": "bin/tsserver" "tsserver": "bin/tsserver"
@ -5544,7 +5532,6 @@
"integrity": "sha512-NL8jTlbo0Tn4dUEXEsUg8KeyG/Lkmc4Fnzb8JXN/Ykm9G4HNImjtABMJgkQoVjOBN/j2WAwDTRytdqJbZsah7w==", "integrity": "sha512-NL8jTlbo0Tn4dUEXEsUg8KeyG/Lkmc4Fnzb8JXN/Ykm9G4HNImjtABMJgkQoVjOBN/j2WAwDTRytdqJbZsah7w==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"esbuild": "^0.25.0", "esbuild": "^0.25.0",
"fdir": "^6.5.0", "fdir": "^6.5.0",
@ -5835,7 +5822,6 @@
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"engines": { "engines": {
"node": ">=12" "node": ">=12"
}, },
@ -5855,7 +5841,6 @@
"resolved": "https://registry.npmjs.org/vue/-/vue-3.5.25.tgz", "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.25.tgz",
"integrity": "sha512-YLVdgv2K13WJ6n+kD5owehKtEXwdwXuj2TTyJMsO7pSeKw2bfRNZGjhB7YzrpbMYj5b5QsUebHpOqR3R3ziy/g==", "integrity": "sha512-YLVdgv2K13WJ6n+kD5owehKtEXwdwXuj2TTyJMsO7pSeKw2bfRNZGjhB7YzrpbMYj5b5QsUebHpOqR3R3ziy/g==",
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"@vue/compiler-dom": "3.5.25", "@vue/compiler-dom": "3.5.25",
"@vue/compiler-sfc": "3.5.25", "@vue/compiler-sfc": "3.5.25",

View File

@ -17,5 +17,7 @@
box-sizing border-box box-sizing border-box
box-shadow: rgba(0, 0, 0, 0.12) 0px 0px 12px 0px; box-shadow: rgba(0, 0, 0, 0.12) 0px 0px 12px 0px;
background-color: white; background-color: white;
display flex
flex-direction column
} }
</style> </style>

View File

@ -85,24 +85,6 @@ declare global {
// for type re-export // for type re-export
declare global { declare global {
// @ts-ignore // @ts-ignore
export type { export type { Component, Slot, Slots, ComponentPublicInstance, ComputedRef, DirectiveBinding, ExtractDefaultPropTypes, ExtractPropTypes, ExtractPublicPropTypes, InjectionKey, PropType, Ref, ShallowRef, MaybeRef, MaybeRefOrGetter, VNode, WritableComputedRef } from 'vue'
Component,
Slot,
Slots,
ComponentPublicInstance,
ComputedRef,
DirectiveBinding,
ExtractDefaultPropTypes,
ExtractPropTypes,
ExtractPublicPropTypes,
InjectionKey,
PropType,
Ref,
ShallowRef,
MaybeRef,
MaybeRefOrGetter,
VNode,
WritableComputedRef,
} from 'vue'
import('vue') import('vue')
} }

View File

@ -173,10 +173,7 @@ function submitHandler() {
} }
defineExpose({ defineExpose({
getValue() { open(data: MenuTypes.MenuForm = {}) {
return menuForm
},
setValue(data: MenuTypes.MenuForm = {}) {
if (!Strings.isBlank(data.id)) { if (!Strings.isBlank(data.id)) {
status.value = 'modify' status.value = 'modify'
} }
@ -185,14 +182,7 @@ defineExpose({
if (data.icon != null) { if (data.icon != null) {
selectedRowKeys.value = [ data.icon ] selectedRowKeys.value = [ data.icon ]
} }
}, }
reset() {
Object.assign(menuForm, {})
MenuApi.list()
.then(({data}) => {
menuTreeDataSource.value = Colls.toTree(data.map(it => ({key: it.id, label: it.title, ...it})))
})
},
}) })
onMounted(() => { onMounted(() => {

View File

@ -1,5 +1,5 @@
<template> <template>
<Page class="page"> <Page>
<ElForm v-show="showSearchForm" inline @submit.prevent="listAll"> <ElForm v-show="showSearchForm" inline @submit.prevent="listAll">
<ElFormItem label="菜单名称"> <ElFormItem label="菜单名称">
<ElInput v-model="searchForm.title" placeholder="菜单名称"/> <ElInput v-model="searchForm.title" placeholder="菜单名称"/>
@ -26,14 +26,26 @@
header-row-class-name="table-header" header-row-class-name="table-header"
lazy lazy
row-key="id"> row-key="id">
<ElTableColumn label="图标" prop="icon"/> <ElTableColumn label="图标" prop="icon" width="60"/>
<ElTableColumn label="类型" prop="menuCategoryTxt" width="140"/>
<ElTableColumn label="菜单名称" prop="title"/> <ElTableColumn label="菜单名称" prop="title"/>
<ElTableColumn label="类型" prop="menuCategoryTxt"/> <!-- <ElTableColumn label="路径" prop="breadcrumb"/> -->
<ElTableColumn label="路径" prop="breadcrumb"/> <ElTableColumn label="路由名称" prop="routeName">
<ElTableColumn label="路由名称" prop="routeName"/> <template #default="scope">
<ElTableColumn label="路由地址" prop="routePath"/> <span>
<ElTableColumn label="排序" prop="sort"/> {{ Strings.isBlank(scope.row.routeName) ? '-' : scope.row.routeName }}
<ElTableColumn label="操作"> </span>
</template>
</ElTableColumn>
<ElTableColumn label="路由地址" prop="routePath">
<template #default="scope">
<span>
{{ Strings.isBlank(scope.row.routePath) ? '-' : scope.row.routePath }}
</span>
</template>
</ElTableColumn>
<!-- <ElTableColumn label="排序" prop="sort" width="60"/> -->
<ElTableColumn label="操作" width="180">
<template #default="scope"> <template #default="scope">
<ElButton text type="danger" @click="delHandler(scope)"></ElButton> <ElButton text type="danger" @click="delHandler(scope)"></ElButton>
<ElButton text type="primary" @click="modifyHandler(scope)"></ElButton> <ElButton text type="primary" @click="modifyHandler(scope)"></ElButton>
@ -51,7 +63,8 @@ import MenuApi from '@/pages/sys/menus/menu-api.ts'
import Page from '@/components/page/Page.vue' import Page from '@/components/page/Page.vue'
import { onMounted } from 'vue' import { onMounted } from 'vue'
import { elIcons } from '@/common/element/element.ts' import { elIcons } from '@/common/element/element.ts'
import MenuForm from '@/pages/sys/menus/menu-form/MenuForm.vue' import MenuForm from '@/pages/sys/menus/MenuForm.vue'
import Strings from '@/common/utils/strings.ts'
const tableData = ref<MenuTypes.SysMenu[]>([]) const tableData = ref<MenuTypes.SysMenu[]>([])
const searchForm = reactive<MenuTypes.SearchForm>({}) const searchForm = reactive<MenuTypes.SearchForm>({})
@ -60,7 +73,7 @@ const showSearchForm = ref(true)
const menuFormIns = useTemplateRef<InstanceType<typeof MenuForm>>('menuForm') const menuFormIns = useTemplateRef<InstanceType<typeof MenuForm>>('menuForm')
function showDialog(data?: MenuTypes.MenuForm) { function showDialog(data?: MenuTypes.MenuForm) {
menuFormIns.value?.setValue(data) menuFormIns.value?.open(data)
} }
function delHandler({row}: { row: MenuTypes.MenuForm, }) { function delHandler({row}: { row: MenuTypes.MenuForm, }) {
@ -115,13 +128,9 @@ onMounted(() => {
</script> </script>
<style lang="stylus" scoped> <style lang="stylus" scoped>
.page {
display flex
flex-direction column
}
.table-list { .table-list {
flex 1; flex 1;
width 100%
:deep(.table-header) { :deep(.table-header) {
color black color black

View File

@ -1,52 +0,0 @@
<template>
<Page :left="leftFuns">
<MenuForm ref="menuForm"/>
</Page>
</template>
<script lang="ts" setup>
import MenuForm from '@/pages/sys/menus/menu-form/MenuForm.vue'
import Page from '@/components/page/Page.vue'
import Nav from '@/common/router/nav.ts'
import MenuApi from '@/pages/sys/menus/menu-api.ts'
import Toast from '@/components/toast'
const menuForm = ref<InstanceType<typeof MenuForm> | null>(null)
const leftFuns = computed<PageTypes.Fun[]>(() => {
return [
{
title: '查看列表',
mode: 'text',
icon: 'view-list',
onClick() {
Nav.open('menus')
},
},
{
title: '提交',
mode: 'text',
icon: 'check',
onClick() {
const toastId = Toast.loading('正在提交')
MenuApi.add(menuForm.value!.getValue())
.then(_ => {
Toast.success('添加成功')
menuForm.value!.reset()
})
.catch(_ => {
Toast.error('添加失败')
})
.finally(() => {
Toast.close(toastId)
})
},
},
]
})
</script>
<style lang="stylus" scoped>
</style>

View File

@ -1,3 +0,0 @@
export default {
component: () => import('@/pages/sys/menus/menu-create/MenuCreate.vue'),
} as RouterTypes.RouteConfig

View File

@ -1,75 +0,0 @@
<template>
<Page :left="leftFuns">
<MenuForm ref="menuForm" :status="formStatus"/>
</Page>
</template>
<script lang="ts" setup>
import MenuForm from '@/pages/sys/menus/menu-form/MenuForm.vue'
import Page from '@/components/page/Page.vue'
import Nav from '@/common/router/nav.ts'
import { useMenuDetailStore } from '@/pages/sys/menus/menu-detail/menu-detail-store.ts'
import MenuApi from '@/pages/sys/menus/menu-api.ts'
import Toast from '@/components/toast'
const menuDetailStore = useMenuDetailStore()
const menuForm = ref<InstanceType<typeof MenuForm> | null>(null)
const formStatus = computed<'create' | 'view' | 'edit'>(() => {
return menuDetailStore.edit ? 'edit' : 'view'
})
const leftFuns = computed<PageTypes.Fun[]>(() => {
return [
{
title: '返回列表',
icon: 'view-list',
mode: 'primary',
onClick() {
Nav.open('menus')
},
},
/* {
title: '上一条',
mode: 'text',
icon: 'arrow-left',
onClick() {
}
}, */
{
title: menuDetailStore.edit ? '提交' : '编辑',
icon: menuDetailStore.edit ? 'check' : 'edit',
onClick() {
if (!menuDetailStore.edit) {
menuDetailStore.$patch({edit: true})
return
}
const toastId = Toast.loading('正在提交')
MenuApi.modify({id: menuDetailStore.id!, ...menuForm.value!.getValue()})
.then((_) => {
Toast.success('修改成功')
})
.finally(() => {
Toast.close(toastId)
})
},
},
/* {
title: '下一条',
mode: 'text',
icon: 'arrow-right',
onClick() {
}
}, */
]
})
onMounted(() => {
MenuApi.detail(menuDetailStore.id!).then((res) => {
menuForm.value!.setValue({...res.data})
})
})
</script>
<style lang="stylus" scoped></style>

View File

@ -1,12 +0,0 @@
export const useMenuDetailStore = defineStore('MenuDetail', () => {
const id = ref<string | null>(null)
const edit = ref<boolean>(false)
return {
id,
edit,
$reset() {
id.value = null
edit.value = false
},
}
})

View File

@ -1,3 +0,0 @@
export default {
component: () => import('@/pages/sys/menus/menu-detail/MenuDetail.vue'),
} as RouterTypes.RouteConfig

View File

@ -1,12 +0,0 @@
export const useMenuFormStore = defineStore('MenuForm', () => {
const id = ref<string | null>(null)
const edit = ref<boolean>(true)
return {
id,
edit,
$reset() {
id.value = null
edit.value = true
},
}
})

View File

@ -0,0 +1,136 @@
<template>
<Page>
<ElForm v-show="showSearchForm" inline @submit.prevent="paging">
<ElFormItem label="昵称">
<ElInput
v-model="searchForm.nickname"
placeholder="昵称"/>
</ElFormItem>
<ElFormItem label="头像">
<ElInput
v-model="searchForm.avatar"
placeholder="头像"/>
</ElFormItem>
<ElFormItem label="邮箱">
<ElInput
v-model="searchForm.email"
placeholder="邮箱"/>
</ElFormItem>
<ElFormItem label="手机号">
<ElInput
v-model="searchForm.phone"
placeholder="手机号"/>
</ElFormItem>
<ElFormItem>
<ElButton :icon="elIcons.Search" :loading="searching" native-type="submit" type="primary">搜索</ElButton>
<ElButton :icon="elIcons.Refresh" :loading="searching" @click="reset"></ElButton>
</ElFormItem>
</ElForm>
<div class="tool-bar">
<ElButton :icon="elIcons.Plus" type="primary" @click="addHandler"></ElButton>
<ElButton :icon="elIcons.Filter" type="default" @click="showSearchForm = !showSearchForm"/>
</div>
<ElTable v-loading="searching" :data="tableData"
cell-class-name="table-cell"
class="table-list"
empty-text="暂无数据"
header-row-class-name="table-header"
row-key="id">
<ElTableColumn label="昵称" prop="nickname"/>
<ElTableColumn label="头像" prop="avatar"/>
<ElTableColumn label="邮箱" prop="email"/>
<ElTableColumn label="手机号" prop="phone"/>
<ElTableColumn label="操作" width="180">
<template #default="scope">
<ElButton text type="danger" @click="delHandler(scope)"></ElButton>
<ElButton text type="primary" @click="modifyHandler(scope)"></ElButton>
</template>
</ElTableColumn>
</ElTable>
<UserForm ref="userForm"/>
</Page>
</template>
<script lang="ts" setup>
import UserApi from '@/pages/sys/user/user-api.ts'
import Page from '@/components/page/Page.vue'
import { elIcons } from '@/common/element/element.ts'
import UserForm from '@/pages/sys/user/UserForm.vue'
const tableData = ref<UserTypes.SearchUserResult[]>([])
const searchForm = reactive<UserTypes.SearchUserParam>({
current: 1,
size: 20,
})
const searching = ref(false)
const showSearchForm = ref(true)
const userFormIns = useTemplateRef<InstanceType<typeof UserForm>>('userForm')
function showDialog(data?: UserTypes.SearchUserResult) {
userFormIns.value?.open(data)
}
function delHandler({row}: { row: UserTypes.SearchUserResult }) {
UserApi.del([ row.id! ])
}
function modifyHandler({row}: { row: UserTypes.SearchUserResult }) {
showDialog(row)
}
function addHandler() {
showDialog()
}
function reset() {
Object.assign(searchForm, {})
paging()
}
function paging() {
searching.value = true
UserApi.paging(searchForm)
.then(res => {
tableData.value = res.data?.records ?? []
})
.finally(() => {
searching.value = false
})
}
onMounted(() => {
paging()
})
</script>
<style lang="stylus" scoped>
.table-list {
flex 1;
width 100%
:deep(.table-header) {
color black
th {
background-color #E1E5EB
font-weight 500
position relative
& > div {
display flex
gap 5px
align-items center
}
&:not(:first-child) > div::before {
position: absolute;
top: 50%;
left: 1px;
width: 1px;
background-color: #A6AFB5;
transform: translateY(-50%);
content: "";
height 50%
}
}
}
:deep(.table-cell) {
color #2F3540
}
}
.tool-bar {
display flex
justify-content space-between
margin 0 0 20px 0
}
</style>

View File

@ -0,0 +1,89 @@
<template>
<ElDialog v-model="showDialog"
:close-on-click-modal="false"
destroy-on-close
width="25vw">
<ElForm :model="userFormData"
class="sys_user-form"
label-width="auto">
<ElFormItem label="昵称">
<ElInput
v-model="userFormData.nickname"
:disabled="status === 'view'"
placeholder="昵称"/>
</ElFormItem>
<ElFormItem label="头像">
<ElInput
v-model="userFormData.avatar"
:disabled="status === 'view'"
placeholder="头像"/>
</ElFormItem>
<ElFormItem label="邮箱">
<ElInput
v-model="userFormData.email"
:disabled="status === 'view'"
placeholder="邮箱"/>
</ElFormItem>
<ElFormItem label="手机号">
<ElInput
v-model="userFormData.phone"
:disabled="status === 'view'"
placeholder="手机号"/>
</ElFormItem>
</ElForm>
<template #footer>
<ElButton @click="showDialog = false">{{ status === 'view' ? '关闭' : '取消' }}</ElButton>
<ElButton v-if="status !== 'view'" :loading="submiting" type="primary" @click="submitHandler"></ElButton>
</template>
</ElDialog>
</template>
<script lang="ts" setup>
import UserApi from '@/pages/sys/user/user-api.ts'
import Strings from '@/common/utils/strings.ts'
import { ElMessage } from 'element-plus'
const showDialog = ref(false)
const submiting = ref(false)
const status = ref<'add' | 'view' | 'modify'>('add')
const userFormData = reactive<UserTypes.SearchUserResult>({})
function submitHandler() {
if (status.value === 'view') return
submiting.value = true
if (userFormData.id != null) {
UserApi.modify(userFormData)
.then(() => {
ElMessage.success('修改成功')
})
.finally(() => {
submiting.value = false
})
} else {
UserApi.add(userFormData)
.then(() => {
ElMessage.success('添加成功')
})
.finally(() => {
submiting.value = false
})
}
}
defineExpose({
open(data: UserTypes.SearchUserResult = {}) {
showDialog.value = true
if (!Strings.isBlank(data.id)) {
status.value = 'modify'
UserApi.detail(data.id!)
.then(res => {
Object.assign(userFormData, res.data)
})
} else {
status.value = 'add'
Object.assign(userFormData, {})
}
}
})
</script>
<style lang="stylus" scoped>
.sys_user-form {
padding 20px
}
</style>

View File

@ -0,0 +1,3 @@
export default {
component: () => import('@/pages/sys/user/User.vue'),
} as RouterTypes.RouteConfig

View File

@ -1,10 +1,21 @@
import { post } from '@/common/utils/http-util.ts' import {
get,
post
} from '@/common/utils/http-util.ts'
export default { export default {
modifyInfo(data: { nickname?: string; avatar?: string; phone?: string }) { paging(data: UserTypes.SearchUserParam) {
return post('/user/modify_info', data) return get<G.PageResult<UserTypes.SearchUserResult>>('/sys_user/paging', data)
}, },
modifyPasswd(data: { oldPasswd: string; newPasswd: string }) { detail(id: string) {
return post('/user/modify_passwd', data) return get<UserTypes.SearchUserResult>('/sys_user/detail', {id})
},
add(data: UserTypes.AddUserParam) {
return post('/sys_user/add', data)
},
modify(data: UserTypes.ModifyUserParam) {
return post('/sys_user/modify', data)
},
del(ids: string[]) {
return post('/sys_user/del', ids)
}, },
} }

45
src/pages/sys/user/user.d.ts vendored 100644
View File

@ -0,0 +1,45 @@
export {}
declare global {
namespace UserTypes {
interface SearchUserParam extends G.PageParam {
// 昵称
nickname?: string
// 头像
avatar?: string
// 邮箱
email?: string
// 手机号
phone?: string
}
interface SearchUserResult {
// 昵称
nickname?: string
// 头像
avatar?: string
// 邮箱
email?: string
// 手机号
phone?: string
}
interface AddUserParam {
// 昵称
nickname?: string
// 头像
avatar?: string
// 邮箱
email?: string
// 手机号
phone?: string
}
interface ModifyUserParam {
// 昵称
nickname?: string
// 头像
avatar?: string
// 邮箱
email?: string
// 手机号
phone?: string
}
}
}