diff --git a/src/api/crm/contract/index.ts b/src/api/crm/contract/index.ts
new file mode 100644
index 00000000..bf438323
--- /dev/null
+++ b/src/api/crm/contract/index.ts
@@ -0,0 +1,53 @@
+import request from '@/config/axios'
+
+export interface ContractVO {
+ id: number
+ name: string
+ customerId: number
+ businessId: number
+ processInstanceId: number
+ orderDate: Date
+ ownerUserId: number
+ no: string
+ startTime: Date
+ endTime: Date
+ price: number
+ discountPercent: number
+ productPrice: number
+ roUserIds: string
+ rwUserIds: string
+ contactId: number
+ signUserId: number
+ contactLastTime: Date
+ remark: string
+}
+
+// 查询合同列表
+export const getContractPage = async (params) => {
+ return await request.get({ url: `/crm/contract/page`, params })
+}
+
+// 查询合同详情
+export const getContract = async (id: number) => {
+ return await request.get({ url: `/crm/contract/get?id=` + id })
+}
+
+// 新增合同
+export const createContract = async (data: ContractVO) => {
+ return await request.post({ url: `/crm/contract/create`, data })
+}
+
+// 修改合同
+export const updateContract = async (data: ContractVO) => {
+ return await request.put({ url: `/crm/contract/update`, data })
+}
+
+// 删除合同
+export const deleteContract = async (id: number) => {
+ return await request.delete({ url: `/crm/contract/delete?id=` + id })
+}
+
+// 导出合同 Excel
+export const exportContract = async (params) => {
+ return await request.download({ url: `/crm/contract/export-excel`, params })
+}
diff --git a/src/views/crm/contract/ContractForm.vue b/src/views/crm/contract/ContractForm.vue
new file mode 100644
index 00000000..5d5578f9
--- /dev/null
+++ b/src/views/crm/contract/ContractForm.vue
@@ -0,0 +1,228 @@
+
+
+
+
diff --git a/src/views/crm/contract/contract.data.ts b/src/views/crm/contract/contract.data.ts
new file mode 100644
index 00000000..7550677b
--- /dev/null
+++ b/src/views/crm/contract/contract.data.ts
@@ -0,0 +1,227 @@
+import type { CrudSchema } from '@/hooks/web/useCrudSchemas'
+import { dateFormatter } from '@/utils/formatTime'
+
+// 表单校验
+export const rules = reactive({
+ name: [required]
+})
+
+// CrudSchema https://doc.iocoder.cn/vue3/crud-schema/
+const crudSchemas = reactive([
+ {
+ label: '合同编号',
+ field: 'id',
+ isForm: false
+ },
+ {
+ label: '合同名称',
+ field: 'name',
+ isSearch: true
+ },
+ {
+ label: '客户编号',
+ field: 'customerId',
+ isSearch: true,
+ form: {
+ component: 'InputNumber',
+ value: 0
+ }
+ },
+ {
+ label: '商机编号',
+ field: 'businessId',
+ isSearch: true,
+ form: {
+ component: 'InputNumber',
+ value: 0
+ }
+ },
+ {
+ label: '工作流编号',
+ field: 'processInstanceId',
+ isSearch: true,
+ form: {
+ component: 'InputNumber',
+ value: 0
+ }
+ },
+ {
+ label: '下单日期',
+ field: 'orderDate',
+ formatter: dateFormatter,
+ isSearch: true,
+ search: {
+ component: 'DatePicker',
+ componentProps: {
+ valueFormat: 'YYYY-MM-DD HH:mm:ss',
+ type: 'daterange',
+ defaultTime: [new Date('1 00:00:00'), new Date('1 23:59:59')]
+ }
+ },
+ form: {
+ component: 'DatePicker',
+ componentProps: {
+ type: 'datetime',
+ valueFormat: 'x'
+ }
+ }
+ },
+ {
+ label: '负责人的用户编号',
+ field: 'ownerUserId',
+ isSearch: true,
+ form: {
+ component: 'InputNumber',
+ value: 0
+ }
+ },
+ {
+ label: '创建时间',
+ field: 'createTime',
+ formatter: dateFormatter,
+ isSearch: true,
+ search: {
+ component: 'DatePicker',
+ componentProps: {
+ valueFormat: 'YYYY-MM-DD HH:mm:ss',
+ type: 'daterange',
+ defaultTime: [new Date('1 00:00:00'), new Date('1 23:59:59')]
+ }
+ },
+ isForm: false
+ },
+ {
+ label: '合同编号',
+ field: 'no',
+ isSearch: true
+ },
+ {
+ label: '开始时间',
+ field: 'startTime',
+ formatter: dateFormatter,
+ isSearch: true,
+ search: {
+ component: 'DatePicker',
+ componentProps: {
+ valueFormat: 'YYYY-MM-DD HH:mm:ss',
+ type: 'daterange',
+ defaultTime: [new Date('1 00:00:00'), new Date('1 23:59:59')]
+ }
+ },
+ form: {
+ component: 'DatePicker',
+ componentProps: {
+ type: 'datetime',
+ valueFormat: 'x'
+ }
+ }
+ },
+ {
+ label: '结束时间',
+ field: 'endTime',
+ formatter: dateFormatter,
+ isSearch: true,
+ search: {
+ component: 'DatePicker',
+ componentProps: {
+ valueFormat: 'YYYY-MM-DD HH:mm:ss',
+ type: 'daterange',
+ defaultTime: [new Date('1 00:00:00'), new Date('1 23:59:59')]
+ }
+ },
+ form: {
+ component: 'DatePicker',
+ componentProps: {
+ type: 'datetime',
+ valueFormat: 'x'
+ }
+ }
+ },
+ {
+ label: '合同金额',
+ field: 'price',
+ isSearch: true,
+ form: {
+ component: 'InputNumber',
+ value: 0
+ }
+ },
+ {
+ label: '整单折扣',
+ field: 'discountPercent',
+ isSearch: true,
+ form: {
+ component: 'InputNumber',
+ value: 0
+ }
+ },
+ {
+ label: '产品总金额',
+ field: 'productPrice',
+ isSearch: true,
+ form: {
+ component: 'InputNumber',
+ value: 0
+ }
+ },
+ {
+ label: '只读权限的用户编号数组',
+ field: 'roUserIds',
+ isSearch: true
+ },
+ {
+ label: '读写权限的用户编号数组',
+ field: 'rwUserIds',
+ isSearch: true
+ },
+ {
+ label: '联系人编号',
+ field: 'contactId',
+ isSearch: true,
+ form: {
+ component: 'InputNumber',
+ value: 0
+ }
+ },
+ {
+ label: '备注',
+ field: 'remark',
+ isSearch: true
+ },
+ {
+ label: '公司签约人',
+ field: 'signUserId',
+ isSearch: true,
+ form: {
+ component: 'InputNumber',
+ value: 0
+ }
+ },
+ {
+ label: '最后跟进时间',
+ field: 'contactLastTime',
+ formatter: dateFormatter,
+ isSearch: true,
+ search: {
+ component: 'DatePicker',
+ componentProps: {
+ valueFormat: 'YYYY-MM-DD HH:mm:ss',
+ type: 'daterange',
+ defaultTime: [new Date('1 00:00:00'), new Date('1 23:59:59')]
+ }
+ },
+ form: {
+ component: 'DatePicker',
+ componentProps: {
+ type: 'datetime',
+ valueFormat: 'x'
+ }
+ }
+ },
+ {
+ label: '操作',
+ field: 'action',
+ isForm: false
+ }
+])
+export const { allSchemas } = useCrudSchemas(crudSchemas)
diff --git a/src/views/crm/contract/index.vue b/src/views/crm/contract/index.vue
new file mode 100644
index 00000000..7a8211be
--- /dev/null
+++ b/src/views/crm/contract/index.vue
@@ -0,0 +1,253 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 搜索
+ 重置
+
+ 新增
+
+
+ 导出
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 编辑
+
+
+ 删除
+
+
+
+
+
+
+
+
+
+
+
+
+