字段权限
diff --git a/apps/web-antd/src/components/simple-process-design/components/nodes/copy-task-node.vue b/apps/web-antd/src/components/simple-process-design/components/nodes/copy-task-node.vue
new file mode 100644
index 000000000..a3226a576
--- /dev/null
+++ b/apps/web-antd/src/components/simple-process-design/components/nodes/copy-task-node.vue
@@ -0,0 +1,118 @@
+
+
+
+
+
+
+
+
+
+
+
+ {{ currentNode.name }}
+
+
+
+
+ {{ currentNode.showText }}
+
+
+ {{ NODE_DEFAULT_TEXT.get(NodeType.COPY_TASK_NODE) }}
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/apps/web-antd/src/components/simple-process-design/components/process-node-tree.vue b/apps/web-antd/src/components/simple-process-design/components/process-node-tree.vue
index 9060b6c62..890b7ad07 100644
--- a/apps/web-antd/src/components/simple-process-design/components/process-node-tree.vue
+++ b/apps/web-antd/src/components/simple-process-design/components/process-node-tree.vue
@@ -3,6 +3,7 @@ import type { SimpleFlowNode } from '../consts';
import { NodeType } from '../consts';
import { useWatchNode } from '../helpers';
+import CopyTaskNode from './nodes/copy-task-node.vue';
import EndEventNode from './nodes/end-event-node.vue';
import StartUserNode from './nodes/start-user-node.vue';
import UserTaskNode from './nodes/user-task-node.vue';
@@ -77,11 +78,11 @@ const recursiveFindParentNode = (
@find-parent-node="findParentNode"
/>
-
+ />
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/apps/web-antd/src/views/crm/contract/modules/form.vue b/apps/web-antd/src/views/crm/contract/modules/form.vue
new file mode 100644
index 000000000..5d2b0b78a
--- /dev/null
+++ b/apps/web-antd/src/views/crm/contract/modules/form.vue
@@ -0,0 +1,85 @@
+
+
+
+
+
+
+
diff --git a/apps/web-antd/src/views/crm/product/data.ts b/apps/web-antd/src/views/crm/product/data.ts
index 592460a61..348afb372 100644
--- a/apps/web-antd/src/views/crm/product/data.ts
+++ b/apps/web-antd/src/views/crm/product/data.ts
@@ -1,7 +1,10 @@
import type { VbenFormSchema } from '#/adapter/form';
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
+import { handleTree } from '@vben/utils';
+
import { z } from '#/adapter/form';
+import { getProductCategoryList } from '#/api/crm/product/category';
import { CommonStatusEnum, DICT_TYPE, getDictOptions } from '#/utils';
/** 新增/修改的表单 */
@@ -28,17 +31,24 @@ export function useFormSchema(): VbenFormSchema[] {
rules: 'required',
},
{
- component: 'Input',
+ component: 'ApiTreeSelect',
fieldName: 'categoryName',
label: '产品类型',
rules: 'required',
+ componentProps: {
+ api: async () => {
+ const data = await getProductCategoryList();
+ return handleTree(data);
+ },
+ fieldNames: { label: 'name', value: 'id', children: 'children' },
+ },
},
{
fieldName: 'unit',
label: '产品单位',
component: 'Select',
componentProps: {
- options: getDictOptions(DICT_TYPE.CRM_PRODUCT_UNIT),
+ options: getDictOptions(DICT_TYPE.CRM_PRODUCT_UNIT, 'number'),
},
rules: 'required',
},
From d71d3122372db5d4baca649801b742145871175d Mon Sep 17 00:00:00 2001
From: xingyu4j
Date: Thu, 29 May 2025 17:47:59 +0800
Subject: [PATCH 15/53] feat: crm receivable
---
.../web-antd/src/views/crm/receivable/data.ts | 205 +++++++++++++
.../src/views/crm/receivable/index.vue | 275 ++++++++++++++++--
.../src/views/crm/receivable/modules/form.vue | 87 ++++++
3 files changed, 538 insertions(+), 29 deletions(-)
create mode 100644 apps/web-antd/src/views/crm/receivable/data.ts
create mode 100644 apps/web-antd/src/views/crm/receivable/modules/form.vue
diff --git a/apps/web-antd/src/views/crm/receivable/data.ts b/apps/web-antd/src/views/crm/receivable/data.ts
new file mode 100644
index 000000000..558b284fc
--- /dev/null
+++ b/apps/web-antd/src/views/crm/receivable/data.ts
@@ -0,0 +1,205 @@
+import type { VbenFormSchema } from '#/adapter/form';
+import type { VxeTableGridOptions } from '#/adapter/vxe-table';
+
+import { getCustomerSimpleList } from '#/api/crm/customer';
+import { DICT_TYPE } from '#/utils/dict';
+
+/** 新增/修改的表单 */
+export function useFormSchema(): VbenFormSchema[] {
+ return [
+ {
+ fieldName: 'no',
+ label: '回款编号',
+ component: 'Input',
+ rules: 'required',
+ componentProps: {
+ placeholder: '请输入回款编号',
+ },
+ },
+ {
+ fieldName: 'customerId',
+ label: '客户',
+ component: 'ApiSelect',
+ rules: 'required',
+ componentProps: {
+ api: getCustomerSimpleList,
+ labelField: 'name',
+ valueField: 'id',
+ placeholder: '请选择客户',
+ },
+ },
+ {
+ fieldName: 'contractId',
+ label: '合同',
+ component: 'ApiSelect',
+ rules: 'required',
+ componentProps: {
+ api: getCustomerSimpleList,
+ labelField: 'name',
+ valueField: 'id',
+ placeholder: '请选择合同',
+ },
+ },
+ {
+ fieldName: 'returnTime',
+ label: '回款日期',
+ component: 'DatePicker',
+ rules: 'required',
+ componentProps: {
+ placeholder: '请选择回款日期',
+ },
+ },
+ {
+ fieldName: 'price',
+ label: '回款金额',
+ component: 'InputNumber',
+ rules: 'required',
+ componentProps: {
+ placeholder: '请输入回款金额',
+ min: 0,
+ precision: 2,
+ },
+ },
+ {
+ fieldName: 'returnType',
+ label: '回款方式',
+ component: 'DictSelect',
+ rules: 'required',
+ componentProps: {
+ type: DICT_TYPE.CRM_RECEIVABLE_RETURN_TYPE,
+ placeholder: '请选择回款方式',
+ },
+ },
+ {
+ fieldName: 'remark',
+ label: '备注',
+ component: 'Textarea',
+ componentProps: {
+ placeholder: '请输入备注',
+ rows: 4,
+ },
+ },
+ ];
+}
+
+/** 列表的搜索表单 */
+export function useGridFormSchema(): VbenFormSchema[] {
+ return [
+ {
+ fieldName: 'no',
+ label: '回款编号',
+ component: 'Input',
+ },
+ {
+ fieldName: 'customerId',
+ label: '客户',
+ component: 'ApiSelect',
+ componentProps: {
+ api: getCustomerSimpleList,
+ labelField: 'name',
+ valueField: 'id',
+ placeholder: '请选择客户',
+ },
+ },
+ ];
+}
+
+export function useGridColumns(): VxeTableGridOptions['columns'] {
+ return [
+ {
+ title: '回款编号',
+ field: 'no',
+ width: 150,
+ fixed: 'left',
+ slots: { default: 'no' },
+ },
+ {
+ title: '客户名称',
+ field: 'customerName',
+ width: 150,
+ slots: { default: 'customerName' },
+ },
+ {
+ title: '合同编号',
+ field: 'contract',
+ width: 150,
+ slots: { default: 'contractNo' },
+ },
+ {
+ title: '回款日期',
+ field: 'returnTime',
+ width: 150,
+ formatter: 'formatDateTime',
+ },
+ {
+ title: '回款金额(元)',
+ field: 'price',
+ width: 150,
+ formatter: 'formatNumber',
+ },
+ {
+ title: '回款方式',
+ field: 'returnType',
+ width: 150,
+ cellRender: {
+ name: 'CellDict',
+ props: { type: DICT_TYPE.CRM_RECEIVABLE_RETURN_TYPE },
+ },
+ },
+ {
+ title: '备注',
+ field: 'remark',
+ width: 150,
+ },
+ {
+ title: '合同金额(元)',
+ field: 'contract.totalPrice',
+ width: 150,
+ formatter: 'formatNumber',
+ },
+ {
+ title: '负责人',
+ field: 'ownerUserName',
+ width: 150,
+ },
+ {
+ title: '所属部门',
+ field: 'ownerUserDeptName',
+ width: 150,
+ },
+ {
+ title: '更新时间',
+ field: 'updateTime',
+ width: 150,
+ formatter: 'formatDateTime',
+ },
+ {
+ title: '创建时间',
+ field: 'createTime',
+ width: 150,
+ formatter: 'formatDateTime',
+ },
+ {
+ title: '创建人',
+ field: 'creatorName',
+ width: 150,
+ },
+ {
+ title: '回款状态',
+ field: 'auditStatus',
+ width: 100,
+ fixed: 'right',
+ cellRender: {
+ name: 'CellDict',
+ props: { type: DICT_TYPE.CRM_AUDIT_STATUS },
+ },
+ },
+ {
+ title: '操作',
+ field: 'actions',
+ width: 130,
+ fixed: 'right',
+ slots: { default: 'actions' },
+ },
+ ];
+}
diff --git a/apps/web-antd/src/views/crm/receivable/index.vue b/apps/web-antd/src/views/crm/receivable/index.vue
index 016c4968a..14802db09 100644
--- a/apps/web-antd/src/views/crm/receivable/index.vue
+++ b/apps/web-antd/src/views/crm/receivable/index.vue
@@ -1,38 +1,255 @@
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ --
+
+
+
+
+
diff --git a/apps/web-antd/src/views/crm/receivable/modules/form.vue b/apps/web-antd/src/views/crm/receivable/modules/form.vue
new file mode 100644
index 000000000..0166fb2b3
--- /dev/null
+++ b/apps/web-antd/src/views/crm/receivable/modules/form.vue
@@ -0,0 +1,87 @@
+
+
+
+
+
+
+
From 54247753176087eb0ec5166e7c2ebc9636bb7783 Mon Sep 17 00:00:00 2001
From: xingyu4j
Date: Thu, 29 May 2025 19:58:40 +0800
Subject: [PATCH 16/53] feat: crm receivable
---
.../web-antd/src/views/crm/receivable/data.ts | 90 ++++++-
.../src/views/crm/receivable/index.vue | 2 +-
.../src/views/crm/receivable/modules/form.vue | 20 +-
.../src/views/crm/receivable/plan/data.ts | 229 +++++++++++++++++
.../src/views/crm/receivable/plan/index.vue | 237 +++++++++++++++---
.../crm/receivable/plan/modules/form.vue | 88 +++++++
6 files changed, 621 insertions(+), 45 deletions(-)
create mode 100644 apps/web-antd/src/views/crm/receivable/plan/data.ts
create mode 100644 apps/web-antd/src/views/crm/receivable/plan/modules/form.vue
diff --git a/apps/web-antd/src/views/crm/receivable/data.ts b/apps/web-antd/src/views/crm/receivable/data.ts
index 558b284fc..cbbc5c25f 100644
--- a/apps/web-antd/src/views/crm/receivable/data.ts
+++ b/apps/web-antd/src/views/crm/receivable/data.ts
@@ -1,24 +1,48 @@
import type { VbenFormSchema } from '#/adapter/form';
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
+import { getContractSimpleList } from '#/api/crm/contract';
import { getCustomerSimpleList } from '#/api/crm/customer';
-import { DICT_TYPE } from '#/utils/dict';
+import { getReceivablePlanSimpleList } from '#/api/crm/receivable/plan';
+import { getSimpleUserList } from '#/api/system/user';
+import { DICT_TYPE, getDictOptions } from '#/utils/dict';
/** 新增/修改的表单 */
export function useFormSchema(): VbenFormSchema[] {
return [
+ {
+ fieldName: 'id',
+ component: 'Input',
+ dependencies: {
+ triggerFields: [''],
+ show: () => false,
+ },
+ },
{
fieldName: 'no',
label: '回款编号',
component: 'Input',
rules: 'required',
componentProps: {
- placeholder: '请输入回款编号',
+ placeholder: '保存时自动生成',
+ disabled: true,
+ },
+ },
+ {
+ fieldName: 'ownerUserId',
+ label: '负责人',
+ component: 'ApiSelect',
+ rules: 'required',
+ componentProps: {
+ api: getSimpleUserList,
+ labelField: 'nickname',
+ valueField: 'id',
+ placeholder: '请选择客户',
},
},
{
fieldName: 'customerId',
- label: '客户',
+ label: '客户名称',
component: 'ApiSelect',
rules: 'required',
componentProps: {
@@ -30,23 +54,63 @@ export function useFormSchema(): VbenFormSchema[] {
},
{
fieldName: 'contractId',
- label: '合同',
- component: 'ApiSelect',
+ label: '合同名称',
+ component: 'Select',
rules: 'required',
- componentProps: {
- api: getCustomerSimpleList,
- labelField: 'name',
- valueField: 'id',
- placeholder: '请选择合同',
+ dependencies: {
+ triggerFields: ['customerId'],
+ disabled: (values) => !values.customerId,
+ async componentProps(values) {
+ if (values.customerId) {
+ values.contractId = undefined;
+ const contracts = await getContractSimpleList(values.customerId);
+ return {
+ options: contracts.map((item) => ({
+ label: item.name,
+ value: item.id,
+ disabled: item.auditStatus === 20,
+ })),
+ placeholder: '请选择合同',
+ } as any;
+ }
+ },
+ },
+ },
+ {
+ fieldName: 'planId',
+ label: '回款期数',
+ component: 'Select',
+ rules: 'required',
+ dependencies: {
+ triggerFields: ['contractId'],
+ disabled: (values) => !values.contractId,
+ async componentProps(values) {
+ if (values.contractId) {
+ values.planId = undefined;
+ const plans = await getReceivablePlanSimpleList(
+ values.customerId,
+ values.contractId,
+ );
+ return {
+ options: plans.map((item) => ({
+ label: item.period,
+ value: item.id,
+ })),
+ placeholder: '请选择回款期数',
+ } as any;
+ }
+ },
},
},
{
fieldName: 'returnTime',
label: '回款日期',
component: 'DatePicker',
- rules: 'required',
componentProps: {
placeholder: '请选择回款日期',
+ showTime: false,
+ valueFormat: 'x',
+ format: 'YYYY-MM-DD',
},
},
{
@@ -63,10 +127,10 @@ export function useFormSchema(): VbenFormSchema[] {
{
fieldName: 'returnType',
label: '回款方式',
- component: 'DictSelect',
+ component: 'Select',
rules: 'required',
componentProps: {
- type: DICT_TYPE.CRM_RECEIVABLE_RETURN_TYPE,
+ options: getDictOptions(DICT_TYPE.CRM_RECEIVABLE_RETURN_TYPE, 'number'),
placeholder: '请选择回款方式',
},
},
diff --git a/apps/web-antd/src/views/crm/receivable/index.vue b/apps/web-antd/src/views/crm/receivable/index.vue
index 14802db09..ff187d968 100644
--- a/apps/web-antd/src/views/crm/receivable/index.vue
+++ b/apps/web-antd/src/views/crm/receivable/index.vue
@@ -49,7 +49,7 @@ function handleCreate() {
/** 编辑回款 */
function handleEdit(row: CrmReceivableApi.Receivable) {
- formModalApi.setData(row).open();
+ formModalApi.setData({ receivable: row }).open();
}
/** 删除回款 */
diff --git a/apps/web-antd/src/views/crm/receivable/modules/form.vue b/apps/web-antd/src/views/crm/receivable/modules/form.vue
index 0166fb2b3..e92610c25 100644
--- a/apps/web-antd/src/views/crm/receivable/modules/form.vue
+++ b/apps/web-antd/src/views/crm/receivable/modules/form.vue
@@ -65,12 +65,28 @@ const [Modal, modalApi] = useVbenModal({
}
// 加载数据
const data = modalApi.getData();
- if (!data || !data.id) {
+ if (!data) {
return;
}
+ const { receivable, plan } = data;
modalApi.lock();
try {
- formData.value = await getReceivable(data.id as number);
+ if (receivable) {
+ formData.value = await getReceivable(receivable.id as number);
+ } else if (plan) {
+ formData.value = plan.id
+ ? {
+ planId: plan.id,
+ price: plan.price,
+ returnType: plan.returnType,
+ customerId: plan.customerId,
+ contractId: plan.contractId,
+ }
+ : {
+ customerId: plan.customerId,
+ contractId: plan.contractId,
+ };
+ }
// 设置到 values
await formApi.setValues(formData.value);
} finally {
diff --git a/apps/web-antd/src/views/crm/receivable/plan/data.ts b/apps/web-antd/src/views/crm/receivable/plan/data.ts
new file mode 100644
index 000000000..cc76b1eeb
--- /dev/null
+++ b/apps/web-antd/src/views/crm/receivable/plan/data.ts
@@ -0,0 +1,229 @@
+import type { VbenFormSchema } from '#/adapter/form';
+import type { VxeTableGridOptions } from '#/adapter/vxe-table';
+
+import { getCustomerSimpleList } from '#/api/crm/customer';
+import { DICT_TYPE, getDictOptions } from '#/utils/dict';
+
+/** 新增/修改的表单 */
+export function useFormSchema(): VbenFormSchema[] {
+ return [
+ {
+ fieldName: 'customerId',
+ label: '客户',
+ component: 'ApiSelect',
+ rules: 'required',
+ componentProps: {
+ api: getCustomerSimpleList,
+ labelField: 'name',
+ valueField: 'id',
+ placeholder: '请选择客户',
+ },
+ },
+ {
+ fieldName: 'contractId',
+ label: '合同',
+ component: 'ApiSelect',
+ rules: 'required',
+ componentProps: {
+ api: getCustomerSimpleList,
+ labelField: 'name',
+ valueField: 'id',
+ placeholder: '请选择合同',
+ },
+ },
+ {
+ fieldName: 'period',
+ label: '期数',
+ component: 'Input',
+ componentProps: {
+ placeholder: '保存时自动生成',
+ disabled: true,
+ },
+ },
+ {
+ fieldName: 'price',
+ label: '计划回款金额',
+ component: 'InputNumber',
+ rules: 'required',
+ componentProps: {
+ placeholder: '请输入计划回款金额',
+ min: 0,
+ precision: 2,
+ },
+ },
+ {
+ fieldName: 'returnTime',
+ label: '计划回款日期',
+ component: 'DatePicker',
+ rules: 'required',
+ componentProps: {
+ placeholder: '请选择计划回款日期',
+ },
+ },
+ {
+ fieldName: 'remindDays',
+ label: '提前几天提醒',
+ component: 'InputNumber',
+ rules: 'required',
+ componentProps: {
+ placeholder: '请输入提前几天提醒',
+ min: 0,
+ },
+ },
+ {
+ fieldName: 'returnType',
+ label: '回款方式',
+ component: 'Select',
+ rules: 'required',
+ componentProps: {
+ options: getDictOptions(DICT_TYPE.CRM_RECEIVABLE_RETURN_TYPE, 'number'),
+ placeholder: '请选择回款方式',
+ },
+ },
+ {
+ fieldName: 'remark',
+ label: '备注',
+ component: 'Textarea',
+ componentProps: {
+ placeholder: '请输入备注',
+ rows: 4,
+ },
+ },
+ ];
+}
+
+/** 列表的搜索表单 */
+export function useGridFormSchema(): VbenFormSchema[] {
+ return [
+ {
+ fieldName: 'customerId',
+ label: '客户',
+ component: 'ApiSelect',
+ componentProps: {
+ api: getCustomerSimpleList,
+ labelField: 'name',
+ valueField: 'id',
+ placeholder: '请选择客户',
+ },
+ },
+ {
+ fieldName: 'contractNo',
+ label: '合同编号',
+ component: 'Input',
+ componentProps: {
+ placeholder: '请输入合同编号',
+ },
+ },
+ ];
+}
+
+export function useGridColumns(): VxeTableGridOptions['columns'] {
+ return [
+ {
+ title: '客户名称',
+ field: 'customerName',
+ width: 150,
+ fixed: 'left',
+ slots: { default: 'customerName' },
+ },
+ {
+ title: '合同编号',
+ field: 'contractNo',
+ width: 200,
+ },
+ {
+ title: '期数',
+ field: 'period',
+ width: 150,
+ slots: { default: 'period' },
+ },
+ {
+ title: '计划回款金额(元)',
+ field: 'price',
+ width: 160,
+ formatter: 'formatNumber',
+ },
+ {
+ title: '计划回款日期',
+ field: 'returnTime',
+ width: 180,
+ formatter: 'formatDateTime',
+ },
+ {
+ title: '提前几天提醒',
+ field: 'remindDays',
+ width: 150,
+ },
+ {
+ title: '提醒日期',
+ field: 'remindTime',
+ width: 180,
+ formatter: 'formatDateTime',
+ },
+ {
+ title: '回款方式',
+ field: 'returnType',
+ width: 130,
+ cellRender: {
+ name: 'CellDict',
+ props: { type: DICT_TYPE.CRM_RECEIVABLE_RETURN_TYPE },
+ },
+ },
+ {
+ title: '备注',
+ field: 'remark',
+ },
+ {
+ title: '负责人',
+ field: 'ownerUserName',
+ width: 120,
+ },
+ {
+ title: '实际回款金额(元)',
+ field: 'receivable.price',
+ width: 160,
+ formatter: 'formatNumber',
+ },
+ {
+ title: '实际回款日期',
+ field: 'receivable.returnTime',
+ width: 180,
+ formatter: 'formatDateTime',
+ },
+ {
+ title: '未回款金额(元)',
+ field: 'unpaidPrice',
+ width: 160,
+ formatter: ({ row }) => {
+ if (row.receivable) {
+ return row.price - row.receivable.price;
+ }
+ return row.price;
+ },
+ },
+ {
+ title: '更新时间',
+ field: 'updateTime',
+ width: 180,
+ formatter: 'formatDateTime',
+ },
+ {
+ title: '创建时间',
+ field: 'createTime',
+ width: 180,
+ formatter: 'formatDateTime',
+ },
+ {
+ title: '创建人',
+ field: 'creatorName',
+ width: 100,
+ },
+ {
+ title: '操作',
+ field: 'actions',
+ width: 180,
+ fixed: 'right',
+ slots: { default: 'actions' },
+ },
+ ];
+}
diff --git a/apps/web-antd/src/views/crm/receivable/plan/index.vue b/apps/web-antd/src/views/crm/receivable/plan/index.vue
index dc177ae79..1f4c479cb 100644
--- a/apps/web-antd/src/views/crm/receivable/plan/index.vue
+++ b/apps/web-antd/src/views/crm/receivable/plan/index.vue
@@ -1,38 +1,217 @@
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/apps/web-antd/src/views/crm/receivable/plan/modules/form.vue b/apps/web-antd/src/views/crm/receivable/plan/modules/form.vue
new file mode 100644
index 000000000..41a2132c1
--- /dev/null
+++ b/apps/web-antd/src/views/crm/receivable/plan/modules/form.vue
@@ -0,0 +1,88 @@
+
+
+
+
+
+
+
From b4855beb1f96f1b70b0d05911e1b154fd84fd6a2 Mon Sep 17 00:00:00 2001
From: xingyu4j
Date: Thu, 29 May 2025 20:03:12 +0800
Subject: [PATCH 17/53] feat: crm customer pool
---
.../src/views/crm/customer/pool/data.ts | 155 ++++++++++++++++++
.../src/views/crm/customer/pool/index.vue | 113 ++++++++++---
2 files changed, 241 insertions(+), 27 deletions(-)
create mode 100644 apps/web-antd/src/views/crm/customer/pool/data.ts
diff --git a/apps/web-antd/src/views/crm/customer/pool/data.ts b/apps/web-antd/src/views/crm/customer/pool/data.ts
new file mode 100644
index 000000000..b0909b004
--- /dev/null
+++ b/apps/web-antd/src/views/crm/customer/pool/data.ts
@@ -0,0 +1,155 @@
+import type { VbenFormSchema } from '#/adapter/form';
+import type { VxeTableGridOptions } from '#/adapter/vxe-table';
+
+import { DICT_TYPE, getDictOptions } from '#/utils/dict';
+
+/** 列表的搜索表单 */
+export function useGridFormSchema(): VbenFormSchema[] {
+ return [
+ {
+ fieldName: 'name',
+ label: '客户名称',
+ component: 'Input',
+ componentProps: {
+ placeholder: '请输入客户名称',
+ },
+ },
+ {
+ fieldName: 'mobile',
+ label: '手机',
+ component: 'Input',
+ componentProps: {
+ placeholder: '请输入手机',
+ },
+ },
+ {
+ fieldName: 'industryId',
+ label: '所属行业',
+ component: 'Select',
+ componentProps: {
+ options: getDictOptions(DICT_TYPE.CRM_CUSTOMER_INDUSTRY, 'number'),
+ placeholder: '请选择所属行业',
+ },
+ },
+ {
+ fieldName: 'level',
+ label: '客户级别',
+ component: 'Select',
+ componentProps: {
+ options: getDictOptions(DICT_TYPE.CRM_CUSTOMER_LEVEL, 'number'),
+ placeholder: '请选择客户级别',
+ },
+ },
+ {
+ fieldName: 'source',
+ label: '客户来源',
+ component: 'Select',
+ componentProps: {
+ options: getDictOptions(DICT_TYPE.CRM_CUSTOMER_SOURCE, 'number'),
+ placeholder: '请选择客户来源',
+ },
+ },
+ ];
+}
+
+export function useGridColumns(): VxeTableGridOptions['columns'] {
+ return [
+ {
+ title: '客户名称',
+ field: 'name',
+ width: 160,
+ fixed: 'left',
+ slots: { default: 'name' },
+ },
+ {
+ title: '客户来源',
+ field: 'source',
+ width: 100,
+ cellRender: {
+ name: 'CellDict',
+ props: { type: DICT_TYPE.CRM_CUSTOMER_SOURCE },
+ },
+ },
+ {
+ title: '手机',
+ field: 'mobile',
+ width: 120,
+ },
+ {
+ title: '电话',
+ field: 'telephone',
+ width: 120,
+ },
+ {
+ title: '邮箱',
+ field: 'email',
+ width: 140,
+ },
+ {
+ title: '客户级别',
+ field: 'level',
+ width: 135,
+ cellRender: {
+ name: 'CellDict',
+ props: { type: DICT_TYPE.CRM_CUSTOMER_LEVEL },
+ },
+ },
+ {
+ title: '客户行业',
+ field: 'industryId',
+ width: 100,
+ cellRender: {
+ name: 'CellDict',
+ props: { type: DICT_TYPE.CRM_CUSTOMER_INDUSTRY },
+ },
+ },
+ {
+ title: '下次联系时间',
+ field: 'contactNextTime',
+ width: 180,
+ formatter: 'formatDateTime',
+ },
+ {
+ title: '备注',
+ field: 'remark',
+ width: 200,
+ },
+ {
+ title: '成交状态',
+ field: 'dealStatus',
+ width: 80,
+ cellRender: {
+ name: 'CellDict',
+ props: { type: DICT_TYPE.INFRA_BOOLEAN_STRING },
+ },
+ },
+ {
+ title: '最后跟进时间',
+ field: 'contactLastTime',
+ width: 180,
+ formatter: 'formatDateTime',
+ },
+ {
+ title: '最后跟进记录',
+ field: 'contactLastContent',
+ width: 200,
+ },
+ {
+ title: '更新时间',
+ field: 'updateTime',
+ width: 180,
+ formatter: 'formatDateTime',
+ },
+ {
+ title: '创建时间',
+ field: 'createTime',
+ width: 180,
+ formatter: 'formatDateTime',
+ },
+ {
+ title: '创建人',
+ field: 'creatorName',
+ width: 100,
+ },
+ ];
+}
diff --git a/apps/web-antd/src/views/crm/customer/pool/index.vue b/apps/web-antd/src/views/crm/customer/pool/index.vue
index aa330f83c..df3858baa 100644
--- a/apps/web-antd/src/views/crm/customer/pool/index.vue
+++ b/apps/web-antd/src/views/crm/customer/pool/index.vue
@@ -1,38 +1,97 @@
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
From 32bd64a00879192798da044aeb47aa32c9b6eb25 Mon Sep 17 00:00:00 2001
From: xingyu4j
Date: Thu, 29 May 2025 20:58:47 +0800
Subject: [PATCH 18/53] feat: customer pool config
---
.../views/crm/customer/poolConfig/index.vue | 167 +++++++++++++++---
1 file changed, 138 insertions(+), 29 deletions(-)
diff --git a/apps/web-antd/src/views/crm/customer/poolConfig/index.vue b/apps/web-antd/src/views/crm/customer/poolConfig/index.vue
index 717d8cbec..1b6efe91b 100644
--- a/apps/web-antd/src/views/crm/customer/poolConfig/index.vue
+++ b/apps/web-antd/src/views/crm/customer/poolConfig/index.vue
@@ -1,38 +1,147 @@
-
-
-
-
-
-
+
+
+
+
From 62bb005748fc4f73e2578ccd032759e64a952dda Mon Sep 17 00:00:00 2001
From: xingyu4j
Date: Thu, 29 May 2025 21:09:54 +0800
Subject: [PATCH 19/53] feat: config
---
.../src/views/crm/contract/config/index.vue | 124 ++++++++++++++----
.../views/crm/customer/poolConfig/index.vue | 17 ++-
2 files changed, 107 insertions(+), 34 deletions(-)
diff --git a/apps/web-antd/src/views/crm/contract/config/index.vue b/apps/web-antd/src/views/crm/contract/config/index.vue
index db64ed742..d0dcd1aff 100644
--- a/apps/web-antd/src/views/crm/contract/config/index.vue
+++ b/apps/web-antd/src/views/crm/contract/config/index.vue
@@ -1,38 +1,104 @@
-
-
-
-
-
-
+
+
+
+
diff --git a/apps/web-antd/src/views/crm/customer/poolConfig/index.vue b/apps/web-antd/src/views/crm/customer/poolConfig/index.vue
index 1b6efe91b..75244ab15 100644
--- a/apps/web-antd/src/views/crm/customer/poolConfig/index.vue
+++ b/apps/web-antd/src/views/crm/customer/poolConfig/index.vue
@@ -1,7 +1,7 @@
-
-
-
@@ -105,11 +98,17 @@ onMounted(async () => {
- {{ item.name }}
+
+ {{ item.name }}
+
-
-
+
+
diff --git a/apps/web-antd/src/views/crm/backlog/modules/ReceivablePlanRemindList.vue b/apps/web-antd/src/views/crm/backlog/modules/ReceivablePlanRemindList.vue
deleted file mode 100644
index e0137593a..000000000
--- a/apps/web-antd/src/views/crm/backlog/modules/ReceivablePlanRemindList.vue
+++ /dev/null
@@ -1,90 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/apps/web-antd/src/views/crm/backlog/modules/clue-follow-list.vue b/apps/web-antd/src/views/crm/backlog/modules/clue-follow-list.vue
index 60ca44d9b..2c52c2ffb 100644
--- a/apps/web-antd/src/views/crm/backlog/modules/clue-follow-list.vue
+++ b/apps/web-antd/src/views/crm/backlog/modules/clue-follow-list.vue
@@ -1,5 +1,6 @@
-
+
+
+
+
diff --git a/apps/web-antd/src/views/crm/backlog/modules/contract-audit-list.vue b/apps/web-antd/src/views/crm/backlog/modules/contract-audit-list.vue
index f9048a24c..3e3032af5 100644
--- a/apps/web-antd/src/views/crm/backlog/modules/contract-audit-list.vue
+++ b/apps/web-antd/src/views/crm/backlog/modules/contract-audit-list.vue
@@ -1,5 +1,6 @@
-
+
-
-
+ handleConditionUpdate(index, val)"
- /> -->
+ />
diff --git a/apps/web-antd/src/components/simple-process-design/consts.ts b/apps/web-antd/src/components/simple-process-design/consts.ts
index 74c910f60..a5bf43394 100644
--- a/apps/web-antd/src/components/simple-process-design/consts.ts
+++ b/apps/web-antd/src/components/simple-process-design/consts.ts
@@ -475,9 +475,9 @@ export type ListenerHandler = {
* 条件规则结构定义
*/
export type ConditionRule = {
- leftSide: string;
+ leftSide: string | undefined;
opCode: string;
- rightSide: string;
+ rightSide: string | undefined;
};
/**
@@ -725,7 +725,7 @@ export const DEFAULT_CONDITION_GROUP_VALUE = {
rules: [
{
opCode: '==',
- leftSide: '',
+ leftSide: undefined,
rightSide: '',
},
],
From 5fa6ca78e293d106d65b6267e963abb387d3c37e Mon Sep 17 00:00:00 2001
From: xingyu4j
Date: Fri, 30 May 2025 21:24:24 +0800
Subject: [PATCH 30/53] feat: tag
---
apps/web-antd/src/api/mp/account/index.ts | 7 +
apps/web-antd/src/api/mp/tag/index.ts | 3 +-
apps/web-antd/src/views/mp/tag/data.ts | 82 +++++++++
apps/web-antd/src/views/mp/tag/index.vue | 172 +++++++++++++++---
.../src/views/mp/tag/modules/form.vue | 88 +++++++++
5 files changed, 328 insertions(+), 24 deletions(-)
create mode 100644 apps/web-antd/src/views/mp/tag/data.ts
create mode 100644 apps/web-antd/src/views/mp/tag/modules/form.vue
diff --git a/apps/web-antd/src/api/mp/account/index.ts b/apps/web-antd/src/api/mp/account/index.ts
index 918c80202..9e7d27712 100644
--- a/apps/web-antd/src/api/mp/account/index.ts
+++ b/apps/web-antd/src/api/mp/account/index.ts
@@ -33,6 +33,13 @@ export function getAccount(id: number) {
return requestClient.get(`/mp/account/get?id=${id}`);
}
+/** 查询公众号账号列表 */
+export function getSimpleAccountList() {
+ return requestClient.get(
+ '/mp/account/list-all-simple',
+ );
+}
+
/** 新增公众号账号 */
export function createAccount(data: MpAccountApi.Account) {
return requestClient.post('/mp/account/create', data);
diff --git a/apps/web-antd/src/api/mp/tag/index.ts b/apps/web-antd/src/api/mp/tag/index.ts
index 3cf677e7d..b1acd0130 100644
--- a/apps/web-antd/src/api/mp/tag/index.ts
+++ b/apps/web-antd/src/api/mp/tag/index.ts
@@ -6,8 +6,9 @@ export namespace MpTagApi {
/** 标签信息 */
export interface Tag {
id?: number;
- name: string;
accountId: number;
+ name: string;
+ count?: number;
createTime?: Date;
}
diff --git a/apps/web-antd/src/views/mp/tag/data.ts b/apps/web-antd/src/views/mp/tag/data.ts
new file mode 100644
index 000000000..ce0a4f9aa
--- /dev/null
+++ b/apps/web-antd/src/views/mp/tag/data.ts
@@ -0,0 +1,82 @@
+import type { VbenFormSchema } from '#/adapter/form';
+import type { VxeGridPropTypes } from '#/adapter/vxe-table';
+
+import { getSimpleAccountList } from '#/api/mp/account';
+
+/** 新增/修改的表单 */
+export function useFormSchema(): VbenFormSchema[] {
+ return [
+ {
+ component: 'Input',
+ fieldName: 'id',
+ dependencies: {
+ triggerFields: [''],
+ show: () => false,
+ },
+ },
+ {
+ fieldName: 'accountId',
+ label: '公众号',
+ component: 'Input',
+ dependencies: {
+ triggerFields: [''],
+ show: () => false,
+ },
+ },
+ {
+ fieldName: 'name',
+ label: '标签名称',
+ component: 'Input',
+ rules: 'required',
+ componentProps: {
+ placeholder: '请输入名称',
+ },
+ },
+ ];
+}
+
+/** 搜索表单配置 */
+export function useGridFormSchema(): VbenFormSchema[] {
+ return [
+ {
+ fieldName: 'accountId',
+ label: '公众号',
+ component: 'ApiSelect',
+ componentProps: {
+ api: getSimpleAccountList,
+ labelField: 'name',
+ valueField: 'id',
+ allowClear: true,
+ },
+ },
+ ];
+}
+
+/** 表格列配置 */
+export function useGridColumns(): VxeGridPropTypes.Columns {
+ return [
+ {
+ title: '编号',
+ field: 'id',
+ },
+ {
+ title: '标签名称',
+ field: 'name',
+ },
+ {
+ title: '粉丝数',
+ field: 'count',
+ },
+ {
+ title: '创建时间',
+ field: 'createTime',
+ formatter: 'formatDateTime',
+ },
+ {
+ title: '操作',
+ width: 140,
+ fixed: 'right',
+ slots: { default: 'actions' },
+ },
+ ];
+}
diff --git a/apps/web-antd/src/views/mp/tag/index.vue b/apps/web-antd/src/views/mp/tag/index.vue
index a54db51e9..e5ccef0c7 100644
--- a/apps/web-antd/src/views/mp/tag/index.vue
+++ b/apps/web-antd/src/views/mp/tag/index.vue
@@ -1,31 +1,157 @@
-
-
-
- 该功能支持 Vue3 + element-plus 版本!
-
-
-
- 可参考
- https://github.com/yudaocode/yudao-ui-admin-vue3/blob/master/src/views/mp/tag/index
- 代码,pull request 贡献给我们!
-
+
+
+
+
+
+
+
+
+
+
diff --git a/apps/web-antd/src/views/mp/tag/modules/form.vue b/apps/web-antd/src/views/mp/tag/modules/form.vue
new file mode 100644
index 000000000..1c70f95a6
--- /dev/null
+++ b/apps/web-antd/src/views/mp/tag/modules/form.vue
@@ -0,0 +1,88 @@
+
+
+
+
+
+
+
From f105df045709a897a163bd72104a80e871f958c3 Mon Sep 17 00:00:00 2001
From: xingyu4j
Date: Fri, 30 May 2025 22:56:26 +0800
Subject: [PATCH 31/53] fix: mp tag
---
apps/web-antd/src/api/mp/account/index.ts | 7 ++-
apps/web-antd/src/views/mp/tag/data.ts | 19 -------
apps/web-antd/src/views/mp/tag/index.vue | 55 ++++++++++++++++---
.../src/views/mp/tag/modules/form.vue | 11 +---
4 files changed, 57 insertions(+), 35 deletions(-)
diff --git a/apps/web-antd/src/api/mp/account/index.ts b/apps/web-antd/src/api/mp/account/index.ts
index 9e7d27712..60833058c 100644
--- a/apps/web-antd/src/api/mp/account/index.ts
+++ b/apps/web-antd/src/api/mp/account/index.ts
@@ -16,6 +16,11 @@ export namespace MpAccountApi {
remark?: string;
createTime?: Date;
}
+
+ export interface AccountSimple {
+ id: number;
+ name: string;
+ }
}
/** 查询公众号账号列表 */
@@ -35,7 +40,7 @@ export function getAccount(id: number) {
/** 查询公众号账号列表 */
export function getSimpleAccountList() {
- return requestClient.get(
+ return requestClient.get(
'/mp/account/list-all-simple',
);
}
diff --git a/apps/web-antd/src/views/mp/tag/data.ts b/apps/web-antd/src/views/mp/tag/data.ts
index ce0a4f9aa..bdb857050 100644
--- a/apps/web-antd/src/views/mp/tag/data.ts
+++ b/apps/web-antd/src/views/mp/tag/data.ts
@@ -1,8 +1,6 @@
import type { VbenFormSchema } from '#/adapter/form';
import type { VxeGridPropTypes } from '#/adapter/vxe-table';
-import { getSimpleAccountList } from '#/api/mp/account';
-
/** 新增/修改的表单 */
export function useFormSchema(): VbenFormSchema[] {
return [
@@ -35,23 +33,6 @@ export function useFormSchema(): VbenFormSchema[] {
];
}
-/** 搜索表单配置 */
-export function useGridFormSchema(): VbenFormSchema[] {
- return [
- {
- fieldName: 'accountId',
- label: '公众号',
- component: 'ApiSelect',
- componentProps: {
- api: getSimpleAccountList,
- labelField: 'name',
- valueField: 'id',
- allowClear: true,
- },
- },
- ];
-}
-
/** 表格列配置 */
export function useGridColumns(): VxeGridPropTypes.Columns {
return [
diff --git a/apps/web-antd/src/views/mp/tag/index.vue b/apps/web-antd/src/views/mp/tag/index.vue
index e5ccef0c7..b9471c42c 100644
--- a/apps/web-antd/src/views/mp/tag/index.vue
+++ b/apps/web-antd/src/views/mp/tag/index.vue
@@ -2,26 +2,64 @@
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
import type { MpTagApi } from '#/api/mp/tag';
-import { ref } from 'vue';
+import { onMounted, ref } from 'vue';
+import { useRouter } from 'vue-router';
import { Page, useVbenModal } from '@vben/common-ui';
+import { useTabs } from '@vben/hooks';
import { message } from 'ant-design-vue';
import { ACTION_ICON, TableAction, useVbenVxeGrid } from '#/adapter/vxe-table';
+import { getSimpleAccountList } from '#/api/mp/account';
import { deleteTag, getTagPage, syncTag } from '#/api/mp/tag';
import { $t } from '#/locales';
-import { useGridColumns, useGridFormSchema } from './data';
+import { useGridColumns } from './data';
import Form from './modules/form.vue';
+const { push } = useRouter(); // 路由
+const tabs = useTabs();
+
const accountId = ref(-1);
+const accountOptions = ref<{ label: string; value: number }[]>([]);
const [FormModal, formModalApi] = useVbenModal({
connectedComponent: Form,
destroyOnClose: true,
});
+async function getAccountList() {
+ const res = await getSimpleAccountList();
+ if (res.length > 0) {
+ accountId.value = res[0]?.id as number;
+ accountOptions.value = res.map((item) => ({
+ label: item.name,
+ value: item.id,
+ }));
+ gridApi.setState({
+ formOptions: {
+ schema: [
+ {
+ fieldName: 'accountId',
+ label: '公众号',
+ component: 'Select',
+ componentProps: {
+ options: accountOptions,
+ },
+ },
+ ],
+ },
+ });
+ gridApi.formApi.setValues({
+ accountId: accountId.value,
+ });
+ } else {
+ message.error('未配置公众号,请在【公众号管理 -> 账号管理】菜单,进行配置');
+ await push({ name: 'MpAccount' });
+ tabs.closeCurrentTab();
+ }
+}
/** 刷新表格 */
function onRefresh() {
gridApi.query();
@@ -29,12 +67,12 @@ function onRefresh() {
/** 创建标签 */
function handleCreate() {
- formModalApi.setData(null).open();
+ formModalApi.setData({ accountId: accountId.value }).open();
}
/** 编辑标签 */
function handleEdit(row: MpTagApi.Tag) {
- formModalApi.setData(row).open();
+ formModalApi.setData({ row, accountId: accountId.value }).open();
}
/** 删除标签 */
@@ -74,7 +112,7 @@ async function handleSync() {
const [Grid, gridApi] = useVbenVxeGrid({
formOptions: {
- schema: useGridFormSchema(),
+ schema: [],
},
gridOptions: {
columns: useGridColumns(),
@@ -87,7 +125,6 @@ const [Grid, gridApi] = useVbenVxeGrid({
return await getTagPage({
pageNo: page.currentPage,
pageSize: page.pageSize,
- accountId: accountId.value,
...formValues,
});
},
@@ -102,11 +139,15 @@ const [Grid, gridApi] = useVbenVxeGrid({
},
} as VxeTableGridOptions,
});
+
+onMounted(async () => {
+ await getAccountList();
+});
-
+
();
-
const emit = defineEmits(['success']);
const formData = ref();
@@ -48,7 +44,6 @@ const [Modal, modalApi] = useVbenModal({
modalApi.lock();
// 提交表单
const data = (await formApi.getValues()) as MpTagApi.Tag;
- data.accountId = props.accountId;
try {
await (formData.value?.id ? updateTag(data) : createTag(data));
// 关闭并提示
@@ -65,13 +60,13 @@ const [Modal, modalApi] = useVbenModal({
return;
}
// 加载数据
- const data = modalApi.getData();
- if (!data || !data.id) {
+ const data = modalApi.getData<{ accountId: number; row: MpTagApi.Tag }>();
+ if (!data || !data.row || !data.accountId) {
return;
}
modalApi.lock();
try {
- formData.value = await getTag(data.id as number);
+ formData.value = await getTag(data.row.id as number);
// 设置到 values
await formApi.setValues(formData.value);
} finally {
From 1c2b247cf4e5a685e37eebd48d06b7bba795b8c8 Mon Sep 17 00:00:00 2001
From: jason <2667446@qq.com>
Date: Sat, 31 May 2025 08:33:34 +0800
Subject: [PATCH 32/53] =?UTF-8?q?feat:=20[BPM=20=E5=B7=A5=E4=BD=9C?=
=?UTF-8?q?=E6=B5=81]=20Simple=20=E6=A8=A1=E5=9E=8B=20-=20=E5=8C=85?=
=?UTF-8?q?=E5=AE=B9=E8=8A=82=E7=82=B9?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../components/nodes/inclusive-node.vue | 282 ++++++++++++++++++
.../components/process-node-tree.vue | 7 +-
.../simple-process-design/helpers.ts | 22 ++
.../styles/simple-process-designer.scss | 6 +-
4 files changed, 313 insertions(+), 4 deletions(-)
create mode 100644 apps/web-antd/src/components/simple-process-design/components/nodes/inclusive-node.vue
diff --git a/apps/web-antd/src/components/simple-process-design/components/nodes/inclusive-node.vue b/apps/web-antd/src/components/simple-process-design/components/nodes/inclusive-node.vue
new file mode 100644
index 000000000..c47afcbb1
--- /dev/null
+++ b/apps/web-antd/src/components/simple-process-design/components/nodes/inclusive-node.vue
@@ -0,0 +1,282 @@
+
+
+
+
+
+
+
+
+ 添加条件
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ item.name }}
+
+
+
+
+ {{ item.showText }}
+
+
+ {{ NODE_DEFAULT_TEXT.get(NodeType.CONDITION_NODE) }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/apps/web-antd/src/components/simple-process-design/components/process-node-tree.vue b/apps/web-antd/src/components/simple-process-design/components/process-node-tree.vue
index 5f7bb5905..d8681f3e3 100644
--- a/apps/web-antd/src/components/simple-process-design/components/process-node-tree.vue
+++ b/apps/web-antd/src/components/simple-process-design/components/process-node-tree.vue
@@ -5,6 +5,7 @@ import { NodeType } from '../consts';
import { useWatchNode } from '../helpers';
import CopyTaskNode from './nodes/copy-task-node.vue';
import EndEventNode from './nodes/end-event-node.vue';
+import InclusiveNode from './nodes/inclusive-node.vue';
import StartUserNode from './nodes/start-user-node.vue';
import TriggerNode from './nodes/trigger-node.vue';
import UserTaskNode from './nodes/user-task-node.vue';
@@ -99,12 +100,12 @@ const recursiveFindParentNode = (
@find:parent-node="findFromParentNode"
/> -->
-
+ @find-parent-node="findParentNode"
+ />
+
+
+
+
+
+
+
+