新增客户管理;

新增合同管理
This commit is contained in:
2023-06-10 01:29:51 +08:00
parent 4eca2ea5f5
commit 7f080a4c54
24 changed files with 2017 additions and 447 deletions

View File

@@ -1,13 +1,13 @@
import request from '@/utils/request';
import type { ApiResult, PageResult } from '@/api';
import type { Customer, CustomerParam } from './model';
import type {ApiResult, PageResult} from '@/api';
import type {Customer, CustomerParam} from './model';
/**
* 分页查询客户
*/
export async function pageCustomer(params: CustomerParam) {
const res = await request.get<ApiResult<PageResult<Customer>>>(
'/oa/customer/page',
'/tower/tower-customer/page',
{
params
}
@@ -22,9 +22,12 @@ export async function pageCustomer(params: CustomerParam) {
* 查询客户列表
*/
export async function listCustomer(params?: CustomerParam) {
const res = await request.get<ApiResult<Customer[]>>('/oa/customer', {
params
});
const res = await request.get<ApiResult<Customer[]>>(
'/tower/tower-customer',
{
params
}
);
if (res.data.code === 0 && res.data.data) {
return res.data.data;
}
@@ -35,7 +38,9 @@ export async function listCustomer(params?: CustomerParam) {
* 根据id查询客户
*/
export async function getCustomer(id: number) {
const res = await request.get<ApiResult<Customer>>('/oa/customer/' + id);
const res = await request.get<ApiResult<Customer>>(
'/tower/tower-customer/' + id
);
if (res.data.code === 0 && res.data.data) {
return res.data.data;
}
@@ -46,7 +51,10 @@ export async function getCustomer(id: number) {
* 添加客户
*/
export async function addCustomer(data: Customer) {
const res = await request.post<ApiResult<unknown>>('/oa/customer', data);
const res = await request.post<ApiResult<unknown>>(
'/tower/tower-customer',
data
);
if (res.data.code === 0) {
return res.data.message;
}
@@ -57,7 +65,10 @@ export async function addCustomer(data: Customer) {
* 修改客户
*/
export async function updateCustomer(data: Customer) {
const res = await request.put<ApiResult<unknown>>('/oa/customer', data);
const res = await request.put<ApiResult<unknown>>(
'/tower/tower-customer',
data
);
if (res.data.code === 0) {
return res.data.message;
}
@@ -68,7 +79,10 @@ export async function updateCustomer(data: Customer) {
* 批量修改客户
*/
export async function updateBatchCustomer(data: Customer[]) {
const res = await request.put<ApiResult<unknown>>('/oa/customer/batch', data);
const res = await request.put<ApiResult<unknown>>(
'/tower/tower-customer/batch',
data
);
if (res.data.code === 0) {
return res.data.message;
}
@@ -79,7 +93,9 @@ export async function updateBatchCustomer(data: Customer[]) {
* 删除客户
*/
export async function removeCustomer(id?: number) {
const res = await request.delete<ApiResult<unknown>>('/oa/customer/' + id);
const res = await request.delete<ApiResult<unknown>>(
'/tower/tower-customer/' + id
);
if (res.data.code === 0) {
return res.data.message;
}
@@ -90,9 +106,12 @@ export async function removeCustomer(id?: number) {
* 批量删除客户
*/
export async function removeBatchCustomer(data: (number | undefined)[]) {
const res = await request.delete<ApiResult<unknown>>('/oa/customer/batch', {
data
});
const res = await request.delete<ApiResult<unknown>>(
'/tower/tower-customer/batch',
{
data
}
);
if (res.data.code === 0) {
return res.data.message;
}
@@ -107,9 +126,12 @@ export async function checkExistence(
value: string,
id?: number
) {
const res = await request.get<ApiResult<unknown>>('/oa/customer/existence', {
params: { field, value, id }
});
const res = await request.get<ApiResult<unknown>>(
'/tower/tower-customer/existence',
{
params: {field, value, id}
}
);
if (res.data.code === 0) {
return res.data.message;
}

View File

@@ -6,59 +6,44 @@ import type { PageParam } from '@/api';
export interface Customer {
// 客户id
customerId?: number;
// 客户类型
customerType?: string;
// 客户来源
customerSource?: string;
// 客户标识
customerCode: string;
creditCode: string;
// 客户名称
customerName?: string;
name: string;
// 客户全称
customerFullName?: string;
fullName?: string;
// 客户头像
customerAvatar?: string;
avatar?: string;
// 座机电话
customerPhone?: string;
phone?: string;
// 手机号码
customerMobile?: string;
telPhone?: string;
// 联系人
customerContacts?: string;
contact?: string;
// 联系地址
customerAddress?: string;
customerProvince?: string;
customerCity?: string;
customerRegion?: string;
longitude?: string;
latitude?: string;
// 跟进状态
progress?: string;
address?: string;
// 排序
sortNumber?: number;
// 备注
comments?: string;
// 创建时间
createTime?: string;
// 状态
status?: string;
// 备注
remark?: string;
// 用户ID
userId?: any;
// 发布者昵称
nickname?: string;
projectName?: any;
companyName?: any;
customerName?: any;
}
/**
* 客户搜索条件
*/
export interface CustomerParam extends PageParam {
customerName?: string;
customerCode?: string;
customerType?: string;
name?: string;
creditCode?: string;
createTimeStart?: string;
createTimeEnd?: string;
customerCategory?: string;
progress?: string;
customerSource?: string;
betweenTime?: any;
userId?: number;
nickname?: string;

View File

@@ -0,0 +1,119 @@
import request from '@/utils/request';
import type {ApiResult, PageResult} from '@/api';
import type {Contract, ContractParam} from './model';
/**
* 分页查询合同
*/
export async function pageContract(params: ContractParam) {
const res = await request.get<ApiResult<PageResult<Contract>>>(
'/tower/tower-contract/page',
{
params
}
);
if (res.data.code === 0) {
return res.data.data;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 查询合同列表
*/
export async function listContract(params?: ContractParam) {
const res = await request.get<ApiResult<Contract[]>>(
'/tower/tower-contract',
{
params
}
);
if (res.data.code === 0 && res.data.data) {
return res.data.data;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 根据id查询合同
*/
export async function getContract(id: number) {
const res = await request.get<ApiResult<Contract>>(
'/tower/tower-contract/' + id
);
if (res.data.code === 0 && res.data.data) {
return res.data.data;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 添加合同
*/
export async function addContract(data: Contract) {
const res = await request.post<ApiResult<unknown>>(
'/tower/tower-contract',
data
);
if (res.data.code === 0) {
return res.data;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 修改合同
*/
export async function updateContract(data: Contract) {
const res = await request.put<ApiResult<unknown>>(
'/tower/tower-contract',
data
);
if (res.data.code === 0) {
return res.data;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 批量修改合同
*/
export async function updateBatchContract(data: Contract[]) {
const res = await request.put<ApiResult<unknown>>(
'/tower/tower-contract/batch',
data
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 删除合同
*/
export async function removeContract(id?: number) {
const res = await request.delete<ApiResult<unknown>>(
'/tower/tower-contract/' + id
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 批量删除合同
*/
export async function removeBatchContract(data: (number | undefined)[]) {
const res = await request.delete<ApiResult<unknown>>(
'/tower/tower-contract/batch',
{
data
}
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}

View File

@@ -0,0 +1,46 @@
import type { PageParam } from '@/api';
/**
* 合同
*/
export interface Contract {
// 合同id
contractId?: any;
// 项目id
projectId: any;
// 承租方
companyId: any;
// 出租方
customerId: any;
// 业务负责人
customerContact?: string;
// 合同编号
contactNumber: string;
// 签订日期
signDate?: string;
// 开始日期
startDate?: string;
// 截止日期
endDate?: string;
// 合同金额
contractAmount?: number;
// 合同约定金额
contactAgreeAmount?: string;
// 合同是否已存档
isInStock?: number;
// 是否自动结算
autoSettle?: number;
userId?: any;
}
/**
* 合同搜索条件
*/
export interface ContractParam extends PageParam {
contactNumber?: string;
createTimeStart?: string;
createTimeEnd?: string;
betweenTime?: any;
}

View File

@@ -0,0 +1,133 @@
import request from '@/utils/request';
import type {ApiResult, PageResult} from '@/api';
import type {ContractEquipment, ContractEquipmentParam} from './model';
/**
* 分页查询合同设备
*/
export async function pageContract(params: ContractEquipmentParam) {
const res = await request.get<ApiResult<PageResult<ContractEquipment>>>(
'/tower/tower-contract-equipment/page',
{
params
}
);
if (res.data.code === 0) {
return res.data.data;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 查询合同设备列表
*/
export async function listContractEquipment(params?: ContractEquipmentParam) {
const res = await request.get<ApiResult<ContractEquipment[]>>(
'/tower/tower-contract-equipment',
{
params
}
);
if (res.data.code === 0 && res.data.data) {
return res.data.data;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 根据id查询合同设备
*/
export async function getContractEquipment(id: number) {
const res = await request.get<ApiResult<ContractEquipment>>(
'/tower/tower-contract-equipment/' + id
);
if (res.data.code === 0 && res.data.data) {
return res.data.data;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 添加合同设备
*/
export async function addContractEquipment(data: ContractEquipment) {
const res = await request.post<ApiResult<unknown>>(
'/tower/tower-contract-equipment',
data
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 修改合同设备
*/
export async function updateContractEquipment(data: ContractEquipment) {
const res = await request.put<ApiResult<unknown>>(
'/tower/tower-contract-equipment',
data
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 批量修改合同设备
*/
export async function updateBatchContractEquipment(data: ContractEquipment[]) {
const res = await request.put<ApiResult<unknown>>(
'/tower/tower-contract-equipment/batch',
data
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 批量添加合同设备
*/
export async function addBatchContractEquipment(data: ContractEquipment[]) {
const res = await request.post<ApiResult<unknown>>(
'/tower/tower-contract-equipment/batch',
data
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 删除合同设备
*/
export async function removeContractEquipment(id?: number) {
const res = await request.delete<ApiResult<unknown>>(
'/tower/tower-contract-equipment/' + id
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 批量删除合同设备
*/
export async function removeBatchContractEquipment(data: (number | undefined)[]) {
const res = await request.delete<ApiResult<unknown>>(
'/tower/tower-contract-equipment/batch',
{
data
}
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}

View File

@@ -0,0 +1,39 @@
import type { PageParam } from '@/api';
/**
* 合同
*/
export interface ContractEquipment {
contractEquipmentId?: any;
// 合同id
contractId: any;
// 设备名
equipmentName: string;
// 规格
equipmentModel: string;
// 数量
num: any;
// 租期
planRentMonth: any;
// 租金
rentAmount: any;
// 进退场费
inOutAmount: any;
// 劳务费
workerAmount: any;
// 其他费用
otherAmount: any;
// 预埋费
preBuryAmount: any;
// 备注
remark?: any;
userId?: any;
}
/**
* 合同搜索条件
*/
export interface ContractEquipmentParam extends PageParam {
contactId?: string;
}

View File

@@ -0,0 +1,133 @@
import request from "@/utils/request";
import type { ApiResult, PageResult } from "@/api";
import type { ContractFile, ContractFileParam } from "./model";
/**
* 分页查询合同文件
*/
export async function pageContract(params: ContractFileParam) {
const res = await request.get<ApiResult<PageResult<ContractFile>>>(
"/tower/tower-contract/page",
{
params
}
);
if (res.data.code === 0) {
return res.data.data;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 查询合同文件列表
*/
export async function listContractFile(params?: ContractFileParam) {
const res = await request.get<ApiResult<ContractFile[]>>(
"/tower/tower-contract-file",
{
params
}
);
if (res.data.code === 0 && res.data.data) {
return res.data.data;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 根据id查询合同文件
*/
export async function getContractFile(id: number) {
const res = await request.get<ApiResult<ContractFile>>(
"/tower/tower-contract-file/" + id
);
if (res.data.code === 0 && res.data.data) {
return res.data.data;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 添加合同文件
*/
export async function addContractFile(data: ContractFile) {
const res = await request.post<ApiResult<unknown>>(
"/tower/tower-contract-file",
data
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 修改合同文件
*/
export async function updateContractFile(data: ContractFile) {
const res = await request.put<ApiResult<unknown>>(
"/tower/tower-contract-file",
data
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 批量修改合同文件
*/
export async function updateBatchContractFile(data: ContractFile[]) {
const res = await request.put<ApiResult<unknown>>(
"/tower/tower-contract-file/batch",
data
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 批量添加合同文件
*/
export async function addBatchContractFile(data: ContractFile[]) {
const res = await request.post<ApiResult<unknown>>(
"/tower/tower-contract-file/batch",
data
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 删除合同文件
*/
export async function removeContractFile(id?: number) {
const res = await request.delete<ApiResult<unknown>>(
"/tower/tower-contract-file/" + id
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 批量删除合同文件
*/
export async function removeBatchContractFile(data: (number | undefined)[]) {
const res = await request.delete<ApiResult<unknown>>(
"/tower/tower-contract-file/batch",
{
data
}
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}

View File

@@ -0,0 +1,24 @@
import type { PageParam } from '@/api';
/**
* 合同
*/
export interface ContractFile {
// 文件id
contractFileId?: any;
// 项目id
contractId?: any;
// 路径
path: string;
// 文件类型
type?: any;
userId?: any;
}
/**
* 合同搜索条件
*/
export interface ContractFileParam extends PageParam {
contactId?: string;
}

View File

@@ -0,0 +1,156 @@
<template>
<ele-modal
:width="750"
:visible="visible"
:maskClosable="false"
:title="title"
:body-style="{ paddingBottom: '28px' }"
@update:visible="updateVisible"
>
<ele-pro-table
ref="tableRef"
row-key="modelId"
:datasource="datasource"
:columns="columns"
:customRow="customRow"
:striped="true"
:pagination="false"
>
<template #toolbar>
<a-input-search
allow-clear
v-model:value="searchText"
placeholder="请输入搜索关键词"
style="width: 200px"
@search="reload"
@pressEnter="reload"
/>
</template>
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'customerLogo'">
<a-image
v-if="record.customerAvatar"
:src="FILE_THUMBNAIL + record.customerAvatar"
:preview="false"
:width="45"
/>
</template>
<template v-if="column.key === 'action'">
<a-space>
<a-button type="link">选择</a-button>
</a-space>
</template>
</template>
</ele-pro-table>
</ele-modal>
</template>
<script lang="ts" setup>
import { ref } from 'vue';
import {
ColumnItem,
DatasourceFunction
} from 'ele-admin-pro/es/ele-pro-table/types';
import { pageProject } from '@/api/tower/project';
import { FILE_THUMBNAIL } from '@/config/setting';
import { EleProTable } from 'ele-admin-pro';
import { TowerModel, TowerModelParam } from '@/api/tower/model/model';
defineProps<{
// 弹窗是否打开
visible: boolean;
// 标题
title?: string;
// 修改回显的数据
data?: TowerModel | null;
selection?: TowerModel[];
}>();
const emit = defineEmits<{
(e: 'done', data: TowerModel): void;
(e: 'update:visible', visible: boolean): void;
}>();
/* 更新visible */
const updateVisible = (value: boolean) => {
emit('update:visible', value);
};
// 搜索内容
const searchText = ref(null);
// 表格实例
const tableRef = ref<InstanceType<typeof EleProTable> | null>(null);
// 表格配置
const columns = ref<ColumnItem[]>([
{
key: 'index',
width: 48,
align: 'center',
fixed: 'left',
hideInSetting: true,
customRender: ({ index }) => index + (tableRef.value?.tableIndex ?? 0)
},
{
title: '项目状态',
dataIndex: 'projectStatus'
},
{
title: '项目名称',
dataIndex: 'projectName'
},
{
title: '项目地址',
dataIndex: 'projectAddress'
},
{
title: '承租单位',
dataIndex: 'customerName'
},
{
title: '项目负责人',
dataIndex: 'director'
},
{
title: '是否关联',
dataIndex: 'yearLife'
},
{
title: '操作',
key: 'action',
align: 'center'
}
]);
// 表格数据源
const datasource: DatasourceFunction = ({ page, limit, where, orders }) => {
// 搜索条件
if (searchText.value) {
where.keywords = searchText.value;
}
return pageProject({
...where,
...orders,
page,
limit
});
};
/* 搜索 */
const reload = (where?: TowerModelParam) => {
tableRef?.value?.reload({ page: 1, where });
};
/* 自定义行属性 */
const customRow = (record: TowerModel) => {
return {
// 行点击事件
onClick: () => {
updateVisible(false);
emit('done', record);
}
};
};
</script>
<style lang="less"></style>

View File

@@ -0,0 +1,65 @@
<template>
<div>
<a-input-group compact>
<a-input
disabled
style="width: calc(100% - 32px)"
v-model:value="value"
:placeholder="placeholder"
/>
<a-button @click="openEdit">
<template #icon><BulbOutlined class="ele-text-warning" /></template>
</a-button>
</a-input-group>
<!-- 选择弹窗 -->
<SelectData
v-model:visible="showEdit"
:data="current"
:title="placeholder"
:customer-type="customerType"
@done="onChange"
/>
</div>
</template>
<script lang="ts" setup>
import { BulbOutlined } from '@ant-design/icons-vue';
import { ref } from 'vue';
import SelectData from './components/select-data.vue';
import { Project } from '@/api/tower/project/model';
const props = withDefaults(
defineProps<{
value?: any;
customerType?: string;
placeholder?: string;
index?: number;
}>(),
{
placeholder: '请选择数据'
}
);
const emit = defineEmits<{
(e: 'done', TowerModel): void;
(e: 'clear'): void;
(e: 'multiple', any): void;
}>();
// 是否显示编辑弹窗
const showEdit = ref(false);
// 当前编辑数据
const current = ref<Project | null>(null);
/* 打开编辑弹窗 */
const openEdit = (row?: Project) => {
current.value = row ?? null;
showEdit.value = true;
};
const onChange = (row) => {
// 第几行
row.index = Number(props.index);
emit('done', row);
};
</script>

View File

@@ -94,17 +94,16 @@
customRender: ({ index }) => index + (tableRef.value?.tableIndex ?? 0)
},
{
title: '企业名称',
dataIndex: 'customerName'
title: '客户名称',
dataIndex: 'name'
},
{
title: '企业类型',
dataIndex: 'customerType'
title: '联系人',
dataIndex: 'contact'
},
{
title: '企业LOGO',
dataIndex: 'customerLogo',
key: 'customerLogo'
title: '联系电话',
dataIndex: 'telPhone'
},
{
title: '操作',

104
src/styles/common.less Normal file
View File

@@ -0,0 +1,104 @@
.text-white {
color: white;
}
.h-full{
height: 100%;
}
.border{
border: 1px solid #ebeef5;
}
.border-r-white {
border-right: 1px solid white;
}
.p-05{
padding: .5rem 0;
}
.bg-blue {
background-color: #1890ff;
}
.flex {
display: flex;
}
.flex-wrap {
flex-wrap: wrap;
}
.justify-center {
justify-content: center;
}
.justify-start {
justify-content: flex-start;
}
.justify-end {
justify-content: flex-end;
}
.justify-between {
justify-content: space-between;
}
.justify-around {
justify-content: space-around;
}
.items-center {
align-items: center;
}
.items-start {
align-items: flex-start;
}
.items-end {
align-items: flex-end;
}
.flex-col {
flex-direction: column;
}
.flex-1 {
flex: 1;
}
.flex-2 {
flex: 2;
}
.flex-shrink {
flex-shrink: 0;
}
.flex-none {
flex: none;
}
.flex-grow {
flex-grow: 1
}
.flex-grow-0 {
flex-grow: 0
}
.text-center{
text-align: center;
}
.text-grey{
color: #999;
}
.my-05{
margin-top: .5rem;
margin-bottom: .5rem;
}

View File

@@ -2,6 +2,7 @@
@style-entry-file: as-needed;
@import './@{style-entry-file}.less';
@import './transition/index.less';
@import './common.less';
// 主题
@import 'ele-admin-pro/es/style/themes/dynamic.less';

View File

@@ -0,0 +1,139 @@
import request from '@/utils/request';
import type {ApiResult, PageResult} from '@/api';
import type {Customer, CustomerParam} from './model';
/**
* 分页查询客户
*/
export async function pageCustomer(params: CustomerParam) {
const res = await request.get<ApiResult<PageResult<Customer>>>(
'/tower/tower-customer/page',
{
params
}
);
if (res.data.code === 0) {
return res.data.data;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 查询客户列表
*/
export async function listCustomer(params?: CustomerParam) {
const res = await request.get<ApiResult<Customer[]>>(
'/tower/tower-customer',
{
params
}
);
if (res.data.code === 0 && res.data.data) {
return res.data.data;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 根据id查询客户
*/
export async function getCustomer(id: number) {
const res = await request.get<ApiResult<Customer>>(
'/tower/tower-customer/' + id
);
if (res.data.code === 0 && res.data.data) {
return res.data.data;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 添加客户
*/
export async function addCustomer(data: Customer) {
const res = await request.post<ApiResult<unknown>>(
'/tower/tower-customer',
data
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 修改客户
*/
export async function updateCustomer(data: Customer) {
const res = await request.put<ApiResult<unknown>>(
'/tower/tower-customer',
data
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 批量修改客户
*/
export async function updateBatchCustomer(data: Customer[]) {
const res = await request.put<ApiResult<unknown>>(
'/tower/tower-customer/batch',
data
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 删除客户
*/
export async function removeCustomer(id?: number) {
const res = await request.delete<ApiResult<unknown>>(
'/tower/tower-customer/' + id
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 批量删除客户
*/
export async function removeBatchCustomer(data: (number | undefined)[]) {
const res = await request.delete<ApiResult<unknown>>(
'/tower/tower-customer/batch',
{
data
}
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 检查IP是否存在
*/
export async function checkExistence(
field: string,
value: string,
id?: number
) {
const res = await request.get<ApiResult<unknown>>(
'/tower/tower-customer/existence',
{
params: {field, value, id}
}
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}

View File

@@ -0,0 +1,49 @@
import type { PageParam } from '@/api';
/**
* 客户
*/
export interface Customer {
// 客户id
customerId?: number;
// 客户标识
creditCode: string;
// 客户名称
name: string;
// 客户全称
fullName?: string;
// 客户头像
avatar?: string;
// 座机电话
phone?: string;
// 手机号码
telPhone?: string;
// 联系人
contact?: string;
// 联系地址
address?: string;
// 排序
sortNumber?: number;
// 创建时间
createTime?: string;
// 备注
remark?: string;
// 用户ID
userId?: any;
}
/**
* 客户搜索条件
*/
export interface CustomerParam extends PageParam {
name?: string;
creditCode?: string;
createTimeStart?: string;
createTimeEnd?: string;
betweenTime?: any;
userId?: number;
nickname?: string;
// 商户编号
merchantCode?: string;
}

View File

@@ -0,0 +1,570 @@
<!-- 用户编辑弹窗 -->
<template>
<ele-modal
:width="'90%'"
:visible="visible"
:confirm-loading="loading"
:maskClosable="false"
:maxable="maxable"
:title="isUpdate ? '编辑合同' : '添加合同'"
:body-style="{ paddingBottom: '8px' }"
@update:visible="updateVisible"
@ok="save"
>
<a-form
:label-col="{ md: { span: 6 }, sm: { span: 20 }, xs: { span: 24 } }"
:wrapper-col="{ md: { span: 24 }, sm: { span: 20 }, xs: { span: 24 } }"
>
<div class="title">填报人信息</div>
<a-row :gutter="16">
<a-col :md="12" :sm="24" :xs="24">
<a-form-item label="填报人">
<a-input disabled v-model:value="loginUser.username" />
</a-form-item>
</a-col>
<a-col :md="12" :sm="24" :xs="24">
<a-form-item label="填报时间">
<a-input disabled v-model:value="now" />
</a-form-item>
</a-col>
</a-row>
<div class="title">合同信息</div>
<a-row :gutter="16">
<a-col :md="8" :sm="24" :xs="24">
<a-form-item label="项目名称" v-bind="validateInfos.projectId">
<ProjectSelectModel
:placeholder="`请选择项目`"
v-model:value="projectName"
@done="chooseProject"
/>
</a-form-item>
<a-form-item label="合同编号" v-bind="validateInfos.contactNumber">
<a-input
allow-clear
:maxlength="20"
placeholder="请输入合同编号"
v-model:value="form.contactNumber"
/>
</a-form-item>
<a-form-item label="开始日期">
<a-date-picker
class="ele-fluid"
placeholder="请选择开始日期"
v-model:value="form.startDate"
valueFormat="YYYY-MM-DD"
/>
</a-form-item>
<a-form-item label="合同存档">
<a-switch :checked="form.isInStock" :checked-value="1" :un-checked-value="0" checked-children="已归档"
un-checked-children="未归档" @change="changeInStock" />
</a-form-item>
</a-col>
<a-col :md="8" :sm="24" :xs="24">
<a-form-item label="出租单位" v-bind="validateInfos.companyId">
<SelectCompany
:placeholder="`请选择出租单位`"
v-model:value="companyName"
@done="chooseCompany"
/>
</a-form-item>
<a-form-item label="承租单位" v-bind="validateInfos.customerId">
<SelectCustomer
:placeholder="`请选择承租单位`"
v-model:value="customerName"
@done="chooseCustomer"
/>
</a-form-item>
<a-form-item label="合同金额">
<a-input
allow-clear
:maxlength="20"
placeholder="请输入合同金额"
v-model:value="form.contractAmount"
>
<template #addonAfter>
<span></span>
</template>
</a-input>
</a-form-item>
<a-form-item label="截止日期">
<a-date-picker
class="ele-fluid"
placeholder="请选择截止日期"
v-model:value="form.endDate"
valueFormat="YYYY-MM-DD"
/>
</a-form-item>
</a-col>
<a-col :md="8" :sm="24" :xs="24">
<a-form-item label="业务负责人">
<a-input
disabled
placeholder="自动填写"
v-model:value="form.customerContact"
/>
</a-form-item>
<a-form-item label="签订日期">
<a-date-picker
class="ele-fluid"
placeholder="请选择签订日期"
v-model:value="form.signDate"
valueFormat="YYYY-MM-DD"
/>
</a-form-item>
<a-form-item label="合同约定金额">
<a-input
allow-clear
:maxlength="20"
placeholder="请输入合同约定金额"
v-model:value="form.contactAgreeAmount"
>
<template #addonAfter>
<span></span>
</template>
</a-input>
</a-form-item>
<a-form-item label="是否自动结算">
<a-switch :checked="form.autoSettle" :checked-value="1" :un-checked-value="0" checked-children=""
un-checked-children="" @change="changeAutoSettle" />
</a-form-item>
</a-col>
</a-row>
</a-form>
<div class="flex flex-col justify-start justify-start"
style="padding: 1rem 0;border-top: 1px solid #dcdfe6; border-bottom: 1px solid #dcdfe6">
<div class="flex justify-between items-center">
<span>合同电子存档</span>
<UploadFile @update:value="uploadFile" />
</div>
<div class="flex justify-start flex-wrap items-start">
<a-tag closable @close="delFile(index)" v-for="(item, index) in contractFileList" :key="index">{{ item.path }}
</a-tag>
</div>
</div>
<div class="flex justify-start items-center"
style="padding: 1rem 0;border-top: 1px solid #dcdfe6;">
<div class="flex justify-start items-center">
<unordered-list-outlined />
<span>合同签订设备清单</span>
</div>
</div>
<div>
<a-row class="bg-blue text-white text-center">
<a-col :span="3" class="p-05 border-r-white">
<span>设备名称</span>
</a-col>
<a-col :span="3" class="p-05 border-r-white">
<span>规格型号</span>
</a-col>
<a-col :span="2" class="p-05 border-r-white">
<span>签订数量</span>
</a-col>
<a-col :span="2" class="p-05 border-r-white">
<span>计划租期()</span>
</a-col>
<a-col :span="2" class="p-05 border-r-white">
<span>租金()</span>
</a-col>
<a-col :span="2" class="p-05 border-r-white">
<span>进退场费()</span>
</a-col>
<a-col :span="2" class="p-05 border-r-white">
<span>劳务费用()</span>
</a-col>
<a-col :span="2" class="p-05 border-r-white">
<span>其他费用()</span>
</a-col>
<a-col :span="2" class="p-05 border-r-white">
<span>预埋费()</span>
</a-col>
<a-col :span="2" class="p-05 border-r-white">
<span>备注</span>
</a-col>
<a-col :span="1" class="p-05">
<span>操作</span>
</a-col>
</a-row>
<div style="min-height: 10rem">
<div class=" p-05 flex justify-center items-center" v-if="contractEquipmentList.length === 0">
<span class="text-grey">暂无数据</span>
</div>
<template v-else>
<a-row class="text-center" v-for="(item, index) in contractEquipmentList"
:key="index">
<a-col :span="3" class="p-05 border-r-white">
<a-select placeholder="必选项" style="width: 100%" size="small"
v-model:value="contractEquipmentList[index].equipmentName">
<a-select-option v-for="(item, index) in equipmentList" :key="index" :value="item.name">{{ item.name
}}
</a-select-option>
</a-select>
</a-col>
<a-col :span="3" class="p-05 border-r-white">
<a-select placeholder="必选项" style="width: 100%" size="small"
v-model:value="contractEquipmentList[index].equipmentModel">
<a-select-option v-for="(item, index) in equipmentList" :key="index" :value="item.model">{{ item.model
}}
</a-select-option>
</a-select>
</a-col>
<a-col :span="2" class="p-05 border-r-white">
<a-input v-model:value="contractEquipmentList[index].num" size="small" placeholder="必填项" type="number">
<template #suffix></template>
</a-input>
</a-col>
<a-col :span="2" class="p-05 border-r-white">
<a-input v-model:value="contractEquipmentList[index].planRentMonth" size="small" placeholder="必填项"
type="number" />
</a-col>
<a-col :span="2" class="p-05 border-r-white">
<a-input v-model:value="contractEquipmentList[index].rentAmount" size="small" placeholder="必填项"
type="number" />
</a-col>
<a-col :span="2" class="p-05 border-r-white">
<a-input v-model:value="contractEquipmentList[index].inOutAmount" size="small" placeholder="必填项"
type="number" />
</a-col>
<a-col :span="2" class="p-05 border-r-white">
<a-input v-model:value="contractEquipmentList[index].workerAmount" size="small" placeholder="必填项"
type="number" />
</a-col>
<a-col :span="2" class="p-05 border-r-white">
<a-input v-model:value="contractEquipmentList[index].otherAmount" size="small" placeholder="必填项"
type="number" />
</a-col>
<a-col :span="2" class="p-05 border-r-white">
<a-input v-model:value="contractEquipmentList[index].preBuryAmount" size="small" placeholder="必填项"
type="number" />
</a-col>
<a-col :span="2" class="p-05 border-r-white">
<a-input v-model:value="contractEquipmentList[index].remark" size="small" placeholder="可选项" />
</a-col>
<a-col :span="1" class="p-05">
<div class="flex justify-center items-center">
<close-circle-outlined style="font-size: 1.5rem; color: pink;cursor: pointer"
@click.native="delEquipment(index)" />
</div>
</a-col>
</a-row>
</template>
</div>
<div class="my-05">
<a-button type="primary" @click.native="addEquipment">
<template #icon>
<PlusOutlined />
</template>
添加
</a-button>
</div>
</div>
</ele-modal>
</template>
<script lang="ts" setup>
import { ref, reactive, watch, computed } from "vue";
import { Form, message } from "ant-design-vue";
import { assignObject } from "ele-admin-pro";
import { updateContract, addContract } from "@/api/tower/contract";
import type { Customer } from "@/api/oa/customer/model";
import { useUserStore } from "@/store/modules/user";
import { Contract } from "@/api/tower/contract/model";
import dayjs from "dayjs";
import { ContractFile } from "@/api/tower/contractFile/model";
import {
PlusOutlined,
UnorderedListOutlined,
CloseCircleOutlined
} from "@ant-design/icons-vue";
import { ContractEquipment } from "@/api/tower/contractEquipment/model";
import { TowerModel } from "@/api/tower/model/model";
import { listTowerModel } from "@/api/tower/model";
import { addBatchContractFile } from "@/api/tower/contractFile";
import { addBatchContractEquipment } from "@/api/tower/contractEquipment";
const userStore = useUserStore();
// 当前用户信息
const loginUser = computed(() => userStore.info ?? {});
const now = dayjs().format("YYYY-MM-DD HH:mm:ss");
// 是否是修改
const isUpdate = ref(false);
const useForm = Form.useForm;
const props = defineProps<{
// 弹窗是否打开
visible: boolean;
// 修改回显的数据
data?: Customer | null;
}>();
const emit = defineEmits<{
(e: "done"): void;
(e: "update:visible", visible: boolean): void;
}>();
// 提交状态
const loading = ref(false);
// 是否显示最大化切换按钮
const maxable = ref(true);
// 用户信息
const form = reactive<Contract>({
contractId: undefined,
projectId: undefined,
companyId: undefined,
customerId: undefined,
customerContact: "",
contactNumber: "",
signDate: "",
startDate: "",
endDate: "",
contractAmount: undefined,
contactAgreeAmount: undefined,
isInStock: 0,
autoSettle: 0
});
/* 更新visible */
const updateVisible = (value: boolean) => {
emit("update:visible", value);
};
// 表单验证规则
const rules = reactive({
projectId: [
{
required: true,
message: "请选择项目",
trigger: "blur"
}
],
contactNumber: [
{
required: true,
message: "请输入合同编号",
trigger: "blur"
}
],
companyId: [
{
required: true,
message: "请选择出租单位",
trigger: "blur"
}
],
customerId: [
{
required: true,
message: "请选择承租单位",
trigger: "blur"
}
]
});
const projectName = ref<string>("");
const chooseProject = (res) => {
projectName.value = res.projectName;
form.projectId = res.projectId;
};
const companyName = ref<string>("");
const chooseCompany = (res) => {
companyName.value = res.companyName;
form.companyId = res.companyId;
};
const customerName = ref<string>("");
const chooseCustomer = (res) => {
customerName.value = res.name;
form.customerId = res.customerId;
form.customerContact = res.contact;
};
const changeInStock = (checked) => {
form.isInStock = checked;
};
const changeAutoSettle = (checked) => {
form.autoSettle = checked;
};
const contractFileList = ref<ContractFile[]>([]);
const uploadFile = path => {
contractFileList.value.push({ path, contractId: 0, userId: loginUser.value.userId });
};
const delFile = index => {
contractFileList.value.splice(index, 1);
};
const getContractFileList = async () => {
};
const equipmentList = ref<TowerModel[]>([]);
const getEquipmentList = async () => {
equipmentList.value = await listTowerModel();
};
const contractEquipmentList = ref<ContractEquipment[]>([]);
const getContractEquipmentList = async () => {
};
const chooseEquipmentName = (res, index) => {
contractEquipmentList.value[index].equipmentName = res.name;
};
const delEquipment = index => {
contractEquipmentList.value.splice(index, 1);
};
const addEquipment = () => {
contractEquipmentList.value.push({
contractEquipmentId: null,
contractId: null,
equipmentName: "",
equipmentModel: "",
num: null,
planRentMonth: null,
rentAmount: null,
inOutAmount: null,
workerAmount: null,
otherAmount: null,
preBuryAmount: null,
remark: null
});
};
const { resetFields, validate, validateInfos } = useForm(form, rules);
/* 保存编辑 */
const save = () => {
validate()
.then(async () => {
loading.value = true;
// 去除空格
form.contactNumber = form.contactNumber?.replace(/\s*/g, "");
// 判断权限
// if (loginUser.value.roles?.[0].roleCode != 'admin'){
// form.status = '1';
// }
const data = {
...form
};
console.log(contractEquipmentList.value)
for (let i = 0; i < contractEquipmentList.value.length; i++) {
if (!contractEquipmentList.value[i].equipmentName) {
console.log(contractEquipmentList.value[i].equipmentName)
loading.value = false;
message.error("请选择设备");
return;
}
if (!contractEquipmentList.value[i].equipmentModel) {
loading.value = false;
message.error("请选择设备型号");
return;
}
if (!contractEquipmentList.value[i].num) {
loading.value = false;
message.error("请输入签订数量");
return;
}
if (contractEquipmentList.value[i].planRentMonth === null) {
loading.value = false;
message.error("请输入计划租期");
return;
}
if (contractEquipmentList.value[i].rentAmount === null) {
loading.value = false;
message.error("请输入租金");
return;
}
if (contractEquipmentList.value[i].inOutAmount === null) {
loading.value = false;
message.error("请输入进退场费");
return;
}
if (contractEquipmentList.value[i].workerAmount === null) {
loading.value = false;
message.error("请输入劳务费用");
return;
}
if (contractEquipmentList.value[i].otherAmount === null) {
loading.value = false;
message.error("请输入其他费用");
return;
}
if (contractEquipmentList.value[i].preBuryAmount === null) {
loading.value = false;
message.error("请输入预埋费");
return;
}
}
// 转字符串
const saveOrUpdate = isUpdate.value ? updateContract : addContract;
const res = await saveOrUpdate(data).catch((e) => {
loading.value = false;
message.error(e.message);
});
const contractId = res.data;
if (contractFileList.value.length > 0) await saveFileList(contractId);
if (contractEquipmentList.value.length > 0) await saveEquipmentList(contractId);
loading.value = false;
message.success(res.message);
updateVisible(false);
emit("done");
})
.catch(() => {
});
};
const saveFileList = async (contractId) => {
contractFileList.value.forEach((item, index) => {
contractFileList.value[index].contractId = contractId;
});
await addBatchContractFile(contractFileList.value);
};
const saveEquipmentList = async (contractId) => {
contractEquipmentList.value.forEach((item, index) => {
contractEquipmentList.value[index].contractId = contractId;
});
await addBatchContractEquipment(contractEquipmentList.value);
};
watch(
() => props.visible,
(visible) => {
if (visible) {
getEquipmentList();
if (props.data) {
loading.value = false;
assignObject(form, props.data);
isUpdate.value = true;
getContractFileList();
projectName.value = props.data.projectName;
customerName.value = props.data.customerName;
companyName.value = props.data.companyName;
} else {
isUpdate.value = false;
}
} else {
resetFields();
}
}
);
</script>
<style lang="less">
.title {
font-weight: bold;
font-size: 1.1rem;
padding-bottom: 10px;
border-bottom: 1px solid #dcdfe6;
color: #494949;
margin-bottom: 10px;
}
</style>

View File

@@ -1,266 +0,0 @@
<!-- 用户编辑弹窗 -->
<template>
<ele-modal
:width="750"
:visible="visible"
:confirm-loading="loading"
:maskClosable="false"
:maxable="maxable"
:title="isUpdate ? '编辑合同' : '添加合同'"
:body-style="{ paddingBottom: '8px' }"
@update:visible="updateVisible"
@ok="save"
>
<a-form
:label-col="{ md: { span: 6 }, sm: { span: 20 }, xs: { span: 24 } }"
:wrapper-col="{ md: { span: 24 }, sm: { span: 20 }, xs: { span: 24 } }"
>
<a-row :gutter="16">
<a-col :md="12" :sm="24" :xs="24">
<a-form-item label="合同名称" v-bind="validateInfos.customerName">
<a-input
allow-clear
:maxlength="30"
placeholder="请输入合同名称"
v-model:value="form.customerName"
@blur="
validate('customerName', { trigger: 'blur' }).catch(() => {})
"
/>
</a-form-item>
<a-form-item label="合同标识" v-bind="validateInfos.customerCode">
<a-input
allow-clear
:maxlength="20"
placeholder="请输入社会统一信用代码"
v-model:value="form.customerCode"
/>
</a-form-item>
<a-form-item label="联系人" v-bind="validateInfos.customerContacts">
<a-input
allow-clear
:maxlength="20"
placeholder="请填写联系人"
v-model:value="form.customerContacts"
/>
</a-form-item>
<a-form-item label="手机号码" v-bind="validateInfos.customerMobile">
<a-input
allow-clear
:maxlength="20"
placeholder="请填写联系人手机号码"
v-model:value="form.customerMobile"
/>
</a-form-item>
<a-form-item label="头像" v-bind="validateInfos.customerAvatar">
<ele-image-upload
v-model:value="images"
:item-style="{ width: '90px', height: '90px' }"
:limit="1"
@upload="onUpload"
/>
</a-form-item>
</a-col>
<a-col :md="12" :sm="24" :xs="24">
<a-form-item label="合同全称" v-bind="validateInfos.customerFullName">
<a-input
allow-clear
:maxlength="30"
placeholder="请输入合同全称"
v-model:value="form.customerFullName"
@blur="
validate('customerFullName', { trigger: 'blur' }).catch(() => {})
"
/>
</a-form-item>
<a-form-item
label="联系地址"
v-bind="validateInfos.customerAddress"
>
<a-input
allow-clear
placeholder="请填写联系地址"
v-model:value="form.customerAddress"
/>
</a-form-item>
<a-form-item label="公司座机" v-bind="validateInfos.customerPhone">
<a-input
allow-clear
:maxlength="20"
placeholder="请填写公司座机电话"
v-model:value="form.customerPhone"
/>
</a-form-item>
<a-form-item label="排序" v-bind="validateInfos.sortNumber">
<a-input
allow-clear
:maxlength="20"
placeholder="排序"
v-model:value="form.sortNumber"
/>
</a-form-item>
<a-form-item label="备注" v-bind="validateInfos.comments">
<a-textarea
:rows="4"
:maxlength="200"
placeholder="请输入备注"
v-model:value="form.comments"
/>
</a-form-item>
</a-col>
</a-row>
</a-form>
</ele-modal>
</template>
<script lang="ts" setup>
import {ref, reactive, watch, computed} from 'vue';
import { Form, message } from 'ant-design-vue';
import { assignObject } from 'ele-admin-pro';
import { addCustomer, updateCustomer } from '@/api/oa/customer';
import type { Customer } from '@/api/oa/customer/model';
import { createCode } from '@/utils/common';
import { uploadFile } from '@/api/system/file';
import type { ItemType } from 'ele-admin-pro/es/ele-image-upload/types';
import { FILE_SERVER } from '@/config/setting';
import { useUserStore } from '@/store/modules/user';
const userStore = useUserStore();
// 当前用户信息
const loginUser = computed(() => userStore.info ?? {});
// 是否是修改
const isUpdate = ref(false);
const useForm = Form.useForm;
const props = defineProps<{
// 弹窗是否打开
visible: boolean;
// 修改回显的数据
data?: Customer | null;
}>();
const emit = defineEmits<{
(e: 'done'): void;
(e: 'update:visible', visible: boolean): void;
}>();
// 提交状态
const loading = ref(false);
// 是否显示最大化切换按钮
const maxable = ref(true);
// 用户信息
const form = reactive<Customer>({
customerCode: '',
customerName: '',
customerFullName: '',
customerType: undefined,
progress: undefined,
customerMobile: '',
customerAvatar: '',
customerPhone: '',
customerSource: '',
customerContacts: '',
customerAddress: '',
comments: '',
status: '0',
sortNumber: 100,
customerId: 0,
userId: '',
});
// 已上传数据, 可赋初始值用于回显
const images = ref(<any>[]);
/* 更新visible */
const updateVisible = (value: boolean) => {
emit('update:visible', value);
};
// 表单验证规则
const rules = reactive({
customerName: [
{
required: true,
type: 'string',
message: '请输入合同名称',
trigger: 'blur'
}
],
customerCode: [
{
required: true,
type: 'string',
message: '请输入合法的IP地址',
trigger: 'blur'
}
]
});
const { resetFields, validate, validateInfos } = useForm(form, rules);
/* 保存编辑 */
const save = () => {
validate()
.then(() => {
loading.value = true;
// 去除空格
form.customerName = form.customerName?.replace(/\s*/g, '');
// 判断权限
// if (loginUser.value.roles?.[0].roleCode != 'admin'){
// form.status = '1';
// }
const data = {
...form
};
// 转字符串
const saveOrUpdate = isUpdate.value ? updateCustomer : addCustomer;
saveOrUpdate(data)
.then((msg) => {
loading.value = false;
message.success(msg);
updateVisible(false);
emit('done');
})
.catch((e) => {
loading.value = false;
message.error(e.message);
});
})
.catch(() => {});
};
// 上传文件
const onUpload = (d: ItemType) => {
uploadFile(<File>d.file)
.then((result) => {
form.customerAvatar = result.path;
message.success('上传成功');
})
.catch((e) => {
message.error(e.message);
});
};
watch(
() => props.visible,
(visible) => {
if (visible) {
if (props.data) {
loading.value = false;
// 头像赋值
images.value = [];
if(props.data.customerAvatar){
images.value.push({ uid:1, url: FILE_SERVER + props.data.customerAvatar, status: '' });
}
assignObject(form, props.data);
isUpdate.value = true;
} else {
isUpdate.value = false;
}
} else {
resetFields();
}
}
);
</script>
<style lang="less"></style>

View File

@@ -66,9 +66,8 @@
// 表单数据
const { where } = useSearch<CustomerParam>({
customerName: '',
customerCode: '',
nickname: '',
name: '',
creditCode: '',
keywords: '',
userId: undefined
});

View File

@@ -22,45 +22,6 @@
/>
</template>
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'customerName'">
<a-avatar
:size="30"
:src="`${record.customerAvatar}`"
style="margin-right: 4px"
:srcset="`https://file.wsdns.cn/${record.customerAvatar}`"
>
<template #icon>
<UserOutlined />
</template>
</a-avatar>
<a-tooltip title="查看详情">
<a href="#" @click="openInfo(record)">{{
record.customerName
}}</a>
</a-tooltip>
</template>
<template v-if="column.key === 'progress'">
<div v-for="(d, i) in progressDict" :key="i">
<span v-if="d.value === record.progress">{{ d.label }}</span>
</div>
</template>
<template v-if="column.key === 'customerType'">
<div v-for="(d, i) in JSON.parse(customerType)" :key="i">
<span v-if="d.value === record.customerType">{{
d.value
}}</span>
</div>
</template>
<template v-if="column.key === 'status'">
<a-tag v-if="record.status === 0" color="green">正常</a-tag>
<a-tag v-if="record.status === 1" color="red">待审核</a-tag>
<a-tag v-if="record.status === 2" color="purple">已驳回</a-tag>
</template>
<template v-if="column.key === 'nickname'">
<a-tooltip :title="`${record.nickname}`">
<a-avatar :src="record.userAvatar" size="small" />
</a-tooltip>
</template>
<template v-if="column.key === 'createTime'">
<a-tooltip :title="`${toDateString(record.createTime)}`">
{{ timeAgo(record.createTime) }}
@@ -83,9 +44,9 @@
</a-card>
<!-- 编辑弹窗 -->
<CustomerEdit v-model:visible="showEdit" :data="current" @done="reload" />
<ContractEdit v-model:visible="showEdit" :data="current" @done="reload" />
<!-- 合同详情弹窗 -->
<CustomerInfo v-model:visible="showInfo" :data="current" @done="reload" />
<ContractInfo v-model:visible="showInfo" :data="current" @done="reload" />
<!-- 批量转移弹窗 -->
<!-- <CustomerMove v-model:visible="showMove" :data="selection" @done="batchMove" />-->
</div>
@@ -106,13 +67,13 @@
} from 'ele-admin-pro/es/ele-pro-table/types';
import { toDateString } from 'ele-admin-pro';
import Search from './components/search.vue';
import CustomerEdit from './components/customer-edit.vue';
import CustomerInfo from './components/customer-info.vue';
import ContractEdit from './components/contract-edit.vue';
import ContractInfo from './components/contract-info.vue';
import {
pageCustomer,
removeCustomer,
removeBatchCustomer
} from '@/api/oa/customer';
pageContract,
removeContract,
removeBatchContract
} from '@/api/tower/contract';
import { timeAgo } from 'ele-admin-pro';
import type { Customer, CustomerParam } from '@/api/oa/customer/model';
import { useUserStore } from '@/store/modules/user';
@@ -151,7 +112,7 @@
where.customerType = filters.customerType;
where.status = filters.status;
}
return pageCustomer({
return pageContract({
...where,
...orders,
page,
@@ -171,33 +132,33 @@
},
{
title: '合同编号',
dataIndex: 'contractNo',
key: 'contractNo',
dataIndex: 'contractNumber',
key: 'contractNumber',
ellipsis: true
},
{
title: '项目名称',
dataIndex: 'customerContacts'
dataIndex: 'projectName'
},
{
title: '预计产值',
dataIndex: 'customerContacts'
dataIndex: ''
},
{
title: '结算产值',
dataIndex: 'customerContacts'
dataIndex: ''
},
{
title: '业务联系人',
dataIndex: 'customerContacts'
dataIndex: 'customerContact'
},
{
title: '签订日期',
dataIndex: 'customerContacts'
dataIndex: 'signDate'
},
{
title: '已生成结算次数',
dataIndex: 'customerContacts'
dataIndex: 'settleNum'
},
{
title: '操作',
@@ -235,7 +196,7 @@
/* 删除单个 */
const remove = (row: Customer) => {
const hide = message.loading('请求中..', 0);
removeCustomer(row.customerId)
removeContract(row.customerId)
.then((msg) => {
hide();
message.success(msg);
@@ -266,7 +227,7 @@
maskClosable: true,
onOk: () => {
const hide = message.loading('请求中..', 0);
removeBatchCustomer(
removeBatchContract(
selection.value.map((d) => {
if (loginUser.value.userId === d.userId) {
return d.customerId;

View File

@@ -17,23 +17,23 @@
>
<a-row :gutter="16">
<a-col :md="12" :sm="24" :xs="24">
<a-form-item label="客户名称" v-bind="validateInfos.customerName">
<a-form-item label="客户名称" v-bind="validateInfos.name">
<a-input
allow-clear
:maxlength="30"
placeholder="请输入客户名称"
v-model:value="form.customerName"
v-model:value="form.name"
@blur="
validate('customerName', { trigger: 'blur' }).catch(() => {})
"
/>
</a-form-item>
<a-form-item label="客户标识" v-bind="validateInfos.customerCode">
<a-form-item label="客户标识" v-bind="validateInfos.creditCode">
<a-input
allow-clear
:maxlength="20"
placeholder="请输入社会统一信用代码"
v-model:value="form.customerCode"
v-model:value="form.creditCode"
/>
</a-form-item>
<a-form-item label="联系人" v-bind="validateInfos.customerContacts">
@@ -41,7 +41,7 @@
allow-clear
:maxlength="20"
placeholder="请填写联系人"
v-model:value="form.customerContacts"
v-model:value="form.contact"
/>
</a-form-item>
<a-form-item label="手机号码" v-bind="validateInfos.phone">
@@ -49,7 +49,7 @@
allow-clear
:maxlength="20"
placeholder="请填写联系人手机号码"
v-model:value="form.phone"
v-model:value="form.telPhone"
/>
</a-form-item>
<a-form-item label="头像" v-bind="validateInfos.customerAvatar">
@@ -67,7 +67,7 @@
allow-clear
:maxlength="30"
placeholder="请输入客户全称"
v-model:value="form.customerFullName"
v-model:value="form.fullName"
@blur="
validate('customerFullName', { trigger: 'blur' }).catch(() => {})
"
@@ -80,7 +80,7 @@
<a-input
allow-clear
placeholder="请填写联系地址"
v-model:value="form.customerAddress"
v-model:value="form.address"
/>
</a-form-item>
<a-form-item label="公司座机" v-bind="validateInfos.customerPhone">
@@ -88,7 +88,7 @@
allow-clear
:maxlength="20"
placeholder="请填写公司座机电话"
v-model:value="form.customerPhone"
v-model:value="form.phone"
/>
</a-form-item>
<a-form-item label="排序" v-bind="validateInfos.sortNumber">
@@ -104,7 +104,7 @@
:rows="4"
:maxlength="200"
placeholder="请输入备注"
v-model:value="form.comments"
v-model:value="form.remark"
/>
</a-form-item>
</a-col>
@@ -150,22 +150,19 @@ import {ref, reactive, watch, computed} from 'vue';
// 用户信息
const form = reactive<Customer>({
customerCode: '',
customerName: '',
customerFullName: '',
customerType: undefined,
progress: undefined,
customerMobile: '',
customerAvatar: '',
customerPhone: '',
customerSource: '',
customerContacts: '',
customerAddress: '',
comments: '',
status: '0',
customerId: undefined,
creditCode: '',
name: '',
fullName: '',
avatar: '',
phone: '',
telPhone: '',
contact: '',
address: '',
remark: '',
sortNumber: 100,
customerId: 0,
userId: '',
createTime: undefined,
userId: 0,
});
// 已上传数据, 可赋初始值用于回显
@@ -178,7 +175,7 @@ import {ref, reactive, watch, computed} from 'vue';
// 表单验证规则
const rules = reactive({
customerName: [
name: [
{
required: true,
type: 'string',
@@ -186,11 +183,11 @@ import {ref, reactive, watch, computed} from 'vue';
trigger: 'blur'
}
],
customerCode: [
creditCode: [
{
required: true,
type: 'string',
message: '请输入合法的IP地址',
message: '请输入客户标识',
trigger: 'blur'
}
]
@@ -204,7 +201,7 @@ import {ref, reactive, watch, computed} from 'vue';
.then(() => {
loading.value = true;
// 去除空格
form.customerName = form.customerName?.replace(/\s*/g, '');
form.name = form.name?.replace(/\s*/g, '');
// 判断权限
// if (loginUser.value.roles?.[0].roleCode != 'admin'){
// form.status = '1';
@@ -233,7 +230,7 @@ import {ref, reactive, watch, computed} from 'vue';
const onUpload = (d: ItemType) => {
uploadFile(<File>d.file)
.then((result) => {
form.customerAvatar = result.path;
form.avatar = result.path;
message.success('上传成功');
})
.catch((e) => {
@@ -249,8 +246,8 @@ import {ref, reactive, watch, computed} from 'vue';
loading.value = false;
// 头像赋值
images.value = [];
if(props.data.customerAvatar){
images.value.push({ uid:1, url: FILE_SERVER + props.data.customerAvatar, status: '' });
if(props.data.avatar){
images.value.push({ uid:1, url: FILE_SERVER + props.data.avatar, status: '' });
}
assignObject(form, props.data);
isUpdate.value = true;

View File

@@ -22,12 +22,12 @@
/>
</template>
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'customerName'">
<template v-if="column.key === 'name'">
<a-avatar
:size="30"
:src="`${record.customerAvatar}`"
:src="`${record.avatar}`"
style="margin-right: 4px"
:srcset="`https://file.wsdns.cn/${record.customerAvatar}`"
:srcset="`https://file.wsdns.cn/${record.avatar}`"
>
<template #icon>
<UserOutlined />
@@ -35,32 +35,10 @@
</a-avatar>
<a-tooltip title="查看详情">
<a href="#" @click="openInfo(record)">{{
record.customerName
record.name
}}</a>
</a-tooltip>
</template>
<template v-if="column.key === 'progress'">
<div v-for="(d, i) in progressDict" :key="i">
<span v-if="d.value === record.progress">{{ d.label }}</span>
</div>
</template>
<template v-if="column.key === 'customerType'">
<div v-for="(d, i) in JSON.parse(customerType)" :key="i">
<span v-if="d.value === record.customerType">{{
d.value
}}</span>
</div>
</template>
<template v-if="column.key === 'status'">
<a-tag v-if="record.status === 0" color="green">正常</a-tag>
<a-tag v-if="record.status === 1" color="red">待审核</a-tag>
<a-tag v-if="record.status === 2" color="purple">已驳回</a-tag>
</template>
<template v-if="column.key === 'nickname'">
<a-tooltip :title="`${record.nickname}`">
<a-avatar :src="record.userAvatar" size="small" />
</a-tooltip>
</template>
<template v-if="column.key === 'createTime'">
<a-tooltip :title="`${toDateString(record.createTime)}`">
{{ timeAgo(record.createTime) }}
@@ -171,18 +149,18 @@
},
{
title: '客户名称',
dataIndex: 'customerName',
key: 'customerName',
dataIndex: 'name',
key: 'name',
width: 280,
ellipsis: true
},
{
title: '联系人',
dataIndex: 'customerContacts'
dataIndex: 'contact'
},
{
title: '联系电话',
dataIndex: 'customerMobile'
dataIndex: 'telPhone'
},
{
title: '操作',