3.1.0稳定版
This commit is contained in:
@@ -35,7 +35,10 @@ export interface TenantExportReqVO {
|
|||||||
export const getTenantPage = (params: TenantPageReqVO) => {
|
export const getTenantPage = (params: TenantPageReqVO) => {
|
||||||
return request.get({ url: '/system/tenant/page', params })
|
return request.get({ url: '/system/tenant/page', params })
|
||||||
}
|
}
|
||||||
|
// 查询租户列表(代理)
|
||||||
|
export const getTenantPageSelf = (params: TenantPageReqVO) => {
|
||||||
|
return request.get({ url: '/system/tenant/page_self', params })
|
||||||
|
}
|
||||||
// 查询租户详情
|
// 查询租户详情
|
||||||
export const getTenant = (id: number) => {
|
export const getTenant = (id: number) => {
|
||||||
return request.get({ url: '/system/tenant/get?id=' + id })
|
return request.get({ url: '/system/tenant/get?id=' + id })
|
||||||
@@ -70,3 +73,7 @@ export const deleteTenantList = (ids: number[]) => {
|
|||||||
export const exportTenant = (params: TenantExportReqVO) => {
|
export const exportTenant = (params: TenantExportReqVO) => {
|
||||||
return request.download({ url: '/system/tenant/export-excel', params })
|
return request.download({ url: '/system/tenant/export-excel', params })
|
||||||
}
|
}
|
||||||
|
// 获取租户等级
|
||||||
|
export const getSelfTenantLevel = () => {
|
||||||
|
return request.get({ url: '/system/tenant/getSelfTenantLevel' })
|
||||||
|
}
|
||||||
@@ -46,3 +46,7 @@ export const deleteTenantPackageList = (ids: number[]) => {
|
|||||||
export const getTenantPackageList = () => {
|
export const getTenantPackageList = () => {
|
||||||
return request.get({ url: '/system/tenant-package/simple-list' })
|
return request.get({ url: '/system/tenant-package/simple-list' })
|
||||||
}
|
}
|
||||||
|
// 获取非总后台租户套餐精简信息列表
|
||||||
|
export const getTenantPackageListagency = () => {
|
||||||
|
return request.get({ url: '/system/tenant-agency-package/get-simple-list' })
|
||||||
|
}
|
||||||
|
|||||||
49
src/api/system/tenantagencypackage/index.ts
Normal file
49
src/api/system/tenantagencypackage/index.ts
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
import request from '@/config/axios'
|
||||||
|
|
||||||
|
// 代理租户套餐 VO
|
||||||
|
export interface TenantAgencyPackageVO {
|
||||||
|
id: number // 套餐编号
|
||||||
|
name: string // 套餐名
|
||||||
|
status: number // 租户状态(0正常 1停用)
|
||||||
|
remark: string // 备注
|
||||||
|
menuIds: string // 关联的菜单编号
|
||||||
|
days: number // 套餐天数
|
||||||
|
price: number // 套餐价格
|
||||||
|
hostslClient: number // 爬主播客户端 0 关闭 1 开启
|
||||||
|
brotherClient: number // 爬大哥客户端 0 关闭 1 开启
|
||||||
|
aiClient: number // AI 客户端 0 关闭 1 开启
|
||||||
|
packageType: number // 套餐类型
|
||||||
|
}
|
||||||
|
|
||||||
|
// 代理租户套餐 API
|
||||||
|
export const TenantAgencyPackageApi = {
|
||||||
|
// 查询代理租户套餐分页
|
||||||
|
getTenantAgencyPackagePage: async (params: any) => {
|
||||||
|
return await request.get({ url: `/system/tenant-agency-package/page`, params })
|
||||||
|
},
|
||||||
|
|
||||||
|
// 查询代理租户套餐详情
|
||||||
|
getTenantAgencyPackage: async (id: number) => {
|
||||||
|
return await request.get({ url: `/system/tenant-agency-package/get?id=` + id })
|
||||||
|
},
|
||||||
|
|
||||||
|
// 新增代理租户套餐
|
||||||
|
createTenantAgencyPackage: async (data: TenantAgencyPackageVO) => {
|
||||||
|
return await request.post({ url: `/system/tenant-agency-package/create`, data })
|
||||||
|
},
|
||||||
|
|
||||||
|
// 修改代理租户套餐
|
||||||
|
updateTenantAgencyPackage: async (data: TenantAgencyPackageVO) => {
|
||||||
|
return await request.put({ url: `/system/tenant-agency-package/update`, data })
|
||||||
|
},
|
||||||
|
|
||||||
|
// 删除代理租户套餐
|
||||||
|
deleteTenantAgencyPackage: async (id: number) => {
|
||||||
|
return await request.delete({ url: `/system/tenant-agency-package/delete?id=` + id })
|
||||||
|
},
|
||||||
|
|
||||||
|
// 导出代理租户套餐 Excel
|
||||||
|
exportTenantAgencyPackage: async (params) => {
|
||||||
|
return await request.download({ url: `/system/tenant-agency-package/export-excel`, params })
|
||||||
|
}
|
||||||
|
}
|
||||||
83
src/api/system/tenantbalance/index.ts
Normal file
83
src/api/system/tenantbalance/index.ts
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
import request from '@/config/axios'
|
||||||
|
|
||||||
|
// 租户余额 VO
|
||||||
|
export interface TenantBalanceVO {
|
||||||
|
id: number // 租户 Id
|
||||||
|
balance: number // 当前积分余额
|
||||||
|
version: number // 乐观锁版本号
|
||||||
|
updatedAt: Date // 更新时间
|
||||||
|
}
|
||||||
|
|
||||||
|
// 租户余额 API
|
||||||
|
export const TenantBalanceApi = {
|
||||||
|
// 查询租户余额分页
|
||||||
|
getTenantBalancePage: async (params: any) => {
|
||||||
|
return await request.get({ url: `/system/tenant-balance/page`, params })
|
||||||
|
},
|
||||||
|
// 查询下级租户余额分页
|
||||||
|
getSubordinateaMountPage: async (params: any) => {
|
||||||
|
return await request.get({ url: `/system/tenant-balance/get-self-subordinate-amount-page`, params })
|
||||||
|
},
|
||||||
|
|
||||||
|
//查看当前余额
|
||||||
|
getselfamount: async () => {
|
||||||
|
return await request.get({ url: `/system/tenant-balance/get-self-amount` })
|
||||||
|
},
|
||||||
|
|
||||||
|
// 查询租户余额详情
|
||||||
|
getTenantBalance: async (id: number) => {
|
||||||
|
return await request.get({ url: `/system/tenant-balance/get?id=` + id })
|
||||||
|
},
|
||||||
|
|
||||||
|
// 新增租户余额
|
||||||
|
createTenantBalance: async (data: TenantBalanceVO) => {
|
||||||
|
return await request.post({ url: `/system/tenant-balance/create`, data })
|
||||||
|
},
|
||||||
|
|
||||||
|
// 修改租户余额
|
||||||
|
updateTenantBalance: async (data: TenantBalanceVO) => {
|
||||||
|
return await request.put({ url: `/system/tenant-balance/update`, data })
|
||||||
|
},
|
||||||
|
|
||||||
|
// 删除租户余额
|
||||||
|
deleteTenantBalance: async (id: number) => {
|
||||||
|
return await request.delete({ url: `/system/tenant-balance/delete?id=` + id })
|
||||||
|
},
|
||||||
|
// 转账租户余额
|
||||||
|
tenantTransfer: async (data: TenantBalanceVO) => {
|
||||||
|
return await request.post({ url: `/system/tenant-balance/transfer`, data })
|
||||||
|
},
|
||||||
|
addAmount: async (data: TenantBalanceVO) => {
|
||||||
|
return await request.post({ url: `/system/tenant-balance/addAmount`, data })
|
||||||
|
},
|
||||||
|
// 导出租户余额 Excel
|
||||||
|
exportTenantBalance: async (params) => {
|
||||||
|
return await request.download({ url: `/system/tenant-balance/export-excel`, params })
|
||||||
|
},
|
||||||
|
|
||||||
|
// ==================== 子表(租户余额) ====================
|
||||||
|
|
||||||
|
// 获得租户余额分页
|
||||||
|
getTenantPointsPage: async (params) => {
|
||||||
|
return await request.get({ url: `/system/tenant-points/transaction-history/page`, params })
|
||||||
|
},
|
||||||
|
// 新增租户余额
|
||||||
|
createTenantPoints: async (data) => {
|
||||||
|
return await request.post({ url: `/system/tenant-balance/tenant-points/create`, data })
|
||||||
|
},
|
||||||
|
|
||||||
|
// 修改租户余额
|
||||||
|
updateTenantPoints: async (data) => {
|
||||||
|
return await request.put({ url: `/system/tenant-balance/tenant-points/update`, data })
|
||||||
|
},
|
||||||
|
|
||||||
|
// 删除租户余额
|
||||||
|
deleteTenantPoints: async (id: number) => {
|
||||||
|
return await request.delete({ url: `/system/tenant-balance/tenant-points/delete?id=` + id })
|
||||||
|
},
|
||||||
|
|
||||||
|
// 获得租户余额
|
||||||
|
getTenantPoints: async (id: number) => {
|
||||||
|
return await request.get({ url: `/system/tenant-balance/tenant-points/get?id=` + id })
|
||||||
|
}
|
||||||
|
}
|
||||||
48
src/api/system/tenantpoints/index.ts
Normal file
48
src/api/system/tenantpoints/index.ts
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
import request from '@/config/axios'
|
||||||
|
|
||||||
|
// 租户积分记录 VO
|
||||||
|
export interface TenantPointsVO {
|
||||||
|
id: number // 主键
|
||||||
|
points: number // 本次变动点数,正加负减
|
||||||
|
balance: number // 变动后余额快照(冗余)
|
||||||
|
type: string // 变动类型,如 RECHARGE, CONSUME, TRANSFER_OUT, TRANSFER_IN
|
||||||
|
remark: string // 备注
|
||||||
|
orderId: number // 订单 Id/业务单号
|
||||||
|
bizNo: string // 业务流水号(转账、订单等唯一标识)
|
||||||
|
operatorId: number // 操作人 Id
|
||||||
|
targetTenantId: number // 目标租户 Id(转账使用)
|
||||||
|
createdAt: Date // 创建时间
|
||||||
|
}
|
||||||
|
|
||||||
|
// 租户积分记录 API
|
||||||
|
export const TenantPointsApi = {
|
||||||
|
// 查询租户积分记录分页
|
||||||
|
getTenantPointsPage: async (params: any) => {
|
||||||
|
return await request.get({ url: `/system/tenant-points/page`, params })
|
||||||
|
},
|
||||||
|
|
||||||
|
// 查询租户积分记录详情
|
||||||
|
getTenantPoints: async (id: number) => {
|
||||||
|
return await request.get({ url: `/system/tenant-points/get?id=` + id })
|
||||||
|
},
|
||||||
|
|
||||||
|
// 新增租户积分记录
|
||||||
|
createTenantPoints: async (data: TenantPointsVO) => {
|
||||||
|
return await request.post({ url: `/system/tenant-points/create`, data })
|
||||||
|
},
|
||||||
|
|
||||||
|
// 修改租户积分记录
|
||||||
|
updateTenantPoints: async (data: TenantPointsVO) => {
|
||||||
|
return await request.put({ url: `/system/tenant-points/update`, data })
|
||||||
|
},
|
||||||
|
|
||||||
|
// 删除租户积分记录
|
||||||
|
deleteTenantPoints: async (id: number) => {
|
||||||
|
return await request.delete({ url: `/system/tenant-points/delete?id=` + id })
|
||||||
|
},
|
||||||
|
|
||||||
|
// 导出租户积分记录 Excel
|
||||||
|
exportTenantPoints: async (params) => {
|
||||||
|
return await request.download({ url: `/system/tenant-points/export-excel`, params })
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -324,7 +324,8 @@ export default {
|
|||||||
typeUpdate: 'Dict Type Eidt',
|
typeUpdate: 'Dict Type Eidt',
|
||||||
dataCreate: 'Dict Data Create',
|
dataCreate: 'Dict Data Create',
|
||||||
dataUpdate: 'Dict Data Eidt',
|
dataUpdate: 'Dict Data Eidt',
|
||||||
fileUpload: 'File Upload'
|
fileUpload: 'File Upload',
|
||||||
|
transfer: 'Transfer',
|
||||||
},
|
},
|
||||||
dialog: {
|
dialog: {
|
||||||
dialog: 'Dialog',
|
dialog: 'Dialog',
|
||||||
|
|||||||
@@ -329,7 +329,8 @@ export default {
|
|||||||
typeCreate: '字典类型新增',
|
typeCreate: '字典类型新增',
|
||||||
typeUpdate: '字典类型编辑',
|
typeUpdate: '字典类型编辑',
|
||||||
dataCreate: '字典数据新增',
|
dataCreate: '字典数据新增',
|
||||||
dataUpdate: '字典数据编辑'
|
dataUpdate: '字典数据编辑',
|
||||||
|
transfer: '转账',
|
||||||
},
|
},
|
||||||
dialog: {
|
dialog: {
|
||||||
dialog: '弹窗',
|
dialog: '弹窗',
|
||||||
|
|||||||
@@ -255,5 +255,7 @@ export enum DICT_TYPE {
|
|||||||
SORT_STATE = 'sort_state', // 升序降序
|
SORT_STATE = 'sort_state', // 升序降序
|
||||||
SORT_TYPE = 'sort_type', // 排序类型
|
SORT_TYPE = 'sort_type', // 排序类型
|
||||||
FLAG_TYPE = 'flag_type', // 旗帜
|
FLAG_TYPE = 'flag_type', // 旗帜
|
||||||
HOSTS_KIND = 'hosts_type' // 直播类型
|
HOSTS_KIND = 'hosts_type', // 直播类型
|
||||||
|
|
||||||
|
PAY_TYPE = 'pay_type', // 支付类型
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -232,7 +232,7 @@ onMounted(async () => {
|
|||||||
await getAllApi()
|
await getAllApi()
|
||||||
|
|
||||||
await getAllocationList()
|
await getAllocationList()
|
||||||
|
//用户id == 1 且
|
||||||
if (wsCache.get('roleRouters').find(item => item.id === 1)?.children.find(item => item.id === 100)) {
|
if (wsCache.get('roleRouters').find(item => item.id === 1)?.children.find(item => item.id === 100)) {
|
||||||
await fetchAllHostsCount(1)
|
await fetchAllHostsCount(1)
|
||||||
|
|
||||||
@@ -246,6 +246,7 @@ onMounted(async () => {
|
|||||||
|
|
||||||
// 每次页面“再次显示”时都会触发(前提:该路由组件被 keep-alive 缓存)
|
// 每次页面“再次显示”时都会触发(前提:该路由组件被 keep-alive 缓存)
|
||||||
onActivated(async () => {
|
onActivated(async () => {
|
||||||
|
console.log(wsCache.get('roleRouters'))
|
||||||
await fetchDailyHostsCount()
|
await fetchDailyHostsCount()
|
||||||
|
|
||||||
await fetchDailyHostsCountDesc()
|
await fetchDailyHostsCountDesc()
|
||||||
|
|||||||
@@ -1,46 +1,46 @@
|
|||||||
<template>
|
<template>
|
||||||
<Dialog v-model="dialogVisible" :title="dialogTitle" width="50%">
|
<Dialog v-model="dialogVisible" :title="dialogTitle" width="60%">
|
||||||
<el-form ref="formRef" v-loading="formLoading" :model="formData" :rules="formRules" label-width="120px">
|
<el-form ref="formRef" v-loading="formLoading" :model="formData" :rules="formRules" label-width="120px">
|
||||||
|
<!-- ========== 1. 基础信息 ========== -->
|
||||||
|
<el-divider>基础信息</el-divider>
|
||||||
|
|
||||||
<el-form-item label="租户名" prop="name">
|
<el-form-item label="租户名" prop="name">
|
||||||
<el-input v-model="formData.name" placeholder="请输入租户名" />
|
<el-input v-model="formData.name" placeholder="请输入租户名" :disabled="formType === 'renew'" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="租户套餐" prop="packageId">
|
|
||||||
<el-select v-model="formData.packageId" clearable placeholder="请选择租户套餐">
|
<el-form-item v-if="tenantLevel <= 1" label="租户类型" prop="tenantType">
|
||||||
<el-option v-for="item in packageList" :key="item.id" :label="item.name" :value="item.id" />
|
<el-radio-group v-model="formData.tenantType" :disabled="formType === 'renew'">
|
||||||
</el-select>
|
<el-radio value="代理">代理</el-radio>
|
||||||
|
<el-radio value="租户">租户</el-radio>
|
||||||
|
</el-radio-group>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-form-item label="联系人" prop="contactName">
|
<el-form-item label="联系人" prop="contactName">
|
||||||
<el-input v-model="formData.contactName" placeholder="请输入联系人" />
|
<el-input v-model="formData.contactName" placeholder="请输入联系人" :disabled="formType === 'renew'" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-form-item label="联系手机" prop="contactMobile">
|
<el-form-item label="联系手机" prop="contactMobile">
|
||||||
<el-input v-model="formData.contactMobile" placeholder="请输入联系手机" />
|
<el-input v-model="formData.contactMobile" placeholder="请输入联系手机" :disabled="formType === 'renew'" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item v-if="formData.id === undefined" label="用户名称" prop="username">
|
|
||||||
|
<el-form-item label="绑定域名" prop="website">
|
||||||
|
<el-input v-model="formData.website" placeholder="请输入绑定域名" :disabled="formType === 'renew'" />
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<!-- 只有创建时才需要用户名+密码 -->
|
||||||
|
<el-form-item v-if="formType === 'create'" label="用户名称" prop="username">
|
||||||
<el-input v-model="formData.username" placeholder="请输入用户名称" />
|
<el-input v-model="formData.username" placeholder="请输入用户名称" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item v-if="formData.id === undefined" label="用户密码" prop="password">
|
|
||||||
|
<el-form-item v-if="formType === 'create'" label="用户密码" prop="password">
|
||||||
<el-input v-model="formData.password" placeholder="请输入用户密码" show-password type="password" />
|
<el-input v-model="formData.password" placeholder="请输入用户密码" show-password type="password" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-form-item label="账号额度" prop="accountCount">
|
<el-form-item label="账号额度" prop="accountCount">
|
||||||
<el-input-number v-model="formData.accountCount" :min="0" controls-position="right" placeholder="请输入账号额度" />
|
<el-input-number v-model="formData.accountCount" :min="0" controls-position="right" placeholder="请输入账号额度"
|
||||||
</el-form-item>
|
:disabled="formType === 'renew'" />
|
||||||
<el-form-item label="AI过期时间" prop="aiExpireTime">
|
|
||||||
<el-date-picker v-model="formData.aiExpireTime" clearable placeholder="请选择AI过期时间" type="date"
|
|
||||||
value-format="x" />
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label="爬大哥过期时间" prop="brotherExpireTime">
|
|
||||||
<el-date-picker v-model="formData.brotherExpireTime" clearable placeholder="请选择爬大哥过期时间" type="date"
|
|
||||||
value-format="x" />
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label="爬虫后台过期时间" prop="expireTime">
|
|
||||||
<el-date-picker v-model="formData.expireTime" clearable placeholder="请选择过期时间" type="date" value-format="x" />
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label="绑定域名" prop="website">
|
|
||||||
<el-input v-model="formData.website" placeholder="请输入绑定域名" />
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label="备注" prop="remark">
|
|
||||||
<el-input v-model="formData.remark" placeholder="请输入备注" />
|
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-form-item label="租户状态" prop="status">
|
<el-form-item label="租户状态" prop="status">
|
||||||
<el-radio-group v-model="formData.status">
|
<el-radio-group v-model="formData.status">
|
||||||
<el-radio v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)" :key="dict.value" :value="dict.value">
|
<el-radio v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)" :key="dict.value" :value="dict.value">
|
||||||
@@ -48,102 +48,203 @@
|
|||||||
</el-radio>
|
</el-radio>
|
||||||
</el-radio-group>
|
</el-radio-group>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<!-- 选择用户 -->
|
|
||||||
<el-form-item v-if="formType !== 'create'" label="选择用户" prop="userId">
|
<el-form-item label="备注" prop="remark">
|
||||||
<el-select v-model="userData.id" @change="changeUser" clearable placeholder="请选择租户">
|
<el-input v-model="formData.remark" placeholder="请输入备注" type="textarea" />
|
||||||
<el-option v-for="item in userList" :key="item.id" :label="item.username" :value="item.id" />
|
</el-form-item>
|
||||||
|
|
||||||
|
<!-- ========== 2. 套餐 & 权限 ========== -->
|
||||||
|
<el-divider>套餐 & 权限</el-divider>
|
||||||
|
|
||||||
|
<el-form-item label="租户套餐" prop="packageId">
|
||||||
|
<el-select v-model="formData.packageId" clearable placeholder="请选择租户套餐" @change="handlePackageChange">
|
||||||
|
<el-option v-for="item in packageList" :key="item.id" :label="item.name" :value="item.id" />
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
|
<!-- 可选:套餐菜单预览(如果套餐里有 menus/menuTree 之类字段) -->
|
||||||
|
<!-- <el-form-item label="套餐菜单">
|
||||||
|
<el-tree v-if="currentPackageMenus.length" :data="currentPackageMenus" node-key="id"
|
||||||
|
:props="{ label: 'name', children: 'children' }" default-expand-all show-checkbox :check-strictly="true"
|
||||||
|
:disabled="true" />
|
||||||
|
<span v-else style="color:#999;">请选择租户套餐后查看菜单</span>
|
||||||
|
</el-form-item> -->
|
||||||
|
|
||||||
|
<!-- ========== 3. 服务到期时间(开通/续费) ========== -->
|
||||||
|
<!-- <el-divider>服务到期时间</el-divider> -->
|
||||||
|
|
||||||
|
<!-- AI 过期时间:改成预设时长 -->
|
||||||
|
<!-- <el-form-item label="AI过期时间" prop="aiExpireTime">
|
||||||
|
<div style="display: flex; align-items: center;">
|
||||||
|
<el-radio-group v-model="aiExpirePreset" @change="handleAiExpireChange">
|
||||||
|
<el-radio-button label="1d">1天</el-radio-button>
|
||||||
|
<el-radio-button label="3d">3天</el-radio-button>
|
||||||
|
<el-radio-button label="1m">1个月</el-radio-button>
|
||||||
|
<el-radio-button label="2m">2个月</el-radio-button>
|
||||||
|
<el-radio-button label="6m">6个月</el-radio-button>
|
||||||
|
<el-radio-button label="1y">1年</el-radio-button>
|
||||||
|
</el-radio-group>
|
||||||
|
<span v-if="formData.aiExpireTime" style="margin-left: 12px; color: #666;">
|
||||||
|
到期时间:{{ formatExpire(formData.aiExpireTime) }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</el-form-item> -->
|
||||||
|
|
||||||
|
<!-- 爬大哥过期时间:改成预设时长 -->
|
||||||
|
<!-- <el-form-item label="爬大哥过期时间" prop="brotherExpireTime">
|
||||||
|
<div style="display: flex; align-items: center;">
|
||||||
|
<el-radio-group v-model="brotherExpirePreset" @change="handleBrotherExpireChange">
|
||||||
|
<el-radio-button label="1d">1天</el-radio-button>
|
||||||
|
<el-radio-button label="3d">3天</el-radio-button>
|
||||||
|
<el-radio-button label="1m">1个月</el-radio-button>
|
||||||
|
<el-radio-button label="2m">2个月</el-radio-button>
|
||||||
|
<el-radio-button label="6m">6个月</el-radio-button>
|
||||||
|
<el-radio-button label="1y">1年</el-radio-button>
|
||||||
|
</el-radio-group>
|
||||||
|
<span v-if="formData.brotherExpireTime" style="margin-left: 12px; color: #666;">
|
||||||
|
到期时间:{{ formatExpire(formData.brotherExpireTime) }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</el-form-item> -->
|
||||||
|
|
||||||
|
<!-- 爬虫后台过期时间:也改成预设时长 -->
|
||||||
|
<el-form-item label="后台过期时间" prop="expireTime">
|
||||||
|
<div style="display: flex; align-items: center;">
|
||||||
|
<el-radio-group v-model="expirePreset" @change="handleExpireChange">
|
||||||
|
<el-radio-button label="1d">1天</el-radio-button>
|
||||||
|
<el-radio-button label="3d">3天</el-radio-button>
|
||||||
|
<el-radio-button label="1m">1个月</el-radio-button>
|
||||||
|
<el-radio-button label="2m">2个月</el-radio-button>
|
||||||
|
<el-radio-button label="6m">6个月</el-radio-button>
|
||||||
|
<el-radio-button label="1y">1年</el-radio-button>
|
||||||
|
</el-radio-group>
|
||||||
|
<span v-if="formData.expireTime" style="margin-left: 12px; color: #666;">
|
||||||
|
到期时间:{{ formatExpire(formData.expireTime) }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<!-- ========== 4. 功能开关(依赖到期时间) ========== -->
|
||||||
|
<!-- <el-divider>功能开关</el-divider> -->
|
||||||
|
|
||||||
|
<!-- 选择用户 -->
|
||||||
|
<!-- <el-form-item v-if="formType !== 'create'" label="选择用户" prop="userId">
|
||||||
|
<el-select v-model="userData.id" @change="changeUser" clearable placeholder="请选择租户用户">
|
||||||
|
<el-option v-for="item in userList" :key="item.id" :label="item.username" :value="item.id" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item> -->
|
||||||
|
|
||||||
<!-- 爬虫:不受限制,直接选 -->
|
<!-- 爬虫:不受限制,直接选 -->
|
||||||
<el-form-item v-if="userData.id" label="爬虫" prop="status">
|
<!-- <el-form-item v-if="userData.id" label="爬虫">
|
||||||
<el-radio-group v-model="userData.crawl">
|
<el-radio-group v-model="userData.crawl">
|
||||||
<el-radio :value="1">开启</el-radio>
|
<el-radio :value="1">开启</el-radio>
|
||||||
<el-radio :value="0">关闭</el-radio>
|
<el-radio :value="0">关闭</el-radio>
|
||||||
</el-radio-group>
|
</el-radio-group>
|
||||||
</el-form-item>
|
</el-form-item> -->
|
||||||
|
|
||||||
<!-- 爬大哥:必须先选“爬大哥过期时间” -->
|
<!-- 爬大哥:必须先选“爬大哥过期时间” -->
|
||||||
<el-form-item v-if="userData.id" label="爬大哥" prop="status">
|
<!-- <el-form-item v-if="userData.id" label="爬大哥">
|
||||||
<el-radio-group v-model="userData.bigBrother" :disabled="!formData.brotherExpireTime">
|
<el-radio-group v-model="userData.bigBrother" :disabled="!formData.brotherExpireTime">
|
||||||
<el-radio :value="1">开启</el-radio>
|
<el-radio :value="1">开启</el-radio>
|
||||||
<el-radio :value="0">关闭</el-radio>
|
<el-radio :value="0">关闭</el-radio>
|
||||||
</el-radio-group>
|
</el-radio-group>
|
||||||
</el-form-item>
|
<small v-if="!formData.brotherExpireTime" style="color:#999;">请先选择爬大哥过期时间</small>
|
||||||
|
</el-form-item> -->
|
||||||
|
|
||||||
<!-- ai自动化:必须先选“AI过期时间” -->
|
<!-- ai自动化:必须先选“AI过期时间” -->
|
||||||
<el-form-item v-if="userData.id" label="ai自动化" prop="status">
|
<!-- <el-form-item v-if="userData.id" label="AI自动化">
|
||||||
<el-radio-group v-model="userData.aiChat" :disabled="!formData.aiExpireTime">
|
<el-radio-group v-model="userData.aiChat" :disabled="!formData.aiExpireTime">
|
||||||
<el-radio :value="1">开启</el-radio>
|
<el-radio :value="1">开启</el-radio>
|
||||||
<el-radio :value="0">关闭</el-radio>
|
<el-radio :value="0">关闭</el-radio>
|
||||||
</el-radio-group>
|
</el-radio-group>
|
||||||
</el-form-item>
|
</el-form-item> -->
|
||||||
|
|
||||||
<!-- ai回复:必须先选“AI过期时间” -->
|
<!-- ai回复:必须先选“AI过期时间” -->
|
||||||
<el-form-item v-if="userData.id" label="ai回复" prop="status">
|
<!-- <el-form-item v-if="userData.id" label="AI回复">
|
||||||
<el-radio-group v-model="userData.aiReplay" :disabled="!formData.aiExpireTime">
|
<el-radio-group v-model="userData.aiReplay" :disabled="!formData.aiExpireTime">
|
||||||
<el-radio :value="1">开启</el-radio>
|
<el-radio :value="1">开启</el-radio>
|
||||||
<el-radio :value="0">关闭</el-radio>
|
<el-radio :value="0">关闭</el-radio>
|
||||||
</el-radio-group>
|
</el-radio-group>
|
||||||
</el-form-item>
|
</el-form-item> -->
|
||||||
</el-form>
|
</el-form>
|
||||||
|
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<el-button :disabled="formLoading" type="primary" @click="submitForm">确 定</el-button>
|
<el-button :disabled="formLoading" type="primary" @click="submitForm">确 定</el-button>
|
||||||
<el-button @click="dialogVisible = false">取 消</el-button>
|
<el-button @click="dialogVisible = false">取 消</el-button>
|
||||||
</template>
|
</template>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
|
import { watch, computed } from 'vue'
|
||||||
import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
|
import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
|
||||||
import * as TenantApi from '@/api/system/tenant'
|
import * as TenantApi from '@/api/system/tenant'
|
||||||
import { getUserByTenant, updateRoleUser } from '@/api/system/user'
|
import { getUserByTenant, updateRoleUser } from '@/api/system/user'
|
||||||
import { CommonStatusEnum } from '@/utils/constants'
|
import { CommonStatusEnum } from '@/utils/constants'
|
||||||
import * as TenantPackageApi from '@/api/system/tenantPackage'
|
import * as TenantPackageApi from '@/api/system/tenantPackage'
|
||||||
import * as userApi from '@/api/system/user'
|
import * as userApi from '@/api/system/user'
|
||||||
import { watch } from 'vue' // ⭐ 确保引入 watch
|
|
||||||
|
|
||||||
|
// 记录打开弹窗时的原始到期时间,用来做续费基准
|
||||||
|
const originalExpireTimes = ref({
|
||||||
|
ai: undefined as number | undefined,
|
||||||
|
brother: undefined as number | undefined,
|
||||||
|
crawler: undefined as number | undefined
|
||||||
|
})
|
||||||
|
|
||||||
|
const tenantLevel = ref(3)
|
||||||
defineOptions({ name: 'SystemTenantForm' })
|
defineOptions({ name: 'SystemTenantForm' })
|
||||||
|
TenantApi.getSelfTenantLevel().then(res => {
|
||||||
|
tenantLevel.value = res.tenantLevel
|
||||||
|
console.log(tenantLevel.value)
|
||||||
|
})
|
||||||
|
const { t } = useI18n()
|
||||||
|
const message = useMessage()
|
||||||
|
const dialogVisible = ref(false)
|
||||||
|
const dialogTitle = ref('')
|
||||||
|
const formLoading = ref(false)
|
||||||
|
// 新增一个类型:renew
|
||||||
|
const formType = ref<'create' | 'update' | 'renew'>('create')
|
||||||
|
|
||||||
|
// 预设选项的 v-model
|
||||||
|
const aiExpirePreset = ref<string | null>(null)
|
||||||
|
const brotherExpirePreset = ref<string | null>(null)
|
||||||
|
const expirePreset = ref<string | null>(null)
|
||||||
|
|
||||||
const { t } = useI18n() // 国际化
|
|
||||||
const message = useMessage() // 消息弹窗
|
|
||||||
const dialogVisible = ref(false) // 弹窗的是否展示
|
|
||||||
const dialogTitle = ref('') // 弹窗的标题
|
|
||||||
const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用
|
|
||||||
const formType = ref('') // 表单的类型:create - 新增;update - 修改
|
|
||||||
const formData = ref({
|
const formData = ref({
|
||||||
id: 0,
|
id: 0,
|
||||||
name: undefined,
|
name: undefined as string | undefined,
|
||||||
packageId: undefined,
|
packageId: undefined as number | undefined,
|
||||||
contactName: undefined,
|
contactName: undefined as string | undefined,
|
||||||
contactMobile: undefined,
|
contactMobile: undefined as string | undefined,
|
||||||
accountCount: undefined,
|
accountCount: undefined as number | undefined,
|
||||||
expireTime: undefined,
|
tenantType: '租户' as string | undefined,
|
||||||
website: undefined,
|
expireTime: undefined as number | undefined,
|
||||||
|
website: undefined as string | undefined,
|
||||||
status: CommonStatusEnum.ENABLE,
|
status: CommonStatusEnum.ENABLE,
|
||||||
// 新增专属
|
username: undefined as string | undefined,
|
||||||
username: undefined,
|
password: undefined as string | undefined,
|
||||||
password: undefined,
|
remark: undefined as string | undefined,
|
||||||
remark: undefined,
|
aiExpireTime: undefined as number | undefined,
|
||||||
aiExpireTime: undefined,
|
brotherExpireTime: undefined as number | undefined
|
||||||
brotherExpireTime: undefined,
|
|
||||||
})
|
})
|
||||||
|
|
||||||
const userData = ref({} as userApi.UserVO)
|
const userData = ref({} as userApi.UserVO)
|
||||||
|
|
||||||
let userList = ref([{
|
const userList = ref<userApi.UserVO[]>([
|
||||||
id: 0,
|
{
|
||||||
aiChat: 0,
|
id: 0,
|
||||||
bigBrother: 0,
|
aiChat: 0,
|
||||||
crawl: 0
|
bigBrother: 0,
|
||||||
}])
|
crawl: 0
|
||||||
|
} as any
|
||||||
|
])
|
||||||
|
|
||||||
const formRules = reactive({
|
const formRules = reactive({
|
||||||
name: [{ required: true, message: '租户名不能为空', trigger: 'blur' }],
|
name: [{ required: true, message: '租户名不能为空', trigger: 'blur' }],
|
||||||
packageId: [{ required: true, message: '租户套餐不能为空', trigger: 'blur' }],
|
packageId: [{ required: true, message: '租户套餐不能为空', trigger: 'blur' }],
|
||||||
contactName: [{ required: true, message: '联系人不能为空', trigger: 'blur' }],
|
contactName: [{ required: true, message: '联系人不能为空', trigger: 'blur' }],
|
||||||
// contactMobile: [
|
|
||||||
// { required: true, message: '手机号不能为空', trigger: 'blur' },
|
|
||||||
// { pattern: /^1[3-9]\d{9}$/, message: '请输入有效的 11 位手机号', trigger: ['blur', 'change'] }
|
|
||||||
// ],
|
|
||||||
status: [{ required: true, message: '租户状态不能为空', trigger: 'blur' }],
|
status: [{ required: true, message: '租户状态不能为空', trigger: 'blur' }],
|
||||||
|
tenantType: [{ required: true, message: '租户类型不能为空', trigger: 'blur' }],
|
||||||
accountCount: [{ required: true, message: '账号额度不能为空', trigger: 'blur' }],
|
accountCount: [{ required: true, message: '账号额度不能为空', trigger: 'blur' }],
|
||||||
expireTime: [{ required: true, message: '过期时间不能为空', trigger: 'blur' }],
|
expireTime: [{ required: true, message: '过期时间不能为空', trigger: 'blur' }],
|
||||||
website: [{ required: true, message: '绑定域名不能为空', trigger: 'blur' }],
|
website: [{ required: true, message: '绑定域名不能为空', trigger: 'blur' }],
|
||||||
@@ -153,55 +254,158 @@ const formRules = reactive({
|
|||||||
],
|
],
|
||||||
password: [{ required: true, message: '用户密码不能为空', trigger: 'blur' }]
|
password: [{ required: true, message: '用户密码不能为空', trigger: 'blur' }]
|
||||||
})
|
})
|
||||||
const formRef = ref() // 表单 Ref
|
|
||||||
const packageList = ref([] as TenantPackageApi.TenantPackageVO[]) // 租户套餐
|
const formRef = ref()
|
||||||
|
const packageList = ref([] as TenantPackageApi.TenantPackageVO[])
|
||||||
|
|
||||||
|
// 当前套餐菜单:用于树形只读展示(后端要在套餐里带 menus / menuTree 等字段)
|
||||||
|
const currentPackageMenus = computed(() => {
|
||||||
|
const pkg = packageList.value.find((p) => p.id === formData.value.packageId)
|
||||||
|
return (pkg && (pkg as any).menus) || []
|
||||||
|
})
|
||||||
|
|
||||||
|
// 工具:根据预设计算到期时间(统一到 0 点,且进一到下一天)
|
||||||
|
function calcExpireFromPreset(preset: string, baseExpire?: number): number {
|
||||||
|
const now = new Date()
|
||||||
|
|
||||||
|
// 1. 基准时间:如果原始到期时间在未来,就从原始到期时间算;否则从今天算
|
||||||
|
let base = now
|
||||||
|
if (baseExpire) {
|
||||||
|
const cur = new Date(baseExpire)
|
||||||
|
if (cur.getTime() > now.getTime()) {
|
||||||
|
base = cur
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 在基准时间上加时长
|
||||||
|
const target = new Date(base)
|
||||||
|
switch (preset) {
|
||||||
|
case '1d':
|
||||||
|
target.setDate(target.getDate() + 1)
|
||||||
|
break
|
||||||
|
case '3d':
|
||||||
|
target.setDate(target.getDate() + 3)
|
||||||
|
break
|
||||||
|
case '1m':
|
||||||
|
target.setMonth(target.getMonth() + 1)
|
||||||
|
break
|
||||||
|
case '2m':
|
||||||
|
target.setMonth(target.getMonth() + 2)
|
||||||
|
break
|
||||||
|
case '6m':
|
||||||
|
target.setMonth(target.getMonth() + 6)
|
||||||
|
break
|
||||||
|
case '1y':
|
||||||
|
target.setFullYear(target.getFullYear() + 1)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. 进一到下一天 0 点
|
||||||
|
const end = new Date(
|
||||||
|
target.getFullYear(),
|
||||||
|
target.getMonth(),
|
||||||
|
target.getDate() + 1,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
)
|
||||||
|
return end.getTime()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 选 AI 过期预设时,同步到真正的 aiExpireTime
|
||||||
|
function handleAiExpireChange(preset: string) {
|
||||||
|
if (!preset) {
|
||||||
|
formData.value.aiExpireTime = undefined
|
||||||
|
} else {
|
||||||
|
formData.value.aiExpireTime = calcExpireFromPreset(
|
||||||
|
preset,
|
||||||
|
originalExpireTimes.value.ai // 🔴 用原始 ai 到期时间
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 选 爬大哥 过期预设时,同步到真正的 brotherExpireTime
|
||||||
|
function handleBrotherExpireChange(preset: string) {
|
||||||
|
if (!preset) {
|
||||||
|
formData.value.brotherExpireTime = undefined
|
||||||
|
} else {
|
||||||
|
formData.value.brotherExpireTime = calcExpireFromPreset(
|
||||||
|
preset,
|
||||||
|
originalExpireTimes.value.brother // 🔴 用原始 brother 到期时间
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 选 爬虫后台 过期预设时,同步到真正的 expireTime
|
||||||
|
function handleExpireChange(preset: string) {
|
||||||
|
if (!preset) {
|
||||||
|
formData.value.expireTime = undefined
|
||||||
|
} else {
|
||||||
|
formData.value.expireTime = calcExpireFromPreset(
|
||||||
|
preset,
|
||||||
|
originalExpireTimes.value.crawler // 🔴 用原始 expireTime
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 套餐切换:现在只负责展示菜单,金额逻辑都在后端
|
||||||
|
function handlePackageChange(id: number) {
|
||||||
|
// 如果将来需要从套餐带出其他信息,可以在这里扩展
|
||||||
|
}
|
||||||
|
|
||||||
/** 打开弹窗 */
|
/** 打开弹窗 */
|
||||||
const open = async (type: string, id?: number) => {
|
const open = async (type: 'create' | 'update' | 'renew', id?: number) => {
|
||||||
dialogVisible.value = true
|
dialogVisible.value = true
|
||||||
dialogTitle.value = t('action.' + type)
|
|
||||||
formType.value = type
|
formType.value = type
|
||||||
|
dialogTitle.value =
|
||||||
|
type === 'create' ? t('action.create') : type === 'update' ? t('action.update') : '租户续费'
|
||||||
resetForm()
|
resetForm()
|
||||||
// 修改时,设置数据
|
|
||||||
if (id) {
|
if (id) {
|
||||||
formLoading.value = true
|
formLoading.value = true
|
||||||
try {
|
try {
|
||||||
formData.value = await TenantApi.getTenant(id)
|
formData.value = await TenantApi.getTenant(id)
|
||||||
getUserByTenant(id).then(res => {
|
// 🔴 这里记录原始到期时间,后面续费都基于这三个算
|
||||||
console.log(res)
|
originalExpireTimes.value.ai = formData.value.aiExpireTime
|
||||||
|
originalExpireTimes.value.brother = formData.value.brotherExpireTime
|
||||||
|
originalExpireTimes.value.crawler = formData.value.expireTime
|
||||||
|
|
||||||
|
getUserByTenant(id).then((res) => {
|
||||||
userList.value = res
|
userList.value = res
|
||||||
})
|
})
|
||||||
} finally {
|
} finally {
|
||||||
formLoading.value = false
|
formLoading.value = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 加载套餐列表
|
|
||||||
packageList.value = await TenantPackageApi.getTenantPackageList()
|
packageList.value = await TenantPackageApi.getTenantPackageList()
|
||||||
}
|
}
|
||||||
defineExpose({ open }) // 提供 open 方法,用于打开弹窗
|
|
||||||
|
defineExpose({ open })
|
||||||
|
|
||||||
/** 提交表单 */
|
/** 提交表单 */
|
||||||
const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调
|
const emit = defineEmits(['success'])
|
||||||
const submitForm = async () => {
|
const submitForm = async () => {
|
||||||
// 校验表单
|
|
||||||
if (!formRef) return
|
if (!formRef) return
|
||||||
const valid = await formRef.value.validate()
|
const valid = await formRef.value.validate()
|
||||||
if (!valid) return
|
if (!valid) return
|
||||||
// 提交请求
|
|
||||||
formLoading.value = true
|
formLoading.value = true
|
||||||
try {
|
try {
|
||||||
const data = formData.value as unknown as TenantApi.TenantVO
|
const data = formData.value as unknown as TenantApi.TenantVO
|
||||||
|
|
||||||
if (formType.value === 'create') {
|
if (formType.value === 'create') {
|
||||||
//下次更改内容,创建账号 给一个权限 爬大哥和AI
|
|
||||||
await TenantApi.createTenant(data)
|
await TenantApi.createTenant(data)
|
||||||
message.success(t('common.createSuccess'))
|
message.success(t('common.createSuccess'))
|
||||||
} else {
|
} else {
|
||||||
|
// update + renew 都用 updateTenant,参数不变
|
||||||
await TenantApi.updateTenant(data)
|
await TenantApi.updateTenant(data)
|
||||||
await updateRoleUser(userData.value)
|
await updateRoleUser(userData.value)
|
||||||
message.success(t('common.updateSuccess'))
|
message.success(formType.value === 'renew' ? '续费成功' : t('common.updateSuccess'))
|
||||||
}
|
}
|
||||||
|
|
||||||
dialogVisible.value = false
|
dialogVisible.value = false
|
||||||
// 发送操作成功的事件
|
|
||||||
emit('success')
|
emit('success')
|
||||||
} finally {
|
} finally {
|
||||||
formLoading.value = false
|
formLoading.value = false
|
||||||
@@ -211,35 +415,62 @@ const submitForm = async () => {
|
|||||||
/** 重置表单 */
|
/** 重置表单 */
|
||||||
const resetForm = () => {
|
const resetForm = () => {
|
||||||
formData.value = {
|
formData.value = {
|
||||||
id: undefined,
|
id: undefined as any,
|
||||||
name: undefined,
|
name: undefined,
|
||||||
packageId: undefined,
|
packageId: undefined,
|
||||||
contactName: undefined,
|
contactName: undefined,
|
||||||
contactMobile: undefined,
|
contactMobile: undefined,
|
||||||
accountCount: undefined,
|
accountCount: undefined,
|
||||||
|
tenantType: '租户', // ✅ 重置时也默认“租户”
|
||||||
expireTime: undefined,
|
expireTime: undefined,
|
||||||
website: undefined,
|
website: undefined,
|
||||||
status: CommonStatusEnum.ENABLE,
|
status: CommonStatusEnum.ENABLE,
|
||||||
username: undefined,
|
username: undefined,
|
||||||
password: undefined,
|
password: undefined,
|
||||||
remark: undefined,
|
remark: undefined,
|
||||||
aiExpireTime: undefined, // ⭐ 加上
|
aiExpireTime: undefined,
|
||||||
brotherExpireTime: undefined, // ⭐ 加上
|
brotherExpireTime: undefined
|
||||||
}
|
}
|
||||||
|
aiExpirePreset.value = null
|
||||||
|
brotherExpirePreset.value = null
|
||||||
|
expirePreset.value = null
|
||||||
userData.value = {} as userApi.UserVO
|
userData.value = {} as userApi.UserVO
|
||||||
formRef.value?.resetFields()
|
originalExpireTimes.value = {
|
||||||
|
ai: undefined,
|
||||||
|
brother: undefined,
|
||||||
|
crawler: undefined
|
||||||
|
}
|
||||||
|
formRef.value?.resetFields?.()
|
||||||
}
|
}
|
||||||
function changeUser(val) {
|
|
||||||
userList.value.forEach(item => {
|
function changeUser(val: number) {
|
||||||
|
userList.value.forEach((item) => {
|
||||||
if (item.id === val) {
|
if (item.id === val) {
|
||||||
userData.value = item
|
userData.value = item
|
||||||
userData.value.tenantId = formData.value.id
|
; (userData.value as any).tenantId = formData.value.id
|
||||||
|
|
||||||
|
if (!formData.value.aiExpireTime) {
|
||||||
|
userData.value.aiChat = 0
|
||||||
|
userData.value.aiReplay = 0
|
||||||
|
}
|
||||||
|
if (!formData.value.brotherExpireTime) {
|
||||||
|
userData.value.bigBrother = 0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
function formatExpire(time?: number) {
|
||||||
|
if (!time) return ''
|
||||||
|
const d = new Date(time)
|
||||||
|
const pad = (n: number) => String(n).padStart(2, '0')
|
||||||
|
const Y = d.getFullYear()
|
||||||
|
const M = pad(d.getMonth() + 1)
|
||||||
|
const D = pad(d.getDate())
|
||||||
|
const h = pad(d.getHours())
|
||||||
|
const m = pad(d.getMinutes())
|
||||||
|
const s = pad(d.getSeconds())
|
||||||
|
return `${Y}-${M}-${D} ${h}:${m}:${s}`
|
||||||
|
}
|
||||||
// AI 过期时间变化:没有时间时,禁止并关闭 ai 功能
|
// AI 过期时间变化:没有时间时,禁止并关闭 ai 功能
|
||||||
watch(
|
watch(
|
||||||
() => formData.value.aiExpireTime,
|
() => formData.value.aiExpireTime,
|
||||||
|
|||||||
@@ -79,14 +79,12 @@
|
|||||||
<el-table-column type="selection" width="55" />
|
<el-table-column type="selection" width="55" />
|
||||||
<el-table-column label="租户编号" align="center" prop="id" />
|
<el-table-column label="租户编号" align="center" prop="id" />
|
||||||
<el-table-column label="租户名" align="center" prop="name" />
|
<el-table-column label="租户名" align="center" prop="name" />
|
||||||
|
<el-table-column label="租户类型" align="center" prop="tenantType" />
|
||||||
<el-table-column label="租户套餐" align="center" prop="packageId">
|
<el-table-column label="租户套餐" align="center" prop="packageId">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-tag v-if="scope.row.packageId === 0" type="danger">系统租户</el-tag>
|
<el-tag :type="scope.row.packageId === 0 ? 'danger' : 'success'">
|
||||||
<template v-else v-for="item in packageList">
|
{{ getPackageName(scope.row.packageId) }}
|
||||||
<el-tag type="success" :key="item.id" v-if="item.id === scope.row.packageId">
|
</el-tag>
|
||||||
{{ item.name }}
|
|
||||||
</el-tag>
|
|
||||||
</template>
|
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="联系人" align="center" prop="contactName" />
|
<el-table-column label="联系人" align="center" prop="contactName" />
|
||||||
@@ -107,12 +105,15 @@
|
|||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="备注" align="center" prop="remark" />
|
<el-table-column label="备注" align="center" prop="remark" />
|
||||||
<el-table-column label="创建时间" align="center" prop="createTime" width="180" :formatter="dateFormatter" />
|
<el-table-column label="创建时间" align="center" prop="createTime" width="180" :formatter="dateFormatter" />
|
||||||
<el-table-column label="操作" align="center" min-width="110" fixed="right">
|
<el-table-column label="操作" align="center" min-width="160" fixed="right">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-button link type="primary" @click="openForm('update', scope.row.id)"
|
<el-button link type="primary" @click="openForm('update', scope.row.id)"
|
||||||
v-hasPermi="['system:tenant:update']">
|
v-hasPermi="['system:tenant:update']">
|
||||||
编辑
|
编辑
|
||||||
</el-button>
|
</el-button>
|
||||||
|
<el-button link type="warning" @click="openForm('renew', scope.row.id)" v-hasPermi="['system:tenant:update']">
|
||||||
|
续费
|
||||||
|
</el-button>
|
||||||
<el-button link type="danger" @click="handleDelete(scope.row.id)" v-hasPermi="['system:tenant:delete']">
|
<el-button link type="danger" @click="handleDelete(scope.row.id)" v-hasPermi="['system:tenant:delete']">
|
||||||
删除
|
删除
|
||||||
</el-button>
|
</el-button>
|
||||||
@@ -134,9 +135,9 @@ import download from '@/utils/download'
|
|||||||
import * as TenantApi from '@/api/system/tenant'
|
import * as TenantApi from '@/api/system/tenant'
|
||||||
import * as TenantPackageApi from '@/api/system/tenantPackage'
|
import * as TenantPackageApi from '@/api/system/tenantPackage'
|
||||||
import TenantForm from './TenantForm.vue'
|
import TenantForm from './TenantForm.vue'
|
||||||
|
import { useUserStore } from '@/store/modules/user'
|
||||||
defineOptions({ name: 'SystemTenant' })
|
defineOptions({ name: 'SystemTenant' })
|
||||||
|
const userStore = useUserStore()
|
||||||
const message = useMessage() // 消息弹窗
|
const message = useMessage() // 消息弹窗
|
||||||
const { t } = useI18n() // 国际化
|
const { t } = useI18n() // 国际化
|
||||||
|
|
||||||
@@ -150,6 +151,7 @@ const queryParams = reactive({
|
|||||||
contactName: undefined,
|
contactName: undefined,
|
||||||
contactMobile: undefined,
|
contactMobile: undefined,
|
||||||
status: undefined,
|
status: undefined,
|
||||||
|
tenantType: undefined,
|
||||||
remark: undefined,
|
remark: undefined,
|
||||||
createTime: [],
|
createTime: [],
|
||||||
aiExpireTime: [],
|
aiExpireTime: [],
|
||||||
@@ -159,12 +161,19 @@ const queryParams = reactive({
|
|||||||
const queryFormRef = ref() // 搜索的表单
|
const queryFormRef = ref() // 搜索的表单
|
||||||
const exportLoading = ref(false) // 导出的加载中
|
const exportLoading = ref(false) // 导出的加载中
|
||||||
const packageList = ref([] as TenantPackageApi.TenantPackageVO[]) //租户套餐列表
|
const packageList = ref([] as TenantPackageApi.TenantPackageVO[]) //租户套餐列表
|
||||||
|
const packageAgencyList = ref([] as TenantPackageApi.TenantPackageVO[]) //租户套餐列表
|
||||||
|
|
||||||
/** 查询列表 */
|
/** 查询列表 */
|
||||||
const getList = async () => {
|
const getList = async () => {
|
||||||
loading.value = true
|
loading.value = true
|
||||||
try {
|
try {
|
||||||
const data = await TenantApi.getTenantPage(queryParams)
|
let data = ''
|
||||||
|
if (userStore.getUser.id === 1) {
|
||||||
|
data = await TenantApi.getTenantPage(queryParams)
|
||||||
|
} else {
|
||||||
|
data = await TenantApi.getTenantPageSelf(queryParams)
|
||||||
|
}
|
||||||
|
|
||||||
list.value = data.list
|
list.value = data.list
|
||||||
total.value = data.total
|
total.value = data.total
|
||||||
} finally {
|
} finally {
|
||||||
@@ -186,7 +195,7 @@ const resetQuery = () => {
|
|||||||
|
|
||||||
/** 添加/修改操作 */
|
/** 添加/修改操作 */
|
||||||
const formRef = ref()
|
const formRef = ref()
|
||||||
const openForm = (type: string, id?: number) => {
|
const openForm = (type: 'create' | 'update' | 'renew', id?: number) => {
|
||||||
formRef.value.open(type, id)
|
formRef.value.open(type, id)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -235,11 +244,31 @@ const handleExport = async () => {
|
|||||||
exportLoading.value = false
|
exportLoading.value = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
const getPackageName = (packageId: number) => {
|
||||||
|
if (packageId === 0) return '系统租户'
|
||||||
|
|
||||||
|
// 先从 packageList 找
|
||||||
|
const pkg = packageList.value.find((p) => p.id === packageId)
|
||||||
|
if (pkg) return pkg.name
|
||||||
|
|
||||||
|
// packageList 未找到,并且 packageId !== 1 时,再从 packageAgencyList 找
|
||||||
|
if (packageId !== 1) {
|
||||||
|
const agency = packageAgencyList.value.find((a) => a.id === packageId)
|
||||||
|
if (agency) return agency.name
|
||||||
|
}
|
||||||
|
|
||||||
|
return '未知套餐'
|
||||||
|
}
|
||||||
|
|
||||||
/** 初始化 **/
|
/** 初始化 **/
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
await getList()
|
await getList()
|
||||||
// 获取租户套餐列表
|
// 获取租户套餐列表
|
||||||
packageList.value = await TenantPackageApi.getTenantPackageList()
|
packageList.value = await TenantPackageApi.getTenantPackageList()
|
||||||
|
if (userStore.getUser.id === 1) {
|
||||||
|
packageAgencyList.value = await TenantPackageApi.getTenantPackageListagency()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -1,12 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<Dialog v-model="dialogVisible" :title="dialogTitle">
|
<Dialog v-model="dialogVisible" :title="dialogTitle">
|
||||||
<el-form
|
<el-form ref="formRef" v-loading="formLoading" :model="formData" :rules="formRules" label-width="80px">
|
||||||
ref="formRef"
|
|
||||||
v-loading="formLoading"
|
|
||||||
:model="formData"
|
|
||||||
:rules="formRules"
|
|
||||||
label-width="80px"
|
|
||||||
>
|
|
||||||
<el-form-item label="套餐名" prop="name">
|
<el-form-item label="套餐名" prop="name">
|
||||||
<el-input v-model="formData.name" placeholder="请输入套餐名" />
|
<el-input v-model="formData.name" placeholder="请输入套餐名" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
@@ -14,39 +8,19 @@
|
|||||||
<el-card class="w-full h-400px !overflow-y-scroll" shadow="never">
|
<el-card class="w-full h-400px !overflow-y-scroll" shadow="never">
|
||||||
<template #header>
|
<template #header>
|
||||||
全选/全不选:
|
全选/全不选:
|
||||||
<el-switch
|
<el-switch v-model="treeNodeAll" active-text="是" inactive-text="否" inline-prompt
|
||||||
v-model="treeNodeAll"
|
@change="handleCheckedTreeNodeAll" />
|
||||||
active-text="是"
|
|
||||||
inactive-text="否"
|
|
||||||
inline-prompt
|
|
||||||
@change="handleCheckedTreeNodeAll"
|
|
||||||
/>
|
|
||||||
全部展开/折叠:
|
全部展开/折叠:
|
||||||
<el-switch
|
<el-switch v-model="menuExpand" active-text="展开" inactive-text="折叠" inline-prompt
|
||||||
v-model="menuExpand"
|
@change="handleCheckedTreeExpand" />
|
||||||
active-text="展开"
|
|
||||||
inactive-text="折叠"
|
|
||||||
inline-prompt
|
|
||||||
@change="handleCheckedTreeExpand"
|
|
||||||
/>
|
|
||||||
</template>
|
</template>
|
||||||
<el-tree
|
<el-tree ref="treeRef" :data="menuOptions" :props="defaultProps" empty-text="加载中,请稍候" node-key="id"
|
||||||
ref="treeRef"
|
show-checkbox />
|
||||||
:data="menuOptions"
|
|
||||||
:props="defaultProps"
|
|
||||||
empty-text="加载中,请稍候"
|
|
||||||
node-key="id"
|
|
||||||
show-checkbox
|
|
||||||
/>
|
|
||||||
</el-card>
|
</el-card>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="状态" prop="status">
|
<el-form-item label="状态" prop="status">
|
||||||
<el-radio-group v-model="formData.status">
|
<el-radio-group v-model="formData.status">
|
||||||
<el-radio
|
<el-radio v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)" :key="dict.value" :value="dict.value">
|
||||||
v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)"
|
|
||||||
:key="dict.value"
|
|
||||||
:value="dict.value"
|
|
||||||
>
|
|
||||||
{{ dict.label }}
|
{{ dict.label }}
|
||||||
</el-radio>
|
</el-radio>
|
||||||
</el-radio-group>
|
</el-radio-group>
|
||||||
|
|||||||
233
src/views/system/tenantagencypackage/TenantAgencyPackageForm.vue
Normal file
233
src/views/system/tenantagencypackage/TenantAgencyPackageForm.vue
Normal file
@@ -0,0 +1,233 @@
|
|||||||
|
<template>
|
||||||
|
<Dialog :title="dialogTitle" v-model="dialogVisible">
|
||||||
|
<el-form ref="formRef" :model="formData" :rules="formRules" label-width="100px" v-loading="formLoading">
|
||||||
|
<el-form-item label="套餐名" prop="name">
|
||||||
|
<el-input v-model="formData.name" placeholder="请输入套餐名" />
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item label="租户状态" prop="status">
|
||||||
|
<el-radio-group v-model="formData.status">
|
||||||
|
<el-radio :value="0">正常</el-radio>
|
||||||
|
<el-radio :value="1">停用</el-radio>
|
||||||
|
</el-radio-group>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item label="备注" prop="remark">
|
||||||
|
<el-input v-model="formData.remark" placeholder="请输入备注" />
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<!-- ✅ 改成树形菜单选择 -->
|
||||||
|
<el-form-item label="菜单权限" prop="menuIds">
|
||||||
|
<el-card class="w-full h-400px !overflow-y-scroll" shadow="never">
|
||||||
|
<template #header>
|
||||||
|
全选/全不选:
|
||||||
|
<el-switch v-model="treeNodeAll" active-text="是" inactive-text="否" inline-prompt
|
||||||
|
@change="handleCheckedTreeNodeAll" />
|
||||||
|
全部展开/折叠:
|
||||||
|
<el-switch v-model="menuExpand" active-text="展开" inactive-text="折叠" inline-prompt
|
||||||
|
@change="handleCheckedTreeExpand" />
|
||||||
|
</template>
|
||||||
|
<el-tree ref="treeRef" :data="menuOptions" :props="defaultProps" empty-text="加载中,请稍候" node-key="id"
|
||||||
|
show-checkbox />
|
||||||
|
</el-card>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item label="套餐天数" prop="days">
|
||||||
|
<el-input v-model="formData.days" placeholder="请输入套餐天数" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="套餐价格" prop="price">
|
||||||
|
<el-input v-model="formData.price" placeholder="请输入套餐价格" />
|
||||||
|
</el-form-item>
|
||||||
|
<!-- 爬大哥:必须先选“爬大哥过期时间” -->
|
||||||
|
<el-form-item label="爬大哥">
|
||||||
|
<el-radio-group v-model="formData.brotherClient">
|
||||||
|
<el-radio :value="1">开启</el-radio>
|
||||||
|
<el-radio :value="0">关闭</el-radio>
|
||||||
|
</el-radio-group>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<!-- ai自动化:必须先选“AI过期时间” -->
|
||||||
|
<el-form-item label="AI自动化">
|
||||||
|
<el-radio-group v-model="formData.hostslClient">
|
||||||
|
<el-radio :value="1">开启</el-radio>
|
||||||
|
<el-radio :value="0">关闭</el-radio>
|
||||||
|
</el-radio-group>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<!-- ai回复:必须先选“AI过期时间” -->
|
||||||
|
<el-form-item label="AI回复">
|
||||||
|
<el-radio-group v-model="formData.aiClient">
|
||||||
|
<el-radio :value="1">开启</el-radio>
|
||||||
|
<el-radio :value="0">关闭</el-radio>
|
||||||
|
</el-radio-group>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="套餐类型" prop="packageType">
|
||||||
|
<el-select v-model="formData.packageType" placeholder="请选择套餐类型">
|
||||||
|
<el-option label="请选择字典生成" value="" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
|
||||||
|
<template #footer>
|
||||||
|
<el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button>
|
||||||
|
<el-button @click="dialogVisible = false">取 消</el-button>
|
||||||
|
</template>
|
||||||
|
</Dialog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { TenantAgencyPackageApi, TenantAgencyPackageVO } from '@/api/system/tenantagencypackage'
|
||||||
|
import * as MenuApi from '@/api/system/menu'
|
||||||
|
import { defaultProps, handleTree } from '@/utils/tree'
|
||||||
|
import { ElTree } from 'element-plus'
|
||||||
|
|
||||||
|
/** 代理租户套餐 表单 */
|
||||||
|
defineOptions({ name: 'TenantAgencyPackageForm' })
|
||||||
|
|
||||||
|
const { t } = useI18n()
|
||||||
|
const message = useMessage()
|
||||||
|
|
||||||
|
const dialogVisible = ref(false)
|
||||||
|
const dialogTitle = ref('')
|
||||||
|
const formLoading = ref(false)
|
||||||
|
const formType = ref<'create' | 'update' | string>('')
|
||||||
|
|
||||||
|
const formData = ref({
|
||||||
|
id: undefined as number | undefined,
|
||||||
|
name: undefined as string | undefined,
|
||||||
|
status: 0 as 0 | 1 | undefined, // 默认正常
|
||||||
|
remark: undefined as string | undefined,
|
||||||
|
menuIds: [] as number[], // ✅ 改成数组
|
||||||
|
days: undefined as number | undefined,
|
||||||
|
price: undefined as number | undefined,
|
||||||
|
hostslClient: undefined as number | undefined,
|
||||||
|
brotherClient: undefined as number | undefined,
|
||||||
|
aiClient: undefined as number | undefined,
|
||||||
|
packageType: undefined as string | undefined
|
||||||
|
})
|
||||||
|
|
||||||
|
const formRules = reactive({
|
||||||
|
name: [{ required: true, message: '套餐名不能为空', trigger: 'blur' }],
|
||||||
|
status: [{ required: true, message: '租户状态不能为空', trigger: 'change' }],
|
||||||
|
// menuIds: [{ required: true, message: '关联的菜单编号不能为空', trigger: 'change' }], // ✅ 校验菜单
|
||||||
|
days: [{ required: true, message: '套餐天数不能为空', trigger: 'blur' }],
|
||||||
|
price: [{ required: true, message: '套餐价格不能为空', trigger: 'blur' }]
|
||||||
|
})
|
||||||
|
const formRef = ref()
|
||||||
|
|
||||||
|
// ✅ 菜单树相关
|
||||||
|
const menuOptions = ref<any[]>([])
|
||||||
|
const menuExpand = ref(false)
|
||||||
|
const treeRef = ref<InstanceType<typeof ElTree>>()
|
||||||
|
const treeNodeAll = ref(false)
|
||||||
|
|
||||||
|
/** 打开弹窗 */
|
||||||
|
const open = async (type: string, id?: number) => {
|
||||||
|
dialogVisible.value = true
|
||||||
|
dialogTitle.value = t('action.' + type)
|
||||||
|
formType.value = type
|
||||||
|
await resetForm()
|
||||||
|
|
||||||
|
// 先加载菜单树数据(一定要先有数据,后 setChecked)
|
||||||
|
formLoading.value = true
|
||||||
|
try {
|
||||||
|
const menus = await MenuApi.getSimpleMenusList()
|
||||||
|
menuOptions.value = handleTree(menus)
|
||||||
|
} finally {
|
||||||
|
formLoading.value = false
|
||||||
|
}
|
||||||
|
|
||||||
|
// 编辑:回显数据并勾选
|
||||||
|
if (id) {
|
||||||
|
formLoading.value = true
|
||||||
|
try {
|
||||||
|
const data = await TenantAgencyPackageApi.getTenantAgencyPackage(id)
|
||||||
|
formData.value = {
|
||||||
|
...formData.value,
|
||||||
|
...data,
|
||||||
|
menuIds: Array.isArray(data.menuIds) ? data.menuIds : []
|
||||||
|
}
|
||||||
|
// 勾选已有关联
|
||||||
|
formData.value.menuIds.forEach((mid: number) => {
|
||||||
|
treeRef.value?.setChecked(mid, true, false)
|
||||||
|
})
|
||||||
|
} finally {
|
||||||
|
formLoading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
defineExpose({ open })
|
||||||
|
|
||||||
|
/** 提交表单 */
|
||||||
|
const emit = defineEmits(['success'])
|
||||||
|
const submitForm = async () => {
|
||||||
|
// 1. 先做表单校验
|
||||||
|
await formRef.value.validate()
|
||||||
|
|
||||||
|
// 2. 从树组件拿选中的菜单 id(包含半选)
|
||||||
|
const checked = (treeRef.value?.getCheckedKeys(false) || []) as number[]
|
||||||
|
const half = (treeRef.value?.getHalfCheckedKeys() || []) as number[]
|
||||||
|
const menuIds = Array.from(new Set([...checked, ...half])) // 去重一下
|
||||||
|
|
||||||
|
// 3. 把 menuIds 塞回 formData(或者直接合并到 data 里)
|
||||||
|
formData.value.menuIds = menuIds
|
||||||
|
|
||||||
|
formLoading.value = true
|
||||||
|
try {
|
||||||
|
// 4. 组装真正发给后端的参数
|
||||||
|
const data = {
|
||||||
|
...(formData.value as any),
|
||||||
|
menuIds // ✅ 确保有这个字段
|
||||||
|
} as TenantAgencyPackageVO
|
||||||
|
if (formType.value === 'create') {
|
||||||
|
await TenantAgencyPackageApi.createTenantAgencyPackage(data)
|
||||||
|
message.success(t('common.createSuccess'))
|
||||||
|
} else {
|
||||||
|
await TenantAgencyPackageApi.updateTenantAgencyPackage(data)
|
||||||
|
message.success(t('common.updateSuccess'))
|
||||||
|
}
|
||||||
|
|
||||||
|
dialogVisible.value = false
|
||||||
|
emit('success')
|
||||||
|
} finally {
|
||||||
|
formLoading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 重置表单 */
|
||||||
|
const resetForm = async () => {
|
||||||
|
treeNodeAll.value = false
|
||||||
|
menuExpand.value = false
|
||||||
|
formData.value = {
|
||||||
|
id: undefined,
|
||||||
|
name: undefined,
|
||||||
|
status: 0,
|
||||||
|
remark: undefined,
|
||||||
|
menuIds: [], // ✅ 清空
|
||||||
|
days: undefined,
|
||||||
|
price: undefined,
|
||||||
|
hostslClient: undefined,
|
||||||
|
brotherClient: undefined,
|
||||||
|
aiClient: undefined,
|
||||||
|
packageType: undefined
|
||||||
|
}
|
||||||
|
treeRef.value?.setCheckedNodes([])
|
||||||
|
formRef.value?.resetFields()
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 全选/全不选 */
|
||||||
|
const handleCheckedTreeNodeAll = () => {
|
||||||
|
treeRef.value?.setCheckedNodes(treeNodeAll.value ? menuOptions.value : [])
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 展开/折叠全部 */
|
||||||
|
const handleCheckedTreeExpand = () => {
|
||||||
|
const nodes = (treeRef.value as any)?.store?.nodesMap
|
||||||
|
if (!nodes) return
|
||||||
|
for (const key in nodes) {
|
||||||
|
if (Object.prototype.hasOwnProperty.call(nodes, key)) {
|
||||||
|
nodes[key].expanded = menuExpand.value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
200
src/views/system/tenantagencypackage/index.vue
Normal file
200
src/views/system/tenantagencypackage/index.vue
Normal file
@@ -0,0 +1,200 @@
|
|||||||
|
<template>
|
||||||
|
<ContentWrap>
|
||||||
|
<!-- 搜索工作栏 -->
|
||||||
|
<el-form class="-mb-15px" :model="queryParams" ref="queryFormRef" :inline="true">
|
||||||
|
<el-form-item label="套餐名" prop="name">
|
||||||
|
<el-input v-model="queryParams.name" placeholder="请输入套餐名" clearable @keyup.enter="handleQuery"
|
||||||
|
class="!w-240px" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="租户状态 " prop="status">
|
||||||
|
<el-select v-model="queryParams.status" placeholder="请选择租户状态 " clearable class="!w-240px">
|
||||||
|
<el-option label="请选择字典生成" value="" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="备注" prop="remark">
|
||||||
|
<el-input v-model="queryParams.remark" placeholder="请输入备注" clearable @keyup.enter="handleQuery"
|
||||||
|
class="!w-240px" />
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item label="创建时间" prop="createTime">
|
||||||
|
<el-date-picker v-model="queryParams.createTime" value-format="YYYY-MM-DD HH:mm:ss" type="daterange"
|
||||||
|
start-placeholder="开始日期" end-placeholder="结束日期"
|
||||||
|
:default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" class="!w-220px" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="套餐天数" prop="days">
|
||||||
|
<el-input v-model="queryParams.days" placeholder="请输入套餐天数" clearable @keyup.enter="handleQuery"
|
||||||
|
class="!w-240px" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="套餐价格" prop="price">
|
||||||
|
<el-input v-model="queryParams.price" placeholder="请输入套餐价格" clearable @keyup.enter="handleQuery"
|
||||||
|
class="!w-240px" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="爬主播客户端 " prop="hostslClient">
|
||||||
|
<el-input v-model="queryParams.hostslClient" placeholder="请输入爬主播客户端 " clearable @keyup.enter="handleQuery"
|
||||||
|
class="!w-240px" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="爬大哥客户端 " prop="brotherClient">
|
||||||
|
<el-input v-model="queryParams.brotherClient" placeholder="请输入爬大哥客户端 " clearable @keyup.enter="handleQuery"
|
||||||
|
class="!w-240px" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="AI 客户端 " prop="aiClient">
|
||||||
|
<el-input v-model="queryParams.aiClient" placeholder="请输入AI 客户端 " clearable @keyup.enter="handleQuery"
|
||||||
|
class="!w-240px" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="套餐类型" prop="packageType">
|
||||||
|
<el-select v-model="queryParams.packageType" placeholder="请选择套餐类型" clearable class="!w-240px">
|
||||||
|
<el-option label="请选择字典生成" value="" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item>
|
||||||
|
<el-button @click="handleQuery">
|
||||||
|
<Icon icon="ep:search" class="mr-5px" /> 搜索
|
||||||
|
</el-button>
|
||||||
|
<el-button @click="resetQuery">
|
||||||
|
<Icon icon="ep:refresh" class="mr-5px" /> 重置
|
||||||
|
</el-button>
|
||||||
|
<el-button type="primary" plain @click="openForm('create')"
|
||||||
|
v-hasPermi="['system:tenant-agency-package:create']">
|
||||||
|
<Icon icon="ep:plus" class="mr-5px" /> 新增
|
||||||
|
</el-button>
|
||||||
|
<el-button type="success" plain @click="handleExport" :loading="exportLoading"
|
||||||
|
v-hasPermi="['system:tenant-agency-package:export']">
|
||||||
|
<Icon icon="ep:download" class="mr-5px" /> 导出
|
||||||
|
</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
</ContentWrap>
|
||||||
|
|
||||||
|
<!-- 列表 -->
|
||||||
|
<ContentWrap>
|
||||||
|
<el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true">
|
||||||
|
<el-table-column label="套餐编号" align="center" prop="id" />
|
||||||
|
<el-table-column label="套餐名" align="center" prop="name" />
|
||||||
|
<el-table-column label="租户状态 " align="center" prop="status" />
|
||||||
|
<el-table-column label="备注" align="center" prop="remark" />
|
||||||
|
<el-table-column label="关联的菜单编号" align="center" prop="menuIds" />
|
||||||
|
<el-table-column label="创建时间" align="center" prop="createTime" :formatter="dateFormatter" width="180px" />
|
||||||
|
<el-table-column label="套餐天数" align="center" prop="days" />
|
||||||
|
<el-table-column label="套餐价格" align="center" prop="price" />
|
||||||
|
<el-table-column label="爬主播客户端 " align="center" prop="hostslClient" />
|
||||||
|
<el-table-column label="爬大哥客户端 " align="center" prop="brotherClient" />
|
||||||
|
<el-table-column label="AI 客户端 " align="center" prop="aiClient" />
|
||||||
|
<el-table-column label="套餐类型" align="center" prop="packageType" />
|
||||||
|
<el-table-column label="操作" align="center" min-width="120px">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-button link type="primary" @click="openForm('update', scope.row.id)"
|
||||||
|
v-hasPermi="['system:tenant-agency-package:update']">
|
||||||
|
编辑
|
||||||
|
</el-button>
|
||||||
|
<el-button link type="danger" @click="handleDelete(scope.row.id)"
|
||||||
|
v-hasPermi="['system:tenant-agency-package:delete']">
|
||||||
|
删除
|
||||||
|
</el-button>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
<!-- 分页 -->
|
||||||
|
<Pagination :total="total" v-model:page="queryParams.pageNo" v-model:limit="queryParams.pageSize"
|
||||||
|
@pagination="getList" />
|
||||||
|
</ContentWrap>
|
||||||
|
|
||||||
|
<!-- 表单弹窗:添加/修改 -->
|
||||||
|
<TenantAgencyPackageForm ref="formRef" @success="getList" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { dateFormatter } from '@/utils/formatTime'
|
||||||
|
import download from '@/utils/download'
|
||||||
|
import { TenantAgencyPackageApi, TenantAgencyPackageVO } from '@/api/system/tenantagencypackage'
|
||||||
|
import TenantAgencyPackageForm from './TenantAgencyPackageForm.vue'
|
||||||
|
|
||||||
|
/** 代理租户套餐 列表 */
|
||||||
|
defineOptions({ name: 'TenantAgencyPackage' })
|
||||||
|
|
||||||
|
const message = useMessage() // 消息弹窗
|
||||||
|
const { t } = useI18n() // 国际化
|
||||||
|
|
||||||
|
const loading = ref(true) // 列表的加载中
|
||||||
|
const list = ref<TenantAgencyPackageVO[]>([]) // 列表的数据
|
||||||
|
const total = ref(0) // 列表的总页数
|
||||||
|
const queryParams = reactive({
|
||||||
|
pageNo: 1,
|
||||||
|
pageSize: 10,
|
||||||
|
name: undefined,
|
||||||
|
status: undefined,
|
||||||
|
remark: undefined,
|
||||||
|
menuIds: undefined,
|
||||||
|
createTime: [],
|
||||||
|
days: undefined,
|
||||||
|
price: undefined,
|
||||||
|
hostslClient: undefined,
|
||||||
|
brotherClient: undefined,
|
||||||
|
aiClient: undefined,
|
||||||
|
packageType: undefined
|
||||||
|
})
|
||||||
|
const queryFormRef = ref() // 搜索的表单
|
||||||
|
const exportLoading = ref(false) // 导出的加载中
|
||||||
|
|
||||||
|
/** 查询列表 */
|
||||||
|
const getList = async () => {
|
||||||
|
loading.value = true
|
||||||
|
try {
|
||||||
|
const data = await TenantAgencyPackageApi.getTenantAgencyPackagePage(queryParams)
|
||||||
|
list.value = data.list
|
||||||
|
total.value = data.total
|
||||||
|
} finally {
|
||||||
|
loading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 搜索按钮操作 */
|
||||||
|
const handleQuery = () => {
|
||||||
|
queryParams.pageNo = 1
|
||||||
|
getList()
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 重置按钮操作 */
|
||||||
|
const resetQuery = () => {
|
||||||
|
queryFormRef.value.resetFields()
|
||||||
|
handleQuery()
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 添加/修改操作 */
|
||||||
|
const formRef = ref()
|
||||||
|
const openForm = (type: string, id?: number) => {
|
||||||
|
formRef.value.open(type, id)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 删除按钮操作 */
|
||||||
|
const handleDelete = async (id: number) => {
|
||||||
|
try {
|
||||||
|
// 删除的二次确认
|
||||||
|
await message.delConfirm()
|
||||||
|
// 发起删除
|
||||||
|
await TenantAgencyPackageApi.deleteTenantAgencyPackage(id)
|
||||||
|
message.success(t('common.delSuccess'))
|
||||||
|
// 刷新列表
|
||||||
|
await getList()
|
||||||
|
} catch { }
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 导出按钮操作 */
|
||||||
|
const handleExport = async () => {
|
||||||
|
try {
|
||||||
|
// 导出的二次确认
|
||||||
|
await message.exportConfirm()
|
||||||
|
// 发起导出
|
||||||
|
exportLoading.value = true
|
||||||
|
const data = await TenantAgencyPackageApi.exportTenantAgencyPackage(queryParams)
|
||||||
|
download.excel(data, '代理租户套餐.xls')
|
||||||
|
} catch {
|
||||||
|
} finally {
|
||||||
|
exportLoading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 初始化 **/
|
||||||
|
onMounted(() => {
|
||||||
|
getList()
|
||||||
|
})
|
||||||
|
</script>
|
||||||
169
src/views/system/tenantbalance/TenantBalanceForm.vue
Normal file
169
src/views/system/tenantbalance/TenantBalanceForm.vue
Normal file
@@ -0,0 +1,169 @@
|
|||||||
|
<template>
|
||||||
|
<Dialog :title="dialogTitle" v-model="dialogVisible">
|
||||||
|
<el-form v-if="formType === 'update'" ref="formRef" :model="formData" :rules="formRules" label-width="100px"
|
||||||
|
v-loading="formLoading">
|
||||||
|
<el-form-item label="充值用户" prop="id">
|
||||||
|
<el-input v-model="formData.id" placeholder="请输入充值用户" />
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item v-if="formType === 'update'" label="充值金额" prop="amount">
|
||||||
|
<!-- 改为 el-input-number,仅允许数值输入,且最小 0 -->
|
||||||
|
<el-input-number v-model.number="formData.amount" :min="0" controls-position="right" placeholder="请输入充值金额" />
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<!-- 只有 transfer 类型时显示 -->
|
||||||
|
<el-form-item label="备注" prop="remark">
|
||||||
|
<el-input v-model="formData.remark" placeholder="请输入备注" />
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
</el-form>
|
||||||
|
|
||||||
|
|
||||||
|
<el-form v-if="formType === 'transfer'" ref="formRef" :model="formData" :rules="formRules" label-width="100px"
|
||||||
|
v-loading="formLoading">
|
||||||
|
<el-form-item label="转账用户" prop="targetTenantId">
|
||||||
|
<el-input v-model="formData.targetTenantId" placeholder="请输入转账用户" />
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item v-if="formType === 'transfer'" label="转账金额" prop="transferAmount">
|
||||||
|
<!-- 改为 el-input-number,仅允许数值输入,且最小 0 -->
|
||||||
|
<el-input-number v-model.number="formData.transferAmount" :min="0" controls-position="right"
|
||||||
|
placeholder="请输入转账金额" />
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item v-if="formType === 'transfer'" label="登录密码" prop="password">
|
||||||
|
<el-input v-model="formData.password" type="password" show-password placeholder="请输入登录密码" />
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<!-- 只有 transfer 类型时显示 -->
|
||||||
|
<el-form-item label="备注" prop="remark">
|
||||||
|
<el-input v-model="formData.remark" placeholder="请输入备注" />
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
</el-form>
|
||||||
|
|
||||||
|
<template #footer>
|
||||||
|
<el-button @click="submitForm" type="primary" :disabled="formLoading">
|
||||||
|
确 定
|
||||||
|
</el-button>
|
||||||
|
<el-button @click="dialogVisible = false">取 消</el-button>
|
||||||
|
</template>
|
||||||
|
</Dialog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { computed, ref, reactive } from 'vue'
|
||||||
|
import { TenantBalanceApi, TenantBalanceVO } from '@/api/system/tenantbalance'
|
||||||
|
|
||||||
|
/** 租户余额 表单 */
|
||||||
|
defineOptions({ name: 'TenantBalanceForm' })
|
||||||
|
|
||||||
|
const { t } = useI18n() // 国际化
|
||||||
|
const message = useMessage() // 消息弹窗
|
||||||
|
|
||||||
|
const dialogVisible = ref(false) // 弹窗的是否展示
|
||||||
|
const dialogTitle = ref('') // 弹窗的标题
|
||||||
|
const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用
|
||||||
|
const formType = ref('') // 表单的类型:create - 新增;update - 修改;transfer - 转账等
|
||||||
|
|
||||||
|
const formData = ref({
|
||||||
|
tenantId: undefined as number | undefined,
|
||||||
|
id: undefined as number | undefined,
|
||||||
|
amount: undefined as number | undefined,
|
||||||
|
transferAmount: undefined as number | undefined,
|
||||||
|
targetTenantId: undefined as number | undefined,
|
||||||
|
remark: undefined as string | undefined, // 变动表述
|
||||||
|
password: undefined as string | undefined // 登录密码
|
||||||
|
})
|
||||||
|
|
||||||
|
/** 校验规则:transfer 时才要求 remark 必填 */
|
||||||
|
const formRules = computed(() => {
|
||||||
|
const baseRules: any = {
|
||||||
|
id: [{ required: true, message: '用户不能为空', trigger: 'blur' }],
|
||||||
|
amount: [{ required: true, message: '金额不能为空', trigger: 'blur' }]
|
||||||
|
}
|
||||||
|
|
||||||
|
if (formType.value === 'transfer') {
|
||||||
|
|
||||||
|
baseRules.password = [
|
||||||
|
{ required: true, message: '登录密码不能为空', trigger: 'blur' }
|
||||||
|
]
|
||||||
|
baseRules.transferAmount = [
|
||||||
|
{ required: true, message: '转账金额不能为空', trigger: 'blur' }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
return baseRules
|
||||||
|
})
|
||||||
|
|
||||||
|
const formRef = ref() // 表单 Ref
|
||||||
|
|
||||||
|
/** 打开弹窗 */
|
||||||
|
const open = async (type: string, id?: number) => {
|
||||||
|
dialogVisible.value = true
|
||||||
|
dialogTitle.value = t('action.' + type)
|
||||||
|
formType.value = type
|
||||||
|
resetForm()
|
||||||
|
// 修改时,设置数据
|
||||||
|
if (id) {
|
||||||
|
formLoading.value = true
|
||||||
|
try {
|
||||||
|
const data = await TenantBalanceApi.getTenantBalance(id)
|
||||||
|
// 保证有 remark 和 password 字段(接口没有的话就保持 undefined)
|
||||||
|
formData.value = {
|
||||||
|
tenantId: data.tenantId,
|
||||||
|
id: data.id,
|
||||||
|
amount: data.amount,
|
||||||
|
targetTenantId: data.id,
|
||||||
|
remark: undefined,
|
||||||
|
password: undefined,
|
||||||
|
transferAmount: undefined
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
formLoading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
defineExpose({ open }) // 提供 open 方法,用于打开弹窗
|
||||||
|
|
||||||
|
/** 提交表单 */
|
||||||
|
const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调
|
||||||
|
const submitForm = async () => {
|
||||||
|
console.log(formData.value)
|
||||||
|
// 校验表单
|
||||||
|
await formRef.value.validate()
|
||||||
|
// 提交请求
|
||||||
|
formLoading.value = true
|
||||||
|
try {
|
||||||
|
const data = formData.value as unknown as TenantBalanceVO
|
||||||
|
if (formType.value === 'create') {
|
||||||
|
await TenantBalanceApi.createTenantBalance(data)
|
||||||
|
message.success(t('common.createSuccess'))
|
||||||
|
} else if (formType.value === 'transfer') {
|
||||||
|
await TenantBalanceApi.tenantTransfer(data)
|
||||||
|
message.success(t('common.updateSuccess'))
|
||||||
|
} else {
|
||||||
|
await TenantBalanceApi.addAmount(data)
|
||||||
|
message.success(t('common.updateSuccess'))
|
||||||
|
}
|
||||||
|
dialogVisible.value = false
|
||||||
|
// 发送操作成功的事件
|
||||||
|
emit('success')
|
||||||
|
} finally {
|
||||||
|
formLoading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 重置表单 */
|
||||||
|
const resetForm = () => {
|
||||||
|
formData.value = {
|
||||||
|
tenantId: undefined,
|
||||||
|
id: undefined,
|
||||||
|
amount: undefined,
|
||||||
|
transferAmount: undefined,
|
||||||
|
remark: undefined,
|
||||||
|
password: undefined
|
||||||
|
}
|
||||||
|
formRef.value?.resetFields()
|
||||||
|
}
|
||||||
|
</script>
|
||||||
132
src/views/system/tenantbalance/components/TenantPointsForm.vue
Normal file
132
src/views/system/tenantbalance/components/TenantPointsForm.vue
Normal file
@@ -0,0 +1,132 @@
|
|||||||
|
<template>
|
||||||
|
<Dialog :title="dialogTitle" v-model="dialogVisible">
|
||||||
|
<el-form ref="formRef" :model="formData" :rules="formRules" label-width="100px" v-loading="formLoading">
|
||||||
|
<el-form-item label="本次变动点数,正加负减" prop="points">
|
||||||
|
<el-input v-model="formData.points" placeholder="请输入本次变动点数,正加负减" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="变动后余额快照(冗余)" prop="balance">
|
||||||
|
<el-input v-model="formData.balance" placeholder="请输入变动后余额快照(冗余)" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="变动类型,如 RECHARGE, CONSUME, TRANSFER_OUT, TRANSFER_IN" prop="type">
|
||||||
|
<el-select v-model="formData.type" placeholder="请选择变动类型,如 RECHARGE, CONSUME, TRANSFER_OUT, TRANSFER_IN">
|
||||||
|
<el-option label="请选择字典生成" value="" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="备注" prop="remark">
|
||||||
|
<Editor v-model="formData.remark" height="150px" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="订单 Id/业务单号" prop="orderId">
|
||||||
|
<el-input v-model="formData.orderId" placeholder="请输入订单 Id/业务单号" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="业务流水号(转账、订单等唯一标识)" prop="bizNo">
|
||||||
|
<el-input v-model="formData.bizNo" placeholder="请输入业务流水号(转账、订单等唯一标识)" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="操作人 Id" prop="operatorId">
|
||||||
|
<el-input v-model="formData.operatorId" placeholder="请输入操作人 Id" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="目标租户 Id(转账使用)" prop="targetTenantId">
|
||||||
|
<el-input v-model="formData.targetTenantId" placeholder="请输入目标租户 Id(转账使用)" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="创建时间" prop="createdAt">
|
||||||
|
<el-date-picker v-model="formData.createdAt" type="date" value-format="x" placeholder="选择创建时间" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="备注" prop="remark">
|
||||||
|
<el-input v-model="formData.remark" placeholder="请输入备注" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
<template #footer>
|
||||||
|
<el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button>
|
||||||
|
<el-button @click="dialogVisible = false">取 消</el-button>
|
||||||
|
</template>
|
||||||
|
</Dialog>
|
||||||
|
</template>
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { TenantBalanceApi } from '@/api/system/tenantbalance'
|
||||||
|
|
||||||
|
const { t } = useI18n() // 国际化
|
||||||
|
const message = useMessage() // 消息弹窗
|
||||||
|
|
||||||
|
const dialogVisible = ref(false) // 弹窗的是否展示
|
||||||
|
const dialogTitle = ref('') // 弹窗的标题
|
||||||
|
const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用
|
||||||
|
const formType = ref('') // 表单的类型:create - 新增;update - 修改
|
||||||
|
const formData = ref({
|
||||||
|
id: undefined,
|
||||||
|
points: undefined,
|
||||||
|
balance: undefined,
|
||||||
|
type: undefined,
|
||||||
|
remark: undefined,
|
||||||
|
orderId: undefined,
|
||||||
|
bizNo: undefined,
|
||||||
|
operatorId: undefined,
|
||||||
|
targetTenantId: undefined,
|
||||||
|
createdAt: undefined,
|
||||||
|
remark: undefined
|
||||||
|
})
|
||||||
|
const formRules = reactive({
|
||||||
|
points: [{ required: true, message: '本次变动点数,正加负减不能为空', trigger: 'blur' }],
|
||||||
|
createdAt: [{ required: true, message: '创建时间不能为空', trigger: 'blur' }]
|
||||||
|
})
|
||||||
|
const formRef = ref() // 表单 Ref
|
||||||
|
|
||||||
|
/** 打开弹窗 */
|
||||||
|
const open = async (type: string, id?: number, tenantId: number) => {
|
||||||
|
dialogVisible.value = true
|
||||||
|
dialogTitle.value = t('action.' + type)
|
||||||
|
formType.value = type
|
||||||
|
resetForm()
|
||||||
|
formData.value.tenantId = tenantId
|
||||||
|
// 修改时,设置数据
|
||||||
|
if (id) {
|
||||||
|
formLoading.value = true
|
||||||
|
try {
|
||||||
|
formData.value = await TenantBalanceApi.getTenantPoints(id)
|
||||||
|
} finally {
|
||||||
|
formLoading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
defineExpose({ open }) // 提供 open 方法,用于打开弹窗
|
||||||
|
|
||||||
|
/** 提交表单 */
|
||||||
|
const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调
|
||||||
|
const submitForm = async () => {
|
||||||
|
// 校验表单
|
||||||
|
await formRef.value.validate()
|
||||||
|
// 提交请求
|
||||||
|
formLoading.value = true
|
||||||
|
try {
|
||||||
|
const data = formData.value
|
||||||
|
if (formType.value === 'create') {
|
||||||
|
await TenantBalanceApi.createTenantPoints(data)
|
||||||
|
message.success(t('common.createSuccess'))
|
||||||
|
} else {
|
||||||
|
await TenantBalanceApi.updateTenantPoints(data)
|
||||||
|
message.success(t('common.updateSuccess'))
|
||||||
|
}
|
||||||
|
dialogVisible.value = false
|
||||||
|
// 发送操作成功的事件
|
||||||
|
emit('success')
|
||||||
|
} finally {
|
||||||
|
formLoading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 重置表单 */
|
||||||
|
const resetForm = () => {
|
||||||
|
formData.value = {
|
||||||
|
id: undefined,
|
||||||
|
points: undefined,
|
||||||
|
balance: undefined,
|
||||||
|
type: undefined,
|
||||||
|
remark: undefined,
|
||||||
|
orderId: undefined,
|
||||||
|
bizNo: undefined,
|
||||||
|
operatorId: undefined,
|
||||||
|
targetTenantId: undefined,
|
||||||
|
createdAt: undefined,
|
||||||
|
|
||||||
|
}
|
||||||
|
formRef.value?.resetFields()
|
||||||
|
}
|
||||||
|
</script>
|
||||||
112
src/views/system/tenantbalance/components/TenantPointsList.vue
Normal file
112
src/views/system/tenantbalance/components/TenantPointsList.vue
Normal file
@@ -0,0 +1,112 @@
|
|||||||
|
<template>
|
||||||
|
<!-- 列表 -->
|
||||||
|
<ContentWrap>
|
||||||
|
<!-- <el-button type="primary" plain @click="openForm('create')" v-hasPermi="['system:tenant-balance:create']">
|
||||||
|
<Icon icon="ep:plus" class="mr-5px" /> 新增
|
||||||
|
</el-button> -->
|
||||||
|
<el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true">
|
||||||
|
<!-- <el-table-column label="主键" align="center" prop="id" /> -->
|
||||||
|
<el-table-column label="金额" align="center" prop="points" />
|
||||||
|
<el-table-column label="变动后余额" align="center" prop="balance" />
|
||||||
|
<el-table-column label="类型" align="center" prop="type" />
|
||||||
|
<el-table-column label="描述" align="center" prop="description" />
|
||||||
|
<el-table-column label="订单 Id/业务单号" align="center" prop="orderId" />
|
||||||
|
<el-table-column label="业务流水号" align="center" prop="bizNo" />
|
||||||
|
<el-table-column label="操作人 Id" align="center" prop="operatorId" />
|
||||||
|
<el-table-column label="目标租户Id" align="center" prop="targetTenantId" />
|
||||||
|
<el-table-column label="创建时间" align="center" prop="createdAt" :formatter="dateFormatter" width="180px" />
|
||||||
|
<el-table-column label="备注" align="center" prop="remark" />
|
||||||
|
<el-table-column label="操作" align="center">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-button link type="primary" @click="openForm('update', scope.row.id)"
|
||||||
|
v-hasPermi="['system:tenant-balance:update']">
|
||||||
|
编辑
|
||||||
|
</el-button>
|
||||||
|
<el-button link type="danger" @click="handleDelete(scope.row.id)"
|
||||||
|
v-hasPermi="['system:tenant-balance:delete']">
|
||||||
|
删除
|
||||||
|
</el-button>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
<!-- 分页 -->
|
||||||
|
<Pagination :total="total" v-model:page="queryParams.pageNo" v-model:limit="queryParams.pageSize"
|
||||||
|
@pagination="getList" />
|
||||||
|
</ContentWrap>
|
||||||
|
<!-- 表单弹窗:添加/修改 -->
|
||||||
|
<TenantPointsForm ref="formRef" @success="getList" />
|
||||||
|
</template>
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { dateFormatter } from '@/utils/formatTime'
|
||||||
|
import { TenantBalanceApi } from '@/api/system/tenantbalance'
|
||||||
|
import TenantPointsForm from './TenantPointsForm.vue'
|
||||||
|
|
||||||
|
const { t } = useI18n() // 国际化
|
||||||
|
const message = useMessage() // 消息弹窗
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
tenantId?: number // 租户 Id(主表的关联字段)
|
||||||
|
}>()
|
||||||
|
const loading = ref(false) // 列表的加载中
|
||||||
|
const list = ref([]) // 列表的数据
|
||||||
|
const total = ref(0) // 列表的总页数
|
||||||
|
const queryParams = reactive({
|
||||||
|
pageNo: 1,
|
||||||
|
pageSize: 10,
|
||||||
|
tenantId: undefined as unknown
|
||||||
|
})
|
||||||
|
|
||||||
|
/** 监听主表的关联字段的变化,加载对应的子表数据 */
|
||||||
|
watch(
|
||||||
|
() => props.tenantId,
|
||||||
|
(val: number) => {
|
||||||
|
if (!val) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
queryParams.tenantId = val
|
||||||
|
handleQuery()
|
||||||
|
},
|
||||||
|
{ immediate: true, deep: true }
|
||||||
|
)
|
||||||
|
|
||||||
|
/** 查询列表 */
|
||||||
|
const getList = async () => {
|
||||||
|
loading.value = true
|
||||||
|
try {
|
||||||
|
const data = await TenantBalanceApi.getTenantPointsPage(queryParams)
|
||||||
|
list.value = data.list
|
||||||
|
total.value = data.total
|
||||||
|
} finally {
|
||||||
|
loading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 搜索按钮操作 */
|
||||||
|
const handleQuery = () => {
|
||||||
|
queryParams.pageNo = 1
|
||||||
|
getList()
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 添加/修改操作 */
|
||||||
|
const formRef = ref()
|
||||||
|
const openForm = (type: string, id?: number) => {
|
||||||
|
if (!props.tenantId) {
|
||||||
|
message.error('请选择一个租户余额')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
formRef.value.open(type, id, props.tenantId)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 删除按钮操作 */
|
||||||
|
const handleDelete = async (id: number) => {
|
||||||
|
try {
|
||||||
|
// 删除的二次确认
|
||||||
|
await message.delConfirm()
|
||||||
|
// 发起删除
|
||||||
|
await TenantBalanceApi.deleteTenantPoints(id)
|
||||||
|
message.success(t('common.delSuccess'))
|
||||||
|
// 刷新列表
|
||||||
|
await getList()
|
||||||
|
} catch { }
|
||||||
|
}
|
||||||
|
</script>
|
||||||
206
src/views/system/tenantbalance/index.vue
Normal file
206
src/views/system/tenantbalance/index.vue
Normal file
@@ -0,0 +1,206 @@
|
|||||||
|
<template>
|
||||||
|
<ContentWrap>
|
||||||
|
<!-- 搜索工作栏 -->
|
||||||
|
<el-form class="-mb-15px" :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
|
||||||
|
<el-form-item label="积分余额" prop="balance">
|
||||||
|
<el-input v-model="queryParams.balance" placeholder="请输入当前积分余额" clearable @keyup.enter="handleQuery"
|
||||||
|
class="!w-240px" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="租户id" prop="id">
|
||||||
|
<el-input v-model="queryParams.id" placeholder="请输入租户id" clearable @keyup.enter="handleQuery"
|
||||||
|
class="!w-240px" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="租户名" prop="tenantName">
|
||||||
|
<el-input v-model="queryParams.tenantName" placeholder="请输入租户id" clearable @keyup.enter="handleQuery"
|
||||||
|
class="!w-240px" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="更新时间" prop="updatedAt">
|
||||||
|
<el-date-picker v-model="queryParams.updatedAt" value-format="YYYY-MM-DD" type="date" placeholder="选择更新时间"
|
||||||
|
clearable class="!w-240px" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item style="width: 100%;">
|
||||||
|
<div class="center-align">
|
||||||
|
<div>
|
||||||
|
<el-button @click="handleQuery">
|
||||||
|
<Icon icon="ep:search" class="mr-5px" /> 搜索
|
||||||
|
</el-button>
|
||||||
|
<el-button @click="resetQuery">
|
||||||
|
<Icon icon="ep:refresh" class="mr-5px" /> 重置
|
||||||
|
</el-button>
|
||||||
|
<el-button type="primary" plain @click="openForm('create')" v-hasPermi="['system:tenant-balance:create']">
|
||||||
|
<Icon icon="ep:plus" class="mr-5px" /> 新增
|
||||||
|
</el-button>
|
||||||
|
<el-button type="success" plain @click="handleExport" :loading="exportLoading"
|
||||||
|
v-hasPermi="['system:tenant-balance:export']">
|
||||||
|
<Icon icon="ep:download" class="mr-5px" /> 导出
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-if="userStore.getUser.id !== 1" class="balance-text">余额:{{ mount }}</div>
|
||||||
|
</div>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
</ContentWrap>
|
||||||
|
|
||||||
|
<!-- 列表 -->
|
||||||
|
<ContentWrap>
|
||||||
|
<el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true" highlight-current-row
|
||||||
|
@current-change="handleCurrentChange">
|
||||||
|
<el-table-column label="当前积分余额" align="center" prop="balance" />
|
||||||
|
<el-table-column label="租户名" align="center" prop="tenantName" />
|
||||||
|
<el-table-column label="租户id" align="center" prop="id" />
|
||||||
|
<el-table-column label="更新时间" align="center" prop="updatedAt" :formatter="dateFormatter" width="180px" />
|
||||||
|
<el-table-column label="描述" align="center" prop="remark" />
|
||||||
|
<el-table-column label="操作" align="center" min-width="120px">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-button link type="primary" @click="openForm('update', scope.row.id)"
|
||||||
|
v-hasPermi="['system:tenant-balance:update']">
|
||||||
|
充值
|
||||||
|
</el-button>
|
||||||
|
<el-button link type="primary" @click="openForm('transfer', scope.row.id)"
|
||||||
|
v-hasPermi="['system:tenant-balance:transfer']">
|
||||||
|
转账
|
||||||
|
</el-button>
|
||||||
|
<el-button link type="danger" @click="handleDelete(scope.row.id)"
|
||||||
|
v-hasPermi="['system:tenant-balance:delete']">
|
||||||
|
删除
|
||||||
|
</el-button>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
<!-- 分页 -->
|
||||||
|
<Pagination :total="total" v-model:page="queryParams.pageNo" v-model:limit="queryParams.pageSize"
|
||||||
|
@pagination="getList" />
|
||||||
|
</ContentWrap>
|
||||||
|
|
||||||
|
<!-- 表单弹窗:添加/修改 -->
|
||||||
|
<TenantBalanceForm ref="formRef" @success="getList" />
|
||||||
|
<!-- 子表的列表 -->
|
||||||
|
<ContentWrap>
|
||||||
|
<el-tabs model-value="tenantPoints">
|
||||||
|
<el-tab-pane label="变动记录" name="tenantPoints">
|
||||||
|
<TenantPointsList :tenant-id="currentRow.id" />
|
||||||
|
</el-tab-pane>
|
||||||
|
</el-tabs>
|
||||||
|
</ContentWrap>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { dateFormatter } from '@/utils/formatTime'
|
||||||
|
import download from '@/utils/download'
|
||||||
|
import { TenantBalanceApi, TenantBalanceVO } from '@/api/system/tenantbalance'
|
||||||
|
import TenantBalanceForm from './TenantBalanceForm.vue'
|
||||||
|
import TenantPointsList from './components/TenantPointsList.vue'
|
||||||
|
import { checkPermi } from '@/utils/permission'
|
||||||
|
|
||||||
|
import { useUserStore } from '@/store/modules/user'
|
||||||
|
const userStore = ref(useUserStore())
|
||||||
|
/** 租户余额 列表 */
|
||||||
|
defineOptions({ name: 'TenantBalance' })
|
||||||
|
|
||||||
|
const message = useMessage() // 消息弹窗
|
||||||
|
const { t } = useI18n() // 国际化
|
||||||
|
|
||||||
|
const loading = ref(true) // 列表的加载中
|
||||||
|
const list = ref<TenantBalanceVO[]>([]) // 列表的数据
|
||||||
|
const total = ref(0) // 列表的总页数
|
||||||
|
const queryParams = reactive({
|
||||||
|
pageNo: 1,
|
||||||
|
pageSize: 10,
|
||||||
|
balance: undefined,
|
||||||
|
version: undefined,
|
||||||
|
updatedAt: undefined,
|
||||||
|
updatedAt: []
|
||||||
|
})
|
||||||
|
const queryFormRef = ref() // 搜索的表单
|
||||||
|
const exportLoading = ref(false) // 导出的加载中
|
||||||
|
const mount = ref(0)
|
||||||
|
/** 查询列表 */
|
||||||
|
const getList = async () => {
|
||||||
|
loading.value = true
|
||||||
|
|
||||||
|
try {
|
||||||
|
let data = {}
|
||||||
|
console.log(checkPermi(['system:tenant-balance:self-subordinate']))
|
||||||
|
if (userStore.value.getUser.id !== 1) {
|
||||||
|
getMount()
|
||||||
|
data = await TenantBalanceApi.getSubordinateaMountPage(queryParams)
|
||||||
|
} else {
|
||||||
|
data = await TenantBalanceApi.getTenantBalancePage(queryParams)
|
||||||
|
}
|
||||||
|
// if (checkPermi(['system:tenant-balance:self-subordinate'])) {
|
||||||
|
|
||||||
|
// } else {
|
||||||
|
|
||||||
|
// }
|
||||||
|
|
||||||
|
list.value = data.list
|
||||||
|
total.value = data.total
|
||||||
|
} finally {
|
||||||
|
loading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/** 查询列表 */
|
||||||
|
const getMount = async () => {
|
||||||
|
const data = await TenantBalanceApi.getselfamount()
|
||||||
|
mount.value = data.balance
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
/** 搜索按钮操作 */
|
||||||
|
const handleQuery = () => {
|
||||||
|
queryParams.pageNo = 1
|
||||||
|
getList()
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 重置按钮操作 */
|
||||||
|
const resetQuery = () => {
|
||||||
|
queryFormRef.value.resetFields()
|
||||||
|
handleQuery()
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 添加/修改操作 */
|
||||||
|
const formRef = ref()
|
||||||
|
const openForm = (type: string, id?: number) => {
|
||||||
|
formRef.value.open(type, id)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 删除按钮操作 */
|
||||||
|
const handleDelete = async (id: number) => {
|
||||||
|
try {
|
||||||
|
// 删除的二次确认
|
||||||
|
await message.delConfirm()
|
||||||
|
// 发起删除
|
||||||
|
await TenantBalanceApi.deleteTenantBalance(id)
|
||||||
|
message.success(t('common.delSuccess'))
|
||||||
|
// 刷新列表
|
||||||
|
await getList()
|
||||||
|
} catch { }
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 导出按钮操作 */
|
||||||
|
const handleExport = async () => {
|
||||||
|
try {
|
||||||
|
// 导出的二次确认
|
||||||
|
await message.exportConfirm()
|
||||||
|
// 发起导出
|
||||||
|
exportLoading.value = true
|
||||||
|
const data = await TenantBalanceApi.exportTenantBalance(queryParams)
|
||||||
|
download.excel(data, '租户余额.xls')
|
||||||
|
} catch {
|
||||||
|
} finally {
|
||||||
|
exportLoading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 选中行操作 */
|
||||||
|
const currentRow = ref({}) // 选中行
|
||||||
|
const handleCurrentChange = (row) => {
|
||||||
|
currentRow.value = row
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 初始化 **/
|
||||||
|
onMounted(() => {
|
||||||
|
getList()
|
||||||
|
})
|
||||||
|
</script>
|
||||||
129
src/views/system/tenantpoints/TenantPointsForm.vue
Normal file
129
src/views/system/tenantpoints/TenantPointsForm.vue
Normal file
@@ -0,0 +1,129 @@
|
|||||||
|
<template>
|
||||||
|
<Dialog :title="dialogTitle" v-model="dialogVisible">
|
||||||
|
<el-form ref="formRef" :model="formData" :rules="formRules" label-width="100px" v-loading="formLoading">
|
||||||
|
<el-form-item label="本次变动点数,正加负减" prop="points">
|
||||||
|
<el-input v-model="formData.points" placeholder="请输入本次变动点数,正加负减" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="变动后余额快照(冗余)" prop="balance">
|
||||||
|
<el-input v-model="formData.balance" placeholder="请输入变动后余额快照(冗余)" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="变动类型,如 RECHARGE, CONSUME, TRANSFER_OUT, TRANSFER_IN" prop="type">
|
||||||
|
<el-select v-model="formData.type" placeholder="请选择变动类型,如 RECHARGE, CONSUME, TRANSFER_OUT, TRANSFER_IN">
|
||||||
|
<el-option label="请选择字典生成" value="" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="备注" prop="description">
|
||||||
|
<Editor v-model="formData.remark" height="150px" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="订单 Id/业务单号" prop="orderId">
|
||||||
|
<el-input v-model="formData.orderId" placeholder="请输入订单 Id/业务单号" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="业务流水号(转账、订单等唯一标识)" prop="bizNo">
|
||||||
|
<el-input v-model="formData.bizNo" placeholder="请输入业务流水号(转账、订单等唯一标识)" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="操作人 Id" prop="operatorId">
|
||||||
|
<el-input v-model="formData.operatorId" placeholder="请输入操作人 Id" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="目标租户 Id(转账使用)" prop="targetTenantId">
|
||||||
|
<el-input v-model="formData.targetTenantId" placeholder="请输入目标租户 Id(转账使用)" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="创建时间" prop="createdAt">
|
||||||
|
<el-date-picker v-model="formData.createdAt" type="date" value-format="x" placeholder="选择创建时间" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
<template #footer>
|
||||||
|
<el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button>
|
||||||
|
<el-button @click="dialogVisible = false">取 消</el-button>
|
||||||
|
</template>
|
||||||
|
</Dialog>
|
||||||
|
</template>
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { TenantPointsApi, TenantPointsVO } from '@/api/system/tenantpoints'
|
||||||
|
|
||||||
|
/** 租户积分记录 表单 */
|
||||||
|
defineOptions({ name: 'TenantPointsForm' })
|
||||||
|
|
||||||
|
const { t } = useI18n() // 国际化
|
||||||
|
const message = useMessage() // 消息弹窗
|
||||||
|
|
||||||
|
const dialogVisible = ref(false) // 弹窗的是否展示
|
||||||
|
const dialogTitle = ref('') // 弹窗的标题
|
||||||
|
const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用
|
||||||
|
const formType = ref('') // 表单的类型:create - 新增;update - 修改
|
||||||
|
const formData = ref({
|
||||||
|
id: undefined,
|
||||||
|
points: undefined,
|
||||||
|
balance: undefined,
|
||||||
|
type: undefined,
|
||||||
|
remark: undefined,
|
||||||
|
orderId: undefined,
|
||||||
|
bizNo: undefined,
|
||||||
|
operatorId: undefined,
|
||||||
|
targetTenantId: undefined,
|
||||||
|
createdAt: undefined
|
||||||
|
})
|
||||||
|
const formRules = reactive({
|
||||||
|
points: [{ required: true, message: '本次变动点数,正加负减不能为空', trigger: 'blur' }],
|
||||||
|
createdAt: [{ required: true, message: '创建时间不能为空', trigger: 'blur' }]
|
||||||
|
})
|
||||||
|
const formRef = ref() // 表单 Ref
|
||||||
|
|
||||||
|
/** 打开弹窗 */
|
||||||
|
const open = async (type: string, id?: number) => {
|
||||||
|
dialogVisible.value = true
|
||||||
|
dialogTitle.value = t('action.' + type)
|
||||||
|
formType.value = type
|
||||||
|
resetForm()
|
||||||
|
// 修改时,设置数据
|
||||||
|
if (id) {
|
||||||
|
formLoading.value = true
|
||||||
|
try {
|
||||||
|
formData.value = await TenantPointsApi.getTenantPoints(id)
|
||||||
|
} finally {
|
||||||
|
formLoading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
defineExpose({ open }) // 提供 open 方法,用于打开弹窗
|
||||||
|
|
||||||
|
/** 提交表单 */
|
||||||
|
const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调
|
||||||
|
const submitForm = async () => {
|
||||||
|
// 校验表单
|
||||||
|
await formRef.value.validate()
|
||||||
|
// 提交请求
|
||||||
|
formLoading.value = true
|
||||||
|
try {
|
||||||
|
const data = formData.value as unknown as TenantPointsVO
|
||||||
|
if (formType.value === 'create') {
|
||||||
|
await TenantPointsApi.createTenantPoints(data)
|
||||||
|
message.success(t('common.createSuccess'))
|
||||||
|
} else {
|
||||||
|
await TenantPointsApi.updateTenantPoints(data)
|
||||||
|
message.success(t('common.updateSuccess'))
|
||||||
|
}
|
||||||
|
dialogVisible.value = false
|
||||||
|
// 发送操作成功的事件
|
||||||
|
emit('success')
|
||||||
|
} finally {
|
||||||
|
formLoading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 重置表单 */
|
||||||
|
const resetForm = () => {
|
||||||
|
formData.value = {
|
||||||
|
id: undefined,
|
||||||
|
points: undefined,
|
||||||
|
balance: undefined,
|
||||||
|
type: undefined,
|
||||||
|
description: undefined,
|
||||||
|
orderId: undefined,
|
||||||
|
bizNo: undefined,
|
||||||
|
operatorId: undefined,
|
||||||
|
targetTenantId: undefined,
|
||||||
|
createdAt: undefined
|
||||||
|
}
|
||||||
|
formRef.value?.resetFields()
|
||||||
|
}
|
||||||
|
</script>
|
||||||
198
src/views/system/tenantpoints/index.vue
Normal file
198
src/views/system/tenantpoints/index.vue
Normal file
@@ -0,0 +1,198 @@
|
|||||||
|
<template>
|
||||||
|
<ContentWrap>
|
||||||
|
<!-- 搜索工作栏 -->
|
||||||
|
<el-form class="-mb-15px" :model="queryParams" ref="queryFormRef" :inline="true" label-width="120px">
|
||||||
|
<!-- <el-form-item label="金额" prop="points">
|
||||||
|
<el-input v-model="queryParams.points" placeholder="请输入金额(正加负减)" clearable @keyup.enter="handleQuery"
|
||||||
|
class="!w-240px" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="变动后余额" prop="balance">
|
||||||
|
<el-input v-model="queryParams.balance" placeholder="请输入变动后余额(冗余)" clearable @keyup.enter="handleQuery"
|
||||||
|
class="!w-240px" />
|
||||||
|
</el-form-item> -->
|
||||||
|
<el-form-item label="类型" prop="type">
|
||||||
|
<el-select v-model="queryParams.type" placeholder="请选择类型" clearable class="!w-240px">
|
||||||
|
<el-option v-for="(dict, index) in getIntDictOptions(DICT_TYPE.PAY_TYPE)" :key="index" :label="dict.label"
|
||||||
|
:value="dict.label" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="订单 Id" prop="orderId">
|
||||||
|
<el-input v-model="queryParams.orderId" placeholder="请输入订单 Id / 业务单号" clearable @keyup.enter="handleQuery"
|
||||||
|
class="!w-240px" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="业务流水号" prop="bizNo">
|
||||||
|
<el-input v-model="queryParams.bizNo" placeholder="请输入业务流水号(转账、订单等唯一标识)" clearable @keyup.enter="handleQuery"
|
||||||
|
class="!w-240px" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="操作人 Id" prop="operatorId">
|
||||||
|
<el-input v-model="queryParams.operatorId" placeholder="请输入操作人 Id" clearable @keyup.enter="handleQuery"
|
||||||
|
class="!w-240px" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="目标租户 Id" prop="targetTenantId">
|
||||||
|
<el-input v-model="queryParams.targetTenantId" placeholder="请输入目标租户 Id(转账使用)" clearable
|
||||||
|
@keyup.enter="handleQuery" class="!w-240px" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="创建时间" prop="createdAt">
|
||||||
|
<el-date-picker v-model="queryParams.createdAt" value-format="YYYY-MM-DD HH:mm:ss" type="daterange"
|
||||||
|
start-placeholder="开始日期" end-placeholder="结束日期"
|
||||||
|
:default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" class="!w-240px" />
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<!-- <el-form-item label="描述/备注" prop="remark">
|
||||||
|
<el-input v-model="queryParams.remark" placeholder="请输入描述或备注" clearable @keyup.enter="handleQuery"
|
||||||
|
class="!w-240px" />
|
||||||
|
</el-form-item> -->
|
||||||
|
|
||||||
|
<el-form-item>
|
||||||
|
<el-button @click="handleQuery">
|
||||||
|
<Icon icon="ep:search" class="mr-5px" /> 搜索
|
||||||
|
</el-button>
|
||||||
|
<el-button @click="resetQuery">
|
||||||
|
<Icon icon="ep:refresh" class="mr-5px" /> 重置
|
||||||
|
</el-button>
|
||||||
|
<!-- <el-button type="primary" plain @click="openForm('create')" v-hasPermi="['system:tenant-points:create']">
|
||||||
|
<Icon icon="ep:plus" class="mr-5px" /> 新增
|
||||||
|
</el-button> -->
|
||||||
|
<el-button type="success" plain @click="handleExport" :loading="exportLoading"
|
||||||
|
v-hasPermi="['system:tenant-points:export']">
|
||||||
|
<Icon icon="ep:download" class="mr-5px" /> 导出
|
||||||
|
</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
</ContentWrap>
|
||||||
|
|
||||||
|
<!-- 列表 -->
|
||||||
|
<ContentWrap>
|
||||||
|
<el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true">
|
||||||
|
<!-- 列头按你给的短名称展示,prop 对应后端字段 -->
|
||||||
|
<el-table-column label="金额" align="center" prop="points" />
|
||||||
|
<el-table-column label="变动后余额" align="center" prop="balance" />
|
||||||
|
<el-table-column label="类型" align="center" prop="type" />
|
||||||
|
|
||||||
|
<el-table-column label="描述" align="center" prop="description" />
|
||||||
|
<el-table-column label="订单 Id/业务单号" align="center" prop="orderId" />
|
||||||
|
<el-table-column label="业务流水号" align="center" prop="bizNo" />
|
||||||
|
<el-table-column label="操作人 Id" align="center" prop="operatorId" />
|
||||||
|
<el-table-column label="目标租户Id" align="center" prop="targetTenantId" />
|
||||||
|
<el-table-column label="创建时间" align="center" prop="createdAt" :formatter="dateFormatter" width="180px" />
|
||||||
|
<el-table-column label="备注" align="center" prop="remark" />
|
||||||
|
<!-- <el-table-column label="操作" align="center" min-width="120px">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-button link type="primary" @click="openForm('update', scope.row.id)"
|
||||||
|
v-hasPermi="['system:tenant-points:update']">
|
||||||
|
编辑
|
||||||
|
</el-button>
|
||||||
|
<el-button link type="danger" @click="handleDelete(scope.row.id)"
|
||||||
|
v-hasPermi="['system:tenant-points:delete']">
|
||||||
|
删除
|
||||||
|
</el-button>
|
||||||
|
</template>
|
||||||
|
</el-table-column> -->
|
||||||
|
</el-table>
|
||||||
|
<!-- 分页 -->
|
||||||
|
<Pagination :total="total" v-model:page="queryParams.pageNo" v-model:limit="queryParams.pageSize"
|
||||||
|
@pagination="getList" />
|
||||||
|
</ContentWrap>
|
||||||
|
|
||||||
|
<!-- 表单弹窗:添加/修改 -->
|
||||||
|
<TenantPointsForm ref="formRef" @success="getList" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
|
||||||
|
import { dateFormatter } from '@/utils/formatTime'
|
||||||
|
import download from '@/utils/download'
|
||||||
|
import { TenantPointsApi, TenantPointsVO } from '@/api/system/tenantpoints'
|
||||||
|
import TenantPointsForm from './TenantPointsForm.vue'
|
||||||
|
|
||||||
|
/** 租户积分记录 列表 */
|
||||||
|
defineOptions({ name: 'TenantPoints' })
|
||||||
|
|
||||||
|
const message = useMessage() // 消息弹窗
|
||||||
|
const { t } = useI18n() // 国际化
|
||||||
|
|
||||||
|
const loading = ref(true) // 列表的加载中
|
||||||
|
const list = ref<TenantPointsVO[]>([]) // 列表的数据
|
||||||
|
const total = ref(0) // 列表的总页数
|
||||||
|
const queryParams = reactive({
|
||||||
|
pageNo: 1,
|
||||||
|
pageSize: 10,
|
||||||
|
points: undefined,
|
||||||
|
balance: undefined,
|
||||||
|
type: undefined,
|
||||||
|
remark: undefined, // 兼容后端的 remark 字段
|
||||||
|
description: undefined, // 如果后端有 description,可用于搜索过滤
|
||||||
|
orderId: undefined,
|
||||||
|
bizNo: undefined,
|
||||||
|
operatorId: undefined,
|
||||||
|
targetTenantId: undefined,
|
||||||
|
createdAt: undefined,
|
||||||
|
createdAtArr: [] // 保留原来的数组字段名兼容用(如果你用范围)
|
||||||
|
})
|
||||||
|
const queryFormRef = ref() // 搜索的表单
|
||||||
|
const exportLoading = ref(false) // 导出的加载中
|
||||||
|
|
||||||
|
/** 查询列表 */
|
||||||
|
const getList = async () => {
|
||||||
|
loading.value = true
|
||||||
|
try {
|
||||||
|
|
||||||
|
const data = await TenantPointsApi.getTenantPointsPage(queryParams)
|
||||||
|
list.value = data.list
|
||||||
|
total.value = data.total
|
||||||
|
} finally {
|
||||||
|
loading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 搜索按钮操作 */
|
||||||
|
const handleQuery = () => {
|
||||||
|
queryParams.pageNo = 1
|
||||||
|
getList()
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 重置按钮操作 */
|
||||||
|
const resetQuery = () => {
|
||||||
|
queryFormRef.value.resetFields()
|
||||||
|
handleQuery()
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 添加/修改操作 */
|
||||||
|
const formRef = ref()
|
||||||
|
const openForm = (type: string, id?: number) => {
|
||||||
|
formRef.value.open(type, id)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 删除按钮操作 */
|
||||||
|
const handleDelete = async (id: number) => {
|
||||||
|
try {
|
||||||
|
// 删除的二次确认
|
||||||
|
await message.delConfirm()
|
||||||
|
// 发起删除
|
||||||
|
await TenantPointsApi.deleteTenantPoints(id)
|
||||||
|
message.success(t('common.delSuccess'))
|
||||||
|
// 刷新列表
|
||||||
|
await getList()
|
||||||
|
} catch { }
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 导出按钮操作 */
|
||||||
|
const handleExport = async () => {
|
||||||
|
try {
|
||||||
|
// 导出的二次确认
|
||||||
|
await message.exportConfirm()
|
||||||
|
// 发起导出
|
||||||
|
exportLoading.value = true
|
||||||
|
const data = await TenantPointsApi.exportTenantPoints(queryParams)
|
||||||
|
download.excel(data, '租户积分记录.xls')
|
||||||
|
} catch {
|
||||||
|
} finally {
|
||||||
|
exportLoading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 初始化 **/
|
||||||
|
onMounted(() => {
|
||||||
|
getList()
|
||||||
|
})
|
||||||
|
</script>
|
||||||
Reference in New Issue
Block a user