diff --git a/.lintstagedrc.mjs b/.lintstagedrc.mjs index 94b0192a7..2a5a5a1ae 100644 --- a/.lintstagedrc.mjs +++ b/.lintstagedrc.mjs @@ -15,6 +15,6 @@ export default { ], 'package.json': ['prettier --cache --write'], '{!(package)*.json,*.code-snippets,.!(browserslist)*rc}': [ - 'prettier --cache --write--parser json', + 'prettier --cache --write --parser json', ], }; diff --git a/.node-version b/.node-version index 48b14e6b2..ee5c24469 100644 --- a/.node-version +++ b/.node-version @@ -1 +1 @@ -20.14.0 +22.1.0 diff --git a/.vscode/settings.json b/.vscode/settings.json index 8b76b2762..46d853ffe 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -14,7 +14,7 @@ "editor.tabSize": 2, "editor.detectIndentation": false, "editor.cursorBlinking": "expand", - "editor.largeFileOptimizations": false, + "editor.largeFileOptimizations": true, "editor.accessibilitySupport": "off", "editor.cursorSmoothCaretAnimation": "on", "editor.guides.bracketPairs": "active", @@ -91,6 +91,7 @@ "**/bower_components": true, "**/.turbo": true, "**/.idea": true, + "**/.vitepress": true, "**/tmp": true, "**/.git": true, "**/.svn": true, @@ -112,6 +113,8 @@ "**/yarn.lock": true }, + "typescript.tsserver.exclude": ["**/node_modules", "**/dist", "**/.turbo"], + // search "search.searchEditor.singleClickBehaviour": "peekDefinition", "search.followSymlinks": false, diff --git a/apps/web-antd/.env b/apps/web-antd/.env index 7cb021270..6b960186e 100644 --- a/apps/web-antd/.env +++ b/apps/web-antd/.env @@ -21,3 +21,6 @@ VITE_APP_DOCALERT_ENABLE=true # 百度统计 VITE_APP_BAIDU_CODE = e98f2eab6ceb8688bc6d8fc5332ff093 + +# GoView域名 +VITE_GOVIEW_URL='http://127.0.0.1:3000' diff --git a/apps/web-antd/package.json b/apps/web-antd/package.json index 0e5589863..e5c1e01d6 100644 --- a/apps/web-antd/package.json +++ b/apps/web-antd/package.json @@ -44,6 +44,7 @@ "@vben/types": "workspace:*", "@vben/utils": "workspace:*", "@vueuse/core": "catalog:", + "@vueuse/integrations": "catalog:", "ant-design-vue": "catalog:", "cropperjs": "catalog:", "crypto-js": "catalog:", diff --git a/apps/web-antd/src/adapter/vxe-table.ts b/apps/web-antd/src/adapter/vxe-table.ts index 545245a78..2b73ff296 100644 --- a/apps/web-antd/src/adapter/vxe-table.ts +++ b/apps/web-antd/src/adapter/vxe-table.ts @@ -30,7 +30,7 @@ setupVbenVxeTable({ }, toolbarConfig: { import: false, // 是否导入 - export: false, // 四否导出 + export: false, // 是否导出 refresh: true, // 是否刷新 print: false, // 是否打印 zoom: true, // 是否缩放 @@ -259,6 +259,21 @@ setupVbenVxeTable({ // 这里可以自行扩展 vxe-table 的全局配置,比如自定义格式化 // vxeUI.formats.add + vxeUI.formats.add('formatAmount', { + cellFormatMethod({ cellValue }, digits = 2) { + if (cellValue === null || cellValue === undefined) { + return ''; + } + if (isString(cellValue)) { + cellValue = Number.parseFloat(cellValue); + } + // 如果非 number,则直接返回空串 + if (Number.isNaN(cellValue)) { + return ''; + } + return cellValue.toFixed(digits); + }, + }); }, useVbenForm, }); diff --git a/apps/web-antd/src/api/bpm/category/index.ts b/apps/web-antd/src/api/bpm/category/index.ts index 852b2a868..1519c758c 100644 --- a/apps/web-antd/src/api/bpm/category/index.ts +++ b/apps/web-antd/src/api/bpm/category/index.ts @@ -1,5 +1,7 @@ import type { PageParam, PageResult } from '@vben/request'; +import type { BpmModelApi } from '#/api/bpm/model'; + import { requestClient } from '#/api/request'; export namespace BpmCategoryApi { @@ -11,6 +13,13 @@ export namespace BpmCategoryApi { status: number; sort: number; // 分类排序 } + + /** 模型分类信息 */ + export interface ModelCategoryInfo { + id: number; + name: string; + modelList: BpmModelApi.ModelVO[]; + } } /** 查询流程分类分页 */ @@ -30,15 +39,30 @@ export async function getCategory(id: number) { /** 新增流程分类 */ export async function createCategory(data: BpmCategoryApi.CategoryVO) { - return requestClient.post('/bpm/category/create', data); + return requestClient.post('/bpm/category/create', data); } /** 修改流程分类 */ export async function updateCategory(data: BpmCategoryApi.CategoryVO) { - return requestClient.put('/bpm/category/update', data); + return requestClient.put('/bpm/category/update', data); } /** 删除流程分类 */ export async function deleteCategory(id: number) { - return requestClient.delete(`/bpm/category/delete?id=${id}`); + return requestClient.delete(`/bpm/category/delete?id=${id}`); +} + +/** 查询流程分类列表 */ +export async function getCategorySimpleList() { + return requestClient.get( + `/bpm/category/simple-list`, + ); +} + +/** 批量修改流程分类的排序 */ +export async function updateCategorySortBatch(ids: number[]) { + const params = ids.join(','); + return requestClient.put( + `/bpm/category/update-sort-batch?ids=${params}`, + ); } diff --git a/apps/web-antd/src/api/bpm/model/index.ts b/apps/web-antd/src/api/bpm/model/index.ts new file mode 100644 index 000000000..06c444e04 --- /dev/null +++ b/apps/web-antd/src/api/bpm/model/index.ts @@ -0,0 +1,107 @@ +import { requestClient } from '#/api/request'; + +export namespace BpmModelApi { + /** 用户信息 TODO 这个是不是可以抽取出来定义在公共模块 */ + export interface UserInfo { + id: number; + nickname: string; + avatar?: string; + deptId?: number; + deptName?: string; + } + /** 流程定义 VO */ + export interface ProcessDefinitionVO { + id: string; + version: number; + deploymentTime: number; + suspensionState: number; + formType?: number; + } + + /** 流程模型 VO */ + export interface ModelVO { + id: number; + key: string; + name: string; + icon?: string; + description: string; + category: string; + formName: string; + formType: number; + formId: number; + formCustomCreatePath: string; + formCustomViewPath: string; + processDefinition: ProcessDefinitionVO; + status: number; + remark: string; + createTime: string; + bpmnXml: string; + startUsers?: UserInfo[]; + } + + /** 模型分类信息 */ + export interface ModelCategoryInfo { + id: number; + name: string; + modelList: ModelVO[]; + } +} + +/** 获取流程模型列表 */ +export async function getModelList(name: string | undefined) { + return requestClient.get('/bpm/model/list', { + params: { name }, + }); +} + +/** 获取流程模型详情 */ +export async function getModel(id: string) { + return requestClient.get(`/bpm/model/get?id=${id}`); +} + +/** 更新流程模型 */ +export async function updateModel(data: BpmModelApi.ModelVO) { + return requestClient.put('/bpm/model/update', data); +} + +/** 批量修改流程模型排序 */ +export async function updateModelSortBatch(ids: number[]) { + const params = ids.join(','); + return requestClient.put( + `/bpm/model/update-sort-batch?ids=${params}`, + ); +} + +/** 更新流程模型的 BPMN XML */ +export async function updateModelBpmn(data: BpmModelApi.ModelVO) { + return requestClient.put('/bpm/model/update-bpmn', data); +} + +/** 更新流程模型状态 */ +export async function updateModelState(id: number, state: number) { + const data = { + id, + state, + }; + return requestClient.put('/bpm/model/update-state', data); +} + +/** 创建流程模型 */ +export async function createModel(data: BpmModelApi.ModelVO) { + return requestClient.post('/bpm/model/create', data); +} + +/** 删除流程模型 */ +export async function deleteModel(id: number) { + return requestClient.delete(`/bpm/model/delete?id=${id}`); +} + +/** 部署流程模型 */ +export async function deployModel(id: number) { + return requestClient.post(`/bpm/model/deploy?id=${id}`); +} + +/** 清理流程模型 */ +export async function cleanModel(id: number) { + return requestClient.delete(`/bpm/model/clean?id=${id}`); +} diff --git a/apps/web-antd/src/api/crm/business/index.ts b/apps/web-antd/src/api/crm/business/index.ts new file mode 100644 index 000000000..ec544b92d --- /dev/null +++ b/apps/web-antd/src/api/crm/business/index.ts @@ -0,0 +1,118 @@ +import type { PageParam, PageResult } from '@vben/request'; + +import type { CrmPermissionApi } from '#/api/crm/permission'; + +import { requestClient } from '#/api/request'; + +export namespace CrmBusinessApi { + /** 商机产品信息 */ + export interface BusinessProduct { + id: number; + productId: number; + productName: string; + productNo: string; + productUnit: number; + productPrice: number; + businessPrice: number; + count: number; + totalPrice: number; + } + + /** 商机信息 */ + export interface Business { + id: number; + name: string; + customerId: number; + customerName?: string; + followUpStatus: boolean; + contactLastTime: Date; + contactNextTime: Date; + ownerUserId: number; + ownerUserName?: string; // 负责人的用户名称 + ownerUserDept?: string; // 负责人的部门名称 + statusTypeId: number; + statusTypeName?: string; + statusId: number; + statusName?: string; + endStatus: number; + endRemark: string; + dealTime: Date; + totalProductPrice: number; + totalPrice: number; + discountPercent: number; + remark: string; + creator: string; // 创建人 + creatorName?: string; // 创建人名称 + createTime: Date; // 创建时间 + updateTime: Date; // 更新时间 + products?: BusinessProduct[]; + } +} + +/** 查询商机列表 */ +export function getBusinessPage(params: PageParam) { + return requestClient.get>( + '/crm/business/page', + { params }, + ); +} + +/** 查询商机列表,基于指定客户 */ +export function getBusinessPageByCustomer(params: PageParam) { + return requestClient.get>( + '/crm/business/page-by-customer', + { params }, + ); +} + +/** 查询商机详情 */ +export function getBusiness(id: number) { + return requestClient.get( + `/crm/business/get?id=${id}`, + ); +} + +/** 获得商机列表(精简) */ +export function getSimpleBusinessList() { + return requestClient.get( + '/crm/business/simple-all-list', + ); +} + +/** 新增商机 */ +export function createBusiness(data: CrmBusinessApi.Business) { + return requestClient.post('/crm/business/create', data); +} + +/** 修改商机 */ +export function updateBusiness(data: CrmBusinessApi.Business) { + return requestClient.put('/crm/business/update', data); +} + +/** 修改商机状态 */ +export function updateBusinessStatus(data: CrmBusinessApi.Business) { + return requestClient.put('/crm/business/update-status', data); +} + +/** 删除商机 */ +export function deleteBusiness(id: number) { + return requestClient.delete(`/crm/business/delete?id=${id}`); +} + +/** 导出商机 */ +export function exportBusiness(params: any) { + return requestClient.download('/crm/business/export-excel', params); +} + +/** 联系人关联商机列表 */ +export function getBusinessPageByContact(params: PageParam) { + return requestClient.get>( + '/crm/business/page-by-contact', + { params }, + ); +} + +/** 商机转移 */ +export function transferBusiness(data: CrmPermissionApi.TransferReq) { + return requestClient.put('/crm/business/transfer', data); +} diff --git a/apps/web-antd/src/api/crm/business/status/index.ts b/apps/web-antd/src/api/crm/business/status/index.ts new file mode 100644 index 000000000..e1c8cfea3 --- /dev/null +++ b/apps/web-antd/src/api/crm/business/status/index.ts @@ -0,0 +1,91 @@ +import type { PageParam, PageResult } from '@vben/request'; + +import { requestClient } from '#/api/request'; + +export namespace CrmBusinessStatusApi { + /** 商机状态信息 */ + export interface BusinessStatus { + id: number; + name: string; + percent: number; + } + + /** 商机状态组信息 */ + export interface BusinessStatusType { + id: number; + name: string; + deptIds: number[]; + statuses?: BusinessStatus[]; + } + + /** 默认商机状态 */ + export const DEFAULT_STATUSES = [ + { + endStatus: 1, + key: '结束', + name: '赢单', + percent: 100, + }, + { + endStatus: 2, + key: '结束', + name: '输单', + percent: 0, + }, + { + endStatus: 3, + key: '结束', + name: '无效', + percent: 0, + }, + ] as const; +} + +/** 查询商机状态组列表 */ +export function getBusinessStatusPage(params: PageParam) { + return requestClient.get>( + '/crm/business-status/page', + { params }, + ); +} + +/** 新增商机状态组 */ +export function createBusinessStatus( + data: CrmBusinessStatusApi.BusinessStatusType, +) { + return requestClient.post('/crm/business-status/create', data); +} + +/** 修改商机状态组 */ +export function updateBusinessStatus( + data: CrmBusinessStatusApi.BusinessStatusType, +) { + return requestClient.put('/crm/business-status/update', data); +} + +/** 查询商机状态类型详情 */ +export function getBusinessStatus(id: number) { + return requestClient.get( + `/crm/business-status/get?id=${id}`, + ); +} + +/** 删除商机状态 */ +export function deleteBusinessStatus(id: number) { + return requestClient.delete(`/crm/business-status/delete?id=${id}`); +} + +/** 获得商机状态组列表 */ +export function getBusinessStatusTypeSimpleList() { + return requestClient.get( + '/crm/business-status/type-simple-list', + ); +} + +/** 获得商机阶段列表 */ +export function getBusinessStatusSimpleList(typeId: number) { + return requestClient.get( + '/crm/business-status/status-simple-list', + { params: { typeId } }, + ); +} diff --git a/apps/web-antd/src/api/crm/clue/index.ts b/apps/web-antd/src/api/crm/clue/index.ts new file mode 100644 index 000000000..9d3447b88 --- /dev/null +++ b/apps/web-antd/src/api/crm/clue/index.ts @@ -0,0 +1,86 @@ +import type { PageParam, PageResult } from '@vben/request'; + +import type { CrmPermissionApi } from '#/api/crm/permission'; + +import { requestClient } from '#/api/request'; + +export namespace CrmClueApi { + /** 线索信息 */ + export interface Clue { + id: number; // 编号 + name: string; // 线索名称 + followUpStatus: boolean; // 跟进状态 + contactLastTime: Date; // 最后跟进时间 + contactLastContent: string; // 最后跟进内容 + contactNextTime: Date; // 下次联系时间 + ownerUserId: number; // 负责人的用户编号 + ownerUserName?: string; // 负责人的用户名称 + ownerUserDept?: string; // 负责人的部门名称 + transformStatus: boolean; // 转化状态 + customerId: number; // 客户编号 + customerName?: string; // 客户名称 + mobile: string; // 手机号 + telephone: string; // 电话 + qq: string; // QQ + wechat: string; // wechat + email: string; // email + areaId: number; // 所在地 + areaName?: string; // 所在地名称 + detailAddress: string; // 详细地址 + industryId: number; // 所属行业 + level: number; // 客户等级 + source: number; // 客户来源 + remark: string; // 备注 + creator: string; // 创建人 + creatorName?: string; // 创建人名称 + createTime: Date; // 创建时间 + updateTime: Date; // 更新时间 + } +} + +/** 查询线索列表 */ +export function getCluePage(params: PageParam) { + return requestClient.get>('/crm/clue/page', { + params, + }); +} + +/** 查询线索详情 */ +export function getClue(id: number) { + return requestClient.get(`/crm/clue/get?id=${id}`); +} + +/** 新增线索 */ +export function createClue(data: CrmClueApi.Clue) { + return requestClient.post('/crm/clue/create', data); +} + +/** 修改线索 */ +export function updateClue(data: CrmClueApi.Clue) { + return requestClient.put('/crm/clue/update', data); +} + +/** 删除线索 */ +export function deleteClue(id: number) { + return requestClient.delete(`/crm/clue/delete?id=${id}`); +} + +/** 导出线索 */ +export function exportClue(params: any) { + return requestClient.download('/crm/clue/export-excel', params); +} + +/** 线索转移 */ +export function transferClue(data: CrmPermissionApi.TransferReq) { + return requestClient.put('/crm/clue/transfer', data); +} + +/** 线索转化为客户 */ +export function transformClue(id: number) { + return requestClient.put('/crm/clue/transform', { id }); +} + +/** 获得分配给我的、待跟进的线索数量 */ +export function getFollowClueCount() { + return requestClient.get('/crm/clue/follow-count'); +} diff --git a/apps/web-antd/src/api/crm/contact/index.ts b/apps/web-antd/src/api/crm/contact/index.ts new file mode 100644 index 000000000..62b5235b2 --- /dev/null +++ b/apps/web-antd/src/api/crm/contact/index.ts @@ -0,0 +1,140 @@ +import type { PageParam, PageResult } from '@vben/request'; + +import type { CrmPermissionApi } from '#/api/crm/permission'; + +import { requestClient } from '#/api/request'; + +export namespace CrmContactApi { + /** 联系人信息 */ + export interface Contact { + id: number; // 编号 + name: string; // 联系人名称 + customerId: number; // 客户编号 + customerName?: string; // 客户名称 + contactLastTime: Date; // 最后跟进时间 + contactLastContent: string; // 最后跟进内容 + contactNextTime: Date; // 下次联系时间 + ownerUserId: number; // 负责人的用户编号 + ownerUserName?: string; // 负责人的用户名称 + ownerUserDept?: string; // 负责人的部门名称 + mobile: string; // 手机号 + telephone: string; // 电话 + qq: string; // QQ + wechat: string; // wechat + email: string; // email + areaId: number; // 所在地 + areaName?: string; // 所在地名称 + detailAddress: string; // 详细地址 + sex: number; // 性别 + master: boolean; // 是否主联系人 + post: string; // 职务 + parentId: number; // 上级联系人编号 + parentName?: string; // 上级联系人名称 + remark: string; // 备注 + creator: string; // 创建人 + creatorName?: string; // 创建人名称 + createTime: Date; // 创建时间 + updateTime: Date; // 更新时间 + } + + /** 联系人商机关联请求 */ + export interface ContactBusinessReq { + contactId: number; + businessIds: number[]; + } + + /** 商机联系人关联请求 */ + export interface BusinessContactReq { + businessId: number; + contactIds: number[]; + } +} + +/** 查询联系人列表 */ +export function getContactPage(params: PageParam) { + return requestClient.get>( + '/crm/contact/page', + { params }, + ); +} + +/** 查询联系人列表,基于指定客户 */ +export function getContactPageByCustomer(params: PageParam) { + return requestClient.get>( + '/crm/contact/page-by-customer', + { params }, + ); +} + +/** 查询联系人列表,基于指定商机 */ +export function getContactPageByBusiness(params: PageParam) { + return requestClient.get>( + '/crm/contact/page-by-business', + { params }, + ); +} + +/** 查询联系人详情 */ +export function getContact(id: number) { + return requestClient.get(`/crm/contact/get?id=${id}`); +} + +/** 新增联系人 */ +export function createContact(data: CrmContactApi.Contact) { + return requestClient.post('/crm/contact/create', data); +} + +/** 修改联系人 */ +export function updateContact(data: CrmContactApi.Contact) { + return requestClient.put('/crm/contact/update', data); +} + +/** 删除联系人 */ +export function deleteContact(id: number) { + return requestClient.delete(`/crm/contact/delete?id=${id}`); +} + +/** 导出联系人 */ +export function exportContact(params: any) { + return requestClient.download('/crm/contact/export-excel', params); +} + +/** 获得联系人列表(精简) */ +export function getSimpleContactList() { + return requestClient.get( + '/crm/contact/simple-all-list', + ); +} + +/** 批量新增联系人商机关联 */ +export function createContactBusinessList( + data: CrmContactApi.ContactBusinessReq, +) { + return requestClient.post('/crm/contact/create-business-list', data); +} + +/** 批量新增商机联系人关联 */ +export function createBusinessContactList( + data: CrmContactApi.BusinessContactReq, +) { + return requestClient.post('/crm/contact/create-business-list2', data); +} + +/** 解除联系人商机关联 */ +export function deleteContactBusinessList( + data: CrmContactApi.ContactBusinessReq, +) { + return requestClient.delete('/crm/contact/delete-business-list', { data }); +} + +/** 解除商机联系人关联 */ +export function deleteBusinessContactList( + data: CrmContactApi.BusinessContactReq, +) { + return requestClient.delete('/crm/contact/delete-business-list2', { data }); +} + +/** 联系人转移 */ +export function transferContact(data: CrmPermissionApi.TransferReq) { + return requestClient.put('/crm/contact/transfer', data); +} diff --git a/apps/web-antd/src/api/crm/contract/config/index.ts b/apps/web-antd/src/api/crm/contract/config/index.ts new file mode 100644 index 000000000..09dbdfe1d --- /dev/null +++ b/apps/web-antd/src/api/crm/contract/config/index.ts @@ -0,0 +1,21 @@ +import { requestClient } from '#/api/request'; + +export namespace CrmContractConfigApi { + /** 合同配置信息 */ + export interface Config { + notifyEnabled?: boolean; + notifyDays?: number; + } +} + +/** 获取合同配置 */ +export function getContractConfig() { + return requestClient.get( + '/crm/contract-config/get', + ); +} + +/** 更新合同配置 */ +export function saveContractConfig(data: CrmContractConfigApi.Config) { + return requestClient.put('/crm/contract-config/save', data); +} diff --git a/apps/web-antd/src/api/crm/contract/index.ts b/apps/web-antd/src/api/crm/contract/index.ts new file mode 100644 index 000000000..1ae165dd4 --- /dev/null +++ b/apps/web-antd/src/api/crm/contract/index.ts @@ -0,0 +1,132 @@ +import type { PageParam, PageResult } from '@vben/request'; + +import type { CrmPermissionApi } from '#/api/crm/permission'; + +import { requestClient } from '#/api/request'; + +export namespace CrmContractApi { + /** 合同产品信息 */ + export interface ContractProduct { + id: number; + productId: number; + productName: string; + productNo: string; + productUnit: number; + productPrice: number; + contractPrice: number; + count: number; + totalPrice: number; + } + + /** 合同信息 */ + export interface Contract { + id: number; + name: string; + no: string; + customerId: number; + customerName?: string; + businessId: number; + businessName: string; + contactLastTime: Date; + ownerUserId: number; + ownerUserName?: string; + ownerUserDeptName?: string; + processInstanceId: number; + auditStatus: number; + orderDate: Date; + startTime: Date; + endTime: Date; + totalProductPrice: number; + discountPercent: number; + totalPrice: number; + totalReceivablePrice: number; + signContactId: number; + signContactName?: string; + signUserId: number; + signUserName: string; + remark: string; + createTime?: Date; + creator: string; + creatorName: string; + updateTime?: Date; + products?: ContractProduct[]; + } +} + +/** 查询合同列表 */ +export function getContractPage(params: PageParam) { + return requestClient.get>( + '/crm/contract/page', + { params }, + ); +} + +/** 查询合同列表,基于指定客户 */ +export function getContractPageByCustomer(params: PageParam) { + return requestClient.get>( + '/crm/contract/page-by-customer', + { params }, + ); +} + +/** 查询合同列表,基于指定商机 */ +export function getContractPageByBusiness(params: PageParam) { + return requestClient.get>( + '/crm/contract/page-by-business', + { params }, + ); +} + +/** 查询合同详情 */ +export function getContract(id: number) { + return requestClient.get( + `/crm/contract/get?id=${id}`, + ); +} + +/** 查询合同下拉列表 */ +export function getContractSimpleList(customerId: number) { + return requestClient.get( + `/crm/contract/simple-list?customerId=${customerId}`, + ); +} + +/** 新增合同 */ +export function createContract(data: CrmContractApi.Contract) { + return requestClient.post('/crm/contract/create', data); +} + +/** 修改合同 */ +export function updateContract(data: CrmContractApi.Contract) { + return requestClient.put('/crm/contract/update', data); +} + +/** 删除合同 */ +export function deleteContract(id: number) { + return requestClient.delete(`/crm/contract/delete?id=${id}`); +} + +/** 导出合同 */ +export function exportContract(params: any) { + return requestClient.download('/crm/contract/export-excel', params); +} + +/** 提交审核 */ +export function submitContract(id: number) { + return requestClient.put(`/crm/contract/submit?id=${id}`); +} + +/** 合同转移 */ +export function transferContract(data: CrmPermissionApi.TransferReq) { + return requestClient.put('/crm/contract/transfer', data); +} + +/** 获得待审核合同数量 */ +export function getAuditContractCount() { + return requestClient.get('/crm/contract/audit-count'); +} + +/** 获得即将到期(提醒)的合同数量 */ +export function getRemindContractCount() { + return requestClient.get('/crm/contract/remind-count'); +} diff --git a/apps/web-antd/src/api/crm/customer/index.ts b/apps/web-antd/src/api/crm/customer/index.ts new file mode 100644 index 000000000..3f7faaab5 --- /dev/null +++ b/apps/web-antd/src/api/crm/customer/index.ts @@ -0,0 +1,146 @@ +import type { PageParam, PageResult } from '@vben/request'; + +import type { CrmPermissionApi } from '#/api/crm/permission'; + +import { requestClient } from '#/api/request'; + +export namespace CrmCustomerApi { + /** 客户信息 */ + export interface Customer { + id: number; // 编号 + name: string; // 客户名称 + followUpStatus: boolean; // 跟进状态 + contactLastTime: Date; // 最后跟进时间 + contactLastContent: string; // 最后跟进内容 + contactNextTime: Date; // 下次联系时间 + ownerUserId: number; // 负责人的用户编号 + ownerUserName?: string; // 负责人的用户名称 + ownerUserDept?: string; // 负责人的部门名称 + lockStatus?: boolean; + dealStatus?: boolean; + mobile: string; // 手机号 + telephone: string; // 电话 + qq: string; // QQ + wechat: string; // wechat + email: string; // email + areaId: number; // 所在地 + areaName?: string; // 所在地名称 + detailAddress: string; // 详细地址 + industryId: number; // 所属行业 + level: number; // 客户等级 + source: number; // 客户来源 + remark: string; // 备注 + creator: string; // 创建人 + creatorName?: string; // 创建人名称 + createTime: Date; // 创建时间 + updateTime: Date; // 更新时间 + } +} + +/** 查询客户列表 */ +export function getCustomerPage(params: PageParam) { + return requestClient.get>( + '/crm/customer/page', + { params }, + ); +} + +/** 查询客户详情 */ +export function getCustomer(id: number) { + return requestClient.get( + `/crm/customer/get?id=${id}`, + ); +} + +/** 新增客户 */ +export function createCustomer(data: CrmCustomerApi.Customer) { + return requestClient.post('/crm/customer/create', data); +} + +/** 修改客户 */ +export function updateCustomer(data: CrmCustomerApi.Customer) { + return requestClient.put('/crm/customer/update', data); +} + +/** 删除客户 */ +export function deleteCustomer(id: number) { + return requestClient.delete(`/crm/customer/delete?id=${id}`); +} + +/** 导出客户 */ +export function exportCustomer(params: any) { + return requestClient.download('/crm/customer/export-excel', params); +} + +/** 下载客户导入模板 */ +export function importCustomerTemplate() { + return requestClient.download('/crm/customer/get-import-template'); +} + +/** 导入客户 */ +export function importCustomer(file: File) { + return requestClient.upload('/crm/customer/import', { file }); +} + +/** 获取客户精简信息列表 */ +export function getCustomerSimpleList() { + return requestClient.get( + '/crm/customer/simple-list', + ); +} + +/** 客户转移 */ +export function transferCustomer(data: CrmPermissionApi.TransferReq) { + return requestClient.put('/crm/customer/transfer', data); +} + +/** 锁定/解锁客户 */ +export function lockCustomer(id: number, lockStatus: boolean) { + return requestClient.put('/crm/customer/lock', { id, lockStatus }); +} + +/** 领取公海客户 */ +export function receiveCustomer(ids: number[]) { + return requestClient.put('/crm/customer/receive', { ids: ids.join(',') }); +} + +/** 分配公海给对应负责人 */ +export function distributeCustomer(ids: number[], ownerUserId: number) { + return requestClient.put('/crm/customer/distribute', { ids, ownerUserId }); +} + +/** 客户放入公海 */ +export function putCustomerPool(id: number) { + return requestClient.put(`/crm/customer/put-pool?id=${id}`); +} + +/** 更新客户的成交状态 */ +export function updateCustomerDealStatus(id: number, dealStatus: boolean) { + return requestClient.put('/crm/customer/update-deal-status', { + id, + dealStatus, + }); +} + +/** 进入公海客户提醒的客户列表 */ +export function getPutPoolRemindCustomerPage(params: PageParam) { + return requestClient.get>( + '/crm/customer/put-pool-remind-page', + { params }, + ); +} + +/** 获得待进入公海客户数量 */ +export function getPutPoolRemindCustomerCount() { + return requestClient.get('/crm/customer/put-pool-remind-count'); +} + +/** 获得今日需联系客户数量 */ +export function getTodayContactCustomerCount() { + return requestClient.get('/crm/customer/today-contact-count'); +} + +/** 获得分配给我、待跟进的线索数量的客户数量 */ +export function getFollowCustomerCount() { + return requestClient.get('/crm/customer/follow-count'); +} diff --git a/apps/web-antd/src/api/crm/customer/limitConfig/index.ts b/apps/web-antd/src/api/crm/customer/limitConfig/index.ts new file mode 100644 index 000000000..773255762 --- /dev/null +++ b/apps/web-antd/src/api/crm/customer/limitConfig/index.ts @@ -0,0 +1,58 @@ +import type { PageParam, PageResult } from '@vben/request'; + +import { requestClient } from '#/api/request'; + +export namespace CrmCustomerLimitConfigApi { + /** 客户限制配置 */ + export interface CustomerLimitConfig { + id?: number; + type?: number; + userIds?: string; + deptIds?: string; + maxCount?: number; + dealCountEnabled?: boolean; + } + + /** + * 客户限制配置类型 + */ + export enum LimitConfType { + /** 锁定客户数限制 */ + CUSTOMER_LOCK_LIMIT = 2, + /** 拥有客户数限制 */ + CUSTOMER_QUANTITY_LIMIT = 1, + } +} + +/** 查询客户限制配置列表 */ +export function getCustomerLimitConfigPage(params: PageParam) { + return requestClient.get< + PageResult + >('/crm/customer-limit-config/page', { params }); +} + +/** 查询客户限制配置详情 */ +export function getCustomerLimitConfig(id: number) { + return requestClient.get( + `/crm/customer-limit-config/get?id=${id}`, + ); +} + +/** 新增客户限制配置 */ +export function createCustomerLimitConfig( + data: CrmCustomerLimitConfigApi.CustomerLimitConfig, +) { + return requestClient.post('/crm/customer-limit-config/create', data); +} + +/** 修改客户限制配置 */ +export function updateCustomerLimitConfig( + data: CrmCustomerLimitConfigApi.CustomerLimitConfig, +) { + return requestClient.put('/crm/customer-limit-config/update', data); +} + +/** 删除客户限制配置 */ +export function deleteCustomerLimitConfig(id: number) { + return requestClient.delete(`/crm/customer-limit-config/delete?id=${id}`); +} diff --git a/apps/web-antd/src/api/crm/customer/poolConfig/index.ts b/apps/web-antd/src/api/crm/customer/poolConfig/index.ts new file mode 100644 index 000000000..ecb29707d --- /dev/null +++ b/apps/web-antd/src/api/crm/customer/poolConfig/index.ts @@ -0,0 +1,26 @@ +import { requestClient } from '#/api/request'; + +export namespace CrmCustomerPoolConfigApi { + /** 客户公海规则设置 */ + export interface CustomerPoolConfig { + enabled?: boolean; + contactExpireDays?: number; + dealExpireDays?: number; + notifyEnabled?: boolean; + notifyDays?: number; + } +} + +/** 获取客户公海规则设置 */ +export function getCustomerPoolConfig() { + return requestClient.get( + '/crm/customer-pool-config/get', + ); +} + +/** 更新客户公海规则设置 */ +export function saveCustomerPoolConfig( + data: CrmCustomerPoolConfigApi.CustomerPoolConfig, +) { + return requestClient.put('/crm/customer-pool-config/save', data); +} diff --git a/apps/web-antd/src/api/crm/followup/index.ts b/apps/web-antd/src/api/crm/followup/index.ts new file mode 100644 index 000000000..361acdcaa --- /dev/null +++ b/apps/web-antd/src/api/crm/followup/index.ts @@ -0,0 +1,53 @@ +import type { PageParam, PageResult } from '@vben/request'; + +import { requestClient } from '#/api/request'; + +export namespace CrmFollowUpApi { + /** 关联商机信息 */ + export interface Business { + id: number; + name: string; + } + + /** 关联联系人信息 */ + export interface Contact { + id: number; + name: string; + } + + /** 跟进记录信息 */ + export interface FollowUpRecord { + id: number; // 编号 + bizType: number; // 数据类型 + bizId: number; // 数据编号 + type: number; // 跟进类型 + content: string; // 跟进内容 + picUrls: string[]; // 图片 + fileUrls: string[]; // 附件 + nextTime: Date; // 下次联系时间 + businessIds: number[]; // 关联的商机编号数组 + businesses: Business[]; // 关联的商机数组 + contactIds: number[]; // 关联的联系人编号数组 + contacts: Contact[]; // 关联的联系人数组 + creator: string; + creatorName?: string; + } +} + +/** 查询跟进记录分页 */ +export function getFollowUpRecordPage(params: PageParam) { + return requestClient.get>( + '/crm/follow-up-record/page', + { params }, + ); +} + +/** 新增跟进记录 */ +export function createFollowUpRecord(data: CrmFollowUpApi.FollowUpRecord) { + return requestClient.post('/crm/follow-up-record/create', data); +} + +/** 删除跟进记录 */ +export function deleteFollowUpRecord(id: number) { + return requestClient.delete(`/crm/follow-up-record/delete?id=${id}`); +} diff --git a/apps/web-antd/src/api/crm/operateLog/index.ts b/apps/web-antd/src/api/crm/operateLog/index.ts new file mode 100644 index 000000000..2c5f8fd27 --- /dev/null +++ b/apps/web-antd/src/api/crm/operateLog/index.ts @@ -0,0 +1,31 @@ +import type { PageParam, PageResult } from '@vben/request'; + +import { requestClient } from '#/api/request'; + +export namespace CrmOperateLogApi { + /** 操作日志查询参数 */ + export interface OperateLogQuery extends PageParam { + bizType: number; + bizId: number; + } + + /** 操作日志信息 */ + export interface OperateLog { + id: number; + bizType: number; + bizId: number; + type: number; + content: string; + creator: string; + creatorName?: string; + createTime: Date; + } +} + +/** 获得操作日志 */ +export function getOperateLogPage(params: CrmOperateLogApi.OperateLogQuery) { + return requestClient.get>( + '/crm/operate-log/page', + { params }, + ); +} diff --git a/apps/web-antd/src/api/crm/permission/index.ts b/apps/web-antd/src/api/crm/permission/index.ts new file mode 100644 index 000000000..a0362e05c --- /dev/null +++ b/apps/web-antd/src/api/crm/permission/index.ts @@ -0,0 +1,79 @@ +import type { PageParam, PageResult } from '@vben/request'; + +import { requestClient } from '#/api/request'; + +export namespace CrmPermissionApi { + /** 数据权限信息 */ + export interface Permission { + id?: number; // 数据权限编号 + userId: number; // 用户编号 + bizType: number; // Crm 类型 + bizId: number; // Crm 类型数据编号 + level: number; // 权限级别 + toBizTypes?: number[]; // 同时添加至 + deptName?: string; // 部门名称 + nickname?: string; // 用户昵称 + postNames?: string[]; // 岗位名称数组 + createTime?: Date; + ids?: number[]; + } + + /** 数据权限转移请求 */ + export interface TransferReq { + id: number; // 模块编号 + newOwnerUserId: number; // 新负责人的用户编号 + oldOwnerPermissionLevel?: number; // 老负责人加入团队后的权限级别 + toBizTypes?: number[]; // 转移客户时,需要额外有【联系人】【商机】【合同】的 checkbox 选择 + } + + /** + * CRM 业务类型枚举 + */ + export enum BizType { + CRM_BUSINESS = 4, // 商机 + CRM_CLUE = 1, // 线索 + CRM_CONTACT = 3, // 联系人 + CRM_CONTRACT = 5, // 合同 + CRM_CUSTOMER = 2, // 客户 + CRM_PRODUCT = 6, // 产品 + CRM_RECEIVABLE = 7, // 回款 + CRM_RECEIVABLE_PLAN = 8, // 回款计划 + } + + /** + * CRM 数据权限级别枚举 + */ + export enum PermissionLevel { + OWNER = 1, // 负责人 + READ = 2, // 只读 + WRITE = 3, // 读写 + } +} + +/** 获得数据权限列表(查询团队成员列表) */ +export function getPermissionList(params: PageParam) { + return requestClient.get>( + '/crm/permission/list', + { params }, + ); +} + +/** 创建数据权限(新增团队成员) */ +export function createPermission(data: CrmPermissionApi.Permission) { + return requestClient.post('/crm/permission/create', data); +} + +/** 编辑数据权限(修改团队成员权限级别) */ +export function updatePermission(data: CrmPermissionApi.Permission) { + return requestClient.put('/crm/permission/update', data); +} + +/** 删除数据权限(删除团队成员) */ +export function deletePermissionBatch(ids: number[]) { + return requestClient.delete(`/crm/permission/delete?ids=${ids.join(',')}`); +} + +/** 删除自己的数据权限(退出团队) */ +export function deleteSelfPermission(id: number) { + return requestClient.delete(`/crm/permission/delete-self?id=${id}`); +} diff --git a/apps/web-antd/src/api/crm/product/category/index.ts b/apps/web-antd/src/api/crm/product/category/index.ts new file mode 100644 index 000000000..656de9835 --- /dev/null +++ b/apps/web-antd/src/api/crm/product/category/index.ts @@ -0,0 +1,46 @@ +import type { PageParam } from '@vben/request'; + +import { requestClient } from '#/api/request'; + +export namespace CrmProductCategoryApi { + /** 产品分类信息 */ + export interface ProductCategory { + id: number; + name: string; + parentId: number; + } +} + +/** 查询产品分类详情 */ +export function getProductCategory(id: number) { + return requestClient.get( + `/crm/product-category/get?id=${id}`, + ); +} + +/** 新增产品分类 */ +export function createProductCategory( + data: CrmProductCategoryApi.ProductCategory, +) { + return requestClient.post('/crm/product-category/create', data); +} + +/** 修改产品分类 */ +export function updateProductCategory( + data: CrmProductCategoryApi.ProductCategory, +) { + return requestClient.put('/crm/product-category/update', data); +} + +/** 删除产品分类 */ +export function deleteProductCategory(id: number) { + return requestClient.delete(`/crm/product-category/delete?id=${id}`); +} + +/** 产品分类列表 */ +export function getProductCategoryList(params?: PageParam) { + return requestClient.get( + '/crm/product-category/list', + { params }, + ); +} diff --git a/apps/web-antd/src/api/crm/product/index.ts b/apps/web-antd/src/api/crm/product/index.ts new file mode 100644 index 000000000..828495f5b --- /dev/null +++ b/apps/web-antd/src/api/crm/product/index.ts @@ -0,0 +1,57 @@ +import type { PageParam, PageResult } from '@vben/request'; + +import { requestClient } from '#/api/request'; + +export namespace CrmProductApi { + /** 产品信息 */ + export interface Product { + id: number; + name: string; + no: string; + unit: number; + price: number; + status: number; + categoryId: number; + categoryName?: string; + description: string; + ownerUserId: number; + } +} + +/** 查询产品列表 */ +export function getProductPage(params: PageParam) { + return requestClient.get>( + '/crm/product/page', + { params }, + ); +} + +/** 获得产品精简列表 */ +export function getProductSimpleList() { + return requestClient.get('/crm/product/simple-list'); +} + +/** 查询产品详情 */ +export function getProduct(id: number) { + return requestClient.get(`/crm/product/get?id=${id}`); +} + +/** 新增产品 */ +export function createProduct(data: CrmProductApi.Product) { + return requestClient.post('/crm/product/create', data); +} + +/** 修改产品 */ +export function updateProduct(data: CrmProductApi.Product) { + return requestClient.put('/crm/product/update', data); +} + +/** 删除产品 */ +export function deleteProduct(id: number) { + return requestClient.delete(`/crm/product/delete?id=${id}`); +} + +/** 导出产品 */ +export function exportProduct(params: any) { + return requestClient.download('/crm/product/export-excel', params); +} diff --git a/apps/web-antd/src/api/crm/receivable/index.ts b/apps/web-antd/src/api/crm/receivable/index.ts new file mode 100644 index 000000000..96936c910 --- /dev/null +++ b/apps/web-antd/src/api/crm/receivable/index.ts @@ -0,0 +1,90 @@ +import type { PageParam, PageResult } from '@vben/request'; + +import { requestClient } from '#/api/request'; + +export namespace CrmReceivableApi { + /** 合同信息 */ + export interface Contract { + id?: number; + name?: string; + no: string; + totalPrice: number; + } + + /** 回款信息 */ + export interface Receivable { + id: number; + no: string; + planId?: number; + period?: number; + customerId?: number; + customerName?: string; + contractId?: number; + contract?: Contract; + auditStatus: number; + processInstanceId: number; + returnTime: Date; + returnType: number; + price: number; + ownerUserId: number; + ownerUserName?: string; + remark: string; + creator: string; // 创建人 + creatorName?: string; // 创建人名称 + createTime: Date; // 创建时间 + updateTime: Date; // 更新时间 + } +} + +/** 查询回款列表 */ +export function getReceivablePage(params: PageParam) { + return requestClient.get>( + '/crm/receivable/page', + { params }, + ); +} + +/** 查询回款列表,基于指定客户 */ +export function getReceivablePageByCustomer(params: PageParam) { + return requestClient.get>( + '/crm/receivable/page-by-customer', + { params }, + ); +} + +/** 查询回款详情 */ +export function getReceivable(id: number) { + return requestClient.get( + `/crm/receivable/get?id=${id}`, + ); +} + +/** 新增回款 */ +export function createReceivable(data: CrmReceivableApi.Receivable) { + return requestClient.post('/crm/receivable/create', data); +} + +/** 修改回款 */ +export function updateReceivable(data: CrmReceivableApi.Receivable) { + return requestClient.put('/crm/receivable/update', data); +} + +/** 删除回款 */ +export function deleteReceivable(id: number) { + return requestClient.delete(`/crm/receivable/delete?id=${id}`); +} + +/** 导出回款 */ +export function exportReceivable(params: any) { + return requestClient.download('/crm/receivable/export-excel', params); +} + +/** 提交审核 */ +export function submitReceivable(id: number) { + return requestClient.put(`/crm/receivable/submit?id=${id}`); +} + +/** 获得待审核回款数量 */ +export function getAuditReceivableCount() { + return requestClient.get('/crm/receivable/audit-count'); +} diff --git a/apps/web-antd/src/api/crm/receivable/plan/index.ts b/apps/web-antd/src/api/crm/receivable/plan/index.ts new file mode 100644 index 000000000..d237c1ed9 --- /dev/null +++ b/apps/web-antd/src/api/crm/receivable/plan/index.ts @@ -0,0 +1,98 @@ +import type { PageParam, PageResult } from '@vben/request'; + +import { requestClient } from '#/api/request'; + +export namespace CrmReceivablePlanApi { + /** 回款计划信息 */ + export interface Plan { + id: number; + period: number; + receivableId: number; + price: number; + returnTime: Date; + remindDays: number; + returnType: number; + remindTime: Date; + customerId: number; + customerName?: string; + contractId?: number; + contractNo?: string; + ownerUserId: number; + ownerUserName?: string; + remark: string; + creator: string; + creatorName?: string; + createTime: Date; + updateTime: Date; + receivable?: { + price: number; + returnTime: Date; + }; + } +} + +/** 查询回款计划列表 */ +export function getReceivablePlanPage(params: PageParam) { + return requestClient.get>( + '/crm/receivable-plan/page', + { params }, + ); +} + +/** 查询回款计划列表(按客户) */ +export function getReceivablePlanPageByCustomer(params: PageParam) { + return requestClient.get>( + '/crm/receivable-plan/page-by-customer', + { params }, + ); +} + +/** 查询回款计划详情 */ +export function getReceivablePlan(id: number) { + return requestClient.get( + '/crm/receivable-plan/get', + { params: { id } }, + ); +} + +/** 查询回款计划下拉数据 */ +export function getReceivablePlanSimpleList( + customerId: number, + contractId: number, +) { + return requestClient.get( + '/crm/receivable-plan/simple-list', + { + params: { customerId, contractId }, + }, + ); +} + +/** 新增回款计划 */ +export function createReceivablePlan(data: CrmReceivablePlanApi.Plan) { + return requestClient.post('/crm/receivable-plan/create', data); +} + +/** 修改回款计划 */ +export function updateReceivablePlan(data: CrmReceivablePlanApi.Plan) { + return requestClient.put('/crm/receivable-plan/update', data); +} + +/** 删除回款计划 */ +export function deleteReceivablePlan(id: number) { + return requestClient.delete('/crm/receivable-plan/delete', { + params: { id }, + }); +} + +/** 导出回款计划 Excel */ +export function exportReceivablePlan(params: PageParam) { + return requestClient.download('/crm/receivable-plan/export-excel', { + params, + }); +} + +/** 获得待回款提醒数量 */ +export function getReceivablePlanRemindCount() { + return requestClient.get('/crm/receivable-plan/remind-count'); +} diff --git a/apps/web-antd/src/api/crm/statistics/customer.ts b/apps/web-antd/src/api/crm/statistics/customer.ts new file mode 100644 index 000000000..e661ba81c --- /dev/null +++ b/apps/web-antd/src/api/crm/statistics/customer.ts @@ -0,0 +1,191 @@ +import type { PageParam } from '@vben/request'; + +import { requestClient } from '#/api/request'; + +export namespace CrmStatisticsCustomerApi { + /** 客户总量分析(按日期) */ + export interface CustomerSummaryByDate { + time: string; + customerCreateCount: number; + customerDealCount: number; + } + + /** 客户总量分析(按用户) */ + export interface CustomerSummaryByUser { + ownerUserName: string; + customerCreateCount: number; + customerDealCount: number; + contractPrice: number; + receivablePrice: number; + } + + /** 客户跟进次数分析(按日期) */ + export interface FollowUpSummaryByDate { + time: string; + followUpRecordCount: number; + followUpCustomerCount: number; + } + + /** 客户跟进次数分析(按用户) */ + export interface FollowUpSummaryByUser { + ownerUserName: string; + followupRecordCount: number; + followupCustomerCount: number; + } + + /** 客户跟进方式统计 */ + export interface FollowUpSummaryByType { + followUpType: string; + followUpRecordCount: number; + } + + /** 合同摘要信息 */ + export interface CustomerContractSummary { + customerName: string; + contractName: string; + totalPrice: number; + receivablePrice: number; + customerType: string; + customerSource: string; + ownerUserName: string; + creatorUserName: string; + createTime: Date; + orderDate: Date; + } + + /** 客户公海分析(按日期) */ + export interface PoolSummaryByDate { + time: string; + customerPutCount: number; + customerTakeCount: number; + } + + /** 客户公海分析(按用户) */ + export interface PoolSummaryByUser { + ownerUserName: string; + customerPutCount: number; + customerTakeCount: number; + } + + /** 客户成交周期(按日期) */ + export interface CustomerDealCycleByDate { + time: string; + customerDealCycle: number; + } + + /** 客户成交周期(按用户) */ + export interface CustomerDealCycleByUser { + ownerUserName: string; + customerDealCycle: number; + customerDealCount: number; + } + + /** 客户成交周期(按地区) */ + export interface CustomerDealCycleByArea { + areaName: string; + customerDealCycle: number; + customerDealCount: number; + } + + /** 客户成交周期(按产品) */ + export interface CustomerDealCycleByProduct { + productName: string; + customerDealCycle: number; + customerDealCount: number; + } +} + +/** 客户总量分析(按日期) */ +export function getCustomerSummaryByDate(params: PageParam) { + return requestClient.get( + '/crm/statistics-customer/get-customer-summary-by-date', + { params }, + ); +} + +/** 客户总量分析(按用户) */ +export function getCustomerSummaryByUser(params: PageParam) { + return requestClient.get( + '/crm/statistics-customer/get-customer-summary-by-user', + { params }, + ); +} + +/** 客户跟进次数分析(按日期) */ +export function getFollowUpSummaryByDate(params: PageParam) { + return requestClient.get( + '/crm/statistics-customer/get-follow-up-summary-by-date', + { params }, + ); +} + +/** 客户跟进次数分析(按用户) */ +export function getFollowUpSummaryByUser(params: PageParam) { + return requestClient.get( + '/crm/statistics-customer/get-follow-up-summary-by-user', + { params }, + ); +} + +/** 获取客户跟进方式统计数 */ +export function getFollowUpSummaryByType(params: PageParam) { + return requestClient.get( + '/crm/statistics-customer/get-follow-up-summary-by-type', + { params }, + ); +} + +/** 合同摘要信息(客户转化率页面) */ +export function getContractSummary(params: PageParam) { + return requestClient.get( + '/crm/statistics-customer/get-contract-summary', + { params }, + ); +} + +/** 获取客户公海分析(按日期) */ +export function getPoolSummaryByDate(params: PageParam) { + return requestClient.get( + '/crm/statistics-customer/get-pool-summary-by-date', + { params }, + ); +} + +/** 获取客户公海分析(按用户) */ +export function getPoolSummaryByUser(params: PageParam) { + return requestClient.get( + '/crm/statistics-customer/get-pool-summary-by-user', + { params }, + ); +} + +/** 获取客户成交周期(按日期) */ +export function getCustomerDealCycleByDate(params: PageParam) { + return requestClient.get( + '/crm/statistics-customer/get-customer-deal-cycle-by-date', + { params }, + ); +} + +/** 获取客户成交周期(按用户) */ +export function getCustomerDealCycleByUser(params: PageParam) { + return requestClient.get( + '/crm/statistics-customer/get-customer-deal-cycle-by-user', + { params }, + ); +} + +/** 获取客户成交周期(按地区) */ +export function getCustomerDealCycleByArea(params: PageParam) { + return requestClient.get( + '/crm/statistics-customer/get-customer-deal-cycle-by-area', + { params }, + ); +} + +/** 获取客户成交周期(按产品) */ +export function getCustomerDealCycleByProduct(params: PageParam) { + return requestClient.get< + CrmStatisticsCustomerApi.CustomerDealCycleByProduct[] + >('/crm/statistics-customer/get-customer-deal-cycle-by-product', { params }); +} diff --git a/apps/web-antd/src/api/crm/statistics/funnel.ts b/apps/web-antd/src/api/crm/statistics/funnel.ts new file mode 100644 index 000000000..a4948e60b --- /dev/null +++ b/apps/web-antd/src/api/crm/statistics/funnel.ts @@ -0,0 +1,67 @@ +import type { PageParam, PageResult } from '@vben/request'; + +import { requestClient } from '#/api/request'; + +export namespace CrmStatisticsFunnelApi { + /** 销售漏斗统计数据 */ + export interface FunnelSummary { + customerCount: number; // 客户数 + businessCount: number; // 商机数 + businessWinCount: number; // 赢单数 + } + + /** 商机分析(按日期) */ + export interface BusinessSummaryByDate { + time: string; // 时间 + businessCreateCount: number; // 商机数 + totalPrice: number | string; // 商机金额 + } + + /** 商机转化率分析(按日期) */ + export interface BusinessInversionRateSummaryByDate { + time: string; // 时间 + businessCount: number; // 商机数量 + businessWinCount: number; // 赢单商机数 + } +} + +/** 获取销售漏斗统计数据 */ +export function getFunnelSummary(params: PageParam) { + return requestClient.get( + '/crm/statistics-funnel/get-funnel-summary', + { params }, + ); +} + +/** 获取商机结束状态统计 */ +export function getBusinessSummaryByEndStatus(params: PageParam) { + return requestClient.get>( + '/crm/statistics-funnel/get-business-summary-by-end-status', + { params }, + ); +} + +/** 获取新增商机分析(按日期) */ +export function getBusinessSummaryByDate(params: PageParam) { + return requestClient.get( + '/crm/statistics-funnel/get-business-summary-by-date', + { params }, + ); +} + +/** 获取商机转化率分析(按日期) */ +export function getBusinessInversionRateSummaryByDate(params: PageParam) { + return requestClient.get< + CrmStatisticsFunnelApi.BusinessInversionRateSummaryByDate[] + >('/crm/statistics-funnel/get-business-inversion-rate-summary-by-date', { + params, + }); +} + +/** 获取商机列表(按日期) */ +export function getBusinessPageByDate(params: PageParam) { + return requestClient.get>( + '/crm/statistics-funnel/get-business-page-by-date', + { params }, + ); +} diff --git a/apps/web-antd/src/api/crm/statistics/performance.ts b/apps/web-antd/src/api/crm/statistics/performance.ts new file mode 100644 index 000000000..ab3451250 --- /dev/null +++ b/apps/web-antd/src/api/crm/statistics/performance.ts @@ -0,0 +1,37 @@ +import type { PageParam } from '@vben/request'; + +import { requestClient } from '#/api/request'; + +export namespace CrmStatisticsPerformanceApi { + /** 员工业绩统计 */ + export interface Performance { + time: string; + currentMonthCount: number; + lastMonthCount: number; + lastYearCount: number; + } +} + +/** 员工获得合同金额统计 */ +export function getContractPricePerformance(params: PageParam) { + return requestClient.get( + '/crm/statistics-performance/get-contract-price-performance', + { params }, + ); +} + +/** 员工获得回款统计 */ +export function getReceivablePricePerformance(params: PageParam) { + return requestClient.get( + '/crm/statistics-performance/get-receivable-price-performance', + { params }, + ); +} + +/** 员工获得签约合同数量统计 */ +export function getContractCountPerformance(params: PageParam) { + return requestClient.get( + '/crm/statistics-performance/get-contract-count-performance', + { params }, + ); +} diff --git a/apps/web-antd/src/api/crm/statistics/portrait.ts b/apps/web-antd/src/api/crm/statistics/portrait.ts new file mode 100644 index 000000000..88ff518de --- /dev/null +++ b/apps/web-antd/src/api/crm/statistics/portrait.ts @@ -0,0 +1,69 @@ +import type { PageParam } from '@vben/request'; + +import { requestClient } from '#/api/request'; + +export namespace CrmStatisticsPortraitApi { + /** 客户基础统计信息 */ + export interface CustomerBase { + customerCount: number; + dealCount: number; + dealPortion: number | string; + } + + /** 客户行业统计信息 */ + export interface CustomerIndustry extends CustomerBase { + industryId: number; + industryPortion: number | string; + } + + /** 客户来源统计信息 */ + export interface CustomerSource extends CustomerBase { + source: number; + sourcePortion: number | string; + } + + /** 客户级别统计信息 */ + export interface CustomerLevel extends CustomerBase { + level: number; + levelPortion: number | string; + } + + /** 客户地区统计信息 */ + export interface CustomerArea extends CustomerBase { + areaId: number; + areaName: string; + areaPortion: number | string; + } +} + +/** 获取客户行业统计数据 */ +export function getCustomerIndustry(params: PageParam) { + return requestClient.get( + '/crm/statistics-portrait/get-customer-industry-summary', + { params }, + ); +} + +/** 获取客户来源统计数据 */ +export function getCustomerSource(params: PageParam) { + return requestClient.get( + '/crm/statistics-portrait/get-customer-source-summary', + { params }, + ); +} + +/** 获取客户级别统计数据 */ +export function getCustomerLevel(params: PageParam) { + return requestClient.get( + '/crm/statistics-portrait/get-customer-level-summary', + { params }, + ); +} + +/** 获取客户地区统计数据 */ +export function getCustomerArea(params: PageParam) { + return requestClient.get( + '/crm/statistics-portrait/get-customer-area-summary', + { params }, + ); +} diff --git a/apps/web-antd/src/api/crm/statistics/rank.ts b/apps/web-antd/src/api/crm/statistics/rank.ts new file mode 100644 index 000000000..f5fcfb167 --- /dev/null +++ b/apps/web-antd/src/api/crm/statistics/rank.ts @@ -0,0 +1,76 @@ +import type { PageParam } from '@vben/request'; + +import { requestClient } from '#/api/request'; + +export namespace CrmStatisticsRankApi { + /** 排行统计数据 */ + export interface Rank { + count: number; + nickname: string; + deptName: string; + } +} + +/** 获得合同排行榜 */ +export function getContractPriceRank(params: PageParam) { + return requestClient.get( + '/crm/statistics-rank/get-contract-price-rank', + { params }, + ); +} + +/** 获得回款排行榜 */ +export function getReceivablePriceRank(params: PageParam) { + return requestClient.get( + '/crm/statistics-rank/get-receivable-price-rank', + { params }, + ); +} + +/** 签约合同排行 */ +export function getContractCountRank(params: PageParam) { + return requestClient.get( + '/crm/statistics-rank/get-contract-count-rank', + { params }, + ); +} + +/** 产品销量排行 */ +export function getProductSalesRank(params: PageParam) { + return requestClient.get( + '/crm/statistics-rank/get-product-sales-rank', + { params }, + ); +} + +/** 新增客户数排行 */ +export function getCustomerCountRank(params: PageParam) { + return requestClient.get( + '/crm/statistics-rank/get-customer-count-rank', + { params }, + ); +} + +/** 新增联系人数排行 */ +export function getContactsCountRank(params: PageParam) { + return requestClient.get( + '/crm/statistics-rank/get-contacts-count-rank', + { params }, + ); +} + +/** 跟进次数排行 */ +export function getFollowCountRank(params: PageParam) { + return requestClient.get( + '/crm/statistics-rank/get-follow-count-rank', + { params }, + ); +} + +/** 跟进客户数排行 */ +export function getFollowCustomerCountRank(params: PageParam) { + return requestClient.get( + '/crm/statistics-rank/get-follow-customer-count-rank', + { params }, + ); +} diff --git a/apps/web-antd/src/api/pay/app/index.ts b/apps/web-antd/src/api/pay/app/index.ts new file mode 100644 index 000000000..1eae34420 --- /dev/null +++ b/apps/web-antd/src/api/pay/app/index.ts @@ -0,0 +1,63 @@ +import type { PageParam, PageResult } from '@vben/request'; + +import { requestClient } from '#/api/request'; + +export namespace PayAppApi { + /** 支付应用信息 */ + export interface App { + id?: number; + appKey: string; + name: string; + status: number; + remark: string; + payNotifyUrl: string; + refundNotifyUrl: string; + transferNotifyUrl: string; + merchantId: number; + merchantName: string; + createTime?: Date; + } + + /** 更新状态请求 */ + export interface UpdateStatusReq { + id: number; + status: number; + } +} + +/** 查询支付应用列表 */ +export function getAppPage(params: PageParam) { + return requestClient.get>('/pay/app/page', { + params, + }); +} + +/** 查询支付应用详情 */ +export function getApp(id: number) { + return requestClient.get(`/pay/app/get?id=${id}`); +} + +/** 新增支付应用 */ +export function createApp(data: PayAppApi.App) { + return requestClient.post('/pay/app/create', data); +} + +/** 修改支付应用 */ +export function updateApp(data: PayAppApi.App) { + return requestClient.put('/pay/app/update', data); +} + +/** 修改支付应用状态 */ +export function changeAppStatus(data: PayAppApi.UpdateStatusReq) { + return requestClient.put('/pay/app/update-status', data); +} + +/** 删除支付应用 */ +export function deleteApp(id: number) { + return requestClient.delete(`/pay/app/delete?id=${id}`); +} + +/** 获取支付应用列表 */ +export function getAppList() { + return requestClient.get('/pay/app/list'); +} diff --git a/apps/web-antd/src/api/pay/channel/index.ts b/apps/web-antd/src/api/pay/channel/index.ts new file mode 100644 index 000000000..99a16c05c --- /dev/null +++ b/apps/web-antd/src/api/pay/channel/index.ts @@ -0,0 +1,54 @@ +import type { PageParam, PageResult } from '@vben/request'; + +import { requestClient } from '#/api/request'; + +export namespace PayChannelApi { + /** 支付渠道信息 */ + export interface Channel { + id: number; + code: string; + config: string; + status: number; + remark: string; + feeRate: number; + appId: number; + createTime: Date; + } +} + +/** 查询支付渠道列表 */ +export function getChannelPage(params: PageParam) { + return requestClient.get>( + '/pay/channel/page', + { + params, + }, + ); +} + +/** 查询支付渠道详情 */ +export function getChannel(appId: string, code: string) { + return requestClient.get('/pay/channel/get', { + params: { appId, code }, + }); +} + +/** 新增支付渠道 */ +export function createChannel(data: PayChannelApi.Channel) { + return requestClient.post('/pay/channel/create', data); +} + +/** 修改支付渠道 */ +export function updateChannel(data: PayChannelApi.Channel) { + return requestClient.put('/pay/channel/update', data); +} + +/** 删除支付渠道 */ +export function deleteChannel(id: number) { + return requestClient.delete(`/pay/channel/delete?id=${id}`); +} + +/** 导出支付渠道 */ +export function exportChannel(params: PageParam) { + return requestClient.download('/pay/channel/export-excel', { params }); +} diff --git a/apps/web-antd/src/api/pay/demo/index.ts b/apps/web-antd/src/api/pay/demo/index.ts new file mode 100644 index 000000000..a0f3c6886 --- /dev/null +++ b/apps/web-antd/src/api/pay/demo/index.ts @@ -0,0 +1,38 @@ +import type { PageParam, PageResult } from '@vben/request'; + +import { requestClient } from '#/api/request'; + +export namespace PayDemoApi { + /** 示例订单信息 */ + export interface DemoOrder { + spuId: number; + createTime: Date; + } +} + +/** 创建示例订单 */ +export function createDemoOrder(data: PayDemoApi.DemoOrder) { + return requestClient.post('/pay/demo-order/create', data); +} + +/** 获得示例订单 */ +export function getDemoOrder(id: number) { + return requestClient.get( + `/pay/demo-order/get?id=${id}`, + ); +} + +/** 获得示例订单分页 */ +export function getDemoOrderPage(params: PageParam) { + return requestClient.get>( + '/pay/demo-order/page', + { + params, + }, + ); +} + +/** 退款示例订单 */ +export function refundDemoOrder(id: number) { + return requestClient.put(`/pay/demo-order/refund?id=${id}`); +} diff --git a/apps/web-antd/src/api/pay/demo/transfer/index.ts b/apps/web-antd/src/api/pay/demo/transfer/index.ts new file mode 100644 index 000000000..e06dbec8b --- /dev/null +++ b/apps/web-antd/src/api/pay/demo/transfer/index.ts @@ -0,0 +1,29 @@ +import type { PageParam, PageResult } from '@vben/request'; + +import { requestClient } from '#/api/request'; + +export namespace PayDemoTransferApi { + /** 示例转账单信息 */ + export interface DemoTransfer { + price: number; + type: number; + userName: string; + alipayLogonId: string; + openid: string; + } +} + +/** 创建示例转账单 */ +export function createDemoTransfer(data: PayDemoTransferApi.DemoTransfer) { + return requestClient.post('/pay/demo-transfer/create', data); +} + +/** 获得示例转账单分页 */ +export function getDemoTransferPage(params: PageParam) { + return requestClient.get>( + '/pay/demo-transfer/page', + { + params, + }, + ); +} diff --git a/apps/web-antd/src/api/pay/notify/index.ts b/apps/web-antd/src/api/pay/notify/index.ts new file mode 100644 index 000000000..b0b916ccb --- /dev/null +++ b/apps/web-antd/src/api/pay/notify/index.ts @@ -0,0 +1,15 @@ +import type { PageParam } from '@vben/request'; + +import { requestClient } from '#/api/request'; + +/** 获得支付通知明细 */ +export function getNotifyTaskDetail(id: number) { + return requestClient.get(`/pay/notify/get-detail?id=${id}`); +} + +/** 获得支付通知分页 */ +export function getNotifyTaskPage(params: PageParam) { + return requestClient.get('/pay/notify/page', { + params, + }); +} diff --git a/apps/web-antd/src/api/pay/order/index.ts b/apps/web-antd/src/api/pay/order/index.ts new file mode 100644 index 000000000..984a5d1f6 --- /dev/null +++ b/apps/web-antd/src/api/pay/order/index.ts @@ -0,0 +1,118 @@ +import type { PageParam, PageResult } from '@vben/request'; + +import { requestClient } from '#/api/request'; + +export namespace PayOrderApi { + /** 支付订单信息 */ + export interface Order { + id: number; + merchantId: number; + appId: number; + channelId: number; + channelCode: string; + merchantOrderId: string; + subject: string; + body: string; + notifyUrl: string; + notifyStatus: number; + amount: number; + channelFeeRate: number; + channelFeeAmount: number; + status: number; + userIp: string; + expireTime: Date; + successTime: Date; + notifyTime: Date; + successExtensionId: number; + refundStatus: number; + refundTimes: number; + refundAmount: number; + channelUserId: string; + channelOrderNo: string; + createTime: Date; + } + + /** 支付订单分页请求 */ + export interface OrderPageReqVO extends PageParam { + merchantId?: number; + appId?: number; + channelId?: number; + channelCode?: string; + merchantOrderId?: string; + subject?: string; + body?: string; + notifyUrl?: string; + notifyStatus?: number; + amount?: number; + channelFeeRate?: number; + channelFeeAmount?: number; + status?: number; + expireTime?: Date[]; + successTime?: Date[]; + notifyTime?: Date[]; + successExtensionId?: number; + refundStatus?: number; + refundTimes?: number; + channelUserId?: string; + channelOrderNo?: string; + createTime?: Date[]; + } + + /** 支付订单导出请求 */ + export interface OrderExportReqVO { + merchantId?: number; + appId?: number; + channelId?: number; + channelCode?: string; + merchantOrderId?: string; + subject?: string; + body?: string; + notifyUrl?: string; + notifyStatus?: number; + amount?: number; + channelFeeRate?: number; + channelFeeAmount?: number; + status?: number; + expireTime?: Date[]; + successTime?: Date[]; + notifyTime?: Date[]; + successExtensionId?: number; + refundStatus?: number; + refundTimes?: number; + channelUserId?: string; + channelOrderNo?: string; + createTime?: Date[]; + } +} + +/** 查询支付订单列表 */ +export function getOrderPage(params: PayOrderApi.OrderPageReqVO) { + return requestClient.get>('/pay/order/page', { + params, + }); +} + +/** 查询支付订单详情 */ +export function getOrder(id: number, sync?: boolean) { + return requestClient.get('/pay/order/get', { + params: { + id, + sync, + }, + }); +} + +/** 获得支付订单的明细 */ +export function getOrderDetail(id: number) { + return requestClient.get(`/pay/order/get-detail?id=${id}`); +} + +/** 提交支付订单 */ +export function submitOrder(data: any) { + return requestClient.post('/pay/order/submit', data); +} + +/** 导出支付订单 */ +export function exportOrder(params: PayOrderApi.OrderExportReqVO) { + return requestClient.download('/pay/order/export-excel', { params }); +} diff --git a/apps/web-antd/src/api/pay/refund/index.ts b/apps/web-antd/src/api/pay/refund/index.ts new file mode 100644 index 000000000..133a8bcb1 --- /dev/null +++ b/apps/web-antd/src/api/pay/refund/index.ts @@ -0,0 +1,129 @@ +import type { PageParam, PageResult } from '@vben/request'; + +import { requestClient } from '#/api/request'; + +export namespace PayRefundApi { + /** 退款订单信息 */ + export interface Refund { + id: number; + merchantId: number; + appId: number; + channelId: number; + channelCode: string; + orderId: string; + tradeNo: string; + merchantOrderId: string; + merchantRefundNo: string; + notifyUrl: string; + notifyStatus: number; + status: number; + type: number; + payAmount: number; + refundAmount: number; + reason: string; + userIp: string; + channelOrderNo: string; + channelRefundNo: string; + channelErrorCode: string; + channelErrorMsg: string; + channelExtras: string; + expireTime: Date; + successTime: Date; + notifyTime: Date; + createTime: Date; + updateTime: Date; + } + + /** 退款订单分页请求 */ + export interface RefundPageReqVO extends PageParam { + merchantId?: number; + appId?: number; + channelId?: number; + channelCode?: string; + orderId?: string; + tradeNo?: string; + merchantOrderId?: string; + merchantRefundNo?: string; + notifyUrl?: string; + notifyStatus?: number; + status?: number; + type?: number; + payAmount?: number; + refundAmount?: number; + reason?: string; + userIp?: string; + channelOrderNo?: string; + channelRefundNo?: string; + channelErrorCode?: string; + channelErrorMsg?: string; + channelExtras?: string; + expireTime?: Date[]; + successTime?: Date[]; + notifyTime?: Date[]; + createTime?: Date[]; + } + + /** 退款订单导出请求 */ + export interface RefundExportReqVO { + merchantId?: number; + appId?: number; + channelId?: number; + channelCode?: string; + orderId?: string; + tradeNo?: string; + merchantOrderId?: string; + merchantRefundNo?: string; + notifyUrl?: string; + notifyStatus?: number; + status?: number; + type?: number; + payAmount?: number; + refundAmount?: number; + reason?: string; + userIp?: string; + channelOrderNo?: string; + channelRefundNo?: string; + channelErrorCode?: string; + channelErrorMsg?: string; + channelExtras?: string; + expireTime?: Date[]; + successTime?: Date[]; + notifyTime?: Date[]; + createTime?: Date[]; + } +} + +/** 查询退款订单列表 */ +export function getRefundPage(params: PayRefundApi.RefundPageReqVO) { + return requestClient.get>( + '/pay/refund/page', + { + params, + }, + ); +} + +/** 查询退款订单详情 */ +export function getRefund(id: number) { + return requestClient.get(`/pay/refund/get?id=${id}`); +} + +/** 创建退款订单 */ +export function createRefund(data: PayRefundApi.Refund) { + return requestClient.post('/pay/refund/create', data); +} + +/** 更新退款订单 */ +export function updateRefund(data: PayRefundApi.Refund) { + return requestClient.put('/pay/refund/update', data); +} + +/** 删除退款订单 */ +export function deleteRefund(id: number) { + return requestClient.delete(`/pay/refund/delete?id=${id}`); +} + +/** 导出退款订单 */ +export function exportRefund(params: PayRefundApi.RefundExportReqVO) { + return requestClient.download('/pay/refund/export-excel', { params }); +} diff --git a/apps/web-antd/src/api/pay/transfer/index.ts b/apps/web-antd/src/api/pay/transfer/index.ts new file mode 100644 index 000000000..fd8bc9d3a --- /dev/null +++ b/apps/web-antd/src/api/pay/transfer/index.ts @@ -0,0 +1,58 @@ +import type { PageParam, PageResult } from '@vben/request'; + +import { requestClient } from '#/api/request'; + +export namespace PayTransferApi { + /** 转账单信息 */ + export interface Transfer { + id: number; + appId: number; + channelId: number; + channelCode: string; + merchantTransferId: string; + type: number; + price: number; + subject: string; + userName: string; + alipayLogonId: string; + openid: string; + status: number; + createTime: Date; + } + + /** 转账单分页请求 */ + export interface TransferPageReqVO extends PageParam { + appId?: number; + channelId?: number; + channelCode?: string; + merchantTransferId?: string; + type?: number; + price?: number; + subject?: string; + userName?: string; + status?: number; + createTime?: Date[]; + } +} + +/** 查询转账单列表 */ +export function getTransferPage(params: PayTransferApi.TransferPageReqVO) { + return requestClient.get>( + '/pay/transfer/page', + { + params, + }, + ); +} + +/** 查询转账单详情 */ +export function getTransfer(id: number) { + return requestClient.get( + `/pay/transfer/get?id=${id}`, + ); +} + +/** 创建转账单 */ +export function createTransfer(data: PayTransferApi.Transfer) { + return requestClient.post('/pay/transfer/create', data); +} diff --git a/apps/web-antd/src/api/pay/wallet/balance/index.ts b/apps/web-antd/src/api/pay/wallet/balance/index.ts new file mode 100644 index 000000000..25a442809 --- /dev/null +++ b/apps/web-antd/src/api/pay/wallet/balance/index.ts @@ -0,0 +1,53 @@ +import type { PageParam, PageResult } from '@vben/request'; + +import { requestClient } from '#/api/request'; + +export namespace PayWalletApi { + /** 用户钱包查询参数 */ + export interface PayWalletUserReqVO { + userId: number; + } + + /** 钱包信息 */ + export interface WalletVO { + id: number; + userId: number; + userType: number; + balance: number; + totalExpense: number; + totalRecharge: number; + freezePrice: number; + } + + /** 钱包分页请求 */ + export interface WalletPageReqVO extends PageParam { + userId?: number; + userType?: number; + balance?: number; + totalExpense?: number; + totalRecharge?: number; + freezePrice?: number; + } +} + +/** 查询用户钱包详情 */ +export function getWallet(params: PayWalletApi.PayWalletUserReqVO) { + return requestClient.get('/pay/wallet/get', { + params, + }); +} + +/** 查询会员钱包列表 */ +export function getWalletPage(params: PayWalletApi.WalletPageReqVO) { + return requestClient.get>( + '/pay/wallet/page', + { + params, + }, + ); +} + +/** 修改会员钱包余额 */ +export function updateWalletBalance(data: PayWalletApi.WalletVO) { + return requestClient.put('/pay/wallet/update-balance', data); +} diff --git a/apps/web-antd/src/api/pay/wallet/rechargePackage/index.ts b/apps/web-antd/src/api/pay/wallet/rechargePackage/index.ts new file mode 100644 index 000000000..32c3bbfaf --- /dev/null +++ b/apps/web-antd/src/api/pay/wallet/rechargePackage/index.ts @@ -0,0 +1,46 @@ +import type { PageParam, PageResult } from '@vben/request'; + +import { requestClient } from '#/api/request'; + +export namespace WalletRechargePackageApi { + /** 充值套餐信息 */ + export interface Package { + id?: number; + name: string; + payPrice: number; + bonusPrice: number; + status: number; + } +} + +/** 查询充值套餐列表 */ +export function getPackagePage(params: PageParam) { + return requestClient.get>( + '/pay/wallet-recharge-package/page', + { + params, + }, + ); +} + +/** 查询充值套餐详情 */ +export function getPackage(id: number) { + return requestClient.get( + `/pay/wallet-recharge-package/get?id=${id}`, + ); +} + +/** 新增充值套餐 */ +export function createPackage(data: WalletRechargePackageApi.Package) { + return requestClient.post('/pay/wallet-recharge-package/create', data); +} + +/** 修改充值套餐 */ +export function updatePackage(data: WalletRechargePackageApi.Package) { + return requestClient.put('/pay/wallet-recharge-package/update', data); +} + +/** 删除充值套餐 */ +export function deletePackage(id: number) { + return requestClient.delete(`/pay/wallet-recharge-package/delete?id=${id}`); +} diff --git a/apps/web-antd/src/api/pay/wallet/transaction/index.ts b/apps/web-antd/src/api/pay/wallet/transaction/index.ts new file mode 100644 index 000000000..bc7ffef13 --- /dev/null +++ b/apps/web-antd/src/api/pay/wallet/transaction/index.ts @@ -0,0 +1,24 @@ +import type { PageParam, PageResult } from '@vben/request'; + +import { requestClient } from '#/api/request'; + +export namespace WalletTransactionApi { + /** 钱包交易流水信息 */ + export interface Transaction { + id: number; + walletId: number; + title: string; + price: number; + balance: number; + } +} + +/** 查询钱包交易流水列表 */ +export function getTransactionPage(params: PageParam) { + return requestClient.get>( + '/pay/wallet-transaction/page', + { + params, + }, + ); +} diff --git a/apps/web-antd/src/components/form-create/components/use-images-upload.tsx b/apps/web-antd/src/components/form-create/components/use-images-upload.tsx index 08b27c597..4e821c6c6 100644 --- a/apps/web-antd/src/components/form-create/components/use-images-upload.tsx +++ b/apps/web-antd/src/components/form-create/components/use-images-upload.tsx @@ -4,6 +4,7 @@ import ImageUpload from '#/components/upload/image-upload.vue'; export const useImagesUpload = () => { return defineComponent({ + name: 'ImagesUpload', props: { multiple: { type: Boolean, @@ -20,6 +21,5 @@ export const useImagesUpload = () => { ); }, - name: 'ImagesUpload', }); }; diff --git a/apps/web-antd/src/layouts/components/help.vue b/apps/web-antd/src/layouts/components/help.vue index 4d19a8e92..5e4647d82 100644 --- a/apps/web-antd/src/layouts/components/help.vue +++ b/apps/web-antd/src/layouts/components/help.vue @@ -81,7 +81,7 @@ function openWindow(url: string) {

- 数舵科技 + 数舵科技

diff --git a/apps/web-antd/src/router/routes/modules/demos.ts b/apps/web-antd/src/router/routes/modules/demos.ts deleted file mode 100644 index b1f9b7916..000000000 --- a/apps/web-antd/src/router/routes/modules/demos.ts +++ /dev/null @@ -1,28 +0,0 @@ -import type { RouteRecordRaw } from 'vue-router'; - -// import { $t } from '#/locales'; - -const routes: RouteRecordRaw[] = [ - // { - // meta: { - // icon: 'ic:baseline-view-in-ar', - // keepAlive: true, - // order: 1000, - // title: $t('demos.title'), - // }, - // name: 'Demos', - // path: '/demos', - // children: [ - // { - // meta: { - // title: $t('demos.antd'), - // }, - // name: 'AntDesignDemos', - // path: '/demos/ant-design', - // component: () => import('#/views/demos/antd/index.vue'), - // }, - // ], - // }, -]; - -export default routes; // update by 芋艿:不展示 diff --git a/apps/web-antd/src/utils/date.ts b/apps/web-antd/src/utils/date.ts index 2c899a9f8..dec8e105a 100644 --- a/apps/web-antd/src/utils/date.ts +++ b/apps/web-antd/src/utils/date.ts @@ -15,14 +15,22 @@ export function getRangePickerDefaultProps() { valueFormat: 'YYYY-MM-DD HH:mm:ss', format: 'YYYY-MM-DD HH:mm:ss', placeholder: ['开始时间', '结束时间'], - // prettier-ignore ranges: { - '今天': [dayjs().startOf('day'), dayjs().endOf('day')], - '昨天': [dayjs().subtract(1, 'day').startOf('day'), dayjs().subtract(1, 'day').endOf('day')], - '本周': [dayjs().startOf('week'), dayjs().endOf('day')], - '本月': [dayjs().startOf('month'), dayjs().endOf('day')], - '最近 7 天': [dayjs().subtract(7, 'day').startOf('day'), dayjs().endOf('day')], - '最近 30 天': [dayjs().subtract(30, 'day').startOf('day'), dayjs().endOf('day')], + 今天: [dayjs().startOf('day'), dayjs().endOf('day')], + 昨天: [ + dayjs().subtract(1, 'day').startOf('day'), + dayjs().subtract(1, 'day').endOf('day'), + ], + 本周: [dayjs().startOf('week'), dayjs().endOf('day')], + 本月: [dayjs().startOf('month'), dayjs().endOf('day')], + '最近 7 天': [ + dayjs().subtract(7, 'day').startOf('day'), + dayjs().endOf('day'), + ], + '最近 30 天': [ + dayjs().subtract(30, 'day').startOf('day'), + dayjs().endOf('day'), + ], }, transformDateFunc: (dates: any) => { if (dates && dates.length === 2) { diff --git a/apps/web-antd/src/views/_core/profile/modules/reset-pwd.vue b/apps/web-antd/src/views/_core/profile/modules/reset-pwd.vue index d34307593..be2114893 100644 --- a/apps/web-antd/src/views/_core/profile/modules/reset-pwd.vue +++ b/apps/web-antd/src/views/_core/profile/modules/reset-pwd.vue @@ -1,11 +1,12 @@ diff --git a/apps/web-antd/src/views/bpm/model/modules/category-draggable-model.vue b/apps/web-antd/src/views/bpm/model/modules/category-draggable-model.vue new file mode 100644 index 000000000..5ebcee1f7 --- /dev/null +++ b/apps/web-antd/src/views/bpm/model/modules/category-draggable-model.vue @@ -0,0 +1,398 @@ + + + + + diff --git a/apps/web-antd/src/views/crm/backlog/data.ts b/apps/web-antd/src/views/crm/backlog/data.ts new file mode 100644 index 000000000..d42be5808 --- /dev/null +++ b/apps/web-antd/src/views/crm/backlog/data.ts @@ -0,0 +1,895 @@ +import type { Ref } from 'vue'; + +import type { VbenFormSchema } from '#/adapter/form'; +import type { OnActionClickFn, VxeTableGridOptions } from '#/adapter/vxe-table'; +import type { CrmContractApi } from '#/api/crm/contract'; +import type { CrmReceivableApi } from '#/api/crm/receivable'; + +import { useAccess } from '@vben/access'; + +import { DICT_TYPE } from '#/utils/dict'; + +const { hasAccessByCodes } = useAccess(); + +export interface LeftSideItem { + name: string; + menu: string; + count: Ref; +} + +/** 跟进状态 */ +export const FOLLOWUP_STATUS = [ + { label: '待跟进', value: false }, + { label: '已跟进', value: true }, +]; + +/** 归属范围 */ +export const SCENE_TYPES = [ + { label: '我负责的', value: 1 }, + { label: '我参与的', value: 2 }, + { label: '下属负责的', value: 3 }, +]; + +/** 联系状态 */ +export const CONTACT_STATUS = [ + { label: '今日需联系', value: 1 }, + { label: '已逾期', value: 2 }, + { label: '已联系', value: 3 }, +]; + +/** 审批状态 */ +export const AUDIT_STATUS = [ + { label: '待审批', value: 10 }, + { label: '审核通过', value: 20 }, + { label: '审核不通过', value: 30 }, +]; + +/** 回款提醒类型 */ +export const RECEIVABLE_REMIND_TYPE = [ + { label: '待回款', value: 1 }, + { label: '已逾期', value: 2 }, + { label: '已回款', value: 3 }, +]; + +/** 合同过期状态 */ +export const CONTRACT_EXPIRY_TYPE = [ + { label: '即将过期', value: 1 }, + { label: '已过期', value: 2 }, +]; + +export const useLeftSides = ( + customerTodayContactCount: Ref, + clueFollowCount: Ref, + customerFollowCount: Ref, + customerPutPoolRemindCount: Ref, + contractAuditCount: Ref, + contractRemindCount: Ref, + receivableAuditCount: Ref, + receivablePlanRemindCount: Ref, +): LeftSideItem[] => { + return [ + { + name: '今日需联系客户', + menu: 'customerTodayContact', + count: customerTodayContactCount, + }, + { + name: '分配给我的线索', + menu: 'clueFollow', + count: clueFollowCount, + }, + { + name: '分配给我的客户', + menu: 'customerFollow', + count: customerFollowCount, + }, + { + name: '待进入公海的客户', + menu: 'customerPutPoolRemind', + count: customerPutPoolRemindCount, + }, + { + name: '待审核合同', + menu: 'contractAudit', + count: contractAuditCount, + }, + { + name: '待审核回款', + menu: 'receivableAudit', + count: receivableAuditCount, + }, + { + name: '待回款提醒', + menu: 'receivablePlanRemind', + count: receivablePlanRemindCount, + }, + { + name: '即将到期的合同', + menu: 'contractRemind', + count: contractRemindCount, + }, + ]; +}; + +/** 分配给我的线索 列表的搜索表单 */ +export function useClueFollowFormSchema(): VbenFormSchema[] { + return [ + { + fieldName: 'followUpStatus', + label: '状态', + component: 'Select', + componentProps: { + allowClear: true, + options: FOLLOWUP_STATUS, + }, + defaultValue: false, + }, + ]; +} + +/** 分配给我的线索 列表的字段 */ +export function useClueFollowColumns(): VxeTableGridOptions['columns'] { + return [ + { + field: 'name', + title: '线索名称', + minWidth: 160, + fixed: 'left', + slots: { default: 'name' }, + }, + { + field: 'source', + title: '线索来源', + minWidth: 100, + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.CRM_CUSTOMER_SOURCE }, + }, + }, + { + field: 'mobile', + title: '手机', + minWidth: 120, + }, + { + field: 'telephone', + title: '电话', + minWidth: 130, + }, + { + field: 'email', + title: '邮箱', + minWidth: 180, + }, + { + field: 'detailAddress', + title: '地址', + minWidth: 180, + }, + { + field: 'industryId', + title: '客户行业', + minWidth: 100, + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.CRM_CUSTOMER_INDUSTRY }, + }, + }, + { + field: 'level', + title: '客户级别', + minWidth: 100, + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.CRM_CUSTOMER_LEVEL }, + }, + }, + { + field: 'contactNextTime', + title: '下次联系时间', + minWidth: 180, + formatter: 'formatDateTime', + }, + { + field: 'remark', + title: '备注', + minWidth: 200, + }, + { + field: 'contactLastTime', + title: '最后跟进时间', + minWidth: 180, + formatter: 'formatDateTime', + }, + { + field: 'contactLastContent', + title: '最后跟进记录', + minWidth: 200, + }, + { + field: 'ownerUserName', + title: '负责人', + minWidth: 100, + }, + { + field: 'ownerUserDeptName', + title: '所属部门', + minWidth: 100, + }, + { + field: 'updateTime', + title: '更新时间', + minWidth: 180, + formatter: 'formatDateTime', + }, + { + field: 'createTime', + title: '创建时间', + minWidth: 180, + formatter: 'formatDateTime', + }, + { + field: 'creatorName', + title: '创建人', + minWidth: 100, + }, + ]; +} + +/** 合同审核列表的搜索表单 */ +export function useContractAuditFormSchema(): VbenFormSchema[] { + return [ + { + fieldName: 'auditStatus', + label: '合同状态', + component: 'Select', + componentProps: { + allowClear: true, + options: AUDIT_STATUS, + }, + defaultValue: 10, + }, + ]; +} + +/** 合同提醒列表的搜索表单 */ +export function useContractRemindFormSchema(): VbenFormSchema[] { + return [ + { + fieldName: 'expiryType', + label: '到期状态', + component: 'Select', + componentProps: { + allowClear: true, + options: CONTRACT_EXPIRY_TYPE, + }, + defaultValue: 1, + }, + ]; +} + +/** 合同审核列表的字段 */ +export function useContractColumns( + onActionClick: OnActionClickFn, +): VxeTableGridOptions['columns'] { + return [ + { + field: 'no', + title: '合同编号', + minWidth: 160, + fixed: 'left', + }, + { + field: 'name', + title: '合同名称', + minWidth: 160, + slots: { + default: 'name', + }, + }, + { + field: 'customerName', + title: '客户名称', + minWidth: 160, + slots: { + default: 'customerName', + }, + }, + { + field: 'businessName', + title: '商机名称', + minWidth: 160, + slots: { + default: 'businessName', + }, + }, + { + field: 'price', + title: '合同金额(元)', + minWidth: 120, + formatter: 'formatAmount', + }, + { + field: 'orderDate', + title: '下单时间', + minWidth: 120, + formatter: 'formatDateTime', + }, + { + field: 'startTime', + title: '合同开始时间', + minWidth: 120, + formatter: 'formatDateTime', + }, + { + field: 'endTime', + title: '合同结束时间', + minWidth: 120, + formatter: 'formatDateTime', + }, + { + field: 'contactName', + title: '客户签约人', + minWidth: 130, + slots: { + default: 'contactName', + }, + }, + { + field: 'signUserName', + title: '公司签约人', + minWidth: 130, + }, + { + field: 'remark', + title: '备注', + minWidth: 200, + }, + { + field: 'totalReceivablePrice', + title: '已回款金额(元)', + minWidth: 140, + formatter: 'formatAmount', + }, + { + field: 'noReceivablePrice', + title: '未回款金额(元)', + minWidth: 120, + formatter: 'formatAmount', + }, + { + field: 'contactLastTime', + title: '最后跟进时间', + minWidth: 180, + formatter: 'formatDateTime', + }, + { + field: 'ownerUserName', + title: '负责人', + minWidth: 120, + }, + { + field: 'ownerUserDeptName', + title: '所属部门', + minWidth: 100, + }, + { + field: 'updateTime', + title: '更新时间', + minWidth: 180, + formatter: 'formatDateTime', + }, + { + field: 'createTime', + title: '创建时间', + minWidth: 180, + formatter: 'formatDateTime', + }, + { + field: 'creatorName', + title: '创建人', + minWidth: 100, + }, + { + field: 'auditStatus', + title: '合同状态', + minWidth: 120, + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.CRM_AUDIT_STATUS }, + }, + }, + { + field: 'operation', + title: '操作', + minWidth: 130, + align: 'center', + fixed: 'right', + cellRender: { + attrs: { + nameField: 'no', + nameTitle: '合同编号', + onClick: onActionClick, + }, + name: 'CellOperation', + options: [ + { + code: 'processDetail', + show: hasAccessByCodes(['crm:contract:update']), + }, + ], + }, + }, + ]; +} + +/** 客户跟进列表的搜索表单 */ +export function useCustomerFollowFormSchema(): VbenFormSchema[] { + return [ + { + fieldName: 'followUpStatus', + label: '状态', + component: 'Select', + componentProps: { + allowClear: true, + options: FOLLOWUP_STATUS, + }, + defaultValue: false, + }, + ]; +} + +/** 待进入公海客户列表的搜索表单 */ +export function useCustomerPutPoolFormSchema(): VbenFormSchema[] { + return [ + { + fieldName: 'sceneType', + label: '归属', + component: 'Select', + componentProps: { + allowClear: true, + options: SCENE_TYPES, + }, + defaultValue: 1, + }, + ]; +} + +/** 今日需联系客户列表的搜索表单 */ +export function useCustomerTodayContactFormSchema(): VbenFormSchema[] { + return [ + { + fieldName: 'contactStatus', + label: '状态', + component: 'Select', + componentProps: { + allowClear: true, + options: CONTACT_STATUS, + }, + defaultValue: 1, + }, + { + fieldName: 'sceneType', + label: '归属', + component: 'Select', + componentProps: { + allowClear: true, + options: SCENE_TYPES, + }, + defaultValue: 1, + }, + ]; +} + +/** 客户列表的字段 */ +export function useCustomerColumns(): VxeTableGridOptions['columns'] { + return [ + { + field: 'name', + title: '客户名称', + minWidth: 160, + slots: { + default: 'name', + }, + }, + { + field: 'source', + title: '客户来源', + minWidth: 100, + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.CRM_CUSTOMER_SOURCE }, + }, + }, + { + field: 'mobile', + title: '手机', + minWidth: 120, + }, + { + field: 'telephone', + title: '电话', + minWidth: 130, + }, + { + field: 'email', + title: '邮箱', + minWidth: 180, + }, + { + field: 'level', + title: '客户级别', + minWidth: 100, + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.CRM_CUSTOMER_LEVEL }, + }, + }, + { + field: 'industryId', + title: '客户行业', + minWidth: 100, + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.CRM_CUSTOMER_INDUSTRY }, + }, + }, + { + field: 'contactNextTime', + title: '下次联系时间', + minWidth: 180, + formatter: 'formatDateTime', + }, + { + field: 'remark', + title: '备注', + minWidth: 200, + }, + { + field: 'lockStatus', + title: '锁定状态', + minWidth: 100, + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.INFRA_BOOLEAN_STRING }, + }, + }, + { + field: 'dealStatus', + title: '成交状态', + minWidth: 100, + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.INFRA_BOOLEAN_STRING }, + }, + }, + { + field: 'contactLastTime', + title: '最后跟进时间', + minWidth: 180, + formatter: 'formatDateTime', + }, + { + field: 'contactLastContent', + title: '最后跟进记录', + minWidth: 200, + }, + { + field: 'detailAddress', + title: '地址', + minWidth: 200, + }, + { + field: 'poolDay', + title: '距离进入公海天数', + minWidth: 180, + }, + { + field: 'ownerUserName', + title: '负责人', + minWidth: 100, + }, + { + field: 'ownerUserDeptName', + title: '所属部门', + minWidth: 100, + }, + { + field: 'updateTime', + title: '更新时间', + minWidth: 180, + formatter: 'formatDateTime', + }, + { + field: 'createTime', + title: '创建时间', + minWidth: 180, + formatter: 'formatDateTime', + }, + { + field: 'creatorName', + title: '创建人', + minWidth: 100, + }, + ]; +} + +/** 回款审核列表的搜索表单 */ +export function useReceivableAuditFormSchema(): VbenFormSchema[] { + return [ + { + fieldName: 'auditStatus', + label: '合同状态', + component: 'Select', + componentProps: { + allowClear: true, + options: AUDIT_STATUS, + }, + defaultValue: 10, + }, + ]; +} + +/** 回款审核列表的字段 */ +export function useReceivableAuditColumns( + onActionClick: OnActionClickFn, +): VxeTableGridOptions['columns'] { + return [ + { + field: 'no', + title: '回款编号', + minWidth: 180, + fixed: 'left', + slots: { + default: 'no', + }, + }, + { + field: 'customerName', + title: '客户名称', + minWidth: 120, + slots: { + default: 'customerName', + }, + }, + { + field: 'contractNo', + title: '合同编号', + minWidth: 180, + slots: { + default: 'contractNo', + }, + }, + { + field: 'returnTime', + title: '回款日期', + minWidth: 150, + formatter: 'formatDateTime', + }, + { + field: 'price', + title: '回款金额(元)', + minWidth: 140, + formatter: 'formatAmount', + }, + { + field: 'returnType', + title: '回款方式', + minWidth: 130, + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.CRM_RECEIVABLE_RETURN_TYPE }, + }, + }, + { + field: 'remark', + title: '备注', + minWidth: 200, + }, + { + field: 'contract.totalPrice', + title: '合同金额(元)', + minWidth: 140, + formatter: 'formatAmount', + }, + { + field: 'ownerUserName', + title: '负责人', + minWidth: 120, + }, + { + field: 'ownerUserDeptName', + title: '所属部门', + minWidth: 100, + }, + { + field: 'updateTime', + title: '更新时间', + minWidth: 180, + formatter: 'formatDateTime', + }, + { + field: 'createTime', + title: '创建时间', + minWidth: 180, + formatter: 'formatDateTime', + }, + { + field: 'creatorName', + title: '创建人', + minWidth: 120, + }, + { + field: 'auditStatus', + title: '回款状态', + minWidth: 120, + fixed: 'right', + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.CRM_AUDIT_STATUS }, + }, + }, + { + field: 'operation', + title: '操作', + width: 140, + fixed: 'right', + align: 'center', + cellRender: { + attrs: { + nameField: 'name', + nameTitle: '角色', + onClick: onActionClick, + }, + name: 'CellOperation', + options: [ + { + code: 'processDetail', + text: '查看审批', + show: hasAccessByCodes(['crm:receivable:update']), + }, + ], + }, + }, + ]; +} + +/** 回款计划提醒列表的搜索表单 */ +export function useReceivablePlanRemindFormSchema(): VbenFormSchema[] { + return [ + { + fieldName: 'remindType', + label: '合同状态', + component: 'Select', + componentProps: { + allowClear: true, + options: RECEIVABLE_REMIND_TYPE, + }, + defaultValue: 1, + }, + ]; +} + +/** 回款计划提醒列表的字段 */ +export function useReceivablePlanRemindColumns( + onActionClick: OnActionClickFn, +): VxeTableGridOptions['columns'] { + return [ + { + field: 'customerName', + title: '客户名称', + minWidth: 160, + fixed: 'left', + slots: { + default: 'customerName', + }, + }, + { + field: 'contractNo', + title: '合同编号', + minWidth: 200, + }, + { + field: 'period', + title: '期数', + minWidth: 160, + slots: { + default: 'period', + }, + }, + { + field: 'price', + title: '计划回款金额(元)', + minWidth: 120, + formatter: 'formatAmount', + }, + { + field: 'returnTime', + title: '计划回款日期', + minWidth: 180, + formatter: 'formatDateTime', + }, + { + field: 'remindDays', + title: '提前几天提醒', + minWidth: 150, + }, + { + field: 'remindTime', + title: '提醒日期', + minWidth: 180, + formatter: 'formatDateTime', + }, + { + field: 'returnType', + title: '回款方式', + minWidth: 120, + fixed: 'right', + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.CRM_RECEIVABLE_RETURN_TYPE }, + }, + }, + { + field: 'remark', + title: '备注', + minWidth: 200, + }, + { + field: 'ownerUserName', + title: '负责人', + minWidth: 100, + }, + { + field: 'receivable.price', + title: '实际回款金额(元)', + minWidth: 160, + formatter: 'formatAmount', + }, + { + field: 'receivable.returnTime', + title: '实际回款日期', + minWidth: 180, + formatter: 'formatDateTime', + }, + { + field: 'updateTime', + title: '更新时间', + minWidth: 180, + formatter: 'formatDateTime', + }, + { + field: 'createTime', + title: '创建时间', + minWidth: 180, + formatter: 'formatDateTime', + }, + { + field: 'creatorName', + title: '创建人', + minWidth: 100, + }, + { + field: 'operation', + title: '操作', + width: 140, + fixed: 'right', + align: 'center', + cellRender: { + attrs: { + nameField: 'customerName', + nameTitle: '客户名称', + onClick: onActionClick, + }, + name: 'CellOperation', + options: [ + { + code: 'receivableForm', + text: '创建回款', + show: hasAccessByCodes(['crm:receivable:create']), + }, + ], + }, + }, + ]; +} diff --git a/apps/web-antd/src/views/crm/backlog/index.vue b/apps/web-antd/src/views/crm/backlog/index.vue index 2c8749d50..971814f55 100644 --- a/apps/web-antd/src/views/crm/backlog/index.vue +++ b/apps/web-antd/src/views/crm/backlog/index.vue @@ -1,34 +1,121 @@ +import { useLeftSides } from './data'; +import ClueFollowList from './modules/ClueFollowList.vue'; +import ContractAuditList from './modules/ContractAuditList.vue'; +import ContractRemindList from './modules/ContractRemindList.vue'; +import CustomerFollowList from './modules/CustomerFollowList.vue'; +import CustomerPutPoolRemindList from './modules/CustomerPutPoolRemindList.vue'; +import CustomerTodayContactList from './modules/CustomerTodayContactList.vue'; +import ReceivableAuditList from './modules/ReceivableAuditList.vue'; +import ReceivablePlanRemindList from './modules/ReceivablePlanRemindList.vue'; + +defineOptions({ name: 'CrmBacklog' }); + +const leftMenu = ref('customerTodayContact'); + +const clueFollowCount = ref(0); +const customerFollowCount = ref(0); +const customerPutPoolRemindCount = ref(0); +const customerTodayContactCount = ref(0); +const contractAuditCount = ref(0); +const contractRemindCount = ref(0); +const receivableAuditCount = ref(0); +const receivablePlanRemindCount = ref(0); + +const leftSides = useLeftSides( + customerTodayContactCount, + clueFollowCount, + customerFollowCount, + customerPutPoolRemindCount, + contractAuditCount, + contractRemindCount, + receivableAuditCount, + receivablePlanRemindCount, +); + +const currentComponent = computed(() => { + const components = { + customerTodayContact: CustomerTodayContactList, + clueFollow: ClueFollowList, + contractAudit: ContractAuditList, + receivableAudit: ReceivableAuditList, + contractRemind: ContractRemindList, + customerFollow: CustomerFollowList, + customerPutPoolRemind: CustomerPutPoolRemindList, + receivablePlanRemind: ReceivablePlanRemindList, + } as const; + return components[leftMenu.value as keyof typeof components]; +}); + +/** 侧边点击 */ +function sideClick(item: { menu: string }) { + leftMenu.value = item.menu; +} + +/** 获取数量 */ +async function getCount() { + customerTodayContactCount.value = + await CustomerApi.getTodayContactCustomerCount(); + customerPutPoolRemindCount.value = + await CustomerApi.getPutPoolRemindCustomerCount(); + customerFollowCount.value = await CustomerApi.getFollowCustomerCount(); + clueFollowCount.value = await ClueApi.getFollowClueCount(); + contractAuditCount.value = await ContractApi.getAuditContractCount(); + contractRemindCount.value = await ContractApi.getRemindContractCount(); + receivableAuditCount.value = await ReceivableApi.getAuditReceivableCount(); + receivablePlanRemindCount.value = + await ReceivablePlanApi.getReceivablePlanRemindCount(); +} + +/** 激活时 */ +onActivated(async () => { + getCount(); +}); + +/** 初始化 */ +onMounted(async () => { + getCount(); +}); + diff --git a/apps/web-antd/src/views/crm/backlog/modules/ClueFollowList.vue b/apps/web-antd/src/views/crm/backlog/modules/ClueFollowList.vue new file mode 100644 index 000000000..23d109c94 --- /dev/null +++ b/apps/web-antd/src/views/crm/backlog/modules/ClueFollowList.vue @@ -0,0 +1,58 @@ + + + + diff --git a/apps/web-antd/src/views/crm/backlog/modules/ContractAuditList.vue b/apps/web-antd/src/views/crm/backlog/modules/ContractAuditList.vue new file mode 100644 index 000000000..a243bfe58 --- /dev/null +++ b/apps/web-antd/src/views/crm/backlog/modules/ContractAuditList.vue @@ -0,0 +1,111 @@ + + + + diff --git a/apps/web-antd/src/views/crm/backlog/modules/ContractRemindList.vue b/apps/web-antd/src/views/crm/backlog/modules/ContractRemindList.vue new file mode 100644 index 000000000..c8ac29657 --- /dev/null +++ b/apps/web-antd/src/views/crm/backlog/modules/ContractRemindList.vue @@ -0,0 +1,111 @@ + + + + diff --git a/apps/web-antd/src/views/crm/backlog/modules/CustomerFollowList.vue b/apps/web-antd/src/views/crm/backlog/modules/CustomerFollowList.vue new file mode 100644 index 000000000..10e427dc9 --- /dev/null +++ b/apps/web-antd/src/views/crm/backlog/modules/CustomerFollowList.vue @@ -0,0 +1,58 @@ + + + + diff --git a/apps/web-antd/src/views/crm/backlog/modules/CustomerPutPoolRemindList.vue b/apps/web-antd/src/views/crm/backlog/modules/CustomerPutPoolRemindList.vue new file mode 100644 index 000000000..11899ace8 --- /dev/null +++ b/apps/web-antd/src/views/crm/backlog/modules/CustomerPutPoolRemindList.vue @@ -0,0 +1,58 @@ + + + + diff --git a/apps/web-antd/src/views/crm/backlog/modules/CustomerTodayContactList.vue b/apps/web-antd/src/views/crm/backlog/modules/CustomerTodayContactList.vue new file mode 100644 index 000000000..8298f90e8 --- /dev/null +++ b/apps/web-antd/src/views/crm/backlog/modules/CustomerTodayContactList.vue @@ -0,0 +1,58 @@ + + + + diff --git a/apps/web-antd/src/views/crm/backlog/modules/ReceivableAuditList.vue b/apps/web-antd/src/views/crm/backlog/modules/ReceivableAuditList.vue new file mode 100644 index 000000000..710c85847 --- /dev/null +++ b/apps/web-antd/src/views/crm/backlog/modules/ReceivableAuditList.vue @@ -0,0 +1,104 @@ + + + + diff --git a/apps/web-antd/src/views/crm/backlog/modules/ReceivablePlanRemindList.vue b/apps/web-antd/src/views/crm/backlog/modules/ReceivablePlanRemindList.vue new file mode 100644 index 000000000..e0137593a --- /dev/null +++ b/apps/web-antd/src/views/crm/backlog/modules/ReceivablePlanRemindList.vue @@ -0,0 +1,90 @@ + + + + diff --git a/apps/web-antd/src/views/crm/business/status/data.ts b/apps/web-antd/src/views/crm/business/status/data.ts new file mode 100644 index 000000000..2cdfce008 --- /dev/null +++ b/apps/web-antd/src/views/crm/business/status/data.ts @@ -0,0 +1,131 @@ +import type { VbenFormSchema } from '#/adapter/form'; +import type { OnActionClickFn, VxeTableGridOptions } from '#/adapter/vxe-table'; +import type { CrmBusinessStatusApi } from '#/api/crm/business/status'; + +import { useAccess } from '@vben/access'; +import { getRangePickerDefaultProps } from '@vben/utils'; + +import { z } from '#/adapter/form'; +import { CommonStatusEnum } from '#/utils/constants'; +import { DICT_TYPE, getDictOptions } from '#/utils/dict'; + +const { hasAccessByCodes } = useAccess(); + +/** 新增/修改的表单 */ +export function useFormSchema(): VbenFormSchema[] { + return [ + { + fieldName: 'id', + component: 'Input', + dependencies: { + triggerFields: [''], + show: () => false, + }, + }, + { + fieldName: 'name', + label: '状态组名', + component: 'Input', + rules: 'required', + }, + { + fieldName: 'deptIds', + label: '应用部门', + component: 'TreeSelect', + componentProps: { + multiple: true, + treeCheckable: true, + showCheckedStrategy: 'SHOW_PARENT', + placeholder: '请选择应用部门', + }, + }, + { + fieldName: 'status', + label: '状态', + component: 'RadioGroup', + componentProps: { + options: getDictOptions(DICT_TYPE.COMMON_STATUS, 'number'), + buttonStyle: 'solid', + optionType: 'button', + }, + rules: z.number().default(CommonStatusEnum.ENABLE), + }, + ]; +} + +/** 列表的搜索表单 */ +export function useGridFormSchema(): VbenFormSchema[] { + return [ + { + fieldName: 'name', + label: '状态组名', + component: 'Input', + }, + { + fieldName: 'createTime', + label: '创建时间', + component: 'RangePicker', + componentProps: { + ...getRangePickerDefaultProps(), + allowClear: true, + }, + }, + ]; +} + +/** 列表的字段 */ +export function useGridColumns( + onActionClick: OnActionClickFn, +): VxeTableGridOptions['columns'] { + return [ + { + field: 'name', + title: '状态组名', + minWidth: 200, + }, + { + field: 'deptNames', + title: '应用部门', + minWidth: 200, + formatter: ({ cellValue }) => { + return cellValue?.length > 0 ? cellValue.join(' ') : '全公司'; + }, + }, + { + field: 'creator', + title: '创建人', + minWidth: 100, + }, + { + field: 'createTime', + title: '创建时间', + minWidth: 180, + formatter: 'formatDateTime', + }, + { + field: 'operation', + title: '操作', + width: 160, + fixed: 'right', + align: 'center', + cellRender: { + name: 'TableAction', + props: { + actions: [ + { + label: '编辑', + code: 'edit', + show: hasAccessByCodes(['crm:business-status:update']), + }, + { + label: '删除', + code: 'delete', + show: hasAccessByCodes(['crm:business-status:delete']), + }, + ], + onActionClick, + }, + }, + }, + ]; +} diff --git a/apps/web-antd/src/views/crm/business/status/index.vue b/apps/web-antd/src/views/crm/business/status/index.vue index adb8b3bb0..8dc07be69 100644 --- a/apps/web-antd/src/views/crm/business/status/index.vue +++ b/apps/web-antd/src/views/crm/business/status/index.vue @@ -1,38 +1,137 @@ diff --git a/apps/web-antd/src/views/crm/business/status/modules/form.vue b/apps/web-antd/src/views/crm/business/status/modules/form.vue new file mode 100644 index 000000000..a9f18663a --- /dev/null +++ b/apps/web-antd/src/views/crm/business/status/modules/form.vue @@ -0,0 +1,94 @@ + + + diff --git a/apps/web-antd/src/views/demos/antd/index.vue b/apps/web-antd/src/views/demos/antd/index.vue deleted file mode 100644 index b3b05cc15..000000000 --- a/apps/web-antd/src/views/demos/antd/index.vue +++ /dev/null @@ -1,66 +0,0 @@ - - - diff --git a/apps/web-antd/src/views/infra/apiAccessLog/modules/detail.vue b/apps/web-antd/src/views/infra/apiAccessLog/modules/detail.vue index bfc8aee06..33c7f2633 100644 --- a/apps/web-antd/src/views/infra/apiAccessLog/modules/detail.vue +++ b/apps/web-antd/src/views/infra/apiAccessLog/modules/detail.vue @@ -28,7 +28,7 @@ const [Modal, modalApi] = useVbenModal({ try { formData.value = data; } finally { - modalApi.lock(false); + modalApi.unlock(); } }, }); diff --git a/apps/web-antd/src/views/infra/apiErrorLog/modules/detail.vue b/apps/web-antd/src/views/infra/apiErrorLog/modules/detail.vue index 7832783a1..dec2b3efb 100644 --- a/apps/web-antd/src/views/infra/apiErrorLog/modules/detail.vue +++ b/apps/web-antd/src/views/infra/apiErrorLog/modules/detail.vue @@ -28,7 +28,7 @@ const [Modal, modalApi] = useVbenModal({ try { formData.value = data; } finally { - modalApi.lock(false); + modalApi.unlock(); } }, }); diff --git a/apps/web-antd/src/views/infra/codegen/modules/import-table.vue b/apps/web-antd/src/views/infra/codegen/modules/import-table.vue index 5c0b59d33..9684d501e 100644 --- a/apps/web-antd/src/views/infra/codegen/modules/import-table.vue +++ b/apps/web-antd/src/views/infra/codegen/modules/import-table.vue @@ -110,7 +110,7 @@ const [Modal, modalApi] = useVbenModal({ }); } finally { hideLoading(); - modalApi.lock(false); + modalApi.unlock(); } }, }); diff --git a/apps/web-antd/src/views/infra/config/modules/form.vue b/apps/web-antd/src/views/infra/config/modules/form.vue index 389648c65..1278efbea 100644 --- a/apps/web-antd/src/views/infra/config/modules/form.vue +++ b/apps/web-antd/src/views/infra/config/modules/form.vue @@ -53,7 +53,7 @@ const [Modal, modalApi] = useVbenModal({ key: 'action_process_msg', }); } finally { - modalApi.lock(false); + modalApi.unlock(); } }, async onOpenChange(isOpen: boolean) { @@ -72,7 +72,7 @@ const [Modal, modalApi] = useVbenModal({ // 设置到 values await formApi.setValues(formData.value); } finally { - modalApi.lock(false); + modalApi.unlock(); } }, }); diff --git a/apps/web-antd/src/views/infra/dataSourceConfig/modules/form.vue b/apps/web-antd/src/views/infra/dataSourceConfig/modules/form.vue index ab66b86be..d73b586cb 100644 --- a/apps/web-antd/src/views/infra/dataSourceConfig/modules/form.vue +++ b/apps/web-antd/src/views/infra/dataSourceConfig/modules/form.vue @@ -60,7 +60,7 @@ const [Modal, modalApi] = useVbenModal({ key: 'action_process_msg', }); } finally { - modalApi.lock(false); + modalApi.unlock(); } }, async onOpenChange(isOpen: boolean) { @@ -79,7 +79,7 @@ const [Modal, modalApi] = useVbenModal({ // 设置到 values await formApi.setValues(formData.value); } finally { - modalApi.lock(false); + modalApi.unlock(); } }, }); diff --git a/apps/web-antd/src/views/infra/demo/demo01/modules/form.vue b/apps/web-antd/src/views/infra/demo/demo01/modules/form.vue index b9b5ea2db..5d01994bd 100644 --- a/apps/web-antd/src/views/infra/demo/demo01/modules/form.vue +++ b/apps/web-antd/src/views/infra/demo/demo01/modules/form.vue @@ -59,7 +59,7 @@ const [Modal, modalApi] = useVbenModal({ key: 'action_process_msg', }); } finally { - modalApi.lock(false); + modalApi.unlock(); } }, async onOpenChange(isOpen: boolean) { @@ -78,7 +78,7 @@ const [Modal, modalApi] = useVbenModal({ try { data = await getDemo01Contact(data.id); } finally { - modalApi.lock(false); + modalApi.unlock(); } } // 设置到 values diff --git a/apps/web-antd/src/views/infra/demo/demo02/modules/form.vue b/apps/web-antd/src/views/infra/demo/demo02/modules/form.vue index 3d38f5bae..3d203b320 100644 --- a/apps/web-antd/src/views/infra/demo/demo02/modules/form.vue +++ b/apps/web-antd/src/views/infra/demo/demo02/modules/form.vue @@ -65,7 +65,7 @@ const [Modal, modalApi] = useVbenModal({ key: 'action_process_msg', }); } finally { - modalApi.lock(false); + modalApi.unlock(); } }, async onOpenChange(isOpen: boolean) { @@ -86,7 +86,7 @@ const [Modal, modalApi] = useVbenModal({ try { data = await getDemo02Category(data.id); } finally { - modalApi.lock(false); + modalApi.unlock(); } } // 设置到 values diff --git a/apps/web-antd/src/views/infra/demo/demo03/erp/modules/demo03-course-form.vue b/apps/web-antd/src/views/infra/demo/demo03/erp/modules/demo03-course-form.vue index d98f4fa1b..b386ed401 100644 --- a/apps/web-antd/src/views/infra/demo/demo03/erp/modules/demo03-course-form.vue +++ b/apps/web-antd/src/views/infra/demo/demo03/erp/modules/demo03-course-form.vue @@ -61,7 +61,7 @@ const [Modal, modalApi] = useVbenModal({ key: 'action_process_msg', }); } finally { - modalApi.lock(false); + modalApi.unlock(); } }, async onOpenChange(isOpen: boolean) { @@ -80,7 +80,7 @@ const [Modal, modalApi] = useVbenModal({ try { data = await getDemo03Course(data.id); } finally { - modalApi.lock(false); + modalApi.unlock(); } } // 设置到 values diff --git a/apps/web-antd/src/views/infra/demo/demo03/erp/modules/demo03-grade-form.vue b/apps/web-antd/src/views/infra/demo/demo03/erp/modules/demo03-grade-form.vue index 4b134e203..23fdeb54b 100644 --- a/apps/web-antd/src/views/infra/demo/demo03/erp/modules/demo03-grade-form.vue +++ b/apps/web-antd/src/views/infra/demo/demo03/erp/modules/demo03-grade-form.vue @@ -61,7 +61,7 @@ const [Modal, modalApi] = useVbenModal({ key: 'action_process_msg', }); } finally { - modalApi.lock(false); + modalApi.unlock(); } }, async onOpenChange(isOpen: boolean) { @@ -80,7 +80,7 @@ const [Modal, modalApi] = useVbenModal({ try { data = await getDemo03Grade(data.id); } finally { - modalApi.lock(false); + modalApi.unlock(); } } // 设置到 values diff --git a/apps/web-antd/src/views/infra/demo/demo03/erp/modules/form.vue b/apps/web-antd/src/views/infra/demo/demo03/erp/modules/form.vue index 8fee6aa28..3795215b1 100644 --- a/apps/web-antd/src/views/infra/demo/demo03/erp/modules/form.vue +++ b/apps/web-antd/src/views/infra/demo/demo03/erp/modules/form.vue @@ -59,7 +59,7 @@ const [Modal, modalApi] = useVbenModal({ key: 'action_process_msg', }); } finally { - modalApi.lock(false); + modalApi.unlock(); } }, async onOpenChange(isOpen: boolean) { @@ -78,7 +78,7 @@ const [Modal, modalApi] = useVbenModal({ try { data = await getDemo03Student(data.id); } finally { - modalApi.lock(false); + modalApi.unlock(); } } // 设置到 values diff --git a/apps/web-antd/src/views/infra/demo/demo03/inner/modules/form.vue b/apps/web-antd/src/views/infra/demo/demo03/inner/modules/form.vue index 1c5e65090..51d91311b 100644 --- a/apps/web-antd/src/views/infra/demo/demo03/inner/modules/form.vue +++ b/apps/web-antd/src/views/infra/demo/demo03/inner/modules/form.vue @@ -61,9 +61,8 @@ const [Modal, modalApi] = useVbenModal({ // 提交表单 const data = (await formApi.getValues()) as Demo03StudentApi.Demo03Student; // 拼接子表的数据 - // TODO @puhui999:字段对不上 - data.demo03Courses = demo03CourseFormRef.value?.getData(); - data.demo03Grade = await demo03GradeFormRef.value?.getValues(); + data.demo03courses = demo03CourseFormRef.value?.getData(); + data.demo03grade = await demo03GradeFormRef.value?.getValues(); try { await (formData.value?.id ? updateDemo03Student(data) @@ -76,7 +75,7 @@ const [Modal, modalApi] = useVbenModal({ key: 'action_process_msg', }); } finally { - modalApi.lock(false); + modalApi.unlock(); } }, async onOpenChange(isOpen: boolean) { @@ -95,7 +94,7 @@ const [Modal, modalApi] = useVbenModal({ try { data = await getDemo03Student(data.id); } finally { - modalApi.lock(false); + modalApi.unlock(); } } // 设置到 values diff --git a/apps/web-antd/src/views/infra/demo/demo03/normal/modules/form.vue b/apps/web-antd/src/views/infra/demo/demo03/normal/modules/form.vue index 520226889..c8e47dcf7 100644 --- a/apps/web-antd/src/views/infra/demo/demo03/normal/modules/form.vue +++ b/apps/web-antd/src/views/infra/demo/demo03/normal/modules/form.vue @@ -61,8 +61,8 @@ const [Modal, modalApi] = useVbenModal({ // 提交表单 const data = (await formApi.getValues()) as Demo03StudentApi.Demo03Student; // 拼接子表的数据 - data.demo03Courses = demo03CourseFormRef.value?.getData(); - data.demo03Grade = await demo03GradeFormRef.value?.getValues(); + data.demo03courses = demo03CourseFormRef.value?.getData(); + data.demo03grade = await demo03GradeFormRef.value?.getValues(); try { await (formData.value?.id ? updateDemo03Student(data) @@ -75,7 +75,7 @@ const [Modal, modalApi] = useVbenModal({ key: 'action_process_msg', }); } finally { - modalApi.lock(false); + modalApi.unlock(); } }, async onOpenChange(isOpen: boolean) { @@ -94,7 +94,7 @@ const [Modal, modalApi] = useVbenModal({ try { data = await getDemo03Student(data.id); } finally { - modalApi.lock(false); + modalApi.unlock(); } } // 设置到 values diff --git a/apps/web-antd/src/views/infra/demo/general/demo01/modules/form.vue b/apps/web-antd/src/views/infra/demo/general/demo01/modules/form.vue index a0862b012..537353c7b 100644 --- a/apps/web-antd/src/views/infra/demo/general/demo01/modules/form.vue +++ b/apps/web-antd/src/views/infra/demo/general/demo01/modules/form.vue @@ -82,7 +82,7 @@ const [Modal, modalApi] = useVbenModal({ key: 'action_process_msg', }); } finally { - modalApi.lock(false); + modalApi.unlock(); } }, async onOpenChange(isOpen: boolean) { @@ -101,7 +101,7 @@ const [Modal, modalApi] = useVbenModal({ try { data = await getDemo01Contact(data.id); } finally { - modalApi.lock(false); + modalApi.unlock(); } } formData.value = data; diff --git a/apps/web-antd/src/views/infra/file/modules/form.vue b/apps/web-antd/src/views/infra/file/modules/form.vue index 9eb497e42..5a668084a 100644 --- a/apps/web-antd/src/views/infra/file/modules/form.vue +++ b/apps/web-antd/src/views/infra/file/modules/form.vue @@ -46,7 +46,7 @@ const [Modal, modalApi] = useVbenModal({ key: 'action_process_msg', }); } finally { - modalApi.lock(false); + modalApi.unlock(); } }, }); diff --git a/apps/web-antd/src/views/infra/fileConfig/modules/form.vue b/apps/web-antd/src/views/infra/fileConfig/modules/form.vue index a7393833d..d9ce11a2f 100644 --- a/apps/web-antd/src/views/infra/fileConfig/modules/form.vue +++ b/apps/web-antd/src/views/infra/fileConfig/modules/form.vue @@ -59,7 +59,7 @@ const [Modal, modalApi] = useVbenModal({ key: 'action_process_msg', }); } finally { - modalApi.lock(false); + modalApi.unlock(); } }, async onOpenChange(isOpen: boolean) { @@ -78,7 +78,7 @@ const [Modal, modalApi] = useVbenModal({ // 设置到 values await formApi.setValues(formData.value); } finally { - modalApi.lock(false); + modalApi.unlock(); } }, }); diff --git a/apps/web-antd/src/views/infra/job/logger/modules/detail.vue b/apps/web-antd/src/views/infra/job/logger/modules/detail.vue index ac33769b3..2b52c6c13 100644 --- a/apps/web-antd/src/views/infra/job/logger/modules/detail.vue +++ b/apps/web-antd/src/views/infra/job/logger/modules/detail.vue @@ -29,7 +29,7 @@ const [Modal, modalApi] = useVbenModal({ try { formData.value = await getJobLog(data.id); } finally { - modalApi.lock(false); + modalApi.unlock(); } }, }); diff --git a/apps/web-antd/src/views/infra/job/modules/detail.vue b/apps/web-antd/src/views/infra/job/modules/detail.vue index 7c9f3f452..8ebd101ec 100644 --- a/apps/web-antd/src/views/infra/job/modules/detail.vue +++ b/apps/web-antd/src/views/infra/job/modules/detail.vue @@ -32,7 +32,7 @@ const [Modal, modalApi] = useVbenModal({ // 获取下一次执行时间 nextTimes.value = await getJobNextTimes(data.id); } finally { - modalApi.lock(false); + modalApi.unlock(); } }, }); diff --git a/apps/web-antd/src/views/infra/job/modules/form.vue b/apps/web-antd/src/views/infra/job/modules/form.vue index 31653a8ee..ea09368c9 100644 --- a/apps/web-antd/src/views/infra/job/modules/form.vue +++ b/apps/web-antd/src/views/infra/job/modules/form.vue @@ -53,7 +53,7 @@ const [Modal, modalApi] = useVbenModal({ key: 'action_process_msg', }); } finally { - modalApi.lock(false); + modalApi.unlock(); } }, async onOpenChange(isOpen: boolean) { @@ -72,7 +72,7 @@ const [Modal, modalApi] = useVbenModal({ // 设置到 values await formApi.setValues(formData.value); } finally { - modalApi.lock(false); + modalApi.unlock(); } }, }); diff --git a/apps/web-antd/src/views/pay/notify/data.ts b/apps/web-antd/src/views/pay/notify/data.ts new file mode 100644 index 000000000..c21814c1f --- /dev/null +++ b/apps/web-antd/src/views/pay/notify/data.ts @@ -0,0 +1,187 @@ +import type { VbenFormSchema } from '#/adapter/form'; +import type { OnActionClickFn, VxeTableGridOptions } from '#/adapter/vxe-table'; + +import { useAccess } from '@vben/access'; + +import { getAppList } from '#/api/pay/app'; +import { DICT_TYPE, getDictOptions } from '#/utils/dict'; + +const { hasAccessByCodes } = useAccess(); + +/** 列表的搜索表单 */ +export function useGridFormSchema(): VbenFormSchema[] { + return [ + { + fieldName: 'appId', + label: '应用编号', + component: 'ApiSelect', + componentProps: { + api: async () => { + const data = await getAppList(); + return data.map((item) => ({ + label: item.name, + value: item.id, + })); + }, + autoSelect: 'first', + placeholder: '请选择数据源', + }, + }, + { + fieldName: 'type', + label: '通知类型', + component: 'Select', + componentProps: { + allowClear: true, + options: getDictOptions(DICT_TYPE.PAY_NOTIFY_TYPE, 'number'), + }, + }, + { + fieldName: 'dataId', + label: '关联编号', + component: 'Input', + }, + { + fieldName: 'status', + label: '通知状态', + component: 'Select', + componentProps: { + allowClear: true, + options: getDictOptions(DICT_TYPE.PAY_NOTIFY_STATUS, 'number'), + }, + }, + { + fieldName: 'merchantOrderId', + label: '商户订单编号', + component: 'Input', + }, + { + fieldName: 'createTime', + label: '创建时间', + component: 'DatePicker', + componentProps: { + type: 'daterange', + valueFormat: 'YYYY-MM-DD HH:mm:ss', + defaultTime: [new Date('1 00:00:00'), new Date('1 23:59:59')], + }, + }, + ]; +} + +/** 列表的字段 */ +export function useGridColumns( + onActionClick: OnActionClickFn, +): VxeTableGridOptions['columns'] { + return [ + { + field: 'id', + title: '任务编号', + minWidth: 100, + }, + { + field: 'appName', + title: '应用编号', + minWidth: 120, + }, + { + field: 'merchantOrderId', + title: '商户订单编号', + minWidth: 180, + }, + { + field: 'type', + title: '通知类型', + minWidth: 120, + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.PAY_NOTIFY_TYPE }, + }, + }, + { + field: 'dataId', + title: '关联编号', + minWidth: 120, + }, + { + field: 'status', + title: '通知状态', + minWidth: 120, + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.PAY_NOTIFY_STATUS }, + }, + }, + { + field: 'lastExecuteTime', + title: '最后通知时间', + minWidth: 180, + formatter: 'formatDateTime', + }, + { + field: 'nextNotifyTime', + title: '下次通知时间', + minWidth: 180, + formatter: 'formatDateTime', + }, + { + field: 'notifyTimes', + title: '通知次数', + minWidth: 120, + cellRender: { + name: 'CellTag', + props: { + type: 'success', + content: '{notifyTimes} / {maxNotifyTimes}', + }, + }, + }, + { + field: 'operation', + title: '操作', + minWidth: 100, + align: 'center', + fixed: 'right', + cellRender: { + attrs: { + onClick: onActionClick, + }, + name: 'CellOperation', + options: [ + { + code: 'detail', + show: hasAccessByCodes(['pay:notify:query']), + }, + ], + }, + }, + ]; +} + +/** 详情列表的字段 */ +export const detailColumns = [ + { + label: '日志编号', + prop: 'id', + key: 'id', + }, + { + label: '通知状态', + prop: 'status', + key: 'status', + }, + { + label: '通知次数', + prop: 'notifyTimes', + key: 'notifyTimes', + }, + { + label: '通知时间', + prop: 'lastExecuteTime', + key: 'lastExecuteTime', + }, + { + label: '响应结果', + prop: 'response', + key: 'response', + }, +]; diff --git a/apps/web-antd/src/views/pay/notify/index.vue b/apps/web-antd/src/views/pay/notify/index.vue index 006c77a13..ae5ec8cad 100644 --- a/apps/web-antd/src/views/pay/notify/index.vue +++ b/apps/web-antd/src/views/pay/notify/index.vue @@ -1,31 +1,78 @@ +import { useGridColumns, useGridFormSchema } from './data'; +import Detail from './modules/detail.vue'; + +const [NotifyDetailModal, notifyDetailModalApi] = useVbenModal({ + connectedComponent: Detail, + destroyOnClose: true, +}); + +/** 刷新表格 */ +function onRefresh() { + gridApi.query(); +} + +/** 查看详情 */ +function onDetail(row: any) { + notifyDetailModalApi.setData(row).open(); +} + +/** 表格操作按钮的回调函数 */ +function onActionClick({ code, row }: OnActionClickParams) { + switch (code) { + case 'detail': { + onDetail(row); + break; + } + } +} + +const [Grid, gridApi] = useVbenVxeGrid({ + formOptions: { + schema: useGridFormSchema(), + }, + gridOptions: { + columns: useGridColumns(onActionClick), + height: 'auto', + keepSource: true, + proxyConfig: { + ajax: { + query: async ({ page }, formValues) => { + return await PayNotifyApi.getNotifyTaskPage({ + pageNo: page.currentPage, + pageSize: page.pageSize, + ...formValues, + }); + }, + }, + }, + rowConfig: { + keyField: 'id', + }, + toolbarConfig: { + refresh: { code: 'query' }, + search: true, + }, + } as VxeTableGridOptions, +}); + diff --git a/apps/web-antd/src/views/pay/notify/modules/detail.vue b/apps/web-antd/src/views/pay/notify/modules/detail.vue new file mode 100644 index 000000000..3d18c41ca --- /dev/null +++ b/apps/web-antd/src/views/pay/notify/modules/detail.vue @@ -0,0 +1,107 @@ + + + diff --git a/apps/web-antd/src/views/pay/refund/data.ts b/apps/web-antd/src/views/pay/refund/data.ts new file mode 100644 index 000000000..2ce8917e6 --- /dev/null +++ b/apps/web-antd/src/views/pay/refund/data.ts @@ -0,0 +1,177 @@ +import type { VbenFormSchema } from '#/adapter/form'; +import type { OnActionClickFn, VxeTableGridOptions } from '#/adapter/vxe-table'; +import type { PayRefundApi } from '#/api/pay/refund'; + +import { useAccess } from '@vben/access'; + +import { getAppList } from '#/api/pay/app'; +import { DICT_TYPE, getIntDictOptions, getStrDictOptions } from '#/utils/dict'; + +const { hasAccessByCodes } = useAccess(); + +/** 列表的搜索表单 */ +export function useGridFormSchema(): VbenFormSchema[] { + return [ + { + fieldName: 'appId', + label: '应用编号', + component: 'ApiSelect', + componentProps: { + api: async () => { + const data = await getAppList(); + return data.map((item) => ({ + label: item.name, + value: item.id, + })); + }, + autoSelect: 'first', + placeholder: '请选择数据源', + }, + }, + { + fieldName: 'channelCode', + label: '退款渠道', + component: 'Select', + componentProps: { + allowClear: true, + options: getStrDictOptions(DICT_TYPE.PAY_CHANNEL_CODE), + }, + }, + { + fieldName: 'merchantOrderId', + label: '商户支付单号', + component: 'Input', + }, + { + fieldName: 'merchantRefundId', + label: '商户退款单号', + component: 'Input', + }, + { + fieldName: 'channelOrderNo', + label: '渠道支付单号', + component: 'Input', + }, + { + fieldName: 'channelRefundNo', + label: '渠道退款单号', + component: 'Input', + }, + { + fieldName: 'status', + label: '退款状态', + component: 'Select', + componentProps: { + allowClear: true, + options: getIntDictOptions(DICT_TYPE.PAY_REFUND_STATUS), + }, + }, + { + fieldName: 'createTime', + label: '创建时间', + component: 'DatePicker', + componentProps: { + type: 'daterange', + valueFormat: 'YYYY-MM-DD HH:mm:ss', + defaultTime: [new Date('1 00:00:00'), new Date('1 23:59:59')], + }, + }, + ]; +} + +/** 列表的字段 */ +export function useGridColumns( + onActionClick: OnActionClickFn, +): VxeTableGridOptions['columns'] { + return [ + { + field: 'id', + title: '编号', + minWidth: 100, + }, + { + field: 'createTime', + title: '创建时间', + minWidth: 180, + formatter: 'formatDateTime', + }, + { + field: 'payPrice', + title: '支付金额', + minWidth: 120, + cellRender: { + name: 'CellTag', + props: { + type: 'success', + content: '¥{payPrice}', + formatter: (value: number) => (value / 100).toFixed(2), + }, + }, + }, + { + field: 'refundPrice', + title: '退款金额', + minWidth: 120, + cellRender: { + name: 'CellTag', + props: { + type: 'danger', + content: '¥{refundPrice}', + formatter: (value: number) => (value / 100).toFixed(2), + }, + }, + }, + { + field: 'merchantRefundId', + title: '退款订单号', + minWidth: 300, + cellRender: { + name: 'CellTag', + props: { + type: 'info', + content: '商户 {merchantRefundId}', + }, + }, + }, + { + field: 'channelRefundNo', + title: '渠道退款单号', + minWidth: 200, + cellRender: { + name: 'CellTag', + props: { + type: 'success', + content: '{channelRefundNo}', + }, + }, + }, + { + field: 'status', + title: '退款状态', + minWidth: 120, + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.PAY_REFUND_STATUS }, + }, + }, + { + field: 'operation', + title: '操作', + minWidth: 100, + align: 'center', + fixed: 'right', + cellRender: { + attrs: { + onClick: onActionClick, + }, + name: 'CellOperation', + options: [ + { + code: 'detail', + show: hasAccessByCodes(['pay:refund:query']), + }, + ], + }, + }, + ]; +} diff --git a/apps/web-antd/src/views/pay/refund/index.vue b/apps/web-antd/src/views/pay/refund/index.vue index fcc2a406d..cbf80df07 100644 --- a/apps/web-antd/src/views/pay/refund/index.vue +++ b/apps/web-antd/src/views/pay/refund/index.vue @@ -1,34 +1,104 @@ +import { $t } from '#/locales'; +import { useGridColumns, useGridFormSchema } from './data'; +import Detail from './modules/detail.vue'; + +const [RefundDetailModal, refundDetailModalApi] = useVbenModal({ + connectedComponent: Detail, + destroyOnClose: true, +}); + +/** 刷新表格 */ +function onRefresh() { + gridApi.query(); +} + +/** 导出表格 */ +async function onExport() { + const data = await RefundApi.exportRefund(await gridApi.formApi.getValues()); + downloadFileFromBlobPart({ fileName: '支付退款.xls', source: data }); +} + +/** 查看详情 */ +function onDetail(row: any) { + refundDetailModalApi.setData(row).open(); +} + +/** 表格操作按钮的回调函数 */ +function onActionClick({ code, row }: OnActionClickParams) { + switch (code) { + case 'detail': { + onDetail(row); + break; + } + } +} + +const [Grid, gridApi] = useVbenVxeGrid({ + formOptions: { + schema: useGridFormSchema(), + }, + gridOptions: { + columns: useGridColumns(onActionClick), + height: 'auto', + keepSource: true, + proxyConfig: { + ajax: { + query: async ({ page }, formValues) => { + return await RefundApi.getRefundPage({ + pageNo: page.currentPage, + pageSize: page.pageSize, + ...formValues, + }); + }, + }, + }, + rowConfig: { + keyField: 'id', + }, + toolbarConfig: { + refresh: { code: 'query' }, + search: true, + }, + } as VxeTableGridOptions, +}); + diff --git a/apps/web-antd/src/views/pay/refund/modules/detail.vue b/apps/web-antd/src/views/pay/refund/modules/detail.vue new file mode 100644 index 000000000..557fb6134 --- /dev/null +++ b/apps/web-antd/src/views/pay/refund/modules/detail.vue @@ -0,0 +1,137 @@ + + + diff --git a/apps/web-antd/src/views/report/goview/index.vue b/apps/web-antd/src/views/report/goview/index.vue index 20e518c14..8f9d991f4 100644 --- a/apps/web-antd/src/views/report/goview/index.vue +++ b/apps/web-antd/src/views/report/goview/index.vue @@ -1,31 +1,25 @@