Commit 407ac853cba1b0e3c6685c95d78f1270d8687023

Authored by xingyu4j
1 parent 88cb5497

feat: tenant

yudao-dependencies/pom.xml
@@ -27,7 +27,6 @@ @@ -27,7 +27,6 @@
27 <mybatis-plus-generator.version>3.5.2</mybatis-plus-generator.version> 27 <mybatis-plus-generator.version>3.5.2</mybatis-plus-generator.version>
28 <dynamic-datasource.version>3.5.2</dynamic-datasource.version> 28 <dynamic-datasource.version>3.5.2</dynamic-datasource.version>
29 <redisson.version>3.18.0</redisson.version> 29 <redisson.version>3.18.0</redisson.version>
30 - <!-- Config 配置中心相关 -->  
31 <!-- 服务保障相关 --> 30 <!-- 服务保障相关 -->
32 <lock4j.version>2.2.2</lock4j.version> 31 <lock4j.version>2.2.2</lock4j.version>
33 <resilience4j.version>1.7.1</resilience4j.version> 32 <resilience4j.version>1.7.1</resilience4j.version>
yudao-ui-admin-vue3/pnpm-lock.yaml
@@ -28,7 +28,7 @@ specifiers: @@ -28,7 +28,7 @@ specifiers:
28 dayjs: ^1.11.6 28 dayjs: ^1.11.6
29 echarts: ^5.4.0 29 echarts: ^5.4.0
30 echarts-wordcloud: ^2.0.0 30 echarts-wordcloud: ^2.0.0
31 - element-plus: 2.2.22 31 + element-plus: 2.2.21
32 eslint: ^8.27.0 32 eslint: ^8.27.0
33 eslint-config-prettier: ^8.5.0 33 eslint-config-prettier: ^8.5.0
34 eslint-define-config: ^1.12.0 34 eslint-define-config: ^1.12.0
@@ -92,7 +92,7 @@ dependencies: @@ -92,7 +92,7 @@ dependencies:
92 dayjs: registry.npmmirror.com/dayjs/1.11.6 92 dayjs: registry.npmmirror.com/dayjs/1.11.6
93 echarts: registry.npmmirror.com/echarts/5.4.0 93 echarts: registry.npmmirror.com/echarts/5.4.0
94 echarts-wordcloud: registry.npmmirror.com/echarts-wordcloud/2.0.0_echarts@5.4.0 94 echarts-wordcloud: registry.npmmirror.com/echarts-wordcloud/2.0.0_echarts@5.4.0
95 - element-plus: registry.npmmirror.com/element-plus/2.2.22_vue@3.2.45 95 + element-plus: registry.npmmirror.com/element-plus/2.2.21_vue@3.2.45
96 intro.js: registry.npmmirror.com/intro.js/6.0.0 96 intro.js: registry.npmmirror.com/intro.js/6.0.0
97 js-cookie: registry.npmmirror.com/js-cookie/3.0.1 97 js-cookie: registry.npmmirror.com/js-cookie/3.0.1
98 jsencrypt: registry.npmmirror.com/jsencrypt/3.3.1 98 jsencrypt: registry.npmmirror.com/jsencrypt/3.3.1
@@ -3645,11 +3645,11 @@ packages: @@ -3645,11 +3645,11 @@ packages:
3645 version: 1.4.284 3645 version: 1.4.284
3646 dev: true 3646 dev: true
3647 3647
3648 - registry.npmmirror.com/element-plus/2.2.22_vue@3.2.45:  
3649 - resolution: {integrity: sha512-gg2g2WOMNpWf0wGesymUvTV0VZDF/4khQKroSNeCV/vWJ/cqssPYdtqfGxTiFRt/f+JpyFkV7O1mo0yzMCzrBg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/element-plus/-/element-plus-2.2.22.tgz}  
3650 - id: registry.npmmirror.com/element-plus/2.2.22 3648 + registry.npmmirror.com/element-plus/2.2.21_vue@3.2.45:
  3649 + resolution: {integrity: sha512-wZUePoXZ1zuCkzENK/8mn+mekuLJ9OoGYiudjUujzCf+T8HfOQl+TKQStwOkGBNk93fK8e9YdFIty4jH4AX6dg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/element-plus/-/element-plus-2.2.21.tgz}
  3650 + id: registry.npmmirror.com/element-plus/2.2.21
3651 name: element-plus 3651 name: element-plus
3652 - version: 2.2.22 3652 + version: 2.2.21
3653 peerDependencies: 3653 peerDependencies:
3654 vue: ^3.2.0 3654 vue: ^3.2.0
3655 dependencies: 3655 dependencies:
yudao-ui-admin-vue3/src/api/system/tenant/index.ts
1 import request from '@/config/axios' 1 import request from '@/config/axios'
2 -import type { TenantVO } from './types' 2 +
  3 +export interface TenantVO {
  4 + id: number
  5 + name: string
  6 + packageId: number
  7 + contactName: string
  8 + contactMobile: string
  9 + username: string
  10 + password: string
  11 + accountCount: number
  12 + expireTime: string
  13 + domain: string
  14 + status: number
  15 + createTime: string
  16 +}
  17 +
  18 +export interface TenantPageReqVO extends PageParam {
  19 + name?: string
  20 + contactName?: string
  21 + contactMobile?: string
  22 + status?: number
  23 +}
  24 +
  25 +export interface TenantExportReqVO {
  26 + name?: string
  27 + contactName?: string
  28 + contactMobile?: string
  29 + status?: number
  30 +}
3 31
4 // 查询租户列表 32 // 查询租户列表
5 -export const getTenantPageApi = (params) => { 33 +export const getTenantPageApi = (params: TenantPageReqVO) => {
6 return request.get({ url: '/system/tenant/page', params }) 34 return request.get({ url: '/system/tenant/page', params })
7 } 35 }
8 36
@@ -27,6 +55,6 @@ export const deleteTenantApi = (id: number) =&gt; { @@ -27,6 +55,6 @@ export const deleteTenantApi = (id: number) =&gt; {
27 } 55 }
28 56
29 // 导出租户 57 // 导出租户
30 -export const exportTenantApi = (params) => { 58 +export const exportTenantApi = (params: TenantExportReqVO) => {
31 return request.download({ url: '/system/tenant/export-excel', params }) 59 return request.download({ url: '/system/tenant/export-excel', params })
32 } 60 }
yudao-ui-admin-vue3/src/api/system/tenant/types.ts deleted
1 -export type TenantVO = {  
2 - id: number  
3 - name: string  
4 - packageId: number  
5 - contactName: string  
6 - contactMobile: string  
7 - username: string  
8 - password: string  
9 - accountCount: number  
10 - expireTime: string  
11 - domain: string  
12 - status: number  
13 - createTime: string  
14 -}  
yudao-ui-admin-vue3/src/api/system/tenantPackage/index.ts
1 import request from '@/config/axios' 1 import request from '@/config/axios'
2 -import type { TenantPackageVO } from './types' 2 +
  3 +export interface TenantPackageVO {
  4 + id: number
  5 + name: string
  6 + status: number
  7 + remark: string
  8 + creator: string
  9 + createTime: string
  10 + updater: string
  11 + updateTime: string
  12 + menuIds: string[]
  13 +}
  14 +
  15 +export interface TenantPackagePageReqVO extends PageParam {
  16 + name?: string
  17 + contactName?: string
  18 + contactMobile?: string
  19 + status?: number
  20 +}
3 21
4 // 查询租户套餐列表 22 // 查询租户套餐列表
5 -export const getTenantPackageTypePageApi = (params) => { 23 +export const getTenantPackageTypePageApi = (params: TenantPackagePageReqVO) => {
6 return request.get({ url: '/system/tenant-package/page', params }) 24 return request.get({ url: '/system/tenant-package/page', params })
7 } 25 }
8 26
@@ -25,7 +43,7 @@ export const updateTenantPackageTypeApi = (data: TenantPackageVO) =&gt; { @@ -25,7 +43,7 @@ export const updateTenantPackageTypeApi = (data: TenantPackageVO) =&gt; {
25 export const deleteTenantPackageTypeApi = (id: number) => { 43 export const deleteTenantPackageTypeApi = (id: number) => {
26 return request.delete({ url: '/system/tenant-package/delete?id=' + id }) 44 return request.delete({ url: '/system/tenant-package/delete?id=' + id })
27 } 45 }
28 -// // 获取租户套餐精简信息列表 46 +// 获取租户套餐精简信息列表
29 export const getTenantPackageList = () => { 47 export const getTenantPackageList = () => {
30 return request.get({ url: '/system/tenant-package/get-simple-list' }) 48 return request.get({ url: '/system/tenant-package/get-simple-list' })
31 } 49 }
yudao-ui-admin-vue3/src/api/system/tenantPackage/types.ts deleted
1 -export type TenantPackageVO = {  
2 - id: number  
3 - name: string  
4 - status: number  
5 - remark: string  
6 - creator: string  
7 - createTime: string  
8 - updater: string  
9 - updateTime: string  
10 - menuIds: string[]  
11 -}  
yudao-ui-admin-vue3/src/views/system/tenant/index.vue
1 <template> 1 <template>
2 - <!-- 搜索工作区 -->  
3 <ContentWrap> 2 <ContentWrap>
4 - <Search :schema="allSchemas.searchSchema" @search="setSearchParams" @reset="setSearchParams" />  
5 - </ContentWrap>  
6 - <ContentWrap>  
7 - <!-- 操作工具栏 -->  
8 - <div class="mb-10px">  
9 - <XButton  
10 - type="primary"  
11 - preIcon="ep:zoom-in"  
12 - :title="t('action.add')"  
13 - v-hasPermi="['system:tenant:create']"  
14 - @click="handleCreate()"  
15 - />  
16 - <XButton  
17 - type="warning"  
18 - preIcon="ep:download"  
19 - :title="t('action.export')"  
20 - v-hasPermi="['system:tenant:export']"  
21 - @click="exportList('租户数据.xls')"  
22 - />  
23 - </div>  
24 <!-- 列表 --> 3 <!-- 列表 -->
25 - <Table  
26 - :columns="allSchemas.tableColumns"  
27 - :selection="false"  
28 - :data="tableObject.tableList"  
29 - :loading="tableObject.loading"  
30 - :pagination="{  
31 - total: tableObject.total  
32 - }"  
33 - v-model:pageSize="tableObject.pageSize"  
34 - v-model:currentPage="tableObject.currentPage"  
35 - @register="register"  
36 - > 4 + <vxe-grid ref="xGrid" v-bind="gridOptions" class="xtable-scrollbar">
  5 + <template #toolbar_buttons>
  6 + <!-- 操作:新增 -->
  7 + <XButton
  8 + type="primary"
  9 + preIcon="ep:zoom-in"
  10 + :title="t('action.add')"
  11 + v-hasPermi="['system:tenant:create']"
  12 + @click="handleCreate()"
  13 + />
  14 + <XButton
  15 + type="warning"
  16 + preIcon="ep:download"
  17 + :title="t('action.export')"
  18 + v-hasPermi="['system:tenant:export']"
  19 + @click="handleExport()"
  20 + />
  21 + </template>
37 <template #accountCount="{ row }"> 22 <template #accountCount="{ row }">
38 <el-tag> {{ row.accountCount }} </el-tag> 23 <el-tag> {{ row.accountCount }} </el-tag>
39 </template> 24 </template>
40 - <template #status="{ row }">  
41 - <DictTag :type="DICT_TYPE.COMMON_STATUS" :value="row.status" />  
42 - </template>  
43 <template #packageId="{ row }"> 25 <template #packageId="{ row }">
44 <el-tag v-if="row.packageId === 0" type="danger">系统租户</el-tag> 26 <el-tag v-if="row.packageId === 0" type="danger">系统租户</el-tag>
45 <el-tag v-else type="success"> {{ getPackageName(row.packageId) }} </el-tag> 27 <el-tag v-else type="success"> {{ getPackageName(row.packageId) }} </el-tag>
46 </template> 28 </template>
47 - <template #expireTime="{ row }">  
48 - <span>{{ dayjs(row.expireTime).format('YYYY-MM-DD HH:mm:ss') }}</span>  
49 - </template>  
50 - <template #createTime="{ row }">  
51 - <span>{{ dayjs(row.createTime).format('YYYY-MM-DD HH:mm:ss') }}</span>  
52 - </template>  
53 - <template #action="{ row }"> 29 + <template #actionbtns_default="{ row }">
54 <!-- 操作:修改 --> 30 <!-- 操作:修改 -->
55 <XTextButton 31 <XTextButton
56 preIcon="ep:edit" 32 preIcon="ep:edit"
57 :title="t('action.edit')" 33 :title="t('action.edit')"
58 v-hasPermi="['system:tenant:update']" 34 v-hasPermi="['system:tenant:update']"
59 - @click="handleUpdate(row)" 35 + @click="handleUpdate(row.id)"
60 /> 36 />
61 <!-- 操作:详情 --> 37 <!-- 操作:详情 -->
62 <XTextButton 38 <XTextButton
63 preIcon="ep:view" 39 preIcon="ep:view"
64 :title="t('action.detail')" 40 :title="t('action.detail')"
65 v-hasPermi="['system:tenant:update']" 41 v-hasPermi="['system:tenant:update']"
66 - @click="handleDetail(row)" 42 + @click="handleDetail(row.id)"
67 /> 43 />
68 <!-- 操作:删除 --> 44 <!-- 操作:删除 -->
69 <XTextButton 45 <XTextButton
70 preIcon="ep:delete" 46 preIcon="ep:delete"
71 :title="t('action.del')" 47 :title="t('action.del')"
72 v-hasPermi="['system:tenant:delete']" 48 v-hasPermi="['system:tenant:delete']"
73 - @click="delList(row.id, false)" 49 + @click="handleDelete(row.id)"
74 /> 50 />
75 </template> 51 </template>
76 - </Table> 52 + </vxe-grid>
77 </ContentWrap> 53 </ContentWrap>
78 54
79 <XModal v-model="dialogVisible" :title="dialogTitle"> 55 <XModal v-model="dialogVisible" :title="dialogTitle">
@@ -124,27 +100,33 @@ @@ -124,27 +100,33 @@
124 <script setup lang="ts"> 100 <script setup lang="ts">
125 import { ref, unref, onMounted } from 'vue' 101 import { ref, unref, onMounted } from 'vue'
126 import dayjs from 'dayjs' 102 import dayjs from 'dayjs'
127 -import { ElMessage, ElTag, ElSelect, ElOption } from 'element-plus'  
128 -import { DICT_TYPE } from '@/utils/dict'  
129 -import { useTable } from '@/hooks/web/useTable'  
130 import { useI18n } from '@/hooks/web/useI18n' 103 import { useI18n } from '@/hooks/web/useI18n'
  104 +import { useMessage } from '@/hooks/web/useMessage'
  105 +import { useVxeGrid } from '@/hooks/web/useVxeGrid'
  106 +import { VxeGridInstance } from 'vxe-table'
  107 +import { ElTag, ElSelect, ElOption } from 'element-plus'
131 import { FormExpose } from '@/components/Form' 108 import { FormExpose } from '@/components/Form'
132 -import type { TenantVO } from '@/api/system/tenant/types'  
133 -import { rules, allSchemas } from './tenant.data'  
134 import * as TenantApi from '@/api/system/tenant' 109 import * as TenantApi from '@/api/system/tenant'
135 -import { getTenantPackageList } from '@/api/system/tenantPackage'  
136 -import { TenantPackageVO } from '@/api/system/tenantPackage/types'  
137 -const { t } = useI18n() // 国际化 110 +import { rules, allSchemas } from './tenant.data'
  111 +import { getTenantPackageList, TenantPackageVO } from '@/api/system/tenantPackage'
138 112
139 -// ========== 列表相关 ==========  
140 -const { register, tableObject, methods } = useTable<TenantVO>({ 113 +const { t } = useI18n() // 国际化
  114 +const message = useMessage() // 消息弹窗
  115 +// 列表相关的变量
  116 +const xGrid = ref<VxeGridInstance>() // 列表 Grid Ref
  117 +const { gridOptions, getList, deleteData, exportList } = useVxeGrid<TenantApi.TenantVO>({
  118 + allSchemas: allSchemas,
141 getListApi: TenantApi.getTenantPageApi, 119 getListApi: TenantApi.getTenantPageApi,
142 - delListApi: TenantApi.deleteTenantApi, 120 + deleteApi: TenantApi.deleteTenantApi,
143 exportListApi: TenantApi.exportTenantApi 121 exportListApi: TenantApi.exportTenantApi
144 }) 122 })
145 -const { getList, setSearchParams, delList, exportList } = methods  
146 123
147 -// ========== 套餐 ========== 124 +const actionLoading = ref(false) // 遮罩层
  125 +const actionType = ref('') // 操作按钮的类型
  126 +const dialogVisible = ref(false) // 是否显示弹出层
  127 +const dialogTitle = ref('edit') // 弹出层标题
  128 +const formRef = ref<FormExpose>() // 表单 Ref
  129 +const detailRef = ref() // 详情 Ref
148 const tenantPackageId = ref() // 套餐 130 const tenantPackageId = ref() // 套餐
149 const tenantPackageOptions = ref<TenantPackageVO[]>([]) //套餐列表 131 const tenantPackageOptions = ref<TenantPackageVO[]>([]) //套餐列表
150 132
@@ -160,12 +142,6 @@ const getPackageName = (packageId: number) =&gt; { @@ -160,12 +142,6 @@ const getPackageName = (packageId: number) =&gt; {
160 } 142 }
161 return '未知套餐' 143 return '未知套餐'
162 } 144 }
163 -// ========== CRUD 相关 ==========  
164 -const actionLoading = ref(false) // 遮罩层  
165 -const actionType = ref('') // 操作按钮的类型  
166 -const dialogVisible = ref(false) // 是否显示弹出层  
167 -const dialogTitle = ref('edit') // 弹出层标题  
168 -const formRef = ref<FormExpose>() // 表单 Ref  
169 145
170 // 设置标题 146 // 设置标题
171 const setDialogTile = (type: string) => { 147 const setDialogTile = (type: string) => {
@@ -182,15 +158,34 @@ const handleCreate = () =&gt; { @@ -182,15 +158,34 @@ const handleCreate = () =&gt; {
182 } 158 }
183 159
184 // 修改操作 160 // 修改操作
185 -const handleUpdate = async (row: any) => { 161 +const handleUpdate = async (rowId: number) => {
186 setDialogTile('update') 162 setDialogTile('update')
187 // 设置数据 163 // 设置数据
188 - const res = await TenantApi.getTenantApi(row.id) 164 + const res = await TenantApi.getTenantApi(rowId)
189 tenantPackageId.value = res.packageId 165 tenantPackageId.value = res.packageId
190 res.expireTime = dayjs(res.expireTime).format('YYYY-MM-DD HH:mm:ss') 166 res.expireTime = dayjs(res.expireTime).format('YYYY-MM-DD HH:mm:ss')
191 unref(formRef)?.setValues(res) 167 unref(formRef)?.setValues(res)
192 } 168 }
193 169
  170 +// 详情操作
  171 +const handleDetail = async (rowId: number) => {
  172 + // 设置数据
  173 + const res = await TenantApi.getTenantApi(rowId)
  174 + tenantPackageId.value = res.packageId
  175 + detailRef.value = res
  176 + setDialogTile('detail')
  177 +}
  178 +
  179 +// 删除操作
  180 +const handleDelete = async (rowId: number) => {
  181 + await deleteData(xGrid, rowId)
  182 +}
  183 +
  184 +// 导出操作
  185 +const handleExport = async () => {
  186 + await exportList(xGrid, '租户列表.xls')
  187 +}
  188 +
194 // 提交按钮 189 // 提交按钮
195 const submitForm = async () => { 190 const submitForm = async () => {
196 const elForm = unref(formRef)?.getElFormRef() 191 const elForm = unref(formRef)?.getElFormRef()
@@ -200,40 +195,30 @@ const submitForm = async () =&gt; { @@ -200,40 +195,30 @@ const submitForm = async () =&gt; {
200 actionLoading.value = true 195 actionLoading.value = true
201 // 提交请求 196 // 提交请求
202 try { 197 try {
203 - const data = unref(formRef)?.formModel as TenantVO 198 + const data = unref(formRef)?.formModel as TenantApi.TenantVO
204 data.packageId = tenantPackageId.value 199 data.packageId = tenantPackageId.value
205 if (actionType.value === 'create') { 200 if (actionType.value === 'create') {
206 data.expireTime = dayjs(data.expireTime).valueOf().toString() 201 data.expireTime = dayjs(data.expireTime).valueOf().toString()
207 await TenantApi.createTenantApi(data) 202 await TenantApi.createTenantApi(data)
208 - ElMessage.success(t('common.createSuccess')) 203 + message.success(t('common.createSuccess'))
209 } else { 204 } else {
210 data.expireTime = dayjs(data.expireTime).valueOf().toString() 205 data.expireTime = dayjs(data.expireTime).valueOf().toString()
211 await TenantApi.updateTenantApi(data) 206 await TenantApi.updateTenantApi(data)
212 - ElMessage.success(t('common.updateSuccess')) 207 + message.success(t('common.updateSuccess'))
213 } 208 }
214 // 操作成功,重新加载列表 209 // 操作成功,重新加载列表
215 dialogVisible.value = false 210 dialogVisible.value = false
216 - await getList()  
217 } finally { 211 } finally {
218 actionLoading.value = false 212 actionLoading.value = false
  213 + // 刷新列表
  214 + await getList(xGrid)
219 } 215 }
220 } 216 }
221 }) 217 })
222 } 218 }
223 219
224 -// ========== 详情相关 ==========  
225 -const detailRef = ref() // 详情 Ref  
226 -  
227 -// 详情操作  
228 -const handleDetail = async (row: any) => {  
229 - // 设置数据  
230 - detailRef.value = row  
231 - setDialogTile('detail')  
232 -}  
233 -  
234 // ========== 初始化 ========== 220 // ========== 初始化 ==========
235 onMounted(async () => { 221 onMounted(async () => {
236 - await getList()  
237 await getTenantPackageOptions() 222 await getTenantPackageOptions()
238 }) 223 })
239 </script> 224 </script>
yudao-ui-admin-vue3/src/views/system/tenant/tenant.data.ts
1 import { reactive } from 'vue' 1 import { reactive } from 'vue'
2 import { useI18n } from '@/hooks/web/useI18n' 2 import { useI18n } from '@/hooks/web/useI18n'
3 import { required } from '@/utils/formRules' 3 import { required } from '@/utils/formRules'
4 -import { CrudSchema, useCrudSchemas } from '@/hooks/web/useCrudSchemas'  
5 import { DICT_TYPE } from '@/utils/dict' 4 import { DICT_TYPE } from '@/utils/dict'
  5 +import { VxeCrudSchema, useVxeCrudSchemas } from '@/hooks/web/useVxeCrudSchemas'
6 const { t } = useI18n() // 国际化 6 const { t } = useI18n() // 国际化
7 7
8 // 表单校验 8 // 表单校验
@@ -18,115 +18,82 @@ export const rules = reactive({ @@ -18,115 +18,82 @@ export const rules = reactive({
18 }) 18 })
19 19
20 // CrudSchema. 20 // CrudSchema.
21 -const crudSchemas = reactive<CrudSchema[]>([  
22 - {  
23 - label: t('common.index'),  
24 - field: 'id',  
25 - type: 'index',  
26 - form: {  
27 - show: false 21 +const crudSchemas = reactive<VxeCrudSchema>({
  22 + primaryKey: 'id',
  23 + primaryType: 'seq',
  24 + action: true,
  25 + columns: [
  26 + {
  27 + title: '租户名称',
  28 + field: 'name',
  29 + isSearch: true
28 }, 30 },
29 - detail: {  
30 - show: false  
31 - }  
32 - },  
33 - {  
34 - label: '租户名称',  
35 - field: 'name',  
36 - search: {  
37 - show: true  
38 - }  
39 - },  
40 - {  
41 - label: '租户套餐',  
42 - field: 'packageId'  
43 - },  
44 - {  
45 - label: '联系人',  
46 - field: 'contactName',  
47 - search: {  
48 - show: true  
49 - }  
50 - },  
51 - {  
52 - label: '联系手机',  
53 - field: 'contactMobile',  
54 - search: {  
55 - show: true  
56 - }  
57 - },  
58 - {  
59 - label: '用户名称',  
60 - field: 'username',  
61 - table: {  
62 - show: false 31 + {
  32 + title: '租户套餐',
  33 + field: 'packageId'
63 }, 34 },
64 - detail: {  
65 - show: false  
66 - }  
67 - },  
68 - {  
69 - label: '用户密码',  
70 - field: 'password',  
71 - table: {  
72 - show: false 35 + {
  36 + title: '联系人',
  37 + field: 'contactName',
  38 + isSearch: true
73 }, 39 },
74 - detail: {  
75 - show: false 40 + {
  41 + title: '联系手机',
  42 + field: 'contactMobile',
  43 + isSearch: true
76 }, 44 },
77 - form: {  
78 - component: 'InputPassword'  
79 - }  
80 - },  
81 - {  
82 - label: '账号额度',  
83 - field: 'accountCount',  
84 - form: {  
85 - component: 'InputNumber'  
86 - }  
87 - },  
88 - {  
89 - label: '过期时间',  
90 - field: 'expireTime',  
91 - form: {  
92 - show: true,  
93 - component: 'DatePicker',  
94 - componentProps: {  
95 - type: 'datetime',  
96 - valueFormat: 'x' 45 + {
  46 + title: '用户名称',
  47 + field: 'username',
  48 + isTable: false,
  49 + isDetail: false
  50 + },
  51 + {
  52 + title: '用户密码',
  53 + field: 'password',
  54 + isTable: false,
  55 + isDetail: false,
  56 + form: {
  57 + component: 'InputPassword'
97 } 58 }
98 - }  
99 - },  
100 - {  
101 - label: '绑定域名',  
102 - field: 'domain'  
103 - },  
104 - {  
105 - label: '租户状态',  
106 - field: 'status',  
107 - dictType: DICT_TYPE.COMMON_STATUS,  
108 - dictClass: 'number',  
109 - search: {  
110 - show: true  
111 - }  
112 - },  
113 - {  
114 - label: t('table.createTime'),  
115 - field: 'createTime',  
116 - form: {  
117 - show: false  
118 - }  
119 - },  
120 - {  
121 - label: t('table.action'),  
122 - field: 'action',  
123 - width: '240px',  
124 - form: {  
125 - show: false  
126 }, 59 },
127 - detail: {  
128 - show: false 60 + {
  61 + title: '账号额度',
  62 + field: 'accountCount',
  63 + form: {
  64 + component: 'InputNumber'
  65 + }
  66 + },
  67 + {
  68 + title: '过期时间',
  69 + field: 'expireTime',
  70 + formatter: 'formatDate',
  71 + form: {
  72 + show: true,
  73 + component: 'DatePicker',
  74 + componentProps: {
  75 + type: 'datetime',
  76 + valueFormat: 'x'
  77 + }
  78 + }
  79 + },
  80 + {
  81 + title: '绑定域名',
  82 + field: 'domain'
  83 + },
  84 + {
  85 + title: '租户状态',
  86 + field: 'status',
  87 + dictType: DICT_TYPE.COMMON_STATUS,
  88 + dictClass: 'number',
  89 + isSearch: true
  90 + },
  91 + {
  92 + title: t('table.createTime'),
  93 + field: 'createTime',
  94 + formatter: 'formatDate',
  95 + isForm: false
129 } 96 }
130 - }  
131 -])  
132 -export const { allSchemas } = useCrudSchemas(crudSchemas) 97 + ]
  98 +})
  99 +export const { allSchemas } = useVxeCrudSchemas(crudSchemas)
yudao-ui-admin-vue3/src/views/system/tenantPackage/index.vue
1 <template> 1 <template>
2 - <!-- 搜索工作区 -->  
3 <ContentWrap> 2 <ContentWrap>
4 - <Search :schema="allSchemas.searchSchema" @search="setSearchParams" @reset="setSearchParams" />  
5 - </ContentWrap>  
6 - <ContentWrap>  
7 - <!-- 操作工具栏 -->  
8 - <div class="mb-10px">  
9 - <XButton  
10 - type="primary"  
11 - preIcon="ep:zoom-in"  
12 - :title="t('action.add')"  
13 - @click="handleCreate()"  
14 - />  
15 - </div>  
16 <!-- 列表 --> 3 <!-- 列表 -->
17 - <Table  
18 - :columns="allSchemas.tableColumns"  
19 - :selection="false"  
20 - :data="tableObject.tableList"  
21 - :loading="tableObject.loading"  
22 - :pagination="{  
23 - total: tableObject.total  
24 - }"  
25 - v-model:pageSize="tableObject.pageSize"  
26 - v-model:currentPage="tableObject.currentPage"  
27 - @register="register"  
28 - >  
29 - <template #status="{ row }">  
30 - <DictTag :type="DICT_TYPE.COMMON_STATUS" :value="row.status" />  
31 - </template>  
32 - <template #createTime="{ row }">  
33 - <span>{{ dayjs(row.createTime).format('YYYY-MM-DD HH:mm:ss') }}</span> 4 + <vxe-grid ref="xGrid" v-bind="gridOptions" class="xtable-scrollbar">
  5 + <template #toolbar_buttons>
  6 + <XButton
  7 + type="primary"
  8 + preIcon="ep:zoom-in"
  9 + :title="t('action.add')"
  10 + @click="handleCreate()"
  11 + />
34 </template> 12 </template>
35 - <template #action="{ row }">  
36 - <XTextButton preIcon="ep:edit" :title="t('action.edit')" @click="handleUpdate(row)" />  
37 - <XTextButton preIcon="ep:delete" :title="t('action.del')" @click="delList(row.id, false)" /> 13 + <template #actionbtns_default="{ row }">
  14 + <XTextButton preIcon="ep:edit" :title="t('action.edit')" @click="handleUpdate(row.id)" />
  15 + <XTextButton preIcon="ep:delete" :title="t('action.del')" @click="handleDelete(row.id)" />
38 </template> 16 </template>
39 - </Table> 17 + </vxe-grid>
40 </ContentWrap> 18 </ContentWrap>
41 19
42 <XModal v-model="dialogVisible" :title="dialogTitle"> 20 <XModal v-model="dialogVisible" :title="dialogTitle">
@@ -89,28 +67,39 @@ @@ -89,28 +67,39 @@
89 </template> 67 </template>
90 <script setup lang="ts"> 68 <script setup lang="ts">
91 import { onMounted, ref, unref } from 'vue' 69 import { onMounted, ref, unref } from 'vue'
92 -import dayjs from 'dayjs'  
93 import { handleTree } from '@/utils/tree' 70 import { handleTree } from '@/utils/tree'
94 -import { DICT_TYPE } from '@/utils/dict'  
95 -import { useTable } from '@/hooks/web/useTable'  
96 import { useI18n } from '@/hooks/web/useI18n' 71 import { useI18n } from '@/hooks/web/useI18n'
  72 +import { useMessage } from '@/hooks/web/useMessage'
  73 +import { useVxeGrid } from '@/hooks/web/useVxeGrid'
  74 +import { VxeGridInstance } from 'vxe-table'
97 import { FormExpose } from '@/components/Form' 75 import { FormExpose } from '@/components/Form'
98 -import { TenantPackageVO } from '@/api/system/tenantPackage/types'  
99 -import { ElMessage, ElCard, ElSwitch, ElTree } from 'element-plus' 76 +import { ElCard, ElSwitch, ElTree } from 'element-plus'
  77 +// 业务相关的 import
100 import { rules, allSchemas } from './tenantPackage.data' 78 import { rules, allSchemas } from './tenantPackage.data'
101 import * as TenantPackageApi from '@/api/system/tenantPackage' 79 import * as TenantPackageApi from '@/api/system/tenantPackage'
102 import { listSimpleMenusApi } from '@/api/system/menu' 80 import { listSimpleMenusApi } from '@/api/system/menu'
  81 +
103 const { t } = useI18n() // 国际化 82 const { t } = useI18n() // 国际化
  83 +const message = useMessage() // 消息弹窗
  84 +
  85 +const menuOptions = ref<any[]>([]) // 树形结构
  86 +const menuExpand = ref(false)
  87 +const menuNodeAll = ref(false)
  88 +const treeRef = ref<InstanceType<typeof ElTree>>()
  89 +const treeNodeAll = ref(false)
  90 +const xGrid = ref<VxeGridInstance>() // 列表 Grid Ref
  91 +const formRef = ref<FormExpose>() // 表单 Ref
  92 +const loading = ref(false) // 遮罩层
  93 +const actionType = ref('') // 操作按钮的类型
  94 +const dialogVisible = ref(false) // 是否显示弹出层
  95 +const dialogTitle = ref('edit') // 弹出层标题
104 96
105 const defaultProps = { 97 const defaultProps = {
106 children: 'children', 98 children: 'children',
107 label: 'name', 99 label: 'name',
108 value: 'id' 100 value: 'id'
109 } 101 }
110 -// ========== 创建菜单树结构 ==========  
111 -const menuOptions = ref<any[]>([]) // 树形结构  
112 -const treeRef = ref<InstanceType<typeof ElTree>>()  
113 -const treeNodeAll = ref(false) 102 +
114 // 全选/全不选 103 // 全选/全不选
115 const handleCheckedTreeNodeAll = () => { 104 const handleCheckedTreeNodeAll = () => {
116 treeRef.value!.setCheckedNodes(treeNodeAll.value ? menuOptions.value : []) 105 treeRef.value!.setCheckedNodes(treeNodeAll.value ? menuOptions.value : [])
@@ -119,22 +108,12 @@ const getTree = async () =&gt; { @@ -119,22 +108,12 @@ const getTree = async () =&gt; {
119 const res = await listSimpleMenusApi() 108 const res = await listSimpleMenusApi()
120 menuOptions.value = handleTree(res) 109 menuOptions.value = handleTree(res)
121 } 110 }
122 -const menuExpand = ref(false)  
123 -const menuNodeAll = ref(false)  
124 111
125 -// ========== 列表相关 ==========  
126 -const { register, tableObject, methods } = useTable<TenantPackageVO>({ 112 +const { gridOptions, getList, deleteData } = useVxeGrid<TenantPackageApi.TenantPackageVO>({
  113 + allSchemas: allSchemas,
127 getListApi: TenantPackageApi.getTenantPackageTypePageApi, 114 getListApi: TenantPackageApi.getTenantPackageTypePageApi,
128 - delListApi: TenantPackageApi.deleteTenantPackageTypeApi 115 + deleteApi: TenantPackageApi.deleteTenantPackageTypeApi
129 }) 116 })
130 -const { getList, setSearchParams, delList } = methods  
131 -  
132 -// ========== CRUD 相关 ==========  
133 -const loading = ref(false) // 遮罩层  
134 -const formRef = ref<FormExpose>() // 表单 Ref  
135 -const actionType = ref('') // 操作按钮的类型  
136 -const dialogVisible = ref(false) // 是否显示弹出层  
137 -const dialogTitle = ref('edit') // 弹出层标题  
138 117
139 // 设置标题 118 // 设置标题
140 const setDialogTile = (type: string) => { 119 const setDialogTile = (type: string) => {
@@ -153,14 +132,20 @@ const handleCreate = () =&gt; { @@ -153,14 +132,20 @@ const handleCreate = () =&gt; {
153 } 132 }
154 133
155 // 修改操作 134 // 修改操作
156 -const handleUpdate = async (row: any) => { 135 +const handleUpdate = async (rowId: number) => {
157 setDialogTile('update') 136 setDialogTile('update')
158 // 设置数据 137 // 设置数据
159 - const res = await TenantPackageApi.getTenantPackageApi(row.id) 138 + const res = await TenantPackageApi.getTenantPackageApi(rowId)
160 unref(formRef)?.setValues(res) 139 unref(formRef)?.setValues(res)
161 // 设置选中 140 // 设置选中
162 unref(treeRef)?.setCheckedKeys(res.menuIds) 141 unref(treeRef)?.setCheckedKeys(res.menuIds)
163 } 142 }
  143 +
  144 +// 删除操作
  145 +const handleDelete = async (rowId: number) => {
  146 + await deleteData(xGrid, rowId)
  147 +}
  148 +
164 // 提交按钮 149 // 提交按钮
165 const submitForm = async () => { 150 const submitForm = async () => {
166 const elForm = unref(formRef)?.getElFormRef() 151 const elForm = unref(formRef)?.getElFormRef()
@@ -170,20 +155,21 @@ const submitForm = async () =&gt; { @@ -170,20 +155,21 @@ const submitForm = async () =&gt; {
170 loading.value = true 155 loading.value = true
171 // 提交请求 156 // 提交请求
172 try { 157 try {
173 - const data = unref(formRef)?.formModel as TenantPackageVO 158 + const data = unref(formRef)?.formModel as TenantPackageApi.TenantPackageVO
174 data.menuIds = treeRef.value!.getCheckedKeys(false) as string[] 159 data.menuIds = treeRef.value!.getCheckedKeys(false) as string[]
175 if (actionType.value === 'create') { 160 if (actionType.value === 'create') {
176 await TenantPackageApi.createTenantPackageTypeApi(data) 161 await TenantPackageApi.createTenantPackageTypeApi(data)
177 - ElMessage.success(t('common.createSuccess')) 162 + message.success(t('common.createSuccess'))
178 } else { 163 } else {
179 await TenantPackageApi.updateTenantPackageTypeApi(data) 164 await TenantPackageApi.updateTenantPackageTypeApi(data)
180 - ElMessage.success(t('common.updateSuccess')) 165 + message.success(t('common.updateSuccess'))
181 } 166 }
182 // 操作成功,重新加载列表 167 // 操作成功,重新加载列表
183 dialogVisible.value = false 168 dialogVisible.value = false
184 - await getList()  
185 } finally { 169 } finally {
186 loading.value = false 170 loading.value = false
  171 + // 刷新列表
  172 + await getList(xGrid)
187 } 173 }
188 } 174 }
189 }) 175 })
@@ -191,7 +177,6 @@ const submitForm = async () =&gt; { @@ -191,7 +177,6 @@ const submitForm = async () =&gt; {
191 177
192 // ========== 初始化 ========== 178 // ========== 初始化 ==========
193 onMounted(async () => { 179 onMounted(async () => {
194 - await getList()  
195 await getTree() 180 await getTree()
196 }) 181 })
197 // getList() 182 // getList()
yudao-ui-admin-vue3/src/views/system/tenantPackage/tenantPackage.data.ts
1 import { reactive } from 'vue' 1 import { reactive } from 'vue'
2 import { required } from '@/utils/formRules' 2 import { required } from '@/utils/formRules'
3 import { useI18n } from '@/hooks/web/useI18n' 3 import { useI18n } from '@/hooks/web/useI18n'
4 -import { CrudSchema, useCrudSchemas } from '@/hooks/web/useCrudSchemas'  
5 import { DICT_TYPE } from '@/utils/dict' 4 import { DICT_TYPE } from '@/utils/dict'
  5 +import { VxeCrudSchema, useVxeCrudSchemas } from '@/hooks/web/useVxeCrudSchemas'
6 const { t } = useI18n() // 国际化 6 const { t } = useI18n() // 国际化
7 7
8 // 表单校验 8 // 表单校验
@@ -16,75 +16,49 @@ export const rules = reactive({ @@ -16,75 +16,49 @@ export const rules = reactive({
16 }) 16 })
17 17
18 // CrudSchema 18 // CrudSchema
19 -const crudSchemas = reactive<CrudSchema[]>([  
20 - {  
21 - label: t('common.index'),  
22 - field: 'id',  
23 - type: 'index',  
24 - form: {  
25 - show: false 19 +const crudSchemas = reactive<VxeCrudSchema>({
  20 + primaryKey: 'id',
  21 + primaryType: 'seq',
  22 + action: true,
  23 + columns: [
  24 + {
  25 + title: '套餐名称',
  26 + field: 'name',
  27 + isSearch: true
26 }, 28 },
27 - detail: {  
28 - show: false  
29 - }  
30 - },  
31 - {  
32 - label: '套餐名称',  
33 - field: 'name',  
34 - search: {  
35 - show: true  
36 - }  
37 - },  
38 - {  
39 - label: t('common.status'),  
40 - field: 'status',  
41 - dictType: DICT_TYPE.COMMON_STATUS,  
42 - dictClass: 'number',  
43 - search: {  
44 - show: true  
45 - }  
46 - },  
47 - {  
48 - label: '菜单权限',  
49 - field: 'menuIds',  
50 - table: {  
51 - show: false  
52 - }  
53 - },  
54 - {  
55 - label: t('form.remark'),  
56 - field: 'remark',  
57 - form: {  
58 - component: 'Input',  
59 - componentProps: {  
60 - type: 'textarea',  
61 - rows: 4  
62 - },  
63 - colProps: {  
64 - span: 24  
65 - } 29 + {
  30 + title: t('common.status'),
  31 + field: 'status',
  32 + dictType: DICT_TYPE.COMMON_STATUS,
  33 + dictClass: 'number',
  34 + isSearch: true
66 }, 35 },
67 - table: {  
68 - show: false  
69 - }  
70 - },  
71 - {  
72 - label: '创建时间',  
73 - field: 'createTime',  
74 - form: {  
75 - show: false  
76 - }  
77 - },  
78 - {  
79 - label: t('table.action'),  
80 - field: 'action',  
81 - width: '240px',  
82 - form: {  
83 - show: false 36 + {
  37 + title: '菜单权限',
  38 + field: 'menuIds',
  39 + isTable: false
84 }, 40 },
85 - detail: {  
86 - show: false 41 + {
  42 + title: t('form.remark'),
  43 + field: 'remark',
  44 + isTable: false,
  45 + form: {
  46 + component: 'Input',
  47 + componentProps: {
  48 + type: 'textarea',
  49 + rows: 4
  50 + },
  51 + colProps: {
  52 + span: 24
  53 + }
  54 + }
  55 + },
  56 + {
  57 + title: '创建时间',
  58 + field: 'createTime',
  59 + formatter: 'formatDate',
  60 + isForm: false
87 } 61 }
88 - }  
89 -])  
90 -export const { allSchemas } = useCrudSchemas(crudSchemas) 62 + ]
  63 +})
  64 +export const { allSchemas } = useVxeCrudSchemas(crudSchemas)