Commit e5743afc96a6448f0e47f71a35885f1b82aaf177

Authored by boyang
2 parents 48b5692b a1ae730f

Merge branch 'clientBy'

src/pages/Client/Client/Components/ClientDrawer.tsx
@@ -5,15 +5,14 @@ import { @@ -5,15 +5,14 @@ import {
5 postDistrictSelectByLevel, 5 postDistrictSelectByLevel,
6 postDistrictSelectByNameAndLevel, 6 postDistrictSelectByNameAndLevel,
7 postDistrictSelOrderProvince, 7 postDistrictSelOrderProvince,
  8 + postResearchGroupsNameSet,
8 postServiceConstClientLevels, 9 postServiceConstClientLevels,
9 postServiceConstClientSource, 10 postServiceConstClientSource,
10 - postServiceConstTradeStatus,  
11 } from '@/services'; 11 } from '@/services';
12 12
13 import { enumToSelect } from '@/utils'; 13 import { enumToSelect } from '@/utils';
14 import { 14 import {
15 DrawerForm, 15 DrawerForm,
16 - ProFormDatePicker,  
17 ProFormSelect, 16 ProFormSelect,
18 ProFormText, 17 ProFormText,
19 } from '@ant-design/pro-components'; 18 } from '@ant-design/pro-components';
@@ -23,17 +22,10 @@ import { useState } from 'react'; @@ -23,17 +22,10 @@ import { useState } from 'react';
23 22
24 export default ({ optType, record, onFinish }) => { 23 export default ({ optType, record, onFinish }) => {
25 const [form] = Form.useForm(); 24 const [form] = Form.useForm();
26 - const requirementsEnum = {  
27 - EXPERIMENTAL_EQUIPMENT: '实验设备',  
28 - EXPERIMENTAL_MATERIALS: '实验材料',  
29 - OTHER: '其他',  
30 - PILOT_TEST_VALIDATION_SERVICES: '中式验证服务',  
31 - };  
32 //省市区 25 //省市区
33 const [province, setProvince] = useState(''); 26 const [province, setProvince] = useState('');
34 const [city, setCity] = useState(''); 27 const [city, setCity] = useState('');
35 const [showReferrers, setShowReferrers] = useState(false); // 控制显示的状态,初始为false 28 const [showReferrers, setShowReferrers] = useState(false); // 控制显示的状态,初始为false
36 - const [showQuoteDatetime, setShowQuoteDatetime] = useState(false); // 控制显示的状态,初始为false  
37 const optTypeEnum = { 29 const optTypeEnum = {
38 add: { 30 add: {
39 text: '新增', 31 text: '新增',
@@ -82,15 +74,6 @@ export default ({ optType, record, onFinish }) => { @@ -82,15 +74,6 @@ export default ({ optType, record, onFinish }) => {
82 } 74 }
83 // 在这里可以添加其他逻辑,比如根据选择更新其他表单项的值 75 // 在这里可以添加其他逻辑,比如根据选择更新其他表单项的值
84 }; 76 };
85 - const handleSchemeChange = (value) => {  
86 - console.log(value);  
87 - if (value === true) {  
88 - setShowQuoteDatetime(true);  
89 - } else {  
90 - setShowQuoteDatetime(false);  
91 - }  
92 - // 在这里可以添加其他逻辑,比如根据选择更新其他表单项的值  
93 - };  
94 77
95 // MODIFIED: 增加处理非 JSON 格式字符串的逻辑 78 // MODIFIED: 增加处理非 JSON 格式字符串的逻辑
96 const parsedRecord = record 79 const parsedRecord = record
@@ -314,13 +297,13 @@ export default ({ optType, record, onFinish }) => { @@ -314,13 +297,13 @@ export default ({ optType, record, onFinish }) => {
314 ]} 297 ]}
315 /> 298 />
316 <ProFormText 299 <ProFormText
317 - name="contacts"  
318 - label="联系人"  
319 - placeholder="请输入联系人" 300 + name="leaderName"
  301 + label="负责人"
  302 + placeholder="请输入负责人"
320 rules={[ 303 rules={[
321 { 304 {
322 required: true, 305 required: true,
323 - message: '请输入联系人', 306 + message: '请输入负责人',
324 }, 307 },
325 ]} 308 ]}
326 /> 309 />
@@ -336,6 +319,60 @@ export default ({ optType, record, onFinish }) =&gt; { @@ -336,6 +319,60 @@ export default ({ optType, record, onFinish }) =&gt; {
336 ]} 319 ]}
337 /> 320 />
338 <ProFormSelect 321 <ProFormSelect
  322 + key={'institutionContactName'}
  323 + width="md"
  324 + showSearch
  325 + name="institutionContactName"
  326 + rules={[{ required: true, message: '请输入课题组名称!' }]}
  327 + request={async (value) => {
  328 + const keywords = value.keyWords;
  329 + const res = await postResearchGroupsNameSet({
  330 + data: {
  331 + status: 'ADD_AUDIT_PASS',
  332 + groupName: keywords,
  333 + },
  334 + });
  335 + let options = res?.data?.map((c: any) => {
  336 + return {
  337 + label: c,
  338 + value: c,
  339 + key: c,
  340 + };
  341 + });
  342 + return options;
  343 + }}
  344 + fieldProps={{
  345 + filterOption() {
  346 + return true;
  347 + },
  348 + }}
  349 + debounceTime={1000}
  350 + label="课题组名称"
  351 + placeholder="请输入名称"
  352 + />
  353 + <ProFormText
  354 + name="department"
  355 + label="部门"
  356 + placeholder="请输入部门"
  357 + rules={[
  358 + {
  359 + required: false,
  360 + message: '请输入部门',
  361 + },
  362 + ]}
  363 + />
  364 + <ProFormText
  365 + name="gradePosition"
  366 + label="年级/职位"
  367 + placeholder="请输入年级/职位"
  368 + rules={[
  369 + {
  370 + required: false,
  371 + message: '请输入年级/职位',
  372 + },
  373 + ]}
  374 + />
  375 + <ProFormSelect
339 name="source" 376 name="source"
340 label="客户来源" 377 label="客户来源"
341 placeholder="请选择客户来源" 378 placeholder="请选择客户来源"
@@ -360,7 +397,7 @@ export default ({ optType, record, onFinish }) =&gt; { @@ -360,7 +397,7 @@ export default ({ optType, record, onFinish }) =&gt; {
360 placeholder="请输入推荐人" 397 placeholder="请输入推荐人"
361 /> 398 />
362 )} 399 )}
363 - <ProFormSelect 400 + {/* <ProFormSelect
364 name="requirements" 401 name="requirements"
365 label="客户需求" 402 label="客户需求"
366 placeholder="请输入客户需求" 403 placeholder="请输入客户需求"
@@ -380,38 +417,7 @@ export default ({ optType, record, onFinish }) =&gt; { @@ -380,38 +417,7 @@ export default ({ optType, record, onFinish }) =&gt; {
380 // console.log(res.data, '5656require'); 417 // console.log(res.data, '5656require');
381 // return enumToSelect(res.data); 418 // return enumToSelect(res.data);
382 // }} 419 // }}
383 - />  
384 - <ProFormSelect  
385 - name="hasScheme"  
386 - label="是否已报方案"  
387 - placeholder="请选择是否已报方案"  
388 - options={[  
389 - {  
390 - label: '是',  
391 - value: true,  
392 - },  
393 - {  
394 - label: '否',  
395 - value: false,  
396 - },  
397 - ]}  
398 - rules={[  
399 - {  
400 - required: true,  
401 - message: '请选择是否已报方案',  
402 - },  
403 - ]}  
404 - fieldProps={{  
405 - onChange: handleSchemeChange, // 添加onChange事件处理函数  
406 - }}  
407 - />  
408 - {showQuoteDatetime && (  
409 - <ProFormDatePicker  
410 - name="quoteDatetime"  
411 - label="报价时间"  
412 - placeholder="请输入报价时间"  
413 - />  
414 - )} 420 + /> */}
415 <ProFormSelect 421 <ProFormSelect
416 name="level" 422 name="level"
417 label="客户等级" 423 label="客户等级"
@@ -437,21 +443,6 @@ export default ({ optType, record, onFinish }) =&gt; { @@ -437,21 +443,6 @@ export default ({ optType, record, onFinish }) =&gt; {
437 return enumToSelectLevel(res.data); 443 return enumToSelectLevel(res.data);
438 }} 444 }}
439 /> 445 />
440 - <ProFormSelect  
441 - name="tradeStatus"  
442 - label="跟进状态"  
443 - placeholder="请输入跟进状态"  
444 - rules={[  
445 - {  
446 - required: true,  
447 - message: '请输入跟进状态',  
448 - },  
449 - ]}  
450 - request={async () => {  
451 - const res = await postServiceConstTradeStatus();  
452 - return enumToSelect(res.data);  
453 - }}  
454 - />  
455 <ProFormText name="notes" label="备注" placeholder="请输入备注" /> 446 <ProFormText name="notes" label="备注" placeholder="请输入备注" />
456 </DrawerForm> 447 </DrawerForm>
457 ); 448 );
src/pages/Client/Client/Components/ClientInformationModal.tsx
1 import { RESPONSE_CODE } from '@/constants/enum'; 1 import { RESPONSE_CODE } from '@/constants/enum';
  2 +import UploadC from '@/pages/Invoice/waitProcessRecord/components/UploadSingleImg';
2 import { 3 import {
3 postAdminClientAddOrModifyClientComunicationInfo, 4 postAdminClientAddOrModifyClientComunicationInfo,
4 postAdminClientQueryClientPage, 5 postAdminClientQueryClientPage,
5 postOrderErpOrderStagesUpload, 6 postOrderErpOrderStagesUpload,
  7 + postOrderErpUsersListByPage,
6 postServiceConstClientWay, 8 postServiceConstClientWay,
  9 + postServiceConstTradeStatus,
7 } from '@/services'; 10 } from '@/services';
8 import { enumToSelect } from '@/utils'; 11 import { enumToSelect } from '@/utils';
9 import { 12 import {
@@ -14,8 +17,9 @@ import { @@ -14,8 +17,9 @@ import {
14 ProFormTextArea, 17 ProFormTextArea,
15 ProFormUploadDragger, 18 ProFormUploadDragger,
16 } from '@ant-design/pro-components'; 19 } from '@ant-design/pro-components';
17 -import { Button, Form, message } from 'antd'; 20 +import { Button, Col, Form, Row, message } from 'antd';
18 import { RcFile } from 'antd/es/upload'; 21 import { RcFile } from 'antd/es/upload';
  22 +import './style.css';
19 export default ({ data, type, reloadTable }) => { 23 export default ({ data, type, reloadTable }) => {
20 const [form] = Form.useForm(); 24 const [form] = Form.useForm();
21 const onfinish = async (values) => { 25 const onfinish = async (values) => {
@@ -64,6 +68,12 @@ export default ({ data, type, reloadTable }) =&gt; { @@ -64,6 +68,12 @@ export default ({ data, type, reloadTable }) =&gt; {
64 const res = await postAdminClientAddOrModifyClientComunicationInfo({ 68 const res = await postAdminClientAddOrModifyClientComunicationInfo({
65 data: { 69 data: {
66 ...values, 70 ...values,
  71 + // ticketsAttachments: form.getFieldValue("ticketsAttachments"),
  72 + ticketsAttachments:
  73 + form.getFieldValue('ticketsAttachments') !== undefined
  74 + ? form.getFieldValue('ticketsAttachments')
  75 + : data?.ticketsAttachments,
  76 + // ticketsAttachments: data?.annexUrl,
67 }, 77 },
68 }); 78 });
69 if (res.result === RESPONSE_CODE.SUCCESS) { 79 if (res.result === RESPONSE_CODE.SUCCESS) {
@@ -165,9 +175,37 @@ export default ({ data, type, reloadTable }) =&gt; { @@ -165,9 +175,37 @@ export default ({ data, type, reloadTable }) =&gt; {
165 }, 175 },
166 ]} 176 ]}
167 ></ProFormSelect> 177 ></ProFormSelect>
  178 + <ProFormText
  179 + name="contact"
  180 + label="联系人"
  181 + width="sm"
  182 + placeholder="请输入联系人"
  183 + initialValue={data?.content}
  184 + readonly={optType[type].readOnly}
  185 + rules={[
  186 + {
  187 + required: true,
  188 + message: '请输入联系人',
  189 + },
  190 + ]}
  191 + ></ProFormText>
  192 + <ProFormText
  193 + name="contactPhone"
  194 + label="联系电话"
  195 + width="sm"
  196 + placeholder="请输入联系电话"
  197 + initialValue={data?.content}
  198 + readonly={optType[type].readOnly}
  199 + rules={[
  200 + {
  201 + required: true,
  202 + message: '请输入联系电话',
  203 + },
  204 + ]}
  205 + ></ProFormText>
168 <ProFormDateTimePicker 206 <ProFormDateTimePicker
169 name="datetime" 207 name="datetime"
170 - label="日期" 208 + label="跟进日期"
171 initialValue={data ? data?.datetime + '' : null} 209 initialValue={data ? data?.datetime + '' : null}
172 placeholder="请选择跟进时间" 210 placeholder="请选择跟进时间"
173 width="sm" 211 width="sm"
@@ -179,6 +217,27 @@ export default ({ data, type, reloadTable }) =&gt; { @@ -179,6 +217,27 @@ export default ({ data, type, reloadTable }) =&gt; {
179 ]} 217 ]}
180 /> 218 />
181 <ProFormSelect 219 <ProFormSelect
  220 + name="tradeStatus"
  221 + label="跟进状态"
  222 + width="sm"
  223 + placeholder="请输入跟进状态"
  224 + readonly={optType[type].readOnly}
  225 + fieldProps={{
  226 + labelInValue: false,
  227 + }}
  228 + initialValue={data?.tradeStatus ? data?.tradeStatus + '' : null}
  229 + rules={[
  230 + {
  231 + required: true,
  232 + message: '请输入跟进状态',
  233 + },
  234 + ]}
  235 + request={async () => {
  236 + const res = await postServiceConstTradeStatus();
  237 + return enumToSelect(res.data);
  238 + }}
  239 + />
  240 + <ProFormSelect
182 name="way" 241 name="way"
183 width="sm" 242 width="sm"
184 readonly={optType[type].readOnly} 243 readonly={optType[type].readOnly}
@@ -186,7 +245,7 @@ export default ({ data, type, reloadTable }) =&gt; { @@ -186,7 +245,7 @@ export default ({ data, type, reloadTable }) =&gt; {
186 labelInValue: false, 245 labelInValue: false,
187 }} 246 }}
188 initialValue={data?.way ? data?.way + '' : null} 247 initialValue={data?.way ? data?.way + '' : null}
189 - label="类型" 248 + label="跟进方式"
190 request={async () => { 249 request={async () => {
191 const res = await postServiceConstClientWay(); 250 const res = await postServiceConstClientWay();
192 return enumToSelect(res.data); 251 return enumToSelect(res.data);
@@ -194,7 +253,7 @@ export default ({ data, type, reloadTable }) =&gt; { @@ -194,7 +253,7 @@ export default ({ data, type, reloadTable }) =&gt; {
194 rules={[ 253 rules={[
195 { 254 {
196 required: true, 255 required: true,
197 - message: '请选择跟进类型', 256 + message: '请选择跟进方式',
198 }, 257 },
199 ]} 258 ]}
200 ></ProFormSelect> 259 ></ProFormSelect>
@@ -242,12 +301,138 @@ export default ({ data, type, reloadTable }) =&gt; { @@ -242,12 +301,138 @@ export default ({ data, type, reloadTable }) =&gt; {
242 <a hidden={!optType[type].readOnly} href={data?.attachments} download> 301 <a hidden={!optType[type].readOnly} href={data?.attachments} download>
243 下载附件 302 下载附件
244 </a> 303 </a>
  304 + <ProFormTextArea
  305 + name="comment"
  306 + label="客户评价"
  307 + placeholder="请输入客户评价"
  308 + initialValue={data?.comment}
  309 + readonly={optType[type].readOnly}
  310 + ></ProFormTextArea>
245 <ProFormText 311 <ProFormText
246 initialValue={data?.attachments} 312 initialValue={data?.attachments}
247 name="attachments" 313 name="attachments"
248 hidden 314 hidden
249 ></ProFormText> 315 ></ProFormText>
250 <ProFormText initialValue={data?.id} name="id" hidden></ProFormText> 316 <ProFormText initialValue={data?.id} name="id" hidden></ProFormText>
  317 + <div className="styled-text">
  318 + <div className="vertical-line"></div>
  319 + <span className="text">工单指派</span>
  320 + </div>
  321 + <ProFormSelect
  322 + name="ticketsType"
  323 + label="工单类型"
  324 + width="sm"
  325 + placeholder="请输入工单类型"
  326 + readonly={optType[type].readOnly}
  327 + fieldProps={{
  328 + labelInValue: false,
  329 + }}
  330 + initialValue={data?.ticketsType ? data?.ticketsType + '' : null}
  331 + request={async () => {
  332 + return [
  333 + { label: '问题', value: 'QUESTION' },
  334 + { label: '需求', value: 'DEMAND' },
  335 + { label: '建议', value: 'ADVICE' },
  336 + ];
  337 + }}
  338 + />
  339 + <ProFormTextArea
  340 + name="ticketsDetail"
  341 + label="工单详情"
  342 + placeholder="请输入工单详情"
  343 + initialValue={data?.ticketsDetail ? data?.ticketsDetail + '' : null}
  344 + readonly={optType[type].readOnly}
  345 + ></ProFormTextArea>
  346 + {/* <ProFormUploadDragger
  347 + label="工单附件"
  348 + name="ticketsAttachment"
  349 + action="upload.do"
  350 + hidden={optType[type].readOnly}
  351 + onChange={(info) => {
  352 + const uploadFile = async ({ fileList: newFileList }) => {
  353 + if (newFileList.length > 0) {
  354 + const formData = new FormData();
  355 + formData.append('file', newFileList[0].originFileObj as RcFile);
  356 + const res = await postOrderErpOrderStagesUpload({
  357 + data: formData,
  358 + headers: {
  359 + 'Content-Type':
  360 + 'multipart/form-data; boundary=----WebKitFormBoundarynl6gT1BKdPWIejNq',
  361 + },
  362 + });
  363 + const url = res.data;
  364 + console.log('ticketsAttachments' + JSON.stringify(url));
  365 + form.setFieldValue('ticketsAttachments', url);
  366 + } else {
  367 + form.setFieldValue('ticketsAttachments', null);
  368 + }
  369 + };
  370 + uploadFile(info);
  371 + }}
  372 + max={1}
  373 + /> */}
  374 + <Row>
  375 + <Col span={4}>附件:</Col>
  376 + <Col span={20}>
  377 + <UploadC
  378 + onFilesChange={async (newFileList) => {
  379 + if (newFileList.length > 0) {
  380 + const urls = []; // 创建一个数组来存储所有的 URL
  381 +
  382 + for (const file of newFileList) {
  383 + const formData = new FormData();
  384 + formData.append('file', file.originFileObj as RcFile);
  385 +
  386 + const res = await postOrderErpOrderStagesUpload({
  387 + data: formData,
  388 + headers: {
  389 + 'Content-Type':
  390 + 'multipart/form-data; boundary=----WebKitFormBoundarynl6gT1BKdPWIejNq',
  391 + },
  392 + });
  393 +
  394 + const url = res.data; // 获取响应中的 URL
  395 + urls.push(url); // 将每个 URL 追加到数组中
  396 + }
  397 +
  398 + // 将所有 URL 使用 ',' 进行拼接
  399 + const combinedUrl = urls.join(',');
  400 + form.setFieldValue('ticketsAttachments', combinedUrl); // 设置表单字段值为拼接后的 URL
  401 + } else {
  402 + form.setFieldValue('ticketsAttachments', null); // 如果没有文件,则清空 URL
  403 + }
  404 + }}
  405 + ></UploadC>
  406 + </Col>
  407 + </Row>
  408 + <a hidden={!optType[type].readOnly} href={data?.orderAttachment} download>
  409 + 下载附件
  410 + </a>
  411 + <ProFormSelect
  412 + name="assignPeople"
  413 + width="sm"
  414 + readonly={optType[type].readOnly}
  415 + fieldProps={{
  416 + labelInValue: false,
  417 + }}
  418 + initialValue={data?.assignPeople ? data?.assignPeople + '' : null}
  419 + label="指派人员"
  420 + request={async () => {
  421 + const res = await postOrderErpUsersListByPage({
  422 + data: {
  423 + pageSize: 10000,
  424 + },
  425 + });
  426 +
  427 + const userOptions = res.data.records
  428 + ? res.data.records.map((user) => ({
  429 + label: user.userName, // 或者使用其他需要的属性
  430 + value: user.userName, // 作为value的字段
  431 + }))
  432 + : [];
  433 + return userOptions;
  434 + }}
  435 + ></ProFormSelect>
251 </ModalForm> 436 </ModalForm>
252 ); 437 );
253 }; 438 };
src/pages/Client/Client/Components/ClientModal.tsx
1 import { RESPONSE_CODE } from '@/constants/enum'; 1 import { RESPONSE_CODE } from '@/constants/enum';
  2 +import UploadC from '@/pages/Invoice/waitProcessRecord/components/UploadSingleImg';
2 import { 3 import {
3 postAdminClientAddOrModifyClientComunicationInfo, 4 postAdminClientAddOrModifyClientComunicationInfo,
4 postAdminClientQueryClientPage, 5 postAdminClientQueryClientPage,
5 postOrderErpOrderStagesUpload, 6 postOrderErpOrderStagesUpload,
  7 + postOrderErpUsersListByPage,
6 postServiceConstClientWay, 8 postServiceConstClientWay,
  9 + postServiceConstTradeStatus,
7 } from '@/services'; 10 } from '@/services';
8 import { enumToSelect } from '@/utils'; 11 import { enumToSelect } from '@/utils';
9 import { 12 import {
@@ -14,13 +17,12 @@ import { @@ -14,13 +17,12 @@ import {
14 ProFormTextArea, 17 ProFormTextArea,
15 ProFormUploadDragger, 18 ProFormUploadDragger,
16 } from '@ant-design/pro-components'; 19 } from '@ant-design/pro-components';
17 -import { Button, Form, message } from 'antd'; 20 +import { Button, Col, Form, Row, message } from 'antd';
18 import { RcFile } from 'antd/es/upload'; 21 import { RcFile } from 'antd/es/upload';
  22 +import './style.css';
19 export default ({ data, type, reloadTable }) => { 23 export default ({ data, type, reloadTable }) => {
20 const [form] = Form.useForm(); 24 const [form] = Form.useForm();
21 const onfinish = async (values) => { 25 const onfinish = async (values) => {
22 - console.log(data, '5656datatest');  
23 - console.log(values, '5656...values');  
24 const res = await postAdminClientAddOrModifyClientComunicationInfo({ 26 const res = await postAdminClientAddOrModifyClientComunicationInfo({
25 data: { 27 data: {
26 ...values, 28 ...values,
@@ -111,7 +113,6 @@ export default ({ data, type, reloadTable }) =&gt; { @@ -111,7 +113,6 @@ export default ({ data, type, reloadTable }) =&gt; {
111 groupFilter: 'all', 113 groupFilter: 'all',
112 }, 114 },
113 }); 115 });
114 - console.log(data?.datetime, '5656data?.datetime');  
115 const namesArray = res.data.data.map((item) => item.name); 116 const namesArray = res.data.data.map((item) => item.name);
116 return enumToSelect(namesArray); 117 return enumToSelect(namesArray);
117 }} 118 }}
@@ -123,9 +124,37 @@ export default ({ data, type, reloadTable }) =&gt; { @@ -123,9 +124,37 @@ export default ({ data, type, reloadTable }) =&gt; {
123 ]} 124 ]}
124 disabled 125 disabled
125 ></ProFormSelect> 126 ></ProFormSelect>
  127 + <ProFormText
  128 + name="contact"
  129 + label="联系人"
  130 + width="sm"
  131 + placeholder="请输入联系人"
  132 + initialValue={data?.content}
  133 + readonly={optType[type].readOnly}
  134 + rules={[
  135 + {
  136 + required: true,
  137 + message: '请输入联系人',
  138 + },
  139 + ]}
  140 + ></ProFormText>
  141 + <ProFormText
  142 + name="contactPhone"
  143 + label="联系电话"
  144 + width="sm"
  145 + placeholder="请输入联系电话"
  146 + initialValue={data?.content}
  147 + readonly={optType[type].readOnly}
  148 + rules={[
  149 + {
  150 + required: true,
  151 + message: '请输入联系电话',
  152 + },
  153 + ]}
  154 + ></ProFormText>
126 <ProFormDateTimePicker 155 <ProFormDateTimePicker
127 name="datetime" 156 name="datetime"
128 - label="日期" 157 + label="跟进日期"
129 initialValue={data.datetime ? data?.datetime + '' : null} 158 initialValue={data.datetime ? data?.datetime + '' : null}
130 placeholder="请选择跟进时间" 159 placeholder="请选择跟进时间"
131 width="sm" 160 width="sm"
@@ -137,6 +166,27 @@ export default ({ data, type, reloadTable }) =&gt; { @@ -137,6 +166,27 @@ export default ({ data, type, reloadTable }) =&gt; {
137 ]} 166 ]}
138 /> 167 />
139 <ProFormSelect 168 <ProFormSelect
  169 + name="tradeStatus"
  170 + label="跟进状态"
  171 + width="sm"
  172 + placeholder="请输入跟进状态"
  173 + readonly={optType[type].readOnly}
  174 + fieldProps={{
  175 + labelInValue: false,
  176 + }}
  177 + initialValue={data?.tradeStatus ? data?.tradeStatus + '' : null}
  178 + rules={[
  179 + {
  180 + required: true,
  181 + message: '请输入跟进状态',
  182 + },
  183 + ]}
  184 + request={async () => {
  185 + const res = await postServiceConstTradeStatus();
  186 + return enumToSelect(res.data);
  187 + }}
  188 + />
  189 + <ProFormSelect
140 name="way" 190 name="way"
141 width="sm" 191 width="sm"
142 readonly={optType[type].readOnly} 192 readonly={optType[type].readOnly}
@@ -200,12 +250,138 @@ export default ({ data, type, reloadTable }) =&gt; { @@ -200,12 +250,138 @@ export default ({ data, type, reloadTable }) =&gt; {
200 <a hidden={!optType[type].readOnly} href={data?.attachments} download> 250 <a hidden={!optType[type].readOnly} href={data?.attachments} download>
201 下载附件 251 下载附件
202 </a> 252 </a>
  253 + <ProFormTextArea
  254 + name="comment"
  255 + label="客户评价"
  256 + placeholder="请输入客户评价"
  257 + initialValue={data?.comment}
  258 + readonly={optType[type].readOnly}
  259 + ></ProFormTextArea>
203 <ProFormText 260 <ProFormText
204 initialValue={data?.attachments} 261 initialValue={data?.attachments}
205 name="attachments" 262 name="attachments"
206 hidden 263 hidden
207 ></ProFormText> 264 ></ProFormText>
208 <ProFormText initialValue={data?.id} name="id" hidden></ProFormText> 265 <ProFormText initialValue={data?.id} name="id" hidden></ProFormText>
  266 + <div className="styled-text">
  267 + <div className="vertical-line"></div>
  268 + <span className="text">工单指派</span>
  269 + </div>
  270 + <ProFormSelect
  271 + name="ticketsType"
  272 + label="工单类型"
  273 + width="sm"
  274 + placeholder="请输入工单类型"
  275 + readonly={optType[type].readOnly}
  276 + fieldProps={{
  277 + labelInValue: false,
  278 + }}
  279 + initialValue={data?.type ? data?.type + '' : null}
  280 + request={async () => {
  281 + return [
  282 + { label: '问题', value: 'QUESTION' },
  283 + { label: '需求', value: 'DEMAND' },
  284 + { label: '建议', value: 'ADVICE' },
  285 + ];
  286 + }}
  287 + />
  288 + <ProFormTextArea
  289 + name="ticketsDetail"
  290 + label="工单详情"
  291 + placeholder="请输入工单详情"
  292 + initialValue={data?.detailText ? data?.detailText + '' : null}
  293 + readonly={optType[type].readOnly}
  294 + ></ProFormTextArea>
  295 + <Row>
  296 + <Col span={4}>附件:</Col>
  297 + <Col span={20}>
  298 + <UploadC
  299 + onFilesChange={async (newFileList) => {
  300 + if (newFileList.length > 0) {
  301 + const urls = []; // 创建一个数组来存储所有的 URL
  302 +
  303 + for (const file of newFileList) {
  304 + const formData = new FormData();
  305 + formData.append('file', file.originFileObj as RcFile);
  306 +
  307 + const res = await postOrderErpOrderStagesUpload({
  308 + data: formData,
  309 + headers: {
  310 + 'Content-Type':
  311 + 'multipart/form-data; boundary=----WebKitFormBoundarynl6gT1BKdPWIejNq',
  312 + },
  313 + });
  314 +
  315 + const url = res.data; // 获取响应中的 URL
  316 + urls.push(url); // 将每个 URL 追加到数组中
  317 + }
  318 +
  319 + // 将所有 URL 使用 ',' 进行拼接
  320 + const combinedUrl = urls.join(',');
  321 + form.setFieldValue('ticketsAttachments', combinedUrl); // 设置表单字段值为拼接后的 URL
  322 + } else {
  323 + form.setFieldValue('ticketsAttachments', null); // 如果没有文件,则清空 URL
  324 + }
  325 + }}
  326 + ></UploadC>
  327 + </Col>
  328 + </Row>
  329 + {/* <ProFormUploadDragger
  330 + label="工单附件"
  331 + name="ticketsAttachment"
  332 + action="upload.do"
  333 + hidden={optType[type].readOnly}
  334 + onChange={(info) => {
  335 + const uploadFile = async ({ fileList: newFileList }) => {
  336 + if (newFileList.length > 0) {
  337 + const formData = new FormData();
  338 + formData.append('file', newFileList[0].originFileObj as RcFile);
  339 + const res = await postOrderErpOrderStagesUpload({
  340 + data: formData,
  341 + headers: {
  342 + 'Content-Type':
  343 + 'multipart/form-data; boundary=----WebKitFormBoundarynl6gT1BKdPWIejNq',
  344 + },
  345 + });
  346 + const url = res.data;
  347 + console.log('ticketsAttachments' + JSON.stringify(url));
  348 + form.setFieldValue('ticketsAttachments', url);
  349 + } else {
  350 + form.setFieldValue('ticketsAttachments', null);
  351 + }
  352 + };
  353 + uploadFile(info);
  354 + }}
  355 + max={1}
  356 + /> */}
  357 + <a hidden={!optType[type].readOnly} href={data?.orderAttachment} download>
  358 + 下载附件
  359 + </a>
  360 + <ProFormSelect
  361 + name="assignPeople"
  362 + width="sm"
  363 + readonly={optType[type].readOnly}
  364 + fieldProps={{
  365 + labelInValue: false,
  366 + }}
  367 + initialValue={data?.assignPeople ? data?.assignPeople + '' : null}
  368 + label="指派人员"
  369 + request={async () => {
  370 + const res = await postOrderErpUsersListByPage({
  371 + data: {
  372 + pageSize: 10000,
  373 + },
  374 + });
  375 +
  376 + const userOptions = res.data.records
  377 + ? res.data.records.map((user) => ({
  378 + label: user.userName, // 或者使用其他需要的属性
  379 + value: user.userName, // 作为value的字段
  380 + }))
  381 + : [];
  382 + return userOptions;
  383 + }}
  384 + ></ProFormSelect>
209 </ModalForm> 385 </ModalForm>
210 ); 386 );
211 }; 387 };
src/pages/Client/Client/Components/CommunicationHistoryModal.tsx
@@ -4,6 +4,7 @@ import { @@ -4,6 +4,7 @@ import {
4 postAdminClientQueryClientComunicationInfo, 4 postAdminClientQueryClientComunicationInfo,
5 postAdminClientRemoveClientComunicationInfo, 5 postAdminClientRemoveClientComunicationInfo,
6 postServiceConstClientWay, 6 postServiceConstClientWay,
  7 + postServiceConstTradeStatus,
7 } from '@/services'; 8 } from '@/services';
8 import { enumToSelect } from '@/utils'; 9 import { enumToSelect } from '@/utils';
9 import { 10 import {
@@ -25,7 +26,6 @@ export default ({ record }) =&gt; { @@ -25,7 +26,6 @@ export default ({ record }) =&gt; {
25 26
26 const reloadInformationHistoryModal = () => { 27 const reloadInformationHistoryModal = () => {
27 actionRef.current.reload(); // 重新加载数据 28 actionRef.current.reload(); // 重新加载数据
28 - console.log('5656flush');  
29 29
30 // 更新 refreshKey,强制刷新 CommunicationHistoryModal 30 // 更新 refreshKey,强制刷新 CommunicationHistoryModal
31 setRefreshKey((prevKey) => prevKey + 1); 31 setRefreshKey((prevKey) => prevKey + 1);
@@ -56,8 +56,19 @@ export default ({ record }) =&gt; { @@ -56,8 +56,19 @@ export default ({ record }) =&gt; {
56 }, 56 },
57 }, 57 },
58 { 58 {
59 - title: '内容',  
60 - width: 100, 59 + title: '跟进状态',
  60 + width: 50,
  61 + dataIndex: 'tradeStatus',
  62 + rules: [{ required: true, message: '请选择方式' }],
  63 + render: (text, record) => record.tradeStatusLike, // 显示 wayText
  64 + request: async () => {
  65 + const res = await postServiceConstTradeStatus();
  66 + return enumToSelect(res.data);
  67 + },
  68 + },
  69 + {
  70 + title: '跟进详情',
  71 + width: 80,
61 valueType: 'textarea', 72 valueType: 'textarea',
62 rules: [{ required: true, message: '请输入内容' }], 73 rules: [{ required: true, message: '请输入内容' }],
63 dataIndex: 'content', 74 dataIndex: 'content',
@@ -65,7 +76,7 @@ export default ({ record }) =&gt; { @@ -65,7 +76,7 @@ export default ({ record }) =&gt; {
65 { 76 {
66 title: '操作', 77 title: '操作',
67 valueType: 'option', 78 valueType: 'option',
68 - width: 50, 79 + width: 60,
69 render: (text, record, _, action) => [ 80 render: (text, record, _, action) => [
70 // <a 81 // <a
71 // key="editable" 82 // key="editable"
@@ -112,14 +123,13 @@ export default ({ record }) =&gt; { @@ -112,14 +123,13 @@ export default ({ record }) =&gt; {
112 }, 123 },
113 ]; 124 ];
114 const [name, setName] = useState(''); // 客户名称 125 const [name, setName] = useState(''); // 客户名称
115 - const [contacts, setContacts] = useState(''); // 联系 126 + const [leaderName, setLeaderName] = useState(''); // 负责
116 const [sourceText, setSourceText] = useState(''); // 来源文本 127 const [sourceText, setSourceText] = useState(''); // 来源文本
117 const [phoneNumber, setPhoneNumber] = useState(''); // 联系电话 128 const [phoneNumber, setPhoneNumber] = useState(''); // 联系电话
118 - const [hasSchemeText, setHasSchemeText] = useState(''); // 报方案状态文本  
119 - const [quoteDatetime, setQuoteDatetime] = useState(null); // 报价时间 129 + const [institutionContactName, setInstitutionContactName] = useState(''); // 联系电话
  130 + const [department, setDepartment] = useState(''); // 联系电话
  131 + const [gradePosition, setGradePosition] = useState(''); // 联系电话
120 const [referrers, setReferrers] = useState(''); // 推荐人 132 const [referrers, setReferrers] = useState(''); // 推荐人
121 - const [requirementsText, setRequirementsText] = useState(''); // 需求文本  
122 - const [tradeStatusText, setTradeStatusText] = useState(''); // 跟进状态文本  
123 const [levelText, setLevelText] = useState(''); // 客户等级文本 133 const [levelText, setLevelText] = useState(''); // 客户等级文本
124 const [createTime, setCreateTime] = useState(null); // 最新沟通时间 134 const [createTime, setCreateTime] = useState(null); // 最新沟通时间
125 const [address, setAddress] = useState(''); // 客户地址 135 const [address, setAddress] = useState(''); // 客户地址
@@ -152,14 +162,13 @@ export default ({ record }) =&gt; { @@ -152,14 +162,13 @@ export default ({ record }) =&gt; {
152 } 162 }
153 setRecordSave(record); 163 setRecordSave(record);
154 setName(record.name); 164 setName(record.name);
155 - setContacts(record.contacts); 165 + setLeaderName(record.leaderName);
156 setSourceText(record.sourceText); 166 setSourceText(record.sourceText);
157 setPhoneNumber(record.phoneNumber); 167 setPhoneNumber(record.phoneNumber);
158 - setHasSchemeText(record.hasSchemeText);  
159 - setQuoteDatetime(record.quoteDatetime); 168 + setInstitutionContactName(record.institutionContactName);
  169 + setDepartment(record.department);
  170 + setGradePosition(record.gradePosition);
160 setReferrers(record.referrers); 171 setReferrers(record.referrers);
161 - setRequirementsText(record.requirementsText);  
162 - setTradeStatusText(record.tradeStatusText);  
163 setLevelText(record.levelText); 172 setLevelText(record.levelText);
164 setCreateTime(record.createTime); 173 setCreateTime(record.createTime);
165 setAddress(record.address); 174 setAddress(record.address);
@@ -176,8 +185,8 @@ export default ({ record }) =&gt; { @@ -176,8 +185,8 @@ export default ({ record }) =&gt; {
176 }, 185 },
177 { 186 {
178 key: '2', 187 key: '2',
179 - label: '联系人',  
180 - children: contacts, // 联系人 188 + label: '负责人',
  189 + children: leaderName, // 负责人
181 }, 190 },
182 { 191 {
183 key: '3', 192 key: '3',
@@ -191,28 +200,23 @@ export default ({ record }) =&gt; { @@ -191,28 +200,23 @@ export default ({ record }) =&gt; {
191 }, 200 },
192 { 201 {
193 key: '5', 202 key: '5',
194 - label: '是否已报方案',  
195 - children: hasSchemeText, // 报方案状态文本 203 + label: '课题组',
  204 + children: institutionContactName, // 推荐人
196 }, 205 },
197 { 206 {
198 key: '6', 207 key: '6',
199 - label: '报价时间',  
200 - children: quoteDatetime, // 报价时间 208 + label: '部门',
  209 + children: department, // 推荐人
201 }, 210 },
202 { 211 {
203 key: '7', 212 key: '7',
204 - label: '推荐人',  
205 - children: referrers, // 推荐人 213 + label: '年级/职位',
  214 + children: gradePosition, // 推荐人
206 }, 215 },
207 { 216 {
208 key: '8', 217 key: '8',
209 - label: '需求',  
210 - children: requirementsText, // 需求文本  
211 - },  
212 - {  
213 - key: '9',  
214 - label: '跟进状态',  
215 - children: tradeStatusText, // 跟进状态文本 218 + label: '推荐人',
  219 + children: referrers, // 推荐人
216 }, 220 },
217 { 221 {
218 key: '10', 222 key: '10',
@@ -265,7 +269,6 @@ export default ({ record }) =&gt; { @@ -265,7 +269,6 @@ export default ({ record }) =&gt; {
265 }} 269 }}
266 type={'add2'} 270 type={'add2'}
267 /> 271 />
268 - ,  
269 <EditableProTable 272 <EditableProTable
270 rowKey="tid" 273 rowKey="tid"
271 formRef={ref} 274 formRef={ref}
src/pages/Client/Client/Components/InformationHistoryModal.tsx
@@ -10,8 +10,6 @@ import { Button, Descriptions, Space } from &#39;antd&#39;; @@ -10,8 +10,6 @@ import { Button, Descriptions, Space } from &#39;antd&#39;;
10 import { useEffect, useRef, useState } from 'react'; 10 import { useEffect, useRef, useState } from 'react';
11 11
12 export default ({ data, reloadTable }) => { 12 export default ({ data, reloadTable }) => {
13 - console.log(data, '5656datafirstshowclient');  
14 -  
15 // const [isModalVisible, setIsModalVisible] = useState(false); // 控制 ClientModal 的显示 13 // const [isModalVisible, setIsModalVisible] = useState(false); // 控制 ClientModal 的显示
16 const actionRef = useRef(); // 引用 actionRef,方便调用 reload 方法 14 const actionRef = useRef(); // 引用 actionRef,方便调用 reload 方法
17 15
@@ -23,22 +21,26 @@ export default ({ data, reloadTable }) =&gt; { @@ -23,22 +21,26 @@ export default ({ data, reloadTable }) =&gt; {
23 // const [clientNameLike, setClientNameLike] = useState(''); // 客户名称模糊查询 21 // const [clientNameLike, setClientNameLike] = useState(''); // 客户名称模糊查询
24 // const [clientAddressLike, setClientAddressLike] = useState(''); // 客户地址模糊查询 22 // const [clientAddressLike, setClientAddressLike] = useState(''); // 客户地址模糊查询
25 // const [tradeStatus, setTradeStatus] = useState(''); // 客户状态 23 // const [tradeStatus, setTradeStatus] = useState(''); // 客户状态
26 - // const [tradeStatusLike, setTradeStatusLike] = useState(''); // 客户状态模糊查询 24 + const [tradeStatusLike, setTradeStatusLike] = useState(''); // 客户状态模糊查询
27 const [content, setContent] = useState(''); // 跟进详情 25 const [content, setContent] = useState(''); // 跟进详情
28 const [createTime, setCreateTime] = useState(null); // 创建时间 26 const [createTime, setCreateTime] = useState(null); // 创建时间
29 const [attachments, setAttachments] = useState(); //附件 27 const [attachments, setAttachments] = useState(); //附件
30 const [attachmentsName, setAttachmentsName] = useState(''); // 附件名称 28 const [attachmentsName, setAttachmentsName] = useState(''); // 附件名称
  29 + const [ticketsType, setTicketsType] = useState(''); // 附件名称
  30 + const [ticketsDetail, setTicketsDetail] = useState(''); // 附件名称
  31 + const [ticketsAttachment, setTicketsAttachment] = useState(''); // 附件名称
  32 + const [assignPeople, setAssignPeople] = useState(''); // 附件名称
  33 + const [comment, setComment] = useState(''); // 客户评价
31 34
32 useEffect(() => { 35 useEffect(() => {
33 const request = async () => { 36 const request = async () => {
34 - console.log(data, '5656datasearch');  
35 const res = await postAdminClientQueryClientComunicationInfo({ 37 const res = await postAdminClientQueryClientComunicationInfo({
36 data: { 38 data: {
37 id: data.id, 39 id: data.id,
38 }, 40 },
39 }); 41 });
40 - console.log(res, '5656res');  
41 const dataSearch = res.data.data[0]; 42 const dataSearch = res.data.data[0];
  43 +
42 if (dataSearch) { 44 if (dataSearch) {
43 if (dataSearch.attachments) { 45 if (dataSearch.attachments) {
44 const url = dataSearch.attachments; 46 const url = dataSearch.attachments;
@@ -52,6 +54,11 @@ export default ({ data, reloadTable }) =&gt; { @@ -52,6 +54,11 @@ export default ({ data, reloadTable }) =&gt; {
52 setAttachmentsName(decodedStr); // 设置跟进日期 54 setAttachmentsName(decodedStr); // 设置跟进日期
53 } 55 }
54 } 56 }
  57 + setComment(dataSearch.comment);
  58 + setTicketsType(dataSearch.ticketsTypeText);
  59 + setTicketsDetail(dataSearch.ticketsDetail);
  60 + setTicketsAttachment(dataSearch.ticketsAttachments);
  61 + setAssignPeople(dataSearch.assignPeople);
55 setDatetime(dataSearch.datetime); // 设置跟进日期 62 setDatetime(dataSearch.datetime); // 设置跟进日期
56 // setDateRange(data.dateRange || []); // 设置跟进时间范围 63 // setDateRange(data.dateRange || []); // 设置跟进时间范围
57 setCreateByName(dataSearch.createByName); // 设置跟进人员 64 setCreateByName(dataSearch.createByName); // 设置跟进人员
@@ -60,13 +67,12 @@ export default ({ data, reloadTable }) =&gt; { @@ -60,13 +67,12 @@ export default ({ data, reloadTable }) =&gt; {
60 // setClientNameLike(data.clientNameLike || ''); // 设置客户名称模糊查询 67 // setClientNameLike(data.clientNameLike || ''); // 设置客户名称模糊查询
61 // setClientAddressLike(data.clientAddressLike || ''); // 设置客户地址模糊查询 68 // setClientAddressLike(data.clientAddressLike || ''); // 设置客户地址模糊查询
62 // setTradeStatus(data.tradeStatus || ''); // 设置客户状态 69 // setTradeStatus(data.tradeStatus || ''); // 设置客户状态
63 - // setTradeStatusLike(data.tradeStatusLike || ''); // 设置客户状态模糊查询 70 + setTradeStatusLike(data.tradeStatusLike); // 设置客户状态模糊查询
64 setContent(dataSearch.content); // 设置跟进详情 71 setContent(dataSearch.content); // 设置跟进详情
65 setCreateTime(dataSearch.createTime); // 设置创建时间 72 setCreateTime(dataSearch.createTime); // 设置创建时间
66 setWay(dataSearch.wayText); 73 setWay(dataSearch.wayText);
67 setAttachments(dataSearch.attachments); 74 setAttachments(dataSearch.attachments);
68 } 75 }
69 - console.log(attachments, '5656attachments');  
70 }; 76 };
71 request(); 77 request();
72 }, []); 78 }, []);
@@ -101,9 +107,38 @@ export default ({ data, reloadTable }) =&gt; { @@ -101,9 +107,38 @@ export default ({ data, reloadTable }) =&gt; {
101 label: '跟进类型', 107 label: '跟进类型',
102 children: way, // 跟进类型 108 children: way, // 跟进类型
103 }, 109 },
  110 + {
  111 + key: '7',
  112 + label: '跟进状态',
  113 + children: tradeStatusLike, // 跟进类型
  114 + },
  115 + {
  116 + key: '8',
  117 + label: '工单类型',
  118 + children: ticketsType, // 跟进状态
  119 + },
  120 + {
  121 + key: '9',
  122 + label: '工单详情',
  123 + children: ticketsDetail, // 跟进状态
  124 + },
  125 + // {
  126 + // key: '10',
  127 + // label: '工单附件',
  128 + // children: ticketsAttachment, // 跟进状态
  129 + // },
  130 + {
  131 + key: '10',
  132 + label: '指派人员',
  133 + children: assignPeople, // 跟进状态
  134 + },
  135 + {
  136 + key: '11',
  137 + label: '客户评价',
  138 + children: comment, // 跟进状态
  139 + },
104 ]; 140 ];
105 const handleDelete = async () => { 141 const handleDelete = async () => {
106 - console.log(JSON.stringify(data), '5656record');  
107 // 调用删除接口 142 // 调用删除接口
108 const success = await postAdminClientRemoveClientComunicationInfo({ 143 const success = await postAdminClientRemoveClientComunicationInfo({
109 query: { 144 query: {
@@ -142,7 +177,6 @@ export default ({ data, reloadTable }) =&gt; { @@ -142,7 +177,6 @@ export default ({ data, reloadTable }) =&gt; {
142 actionRef?.current?.reload(); // 重新加载表格数据 177 actionRef?.current?.reload(); // 重新加载表格数据
143 props.submit(); 178 props.submit();
144 reloadTable(); 179 reloadTable();
145 - console.log('5656close');  
146 }} 180 }}
147 type={'modify'} 181 type={'modify'}
148 onFinish={() => { 182 onFinish={() => {
@@ -178,10 +212,83 @@ export default ({ data, reloadTable }) =&gt; { @@ -178,10 +212,83 @@ export default ({ data, reloadTable }) =&gt; {
178 }} 212 }}
179 > 213 >
180 <Descriptions items={items} column={1} /> 214 <Descriptions items={items} column={1} />
181 - {attachmentsName && ( 215 + {/* {attachmentsName && (
182 <a href={attachments} download> 216 <a href={attachments} download>
183 附件:{attachmentsName} 217 附件:{attachmentsName}
184 </a> 218 </a>
  219 + )} */}
  220 + {attachmentsName && (
  221 + <div>
  222 + {attachmentsName.endsWith('.png') ||
  223 + attachmentsName.endsWith('.jpg') ? (
  224 + <>
  225 + <img
  226 + src={attachments}
  227 + alt={attachmentsName}
  228 + style={{ maxWidth: '300px', height: 'auto' }}
  229 + />
  230 + <div></div>
  231 + <a href={attachments} download>
  232 + 附件:{attachmentsName}
  233 + </a>
  234 + </>
  235 + ) : (
  236 + <a href={attachments} download>
  237 + 附件:{attachmentsName}
  238 + </a>
  239 + )}
  240 + </div>
  241 + )}
  242 +
  243 + <div></div>
  244 + {/* {ticketsAttachment && (
  245 + <a href={ticketsAttachment} download>
  246 + 工单附件:{ticketsAttachment}
  247 + </a>
  248 + )} */}
  249 + {/* {ticketsAttachment && (
  250 + <div>
  251 + {ticketsAttachment.includes('jpg') ||
  252 + ticketsAttachment.includes('png') ? (
  253 + <>
  254 + <img
  255 + src={ticketsAttachment}
  256 + alt={ticketsAttachment}
  257 + style={{ maxWidth: '300px', height: 'auto' }}
  258 + />
  259 + <div></div>
  260 + <a href={ticketsAttachment} download>
  261 + 工单附件:{ticketsAttachment}
  262 + </a>
  263 + </>
  264 + ) : (
  265 + <a href={ticketsAttachment} download>
  266 + 工单附件:{ticketsAttachment}
  267 + </a>
  268 + )}
  269 + </div>
  270 + )} */}
  271 + {ticketsAttachment && (
  272 + <div>
  273 + {ticketsAttachment.split(',').map((ticketsAttachment, index) => (
  274 + <div key={index}>
  275 + {ticketsAttachment.includes('jpg') ||
  276 + ticketsAttachment.includes('png') ? (
  277 + <>
  278 + <img
  279 + src={ticketsAttachment}
  280 + alt={`附件 ${index + 1}`}
  281 + style={{ maxWidth: '300px', height: 'auto' }}
  282 + />
  283 + <div></div>
  284 + </>
  285 + ) : null}
  286 + <a href={ticketsAttachment} download>
  287 + 工单附件:{ticketsAttachment}
  288 + </a>
  289 + </div>
  290 + ))}
  291 + </div>
185 )} 292 )}
186 </ModalForm> 293 </ModalForm>
187 </Space> 294 </Space>
src/pages/Client/Client/Components/style.css 0 → 100644
  1 +.styled-text {
  2 + display: flex;
  3 + align-items: center;
  4 + margin-bottom: 20px;
  5 +}
  6 +
  7 +.vertical-line {
  8 + width: 2px; /* 线的宽度 */
  9 + height: 20px; /* 线的高度 */
  10 + background-color: black; /* 线的颜色 */
  11 + margin-right: 10px; /* 线与文本之间的间距 */
  12 +}
  13 +
  14 +.text {
  15 + font-size: 20px; /* 文本大小 */
  16 + font-family: Arial, sans-serif; /* 字体样式 */
  17 + color: black; /* 文本颜色 */
  18 +}
src/pages/Client/Client/index.tsx
@@ -8,9 +8,8 @@ import { @@ -8,9 +8,8 @@ import {
8 postAdminClientGetStatisticalData, 8 postAdminClientGetStatisticalData,
9 postAdminClientQueryClientPage, 9 postAdminClientQueryClientPage,
10 postServiceConstClientLevels, 10 postServiceConstClientLevels,
11 - postServiceConstClientRequirements,  
12 postServiceConstClientSource, 11 postServiceConstClientSource,
13 - postServiceConstTradeStatus, 12 + postServiceOrderQueryCustomerInformation,
14 } from '@/services'; 13 } from '@/services';
15 import { downloadFile } from '@/services/order'; 14 import { downloadFile } from '@/services/order';
16 import { enumToSelect } from '@/utils'; 15 import { enumToSelect } from '@/utils';
@@ -41,6 +40,12 @@ const columns = [ @@ -41,6 +40,12 @@ const columns = [
41 // hideInSearch: true, 40 // hideInSearch: true,
42 // }, 41 // },
43 { 42 {
  43 + title: '客户名称',
  44 + dataIndex: 'nameLike',
  45 + valueType: 'Text',
  46 + hideInTable: true,
  47 + },
  48 + {
44 title: '客户地址', 49 title: '客户地址',
45 width: 250, 50 width: 250,
46 ellipsis: true, 51 ellipsis: true,
@@ -48,10 +53,10 @@ const columns = [ @@ -48,10 +53,10 @@ const columns = [
48 hideInSearch: false, 53 hideInSearch: false,
49 }, 54 },
50 { 55 {
51 - title: '联系人', 56 + title: '负责人',
52 width: 150, 57 width: 150,
53 ellipsis: true, 58 ellipsis: true,
54 - dataIndex: 'contacts', 59 + dataIndex: 'leaderName',
55 hideInSearch: false, 60 hideInSearch: false,
56 }, 61 },
57 { 62 {
@@ -62,73 +67,110 @@ const columns = [ @@ -62,73 +67,110 @@ const columns = [
62 hideInSearch: true, 67 hideInSearch: true,
63 }, 68 },
64 { 69 {
65 - title: '客户来源', 70 + title: '课题组',
  71 + dataIndex: 'institutionContactName',
66 width: 150, 72 width: 150,
67 ellipsis: true, 73 ellipsis: true,
68 - dataIndex: 'sourceText',  
69 hideInSearch: true, 74 hideInSearch: true,
70 }, 75 },
71 { 76 {
72 - title: '客户来源', 77 + title: '课题组',
  78 + dataIndex: 'institutionContactName',
73 valueType: 'select', 79 valueType: 'select',
74 hideInTable: true, 80 hideInTable: true,
75 - dataIndex: 'source',  
76 - request: async () => {  
77 - const res = await postServiceConstClientSource();  
78 - return enumToSelect(res.data); 81 + fieldProps: {
  82 + showSearch: true,
  83 + // mode: 'tags', // 允许自定义输入
  84 + },
  85 + request: async (value, { params }) => {
  86 + const keywords = value.keyWords;
  87 + const { data } = await postServiceOrderQueryCustomerInformation({
  88 + data: {
  89 + name: 'institutionContactName',
  90 + institutionContactName: keywords,
  91 + },
  92 + params: params,
  93 + });
  94 + let options = data
  95 + .filter((c: any) => {
  96 + return c.orderName === 'institutionCustomerUser';
  97 + })
  98 + .map((item: any) => {
  99 + return {
  100 + label: item.orderValue,
  101 + value: item.orderValue,
  102 + };
  103 + });
  104 + return options;
79 }, 105 },
80 }, 106 },
81 { 107 {
82 - title: '推荐人',  
83 - dataIndex: 'referrers', 108 + title: '部门',
  109 + width: 150,
  110 + ellipsis: true,
  111 + dataIndex: 'department',
  112 + hideInSearch: true,
  113 + },
  114 + {
  115 + title: '年级/职位',
84 width: 150, 116 width: 150,
85 ellipsis: true, 117 ellipsis: true,
  118 + dataIndex: 'gradePosition',
86 hideInSearch: true, 119 hideInSearch: true,
87 }, 120 },
88 { 121 {
89 - title: '客户需求',  
90 - width: 240, 122 + title: '客户来源',
  123 + width: 150,
91 ellipsis: true, 124 ellipsis: true,
92 - dataIndex: 'requirementsText', 125 + dataIndex: 'sourceText',
93 hideInSearch: true, 126 hideInSearch: true,
94 }, 127 },
95 { 128 {
96 - title: '客户需求',  
97 - dataIndex: 'requirements', 129 + title: '客户来源',
98 valueType: 'select', 130 valueType: 'select',
99 hideInTable: true, 131 hideInTable: true,
  132 + dataIndex: 'source',
100 request: async () => { 133 request: async () => {
101 - const res = await postServiceConstClientRequirements();  
102 - // function enumToSelect(data: any) {  
103 - // const keys = Object.keys(data);  
104 - // return keys.map((value) => {  
105 - // return { label: data[value], value: value };  
106 - // });  
107 - // } 134 + const res = await postServiceConstClientSource();
108 return enumToSelect(res.data); 135 return enumToSelect(res.data);
109 }, 136 },
110 }, 137 },
111 { 138 {
112 - title: '是否已报方案',  
113 - width: 150,  
114 - ellipsis: true,  
115 - dataIndex: 'hasSchemeText',  
116 - hideInSearch: true,  
117 - },  
118 - {  
119 - title: '报价时间',  
120 - key: 'since', 139 + title: '推荐人',
  140 + dataIndex: 'referrers',
121 width: 150, 141 width: 150,
122 ellipsis: true, 142 ellipsis: true,
123 - dataIndex: 'quoteDatetime',  
124 - valueType: 'date',  
125 hideInSearch: true, 143 hideInSearch: true,
126 }, 144 },
  145 + // {
  146 + // title: '客户需求',
  147 + // width: 240,
  148 + // ellipsis: true,
  149 + // dataIndex: 'requirementsText',
  150 + // hideInSearch: true,
  151 + // },
  152 + // {
  153 + // title: '客户需求',
  154 + // dataIndex: 'requirements',
  155 + // valueType: 'select',
  156 + // hideInTable: true,
  157 + // hideInSearch: true,
  158 + // request: async () => {
  159 + // const res = await postServiceConstClientRequirements();
  160 + // // function enumToSelect(data: any) {
  161 + // // const keys = Object.keys(data);
  162 + // // return keys.map((value) => {
  163 + // // return { label: data[value], value: value };
  164 + // // });
  165 + // // }
  166 + // return enumToSelect(res.data);
  167 + // },
  168 + // },
127 { 169 {
128 - title: '跟进状态', 170 + title: '创建人',
129 width: 150, 171 width: 150,
130 ellipsis: true, 172 ellipsis: true,
131 - dataIndex: 'tradeStatusText', 173 + dataIndex: 'createByName',
132 hideInSearch: true, 174 hideInSearch: true,
133 }, 175 },
134 { 176 {
@@ -165,41 +207,30 @@ const columns = [ @@ -165,41 +207,30 @@ const columns = [
165 // valueType: 'dateTime', 207 // valueType: 'dateTime',
166 // hideInSearch: true, 208 // hideInSearch: true,
167 // }, 209 // },
168 - {  
169 - title: '客户名称',  
170 - dataIndex: 'nameLike',  
171 - valueType: 'Text',  
172 - hideInTable: true,  
173 - },  
174 // { 210 // {
175 // title: '单位名称', 211 // title: '单位名称',
176 // dataIndex: 'companyNameLike', 212 // dataIndex: 'companyNameLike',
177 // valueType: 'Text', 213 // valueType: 'Text',
178 // hideInTable: true, 214 // hideInTable: true,
179 // }, 215 // },
180 - {  
181 - title: '联系电话',  
182 - dataIndex: 'phoneNumberLike',  
183 - valueType: 'Text',  
184 - hideInTable: true,  
185 - },  
186 - {  
187 - title: '是否已报方案',  
188 - dataIndex: 'hasScheme',  
189 - valueType: 'select',  
190 - width: 1550,  
191 - valueEnum: {  
192 - true: {  
193 - text: '是',  
194 - value: true,  
195 - },  
196 - false: {  
197 - text: '否',  
198 - value: false,  
199 - },  
200 - },  
201 - hideInTable: true,  
202 - }, 216 + // {
  217 + // title: '联系电话',
  218 + // dataIndex: 'phoneNumberLike',
  219 + // valueType: 'Text',
  220 + // hideInTable: true,
  221 + // },
  222 + // {
  223 + // title: '部门',
  224 + // dataIndex: 'department',
  225 + // valueType: 'Text',
  226 + // hideInTable: false,
  227 + // },
  228 + // {
  229 + // title: '年级/职位',
  230 + // dataIndex: 'gradePosition',
  231 + // valueType: 'Text',
  232 + // hideInTable: false,
  233 + // },
203 { 234 {
204 title: '客户等级', 235 title: '客户等级',
205 dataIndex: 'level', 236 dataIndex: 'level',
@@ -218,25 +249,30 @@ const columns = [ @@ -218,25 +249,30 @@ const columns = [
218 }, 249 },
219 }, 250 },
220 { 251 {
221 - title: '跟进状态',  
222 - dataIndex: 'tradeStatus',  
223 - valueType: 'select', 252 + title: '创建时间',
  253 + valueType: 'dateRange',
224 hideInTable: true, 254 hideInTable: true,
225 - request: async () => {  
226 - const res = await postServiceConstTradeStatus();  
227 - return enumToSelect(res.data); 255 + search: {
  256 + transform: (value) => {
  257 + if (value) {
  258 + return {
  259 + createTimeGe: value[0],
  260 + createTimeLe: value[1],
  261 + };
  262 + }
  263 + },
228 }, 264 },
229 }, 265 },
230 { 266 {
231 - title: '创建时间', 267 + title: '最新跟进时间',
232 valueType: 'dateRange', 268 valueType: 'dateRange',
233 hideInTable: true, 269 hideInTable: true,
234 search: { 270 search: {
235 transform: (value) => { 271 transform: (value) => {
236 if (value) { 272 if (value) {
237 return { 273 return {
238 - createTimeGe: value[0],  
239 - createTimeLe: value[1], 274 + updateTimeGe: value[0],
  275 + updateTimeLe: value[1],
240 }; 276 };
241 } 277 }
242 }, 278 },
@@ -249,7 +285,6 @@ const columns = [ @@ -249,7 +285,6 @@ const columns = [
249 width: 200, 285 width: 200,
250 render: (text, record, index, action) => { 286 render: (text, record, index, action) => {
251 const handleDelete = async () => { 287 const handleDelete = async () => {
252 - console.log(JSON.stringify(record), '5656record1');  
253 // 调用删除接口 288 // 调用删除接口
254 const success = await postAdminClientDeleteAdminClient({ 289 const success = await postAdminClientDeleteAdminClient({
255 query: { 290 query: {
@@ -260,7 +295,6 @@ const columns = [ @@ -260,7 +295,6 @@ const columns = [
260 action.reload(); // 刷新表格 295 action.reload(); // 刷新表格
261 } 296 }
262 }; 297 };
263 - console.log(JSON.stringify(record), '5656record2');  
264 return [ 298 return [
265 <CommunicationHistoryModal 299 <CommunicationHistoryModal
266 key={'communicationHistory'} 300 key={'communicationHistory'}
@@ -323,11 +357,11 @@ export default () =&gt; { @@ -323,11 +357,11 @@ export default () =&gt; {
323 const pullStatistic = async () => { 357 const pullStatistic = async () => {
324 let statisticalData = await postAdminClientGetStatisticalData(); 358 let statisticalData = await postAdminClientGetStatisticalData();
325 console.log('stati' + JSON.stringify(statisticalData.data)); 359 console.log('stati' + JSON.stringify(statisticalData.data));
  360 + console.log(clientStatistic);
326 setClientStatistic(statisticalData.data); 361 setClientStatistic(statisticalData.data);
327 - setWarningClientStatistic(statisticalData.data[1].value); 362 + setWarningClientStatistic(statisticalData?.data[1].value);
328 // setAllClientStatistic(statisticalData.data[0].value); 363 // setAllClientStatistic(statisticalData.data[0].value);
329 setTimeout(() => { 364 setTimeout(() => {
330 - console.log(clientStatistic, '5656groupFilterOptions1');  
331 // groupFilterOptions[0].label = groupFilterOptions[0].label + '(' + clientStatistic + ')'; 365 // groupFilterOptions[0].label = groupFilterOptions[0].label + '(' + clientStatistic + ')';
332 }, 100); 366 }, 100);
333 actionRef.current?.reload(); // 可能需要在这里刷新 367 actionRef.current?.reload(); // 可能需要在这里刷新
@@ -361,8 +395,6 @@ export default () =&gt; { @@ -361,8 +395,6 @@ export default () =&gt; {
361 // }, []); 395 // }, []);
362 useEffect(() => { 396 useEffect(() => {
363 // console.log(groupFilterOptions, '5656groupFilterOptions2'); 397 // console.log(groupFilterOptions, '5656groupFilterOptions2');
364 - console.log(clientStatistic, '5656clientStatistic');  
365 - console.log(warningClientStatistic, '5656warningClientStatistic');  
366 actionRef.current?.reload(); 398 actionRef.current?.reload();
367 }, [groupFilter]); 399 }, [groupFilter]);
368 return ( 400 return (
@@ -411,7 +443,6 @@ export default () =&gt; { @@ -411,7 +443,6 @@ export default () =&gt; {
411 'POST', 443 'POST',
412 values, 444 values,
413 () => { 445 () => {
414 - console.log(searchConfig, '5656searchConfig');  
415 messageApi.destroy(); 446 messageApi.destroy();
416 }, 447 },
417 ); 448 );
src/pages/Client/FollowRecord/Components/ClientModal.tsx
1 import { RESPONSE_CODE } from '@/constants/enum'; 1 import { RESPONSE_CODE } from '@/constants/enum';
  2 +import UploadC from '@/pages/Invoice/waitProcessRecord/components/UploadSingleImg';
2 import { 3 import {
3 postAdminClientAddOrModifyClientComunicationInfo, 4 postAdminClientAddOrModifyClientComunicationInfo,
4 postAdminClientQueryClientPage, 5 postAdminClientQueryClientPage,
5 postOrderErpOrderStagesUpload, 6 postOrderErpOrderStagesUpload,
  7 + postOrderErpUsersListByPage,
6 postServiceConstClientWay, 8 postServiceConstClientWay,
  9 + postServiceConstTradeStatus,
7 } from '@/services'; 10 } from '@/services';
8 import { enumToSelect } from '@/utils'; 11 import { enumToSelect } from '@/utils';
9 import { 12 import {
@@ -14,8 +17,9 @@ import { @@ -14,8 +17,9 @@ import {
14 ProFormTextArea, 17 ProFormTextArea,
15 ProFormUploadDragger, 18 ProFormUploadDragger,
16 } from '@ant-design/pro-components'; 19 } from '@ant-design/pro-components';
17 -import { Button, Form, message } from 'antd'; 20 +import { Button, Col, Form, Row, message } from 'antd';
18 import { RcFile } from 'antd/es/upload'; 21 import { RcFile } from 'antd/es/upload';
  22 +import './style.css';
19 export default ({ data, type, reloadTable }) => { 23 export default ({ data, type, reloadTable }) => {
20 const [form] = Form.useForm(); 24 const [form] = Form.useForm();
21 const onfinish = async (values) => { 25 const onfinish = async (values) => {
@@ -37,6 +41,7 @@ export default ({ data, type, reloadTable }) =&gt; { @@ -37,6 +41,7 @@ export default ({ data, type, reloadTable }) =&gt; {
37 const res = await postAdminClientAddOrModifyClientComunicationInfo({ 41 const res = await postAdminClientAddOrModifyClientComunicationInfo({
38 data: { 42 data: {
39 ...values, 43 ...values,
  44 + ticketsAttachments: form.getFieldValue('ticketsAttachments'),
40 clientId: matchedId, 45 clientId: matchedId,
41 }, 46 },
42 }); 47 });
@@ -47,10 +52,10 @@ export default ({ data, type, reloadTable }) =&gt; { @@ -47,10 +52,10 @@ export default ({ data, type, reloadTable }) =&gt; {
47 } 52 }
48 // 不返回不会关闭弹框 53 // 不返回不会关闭弹框
49 }; 54 };
  55 +
50 const editOnfinish = async (values) => { 56 const editOnfinish = async (values) => {
51 // setEditClientId(data.clientId); 57 // setEditClientId(data.clientId);
52 values.clientId = data.clientId; 58 values.clientId = data.clientId;
53 - console.log(values, '5656editClientId');  
54 59
55 // const resSearchId = await postAdminClientQueryClientPage({ 60 // const resSearchId = await postAdminClientQueryClientPage({
56 // data: { 61 // data: {
@@ -60,10 +65,15 @@ export default ({ data, type, reloadTable }) =&gt; { @@ -60,10 +65,15 @@ export default ({ data, type, reloadTable }) =&gt; {
60 // const matchingItem = resSearchId.data.data.find( 65 // const matchingItem = resSearchId.data.data.find(
61 // (item) => item.id === values.name, 66 // (item) => item.id === values.name,
62 // ); 67 // );
63 -  
64 const res = await postAdminClientAddOrModifyClientComunicationInfo({ 68 const res = await postAdminClientAddOrModifyClientComunicationInfo({
65 data: { 69 data: {
66 ...values, 70 ...values,
  71 + // ticketsAttachments: form.getFieldValue("ticketsAttachments"),
  72 + ticketsAttachments:
  73 + form.getFieldValue('ticketsAttachments') !== undefined
  74 + ? form.getFieldValue('ticketsAttachments')
  75 + : data?.ticketsAttachments,
  76 + // ticketsAttachments: data?.annexUrl,
67 }, 77 },
68 }); 78 });
69 if (res.result === RESPONSE_CODE.SUCCESS) { 79 if (res.result === RESPONSE_CODE.SUCCESS) {
@@ -140,7 +150,6 @@ export default ({ data, type, reloadTable }) =&gt; { @@ -140,7 +150,6 @@ export default ({ data, type, reloadTable }) =&gt; {
140 groupFilter: 'all', 150 groupFilter: 'all',
141 }, 151 },
142 }); 152 });
143 - console.log(data, '5656data?.nameedit');  
144 // const namesArray = res.data.data.map((item) => item.name); 153 // const namesArray = res.data.data.map((item) => item.name);
145 // const formattedObject = res.data.data.reduce((acc, name) => { 154 // const formattedObject = res.data.data.reduce((acc, name) => {
146 // acc[name] = name; // 将名称作为键和值 155 // acc[name] = name; // 将名称作为键和值
@@ -165,18 +174,67 @@ export default ({ data, type, reloadTable }) =&gt; { @@ -165,18 +174,67 @@ export default ({ data, type, reloadTable }) =&gt; {
165 }, 174 },
166 ]} 175 ]}
167 ></ProFormSelect> 176 ></ProFormSelect>
  177 + <ProFormText
  178 + name="contact"
  179 + label="联系人"
  180 + width="sm"
  181 + placeholder="请输入联系人"
  182 + initialValue={data?.content}
  183 + readonly={optType[type].readOnly}
  184 + rules={[
  185 + {
  186 + required: true,
  187 + message: '请输入联系人',
  188 + },
  189 + ]}
  190 + ></ProFormText>
  191 + <ProFormText
  192 + name="contactPhone"
  193 + label="联系电话"
  194 + width="sm"
  195 + placeholder="请输入联系电话"
  196 + initialValue={data?.content}
  197 + readonly={optType[type].readOnly}
  198 + rules={[
  199 + {
  200 + required: true,
  201 + message: '请输入联系电话',
  202 + },
  203 + ]}
  204 + ></ProFormText>
168 <ProFormDateTimePicker 205 <ProFormDateTimePicker
169 name="datetime" 206 name="datetime"
170 - label="日期" 207 + label="跟进日期"
171 initialValue={data ? data?.datetime + '' : null} 208 initialValue={data ? data?.datetime + '' : null}
172 placeholder="请选择跟进时间" 209 placeholder="请选择跟进时间"
173 width="sm" 210 width="sm"
174 rules={[ 211 rules={[
175 { 212 {
176 required: true, 213 required: true,
177 - message: '请选择日期', 214 + message: '请选择跟进日期',
  215 + },
  216 + ]}
  217 + />
  218 + <ProFormSelect
  219 + name="tradeStatus"
  220 + label="跟进状态"
  221 + width="sm"
  222 + placeholder="请输入跟进状态"
  223 + readonly={optType[type].readOnly}
  224 + fieldProps={{
  225 + labelInValue: false,
  226 + }}
  227 + initialValue={data?.tradeStatus ? data?.tradeStatus + '' : null}
  228 + rules={[
  229 + {
  230 + required: true,
  231 + message: '请输入跟进状态',
178 }, 232 },
179 ]} 233 ]}
  234 + request={async () => {
  235 + const res = await postServiceConstTradeStatus();
  236 + return enumToSelect(res.data);
  237 + }}
180 /> 238 />
181 <ProFormSelect 239 <ProFormSelect
182 name="way" 240 name="way"
@@ -186,7 +244,7 @@ export default ({ data, type, reloadTable }) =&gt; { @@ -186,7 +244,7 @@ export default ({ data, type, reloadTable }) =&gt; {
186 labelInValue: false, 244 labelInValue: false,
187 }} 245 }}
188 initialValue={data?.way ? data?.way + '' : null} 246 initialValue={data?.way ? data?.way + '' : null}
189 - label="类型" 247 + label="跟进方式"
190 request={async () => { 248 request={async () => {
191 const res = await postServiceConstClientWay(); 249 const res = await postServiceConstClientWay();
192 return enumToSelect(res.data); 250 return enumToSelect(res.data);
@@ -194,20 +252,20 @@ export default ({ data, type, reloadTable }) =&gt; { @@ -194,20 +252,20 @@ export default ({ data, type, reloadTable }) =&gt; {
194 rules={[ 252 rules={[
195 { 253 {
196 required: true, 254 required: true,
197 - message: '请选择跟进类型', 255 + message: '请选择跟进方式',
198 }, 256 },
199 ]} 257 ]}
200 ></ProFormSelect> 258 ></ProFormSelect>
201 <ProFormTextArea 259 <ProFormTextArea
202 name="content" 260 name="content"
203 - label="详情"  
204 - placeholder="请输入详情" 261 + label="跟进详情"
  262 + placeholder="请输入跟进详情"
205 initialValue={data?.content} 263 initialValue={data?.content}
206 readonly={optType[type].readOnly} 264 readonly={optType[type].readOnly}
207 rules={[ 265 rules={[
208 { 266 {
209 required: true, 267 required: true,
210 - message: '请输入详情', 268 + message: '请输入跟进详情',
211 }, 269 },
212 ]} 270 ]}
213 ></ProFormTextArea> 271 ></ProFormTextArea>
@@ -242,12 +300,138 @@ export default ({ data, type, reloadTable }) =&gt; { @@ -242,12 +300,138 @@ export default ({ data, type, reloadTable }) =&gt; {
242 <a hidden={!optType[type].readOnly} href={data?.attachments} download> 300 <a hidden={!optType[type].readOnly} href={data?.attachments} download>
243 下载附件 301 下载附件
244 </a> 302 </a>
  303 + <ProFormTextArea
  304 + name="comment"
  305 + label="客户评价"
  306 + placeholder="请输入客户评价"
  307 + initialValue={data?.comment}
  308 + readonly={optType[type].readOnly}
  309 + ></ProFormTextArea>
245 <ProFormText 310 <ProFormText
246 initialValue={data?.attachments} 311 initialValue={data?.attachments}
247 name="attachments" 312 name="attachments"
248 hidden 313 hidden
249 ></ProFormText> 314 ></ProFormText>
250 <ProFormText initialValue={data?.id} name="id" hidden></ProFormText> 315 <ProFormText initialValue={data?.id} name="id" hidden></ProFormText>
  316 + <div className="styled-text">
  317 + <div className="vertical-line"></div>
  318 + <span className="text">工单指派</span>
  319 + </div>
  320 + <ProFormSelect
  321 + name="ticketsType"
  322 + label="工单类型"
  323 + width="sm"
  324 + placeholder="请输入工单类型"
  325 + readonly={optType[type].readOnly}
  326 + fieldProps={{
  327 + labelInValue: false,
  328 + }}
  329 + initialValue={data?.ticketsType ? data?.ticketsType + '' : null}
  330 + request={async () => {
  331 + return [
  332 + { label: '问题', value: 'QUESTION' },
  333 + { label: '需求', value: 'DEMAND' },
  334 + { label: '建议', value: 'ADVICE' },
  335 + ];
  336 + }}
  337 + />
  338 + <ProFormTextArea
  339 + name="ticketsDetail"
  340 + label="工单详情"
  341 + placeholder="请输入工单详情"
  342 + initialValue={data?.ticketsDetail ? data?.ticketsDetail + '' : null}
  343 + readonly={optType[type].readOnly}
  344 + ></ProFormTextArea>
  345 + {/* <ProFormUploadDragger
  346 + label="工单附件"
  347 + name="ticketsAttachment"
  348 + action="upload.do"
  349 + hidden={optType[type].readOnly}
  350 + onChange={(info) => {
  351 + const uploadFile = async ({ fileList: newFileList }) => {
  352 + if (newFileList.length > 0) {
  353 + const formData = new FormData();
  354 + formData.append('file', newFileList[0].originFileObj as RcFile);
  355 + const res = await postOrderErpOrderStagesUpload({
  356 + data: formData,
  357 + headers: {
  358 + 'Content-Type':
  359 + 'multipart/form-data; boundary=----WebKitFormBoundarynl6gT1BKdPWIejNq',
  360 + },
  361 + });
  362 + const url = res.data;
  363 + console.log('ticketsAttachments' + JSON.stringify(url));
  364 + form.setFieldValue('ticketsAttachments', url);
  365 + } else {
  366 + form.setFieldValue('ticketsAttachments', null);
  367 + }
  368 + };
  369 + uploadFile(info);
  370 + }}
  371 + max={1}
  372 + /> */}
  373 + <Row>
  374 + <Col span={4}>附件:</Col>
  375 + <Col span={20}>
  376 + <UploadC
  377 + onFilesChange={async (newFileList) => {
  378 + if (newFileList.length > 0) {
  379 + const urls = []; // 创建一个数组来存储所有的 URL
  380 +
  381 + for (const file of newFileList) {
  382 + const formData = new FormData();
  383 + formData.append('file', file.originFileObj as RcFile);
  384 +
  385 + const res = await postOrderErpOrderStagesUpload({
  386 + data: formData,
  387 + headers: {
  388 + 'Content-Type':
  389 + 'multipart/form-data; boundary=----WebKitFormBoundarynl6gT1BKdPWIejNq',
  390 + },
  391 + });
  392 +
  393 + const url = res.data; // 获取响应中的 URL
  394 + urls.push(url); // 将每个 URL 追加到数组中
  395 + }
  396 +
  397 + // 将所有 URL 使用 ',' 进行拼接
  398 + const combinedUrl = urls.join(',');
  399 + form.setFieldValue('ticketsAttachments', combinedUrl); // 设置表单字段值为拼接后的 URL
  400 + } else {
  401 + form.setFieldValue('ticketsAttachments', null); // 如果没有文件,则清空 URL
  402 + }
  403 + }}
  404 + ></UploadC>
  405 + </Col>
  406 + </Row>
  407 + <a hidden={!optType[type].readOnly} href={data?.orderAttachment} download>
  408 + {/* <a href={data?.annexUrl} download> */}
  409 + 下载附件
  410 + </a>
  411 + <ProFormSelect
  412 + name="assignPeople"
  413 + width="sm"
  414 + readonly={optType[type].readOnly}
  415 + fieldProps={{
  416 + labelInValue: false,
  417 + }}
  418 + initialValue={data?.assignPeople ? data?.assignPeople + '' : null}
  419 + label="指派人员"
  420 + request={async () => {
  421 + const res = await postOrderErpUsersListByPage({
  422 + data: {
  423 + pageSize: 10000,
  424 + },
  425 + });
  426 + const userOptions = res.data.records
  427 + ? res.data.records.map((user) => ({
  428 + label: user.userName, // 或者使用其他需要的属性
  429 + value: user.userName, // 作为value的字段
  430 + }))
  431 + : [];
  432 + return userOptions;
  433 + }}
  434 + ></ProFormSelect>
251 </ModalForm> 435 </ModalForm>
252 ); 436 );
253 }; 437 };
src/pages/Client/FollowRecord/Components/ClientModal2.tsx 0 → 100644
  1 +import { RESPONSE_CODE } from '@/constants/enum';
  2 +import UploadC from '@/pages/Invoice/waitProcessRecord/components/UploadSingleImg';
  3 +import {
  4 + postAdminClientAddOrModifyClientComunicationInfo,
  5 + postAdminClientQueryClientPage,
  6 + postOrderErpOrderStagesUpload,
  7 + postOrderErpUsersListByPage,
  8 + postServiceConstClientWay,
  9 + postServiceConstTradeStatus,
  10 +} from '@/services';
  11 +import { enumToSelect } from '@/utils';
  12 +import {
  13 + ModalForm,
  14 + ProFormDateTimePicker,
  15 + ProFormSelect,
  16 + ProFormText,
  17 + ProFormTextArea,
  18 + ProFormUploadDragger,
  19 +} from '@ant-design/pro-components';
  20 +import { Button, Col, Form, Row, message } from 'antd';
  21 +import { RcFile } from 'antd/es/upload';
  22 +import './style.css';
  23 +export default ({ data, type, reloadTable }) => {
  24 + const [form] = Form.useForm();
  25 + const onfinish = async (values) => {
  26 + const resSearchId = await postAdminClientQueryClientPage({
  27 + data: {
  28 + groupFilter: 'all',
  29 + },
  30 + });
  31 + const matchingItem = resSearchId.data.data.find(
  32 + (item) => item.id === values.name,
  33 + );
  34 + let matchedId;
  35 + if (matchingItem) {
  36 + matchedId = matchingItem.id; // 匹配成功,取出 id
  37 + values.name = matchingItem.name;
  38 + } else {
  39 + matchedId = null; // 如果没有匹配项,可以设置为 null 或其他值
  40 + }
  41 + const res = await postAdminClientAddOrModifyClientComunicationInfo({
  42 + data: {
  43 + ...values,
  44 + ticketsAttachments: form.getFieldValue('ticketsAttachments'),
  45 + clientId: matchedId,
  46 + },
  47 + });
  48 + if (res.result === RESPONSE_CODE.SUCCESS) {
  49 + message.success('新增成功');
  50 + reloadTable();
  51 + return true;
  52 + }
  53 + // 不返回不会关闭弹框
  54 + };
  55 +
  56 + const editOnfinish = async (values) => {
  57 + // setEditClientId(data.clientId);
  58 + values.clientId = data.clientId;
  59 +
  60 + // const resSearchId = await postAdminClientQueryClientPage({
  61 + // data: {
  62 + // groupFilter: 'all',
  63 + // },
  64 + // });
  65 + // const matchingItem = resSearchId.data.data.find(
  66 + // (item) => item.id === values.name,
  67 + // );
  68 + const res = await postAdminClientAddOrModifyClientComunicationInfo({
  69 + data: {
  70 + ...values,
  71 + // ticketsAttachments: form.getFieldValue("ticketsAttachments"),
  72 + ticketsAttachments:
  73 + form.getFieldValue('ticketsAttachments') !== undefined
  74 + ? form.getFieldValue('ticketsAttachments')
  75 + : data?.ticketsAttachments,
  76 + url:
  77 + form.getFieldValue('url') !== undefined
  78 + ? form.getFieldValue('url')
  79 + : data?.url,
  80 + // ticketsAttachments: data?.annexUrl,
  81 + },
  82 + });
  83 + if (res.result === RESPONSE_CODE.SUCCESS) {
  84 + message.success('新增成功');
  85 + reloadTable();
  86 + return true;
  87 + }
  88 + // 不返回不会关闭弹框
  89 + };
  90 + const optType = {
  91 + add: {
  92 + readOnly: false,
  93 + title: '新增跟进记录',
  94 + button: (
  95 + <Button size={'middle'} type="primary">
  96 + 新增
  97 + </Button>
  98 + ),
  99 + onFinish: onfinish,
  100 + },
  101 + modify: {
  102 + readOnly: false,
  103 + title: '修改跟进记录',
  104 + button: (
  105 + <Button size={'middle'} type="primary">
  106 + 编辑
  107 + </Button>
  108 + ),
  109 + onFinish: editOnfinish,
  110 + },
  111 + detail: {
  112 + readOnly: true,
  113 + title: '查看跟进记录',
  114 + button: (
  115 + <Button size={'middle'} type="primary" color="red">
  116 + 查看
  117 + </Button>
  118 + ),
  119 + onFinish: () => {},
  120 + },
  121 + };
  122 + return (
  123 + <ModalForm
  124 + title={optType[type].title}
  125 + resize={{
  126 + onResize() {
  127 + console.log('resize!');
  128 + },
  129 + maxWidth: window.innerWidth * 0.8,
  130 + minWidth: 400,
  131 + }}
  132 + form={form}
  133 + trigger={optType[type].button}
  134 + autoFocusFirstInput
  135 + drawerProps={{
  136 + destroyOnClose: true,
  137 + }}
  138 + submitTimeout={2000}
  139 + onFinish={optType[type].onFinish}
  140 + >
  141 + <ProFormSelect
  142 + name="name"
  143 + readonly={optType[type].readOnly}
  144 + fieldProps={{
  145 + labelInValue: false,
  146 + disabled: type === 'modify',
  147 + }}
  148 + initialValue={data ? data?.clientName + '' : null}
  149 + label="客户"
  150 + width="sm"
  151 + request={async () => {
  152 + const res = await postAdminClientQueryClientPage({
  153 + data: {
  154 + groupFilter: 'all',
  155 + },
  156 + });
  157 + // const namesArray = res.data.data.map((item) => item.name);
  158 + // const formattedObject = res.data.data.reduce((acc, name) => {
  159 + // acc[name] = name; // 将名称作为键和值
  160 + // return acc;
  161 + // }, {});
  162 + // console.log(namesArray, '5656namesArray');
  163 + // const formattedObject = res.data.data.reduce((acc, item) => {
  164 + // acc[item.name] = item.name; // 使用 name 作为键,id 作为值
  165 + // return acc;
  166 + // }, {});
  167 + // return enumToSelect(formattedObject);
  168 + const options = res.data.data.reduce((acc, item) => {
  169 + acc.push({ label: item.name, value: item.id }); // 使用 name 作为 label,id 作为 value
  170 + return acc;
  171 + }, []);
  172 + return options;
  173 + }}
  174 + rules={[
  175 + {
  176 + required: true,
  177 + message: '请选择客户',
  178 + },
  179 + ]}
  180 + ></ProFormSelect>
  181 + <ProFormText
  182 + name="contact"
  183 + label="联系人"
  184 + width="sm"
  185 + placeholder="请输入联系人"
  186 + initialValue={data?.content}
  187 + readonly={optType[type].readOnly}
  188 + rules={[
  189 + {
  190 + required: true,
  191 + message: '请输入联系人',
  192 + },
  193 + ]}
  194 + ></ProFormText>
  195 + <ProFormText
  196 + name="contactPhone"
  197 + label="联系电话"
  198 + width="sm"
  199 + placeholder="请输入联系电话"
  200 + initialValue={data?.content}
  201 + readonly={optType[type].readOnly}
  202 + rules={[
  203 + {
  204 + required: true,
  205 + message: '请输入联系电话',
  206 + },
  207 + ]}
  208 + ></ProFormText>
  209 + <ProFormDateTimePicker
  210 + name="datetime"
  211 + label="跟进日期"
  212 + initialValue={data ? data?.datetime + '' : null}
  213 + placeholder="请选择跟进时间"
  214 + width="sm"
  215 + rules={[
  216 + {
  217 + required: true,
  218 + message: '请选择跟进日期',
  219 + },
  220 + ]}
  221 + />
  222 + <ProFormSelect
  223 + name="tradeStatus"
  224 + label="跟进状态"
  225 + width="sm"
  226 + placeholder="请输入跟进状态"
  227 + readonly={optType[type].readOnly}
  228 + fieldProps={{
  229 + labelInValue: false,
  230 + }}
  231 + initialValue={data?.tradeStatus ? data?.tradeStatus + '' : null}
  232 + rules={[
  233 + {
  234 + required: true,
  235 + message: '请输入跟进状态',
  236 + },
  237 + ]}
  238 + request={async () => {
  239 + const res = await postServiceConstTradeStatus();
  240 + return enumToSelect(res.data);
  241 + }}
  242 + />
  243 + <ProFormSelect
  244 + name="way"
  245 + width="sm"
  246 + readonly={optType[type].readOnly}
  247 + fieldProps={{
  248 + labelInValue: false,
  249 + }}
  250 + initialValue={data?.way ? data?.way + '' : null}
  251 + label="跟进方式"
  252 + request={async () => {
  253 + const res = await postServiceConstClientWay();
  254 + return enumToSelect(res.data);
  255 + }}
  256 + rules={[
  257 + {
  258 + required: true,
  259 + message: '请选择跟进方式',
  260 + },
  261 + ]}
  262 + ></ProFormSelect>
  263 + <ProFormTextArea
  264 + name="content"
  265 + label="跟进详情"
  266 + placeholder="请输入跟进详情"
  267 + initialValue={data?.content}
  268 + readonly={optType[type].readOnly}
  269 + rules={[
  270 + {
  271 + required: true,
  272 + message: '请输入跟进详情',
  273 + },
  274 + ]}
  275 + ></ProFormTextArea>
  276 + <ProFormUploadDragger
  277 + label="附件"
  278 + name="attachment"
  279 + action="upload.do"
  280 + hidden={optType[type].readOnly}
  281 + onChange={(info) => {
  282 + const uploadFile = async ({ fileList: newFileList }) => {
  283 + if (newFileList.length > 0) {
  284 + const formData = new FormData();
  285 + formData.append('file', newFileList[0].originFileObj as RcFile);
  286 + const res = await postOrderErpOrderStagesUpload({
  287 + data: formData,
  288 + headers: {
  289 + 'Content-Type':
  290 + 'multipart/form-data; boundary=----WebKitFormBoundarynl6gT1BKdPWIejNq',
  291 + },
  292 + });
  293 + const url = res.data;
  294 + console.log('attachments' + JSON.stringify(url));
  295 + form.setFieldValue('attachments', url);
  296 + } else {
  297 + form.setFieldValue('attachments', null);
  298 + }
  299 + };
  300 + uploadFile(info);
  301 + }}
  302 + max={1}
  303 + />
  304 + <a hidden={!optType[type].readOnly} href={data?.attachments} download>
  305 + 下载附件
  306 + </a>
  307 + <ProFormTextArea
  308 + name="comment"
  309 + label="客户评价"
  310 + placeholder="请输入客户评价"
  311 + initialValue={data?.comment}
  312 + readonly={optType[type].readOnly}
  313 + ></ProFormTextArea>
  314 + <ProFormText
  315 + initialValue={data?.attachments}
  316 + name="attachments"
  317 + hidden
  318 + ></ProFormText>
  319 + <ProFormText initialValue={data?.id} name="id" hidden></ProFormText>
  320 + <div className="styled-text">
  321 + <div className="vertical-line"></div>
  322 + <span className="text">工单指派</span>
  323 + </div>
  324 + <ProFormSelect
  325 + name="ticketsType"
  326 + label="工单类型"
  327 + width="sm"
  328 + placeholder="请输入工单类型"
  329 + readonly={optType[type].readOnly}
  330 + fieldProps={{
  331 + labelInValue: false,
  332 + }}
  333 + initialValue={data?.ticketsType ? data?.ticketsType + '' : null}
  334 + request={async () => {
  335 + return [
  336 + { label: '问题', value: 'QUESTION' },
  337 + { label: '需求', value: 'DEMAND' },
  338 + { label: '建议', value: 'ADVICE' },
  339 + ];
  340 + }}
  341 + />
  342 + <ProFormTextArea
  343 + name="ticketsDetail"
  344 + label="工单详情"
  345 + placeholder="请输入工单详情"
  346 + initialValue={data?.ticketsDetail ? data?.ticketsDetail + '' : null}
  347 + readonly={optType[type].readOnly}
  348 + ></ProFormTextArea>
  349 + {/* <ProFormUploadDragger
  350 + label="工单附件"
  351 + name="ticketsAttachment"
  352 + action="upload.do"
  353 + hidden={optType[type].readOnly}
  354 + onChange={(info) => {
  355 + const uploadFile = async ({ fileList: newFileList }) => {
  356 + if (newFileList.length > 0) {
  357 + const formData = new FormData();
  358 + formData.append('file', newFileList[0].originFileObj as RcFile);
  359 + const res = await postOrderErpOrderStagesUpload({
  360 + data: formData,
  361 + headers: {
  362 + 'Content-Type':
  363 + 'multipart/form-data; boundary=----WebKitFormBoundarynl6gT1BKdPWIejNq',
  364 + },
  365 + });
  366 + const url = res.data;
  367 + console.log('ticketsAttachments' + JSON.stringify(url));
  368 + form.setFieldValue('ticketsAttachments', url);
  369 + } else {
  370 + form.setFieldValue('ticketsAttachments', null);
  371 + }
  372 + };
  373 + uploadFile(info);
  374 + }}
  375 + max={1}
  376 + /> */}
  377 + <Row>
  378 + <Col span={4}>附件:</Col>
  379 + <Col span={20}>
  380 + <UploadC
  381 + onFilesChange={async (newFileList) => {
  382 + if (newFileList.length > 0) {
  383 + const urls = []; // 创建一个数组来存储所有的 URL
  384 +
  385 + for (const file of newFileList) {
  386 + const formData = new FormData();
  387 + formData.append('file', file.originFileObj as RcFile);
  388 +
  389 + const res = await postOrderErpOrderStagesUpload({
  390 + data: formData,
  391 + headers: {
  392 + 'Content-Type':
  393 + 'multipart/form-data; boundary=----WebKitFormBoundarynl6gT1BKdPWIejNq',
  394 + },
  395 + });
  396 +
  397 + const url = res.data; // 获取响应中的 URL
  398 + urls.push(url); // 将每个 URL 追加到数组中
  399 + }
  400 +
  401 + // 将所有 URL 使用 ',' 进行拼接
  402 + const combinedUrl = urls.join(',');
  403 + form.setFieldValue('ticketsAttachments', combinedUrl); // 设置表单字段值为拼接后的 URL
  404 + } else {
  405 + form.setFieldValue('ticketsAttachments', null); // 如果没有文件,则清空 URL
  406 + }
  407 + }}
  408 + ></UploadC>
  409 + </Col>
  410 + </Row>
  411 + <a hidden={!optType[type].readOnly} href={data?.orderAttachment} download>
  412 + {/* <a href={data?.annexUrl} download> */}
  413 + 下载附件
  414 + </a>
  415 + <ProFormSelect
  416 + name="assignPeople"
  417 + width="sm"
  418 + readonly={optType[type].readOnly}
  419 + fieldProps={{
  420 + labelInValue: false,
  421 + }}
  422 + initialValue={data?.assignPeople ? data?.assignPeople + '' : null}
  423 + label="指派人员"
  424 + request={async () => {
  425 + const res = await postOrderErpUsersListByPage({
  426 + data: {
  427 + pageSize: 10000,
  428 + },
  429 + });
  430 + const userOptions = res.data.records
  431 + ? res.data.records.map((user) => ({
  432 + label: user.userName, // 或者使用其他需要的属性
  433 + value: user.userName, // 作为value的字段
  434 + }))
  435 + : [];
  436 + return userOptions;
  437 + }}
  438 + ></ProFormSelect>
  439 + {/* <Row>
  440 + <Col span={4}>上传发票:</Col>
  441 + <Col span={20}>
  442 + <UploadC
  443 + onFilesChange={async (newFileList) => {
  444 + if (newFileList.length > 0) {
  445 + const urls = []; // 创建一个数组来存储所有的 URL
  446 +
  447 + for (const file of newFileList) {
  448 + const formData = new FormData();
  449 + formData.append('file', file.originFileObj as RcFile);
  450 +
  451 + const res = await postOrderErpOrderStagesUpload({
  452 + data: formData,
  453 + headers: {
  454 + 'Content-Type':
  455 + 'multipart/form-data; boundary=----WebKitFormBoundarynl6gT1BKdPWIejNq',
  456 + },
  457 + });
  458 +
  459 + const url = res.data; // 获取响应中的 URL
  460 + urls.push(url); // 将每个 URL 追加到数组中
  461 + }
  462 +
  463 + // 将所有 URL 使用 ',' 进行拼接
  464 + const combinedUrl = urls.join(',');
  465 + form.setFieldValue('url', combinedUrl); // 设置表单字段值为拼接后的 URL
  466 + } else {
  467 + form.setFieldValue('url', null); // 如果没有文件,则清空 URL
  468 + }
  469 + }}
  470 + ></UploadC>
  471 + </Col>
  472 + </Row> */}
  473 + </ModalForm>
  474 + );
  475 +};
src/pages/Client/FollowRecord/Components/CommunicationHistoryModal.tsx
@@ -8,8 +8,6 @@ import { Button, Descriptions, Space } from &#39;antd&#39;; @@ -8,8 +8,6 @@ import { Button, Descriptions, Space } from &#39;antd&#39;;
8 import { useEffect, useRef, useState } from 'react'; 8 import { useEffect, useRef, useState } from 'react';
9 9
10 export default ({ data, reloadTable }) => { 10 export default ({ data, reloadTable }) => {
11 - console.log(data, '5656datafirstshowgenjin');  
12 -  
13 // const [isModalVisible, setIsModalVisible] = useState(false); // 控制 ClientModal 的显示 11 // const [isModalVisible, setIsModalVisible] = useState(false); // 控制 ClientModal 的显示
14 const actionRef = useRef(); // 引用 actionRef,方便调用 reload 方法 12 const actionRef = useRef(); // 引用 actionRef,方便调用 reload 方法
15 13
@@ -17,7 +15,8 @@ export default ({ data, reloadTable }) =&gt; { @@ -17,7 +15,8 @@ export default ({ data, reloadTable }) =&gt; {
17 const [createByName, setCreateByName] = useState(''); // 跟进人员 15 const [createByName, setCreateByName] = useState(''); // 跟进人员
18 const [clientName, setClientName] = useState(''); // 客户名称 16 const [clientName, setClientName] = useState(''); // 客户名称
19 // const [clientAddress, setClientAddress] = useState(''); // 客户地址 17 // const [clientAddress, setClientAddress] = useState(''); // 客户地址
20 - const [way, setWay] = useState(); // 类型 18 + const [way, setWay] = useState(); // 跟进方式
  19 + const [tradeStatusText, setTradeStatusText] = useState(); // 状态
21 // const [clientNameLike, setClientNameLike] = useState(''); // 客户名称模糊查询 20 // const [clientNameLike, setClientNameLike] = useState(''); // 客户名称模糊查询
22 // const [clientAddressLike, setClientAddressLike] = useState(''); // 客户地址模糊查询 21 // const [clientAddressLike, setClientAddressLike] = useState(''); // 客户地址模糊查询
23 // const [tradeStatus, setTradeStatus] = useState(''); // 客户状态 22 // const [tradeStatus, setTradeStatus] = useState(''); // 客户状态
@@ -26,18 +25,36 @@ export default ({ data, reloadTable }) =&gt; { @@ -26,18 +25,36 @@ export default ({ data, reloadTable }) =&gt; {
26 const [createTime, setCreateTime] = useState(null); // 创建时间 25 const [createTime, setCreateTime] = useState(null); // 创建时间
27 const [attachments, setAttachments] = useState(); //附件 26 const [attachments, setAttachments] = useState(); //附件
28 const [attachmentsName, setAttachmentsName] = useState(''); // 附件名称 27 const [attachmentsName, setAttachmentsName] = useState(''); // 附件名称
29 - 28 + const [ticketsType, setTicketsType] = useState(''); // 附件名称
  29 + const [ticketsDetail, setTicketsDetail] = useState(''); // 附件名称
  30 + const [ticketsAttachment, setTicketsAttachment] = useState(); // 附件名称
  31 + // const [ticketsAttachmentName, setTicketsAttachmentName] = useState(''); // 附件名称
  32 + const [comment, setComment] = useState(''); // 客户评价
  33 + const [assignPeople, setAssignPeople] = useState(''); // 附件名称
30 useEffect(() => { 34 useEffect(() => {
31 const request = async () => { 35 const request = async () => {
32 - console.log(data, '5656datasearch');  
33 const res = await postAdminClientQueryClientComunicationInfo({ 36 const res = await postAdminClientQueryClientComunicationInfo({
34 data: { 37 data: {
35 id: data.id, 38 id: data.id,
36 }, 39 },
37 }); 40 });
38 - console.log(res, '5656res'); 41 + // const resTicket = await getOrderErpTicketsGetTicketsByClientId({
  42 + // query: {
  43 + // id: data.id,
  44 + // },
  45 + // });
  46 + // data.type = resTicket.data.type;
  47 + // data.detailText = resTicket.data.detailText;
  48 + // data.annexUrl = resTicket.data.annexUrl;
  49 + // data.assignPeople = resTicket.data.assignPeople;
  50 + // console.log(resTicket, '5656resTicket');
39 const dataSearch = res.data.data[0]; 51 const dataSearch = res.data.data[0];
  52 + console.log(dataSearch, '5656dataSearch');
40 if (dataSearch) { 53 if (dataSearch) {
  54 + // data.type = resTicket.data.type;
  55 + // data.detailText = resTicket.data.detailText;
  56 + // data.annexUrl = resTicket.data.annexUrl;
  57 + // data.assignPeople = resTicket.data.assignPeople;
41 if (dataSearch.attachments) { 58 if (dataSearch.attachments) {
42 const url = dataSearch.attachments; 59 const url = dataSearch.attachments;
43 const match = url.match(/aliyuncs\.com\/(.*?)\?/); 60 const match = url.match(/aliyuncs\.com\/(.*?)\?/);
@@ -50,6 +67,24 @@ export default ({ data, reloadTable }) =&gt; { @@ -50,6 +67,24 @@ export default ({ data, reloadTable }) =&gt; {
50 setAttachmentsName(decodedStr); // 设置跟进日期 67 setAttachmentsName(decodedStr); // 设置跟进日期
51 } 68 }
52 } 69 }
  70 + // if (dataSearch.ticketAttachments) {
  71 + // const url = dataSearch.attachments;
  72 + // const match = url.match(/aliyuncs\.com\/(.*?)\?/);
  73 + // let decodedStr = '';
  74 +
  75 + // if (match) {
  76 + // // 获取匹配的字符串并进行解码
  77 + // const encodedStr = match[1];
  78 + // decodedStr = decodeURIComponent(encodedStr);
  79 + // setTicketsAttachmentName(decodedStr); // 设置跟进日期
  80 + // }
  81 + // }
  82 + setComment(dataSearch.comment);
  83 + setTicketsType(dataSearch.ticketsTypeText);
  84 + setTicketsDetail(dataSearch.ticketsDetail);
  85 + setTicketsAttachment(dataSearch.ticketsAttachments);
  86 + setAssignPeople(dataSearch.assignPeople);
  87 + setComment(dataSearch.comment);
53 setDatetime(dataSearch.datetime); // 设置跟进日期 88 setDatetime(dataSearch.datetime); // 设置跟进日期
54 // setDateRange(data.dateRange || []); // 设置跟进时间范围 89 // setDateRange(data.dateRange || []); // 设置跟进时间范围
55 setCreateByName(dataSearch.createByName); // 设置跟进人员 90 setCreateByName(dataSearch.createByName); // 设置跟进人员
@@ -58,13 +93,12 @@ export default ({ data, reloadTable }) =&gt; { @@ -58,13 +93,12 @@ export default ({ data, reloadTable }) =&gt; {
58 // setClientNameLike(data.clientNameLike || ''); // 设置客户名称模糊查询 93 // setClientNameLike(data.clientNameLike || ''); // 设置客户名称模糊查询
59 // setClientAddressLike(data.clientAddressLike || ''); // 设置客户地址模糊查询 94 // setClientAddressLike(data.clientAddressLike || ''); // 设置客户地址模糊查询
60 // setTradeStatus(data.tradeStatus || ''); // 设置客户状态 95 // setTradeStatus(data.tradeStatus || ''); // 设置客户状态
61 - // setTradeStatusLike(data.tradeStatusLike || ''); // 设置客户状态模糊查询 96 + setTradeStatusText(data.tradeStatusLike || ''); // 设置客户状态模糊查询
62 setContent(dataSearch.content); // 设置跟进详情 97 setContent(dataSearch.content); // 设置跟进详情
63 setCreateTime(dataSearch.createTime); // 设置创建时间 98 setCreateTime(dataSearch.createTime); // 设置创建时间
64 setWay(dataSearch.wayText); 99 setWay(dataSearch.wayText);
65 setAttachments(dataSearch.attachments); 100 setAttachments(dataSearch.attachments);
66 } 101 }
67 - console.log(attachments, '5656attachments');  
68 }; 102 };
69 request(); 103 request();
70 }, []); 104 }, []);
@@ -96,12 +130,41 @@ export default ({ data, reloadTable }) =&gt; { @@ -96,12 +130,41 @@ export default ({ data, reloadTable }) =&gt; {
96 }, 130 },
97 { 131 {
98 key: '6', 132 key: '6',
99 - label: '跟进类型',  
100 - children: way, // 跟进类型 133 + label: '跟进方式',
  134 + children: way, // 跟进方式
  135 + },
  136 + {
  137 + key: '7',
  138 + label: '跟进状态',
  139 + children: tradeStatusText, // 跟进状态
  140 + },
  141 + {
  142 + key: '8',
  143 + label: '工单类型',
  144 + children: ticketsType, // 跟进状态
  145 + },
  146 + {
  147 + key: '9',
  148 + label: '工单详情',
  149 + children: ticketsDetail, // 跟进状态
  150 + },
  151 + // {
  152 + // key: '12',
  153 + // label: '工单附件',
  154 + // children: ticketsAttachment, // 跟进状态
  155 + // },
  156 + {
  157 + key: '10',
  158 + label: '指派人员',
  159 + children: assignPeople, // 跟进状态
  160 + },
  161 + {
  162 + key: '11',
  163 + label: '客户评价',
  164 + children: comment, // 跟进状态
101 }, 165 },
102 ]; 166 ];
103 const handleDelete = async () => { 167 const handleDelete = async () => {
104 - console.log(JSON.stringify(data), '5656record');  
105 // 调用删除接口 168 // 调用删除接口
106 const success = await postAdminClientRemoveClientComunicationInfo({ 169 const success = await postAdminClientRemoveClientComunicationInfo({
107 query: { 170 query: {
@@ -117,7 +180,7 @@ export default ({ data, reloadTable }) =&gt; { @@ -117,7 +180,7 @@ export default ({ data, reloadTable }) =&gt; {
117 <Space> 180 <Space>
118 <ModalForm 181 <ModalForm
119 title="跟进记录" 182 title="跟进记录"
120 - trigger={<Button type="link">查看</Button>} 183 + trigger={<Button type="primary">查看</Button>}
121 submitter={{ 184 submitter={{
122 resetButtonProps: { 185 resetButtonProps: {
123 style: { 186 style: {
@@ -135,12 +198,14 @@ export default ({ data, reloadTable }) =&gt; { @@ -135,12 +198,14 @@ export default ({ data, reloadTable }) =&gt; {
135 <> 198 <>
136 <ClientModal 199 <ClientModal
137 key={'modify'} 200 key={'modify'}
138 - data={data} // 将表单数据传递给 ClientModal 201 + // data={data} // 将表单数据传递给 ClientModal
  202 + data={{
  203 + data,
  204 + }} // 传递修改后的 data
139 reloadTable={() => { 205 reloadTable={() => {
140 actionRef?.current?.reload(); // 重新加载表格数据 206 actionRef?.current?.reload(); // 重新加载表格数据
141 props.submit(); 207 props.submit();
142 reloadTable(); 208 reloadTable();
143 - console.log('5656close');  
144 }} 209 }}
145 type={'modify'} 210 type={'modify'}
146 onFinish={() => { 211 onFinish={() => {
@@ -176,11 +241,90 @@ export default ({ data, reloadTable }) =&gt; { @@ -176,11 +241,90 @@ export default ({ data, reloadTable }) =&gt; {
176 }} 241 }}
177 > 242 >
178 <Descriptions items={items} column={1} /> 243 <Descriptions items={items} column={1} />
179 - {attachmentsName && ( 244 + {/* {attachmentsName && (
180 <a href={attachments} download> 245 <a href={attachments} download>
181 附件:{attachmentsName} 246 附件:{attachmentsName}
182 </a> 247 </a>
183 )} 248 )}
  249 + <div></div>
  250 + {ticketsAttachment && (
  251 + <a href={ticketsAttachment} download>
  252 + 工单附件:{ticketsAttachment}
  253 + </a>
  254 + )} */}
  255 + {attachmentsName && (
  256 + <div>
  257 + {attachmentsName.endsWith('.png') ||
  258 + attachmentsName.endsWith('.jpg') ? (
  259 + <>
  260 + <img
  261 + src={attachments}
  262 + alt={attachmentsName}
  263 + style={{ maxWidth: '300px', height: 'auto' }}
  264 + />
  265 + <div></div>
  266 + <a href={attachments} download>
  267 + 附件:{attachmentsName}
  268 + </a>
  269 + </>
  270 + ) : (
  271 + <a href={attachments} download>
  272 + 附件:{attachmentsName}
  273 + </a>
  274 + )}
  275 + </div>
  276 + )}
  277 +
  278 + <div></div>
  279 + {/* {ticketsAttachment && (
  280 + <a href={ticketsAttachment} download>
  281 + 工单附件:{ticketsAttachment}
  282 + </a>
  283 + )} */}
  284 + {/* {ticketsAttachment && (
  285 + <div>
  286 + {ticketsAttachment.includes('jpg') ||
  287 + ticketsAttachment.includes('png') ? (
  288 + <>
  289 + <img
  290 + src={ticketsAttachment}
  291 + alt={ticketsAttachment}
  292 + style={{ maxWidth: '300px', height: 'auto' }}
  293 + />
  294 + <div></div>
  295 + <a href={ticketsAttachment} download>
  296 + 工单附件:{ticketsAttachment}
  297 + </a>
  298 + </>
  299 + ) : (
  300 + <a href={ticketsAttachment} download>
  301 + 工单附件:{ticketsAttachment}
  302 + </a>
  303 + )}
  304 + </div>
  305 + )} */}
  306 + {ticketsAttachment && (
  307 + <div>
  308 + {ticketsAttachment.split(',').map((ticketsAttachment, index) => (
  309 + <div key={index}>
  310 + {ticketsAttachment.includes('jpg') ||
  311 + ticketsAttachment.includes('png') ? (
  312 + <>
  313 + <img
  314 + src={ticketsAttachment}
  315 + alt={`附件 ${index + 1}`}
  316 + style={{ maxWidth: '300px', height: 'auto' }}
  317 + />
  318 + <div></div>
  319 + </>
  320 + ) : null}
  321 + <a href={ticketsAttachment} download>
  322 + 工单附件:{ticketsAttachment}
  323 + </a>
  324 + </div>
  325 + ))}
  326 + </div>
  327 + )}
184 </ModalForm> 328 </ModalForm>
185 </Space> 329 </Space>
186 ); 330 );
src/pages/Client/FollowRecord/Components/style.css 0 → 100644
  1 +.styled-text {
  2 + display: flex;
  3 + align-items: center;
  4 + margin-bottom: 20px;
  5 +}
  6 +
  7 +.vertical-line {
  8 + width: 2px; /* 线的宽度 */
  9 + height: 20px; /* 线的高度 */
  10 + background-color: black; /* 线的颜色 */
  11 + margin-right: 10px; /* 线与文本之间的间距 */
  12 +}
  13 +
  14 +.text {
  15 + font-size: 20px; /* 文本大小 */
  16 + font-family: Arial, sans-serif; /* 字体样式 */
  17 + color: black; /* 文本颜色 */
  18 +}
src/pages/Client/FollowRecord/index.tsx
@@ -10,8 +10,9 @@ import { @@ -10,8 +10,9 @@ import {
10 import { enumToSelect } from '@/utils'; 10 import { enumToSelect } from '@/utils';
11 import type { ActionType } from '@ant-design/pro-components'; 11 import type { ActionType } from '@ant-design/pro-components';
12 import { ProTable } from '@ant-design/pro-components'; 12 import { ProTable } from '@ant-design/pro-components';
13 -import { Button, Space, message } from 'antd'; 13 +import { Button, Popconfirm, Space, message } from 'antd';
14 import { useRef, useState } from 'react'; 14 import { useRef, useState } from 'react';
  15 +import ClientModal2 from './Components/ClientModal2';
15 16
16 export default () => { 17 export default () => {
17 const actionRef = useRef<ActionType>(); 18 const actionRef = useRef<ActionType>();
@@ -19,7 +20,6 @@ export default () =&gt; { @@ -19,7 +20,6 @@ export default () =&gt; {
19 20
20 const reload = () => { 21 const reload = () => {
21 actionRef.current.reload(); // 重新加载数据 22 actionRef.current.reload(); // 重新加载数据
22 - console.log('5656flush');  
23 23
24 // 更新 refreshKey,强制刷新 CommunicationHistoryModal 24 // 更新 refreshKey,强制刷新 CommunicationHistoryModal
25 setRefreshKey((prevKey) => prevKey + 1); 25 setRefreshKey((prevKey) => prevKey + 1);
@@ -46,7 +46,7 @@ export default () =&gt; { @@ -46,7 +46,7 @@ export default () =&gt; {
46 // }, 46 // },
47 }, 47 },
48 { 48 {
49 - title: '跟进时间', 49 + title: '跟进日期',
50 dataIndex: 'dateRange', 50 dataIndex: 'dateRange',
51 valueType: 'dateRange', 51 valueType: 'dateRange',
52 hideInTable: true, 52 hideInTable: true,
@@ -68,6 +68,13 @@ export default () =&gt; { @@ -68,6 +68,13 @@ export default () =&gt; {
68 ellipsis: true, 68 ellipsis: true,
69 hideInSearch: false, 69 hideInSearch: false,
70 }, 70 },
  71 + // {
  72 + // title: '跟进状态',
  73 + // width: 150,
  74 + // ellipsis: true,
  75 + // dataIndex: 'tradeStatusText',
  76 + // hideInSearch: true,
  77 + // },
71 { 78 {
72 title: '客户名称', 79 title: '客户名称',
73 dataIndex: 'clientName', 80 dataIndex: 'clientName',
@@ -75,22 +82,51 @@ export default () =&gt; { @@ -75,22 +82,51 @@ export default () =&gt; {
75 ellipsis: true, 82 ellipsis: true,
76 hideInSearch: true, 83 hideInSearch: true,
77 }, 84 },
  85 + // {
  86 + // title: '客户地址',
  87 + // dataIndex: 'clientAddress',
  88 + // width: 250,
  89 + // ellipsis: true,
  90 + // hideInSearch: true,
  91 + // },
78 { 92 {
79 - title: '客户地址',  
80 - dataIndex: 'clientAddress',  
81 - width: 250, 93 + title: '联系人',
  94 + dataIndex: 'contact',
  95 + width: 150,
  96 + ellipsis: true,
  97 + hideInSearch: false,
  98 + },
  99 + // {
  100 + // title: '联系人',
  101 + // dataIndex: 'contactLike',
  102 + // width: 150,
  103 + // ellipsis: true,
  104 + // hideInSearch: false,
  105 + // hideInTable: true,
  106 + // },
  107 + {
  108 + title: '联系电话',
  109 + dataIndex: 'contactPhone',
  110 + width: 150,
  111 + ellipsis: true,
  112 + hideInSearch: true,
  113 + },
  114 + {
  115 + title: '跟进状态',
  116 + dataIndex: 'tradeStatusLike',
  117 + width: 100,
82 ellipsis: true, 118 ellipsis: true,
83 hideInSearch: true, 119 hideInSearch: true,
84 }, 120 },
85 { 121 {
86 - title: '跟进类型', 122 + title: '跟进方式',
87 dataIndex: 'wayText', 123 dataIndex: 'wayText',
88 width: 100, 124 width: 100,
89 ellipsis: true, 125 ellipsis: true,
90 hideInSearch: true, 126 hideInSearch: true,
91 }, 127 },
92 { 128 {
93 - title: '跟进类型', 129 + title: '跟进方式',
94 dataIndex: 'way', 130 dataIndex: 'way',
95 width: 100, 131 width: 100,
96 ellipsis: true, 132 ellipsis: true,
@@ -101,6 +137,16 @@ export default () =&gt; { @@ -101,6 +137,16 @@ export default () =&gt; {
101 return enumToSelect(res.data); 137 return enumToSelect(res.data);
102 }, 138 },
103 }, 139 },
  140 + // {
  141 + // title: '跟进状态',
  142 + // dataIndex: 'tradeStatus',
  143 + // valueType: 'select',
  144 + // hideInTable: true,
  145 + // request: async () => {
  146 + // const res = await postServiceConstTradeStatus();
  147 + // return enumToSelect(res.data);
  148 + // },
  149 + // },
104 { 150 {
105 title: '客户名称', 151 title: '客户名称',
106 dataIndex: 'clientNameLike', 152 dataIndex: 'clientNameLike',
@@ -109,26 +155,26 @@ export default () =&gt; { @@ -109,26 +155,26 @@ export default () =&gt; {
109 hideInSearch: false, 155 hideInSearch: false,
110 hideInTable: true, 156 hideInTable: true,
111 }, 157 },
  158 + // {
  159 + // title: '客户地址',
  160 + // dataIndex: 'clientAddressLike',
  161 + // width: 250,
  162 + // ellipsis: true,
  163 + // hideInSearch: false,
  164 + // hideInTable: true,
  165 + // },
  166 + // {
  167 + // title: '跟进状态',
  168 + // dataIndex: 'tradeStatus',
  169 + // width: 100,
  170 + // ellipsis: true,
  171 + // hideInSearch: true,
  172 + // },
112 { 173 {
113 - title: '客户地址',  
114 - dataIndex: 'clientAddressLike',  
115 - width: 250,  
116 - ellipsis: true,  
117 - hideInSearch: false,  
118 - hideInTable: true,  
119 - },  
120 - {  
121 - title: '客户状态', 174 + title: '跟进状态',
122 dataIndex: 'tradeStatus', 175 dataIndex: 'tradeStatus',
123 width: 100, 176 width: 100,
124 ellipsis: true, 177 ellipsis: true,
125 - hideInSearch: true,  
126 - },  
127 - {  
128 - title: '客户状态',  
129 - dataIndex: 'tradeStatusLike',  
130 - width: 100,  
131 - ellipsis: true,  
132 hideInSearch: false, 178 hideInSearch: false,
133 hideInTable: true, 179 hideInTable: true,
134 request: async () => { 180 request: async () => {
@@ -141,7 +187,7 @@ export default () =&gt; { @@ -141,7 +187,7 @@ export default () =&gt; {
141 dataIndex: 'content', 187 dataIndex: 'content',
142 width: 250, 188 width: 250,
143 ellipsis: true, 189 ellipsis: true,
144 - hideInSearch: false, 190 + hideInSearch: true,
145 }, 191 },
146 { 192 {
147 title: '创建时间', 193 title: '创建时间',
@@ -159,10 +205,26 @@ export default () =&gt; { @@ -159,10 +205,26 @@ export default () =&gt; {
159 hideInTable: true, 205 hideInTable: true,
160 }, 206 },
161 { 207 {
  208 + title: '创建日期',
  209 + dataIndex: 'createTime',
  210 + valueType: 'dateRange',
  211 + hideInTable: true,
  212 + search: {
  213 + transform: (value) => {
  214 + if (value) {
  215 + return {
  216 + createTimeGe: value[0],
  217 + createTimeLe: value[1],
  218 + };
  219 + }
  220 + },
  221 + },
  222 + },
  223 + {
162 title: '操作', 224 title: '操作',
163 valueType: 'option', 225 valueType: 'option',
164 key: 'option', 226 key: 'option',
165 - width: 150, 227 + width: 220,
166 render: (text, record, index, action) => { 228 render: (text, record, index, action) => {
167 const handleDelete = async () => { 229 const handleDelete = async () => {
168 // console.log(JSON.stringify(record), '5656record'); 230 // console.log(JSON.stringify(record), '5656record');
@@ -187,8 +249,22 @@ export default () =&gt; { @@ -187,8 +249,22 @@ export default () =&gt; {
187 // }} 249 // }}
188 reloadTable={reload} 250 reloadTable={reload}
189 />, 251 />,
  252 + <ClientModal2
  253 + key={'modify'}
  254 + // data={data} // 将表单数据传递给 ClientModal
  255 + data={record} // 传递修改后的 data
  256 + reloadTable={() => {
  257 + actionRef?.current?.reload(); // 重新加载表格数据
  258 + // props.submit();
  259 + }}
  260 + type={'modify'}
  261 + onFinish={() => {
  262 + // setIsModalVisible(false);
  263 + }} // 关闭 Modal
  264 + style={{ marginRight: '10px' }}
  265 + />,
190 <> 266 <>
191 - <Button 267 + {/* <Button
192 key={'delete'} 268 key={'delete'}
193 onClick={() => { 269 onClick={() => {
194 handleDelete(); 270 handleDelete();
@@ -197,15 +273,42 @@ export default () =&gt; { @@ -197,15 +273,42 @@ export default () =&gt; {
197 // reloadTable={() => { 273 // reloadTable={() => {
198 // actionRef.current.reload(); 274 // actionRef.current.reload();
199 // }} 275 // }}
200 - type="link" 276 + type="primary"
201 size="middle" 277 size="middle"
202 - // 使用 danger 属性来将按钮颜色设置为红色  
203 - // onFinish={() => {  
204 - // actionRef.current.reload();  
205 - // }} 278 + danger
  279 + // 使用 danger 属性来将按钮颜色设置为红色
  280 + // onFinish={() => {
  281 + // actionRef.current.reload();
  282 + // }}
206 > 283 >
207 删除 284 删除
208 </Button> 285 </Button>
  286 + <ButtonConfirm
  287 + key={'delete'}
  288 + className="p-0"
  289 + title={'是否确认删除'}
  290 + text="删除"
  291 + type="primary"
  292 + size="middle"
  293 + danger
  294 + onConfirm={async () => {
  295 + handleDelete();
  296 + actionRef.current.reload();
  297 + }}
  298 + /> */}
  299 + <Popconfirm
  300 + title={'是否确认删除'}
  301 + onConfirm={async () => {
  302 + handleDelete();
  303 + actionRef.current.reload();
  304 + }}
  305 + okText="确认"
  306 + cancelText="取消"
  307 + >
  308 + <Button key={'delete'} type="primary" size="middle" danger>
  309 + 删除
  310 + </Button>
  311 + </Popconfirm>
209 </>, 312 </>,
210 ]; 313 ];
211 }, 314 },
@@ -236,7 +339,6 @@ export default () =&gt; { @@ -236,7 +339,6 @@ export default () =&gt; {
236 ...params, 339 ...params,
237 }, 340 },
238 }); 341 });
239 - console.log(params, '5656566params');  
240 if (res.result === RESPONSE_CODE.SUCCESS) { 342 if (res.result === RESPONSE_CODE.SUCCESS) {
241 console.log(JSON.stringify(res.data)); 343 console.log(JSON.stringify(res.data));
242 return { 344 return {
src/tsg.config.ts
@@ -33,8 +33,8 @@ const projects: Project[] = [ @@ -33,8 +33,8 @@ const projects: Project[] = [
33 * openapi 文档地址,可以是远程的json文件,也可以是本地的json文件 33 * openapi 文档地址,可以是远程的json文件,也可以是本地的json文件
34 * 如果使用本地文件,相对路径以当前'tsg.config.ts'为基准 34 * 如果使用本地文件,相对路径以当前'tsg.config.ts'为基准
35 * */ 35 * */
36 - // source: 'http://localhost:8085/v2/api-docs',  
37 - source: 'http://39.108.227.113:8085/v2/api-docs', 36 + source: 'http://localhost:8085/v2/api-docs',
  37 + //source: 'http://39.108.227.113:8085/v2/api-docs',
38 38
39 // source: 'https://petstore3.swagger.io/api/v3/openapi.json', 39 // source: 'https://petstore3.swagger.io/api/v3/openapi.json',
40 // source: './fixture/pet.json', 40 // source: './fixture/pet.json',