Commit b966b1f328041cba5762ac374bc345945becb869

Authored by zhongnanhuang
1 parent 80928860

feat: update 新增课题组模块

.umirc.ts
... ... @@ -66,6 +66,13 @@ export default defineConfig({
66 66 access: 'canReadAdminAndFinanceAndSales',
67 67 },
68 68 {
  69 + name: '课题组管理',
  70 + path: '/researchGroup',
  71 + component: './ResearchGroup',
  72 + icon: 'AccountBookOutlined',
  73 + access: 'canReadAdminAndSales',
  74 + },
  75 + {
69 76 name: '打印',
70 77 path: '/print',
71 78 component: './OrderPrint',
... ...
src/access.ts
... ... @@ -15,5 +15,6 @@ export default (initialState: API.UserInfo) => {
15 15 canReadSales: canReadSales,
16 16 canReadAdminAndFinanceAndSales:
17 17 canReadFinance || canReadAdmin || canReadSales,
  18 + canReadAdminAndSales: canReadAdmin || canReadSales,
18 19 };
19 20 };
... ...
src/pages/Order/components/OrderDrawer.tsx
... ... @@ -10,7 +10,6 @@ import {
10 10 postServiceOrderAfterSalesQuerySnapshotOrder,
11 11 postServiceOrderApplyAfterSales,
12 12 postServiceOrderApplyModify,
13   - postServiceOrderQuerySalesCode,
14 13 postServiceOrderUpdateOrder,
15 14 } from '@/services';
16 15 import {
... ... @@ -22,6 +21,7 @@ import {
22 21 } from '@/utils';
23 22 import { getDefaultString } from '@/utils/StringUtil';
24 23 import { getTeacherCustomFieldNumber } from '@/utils/kingdee';
  24 +import { getSalesCodeOptions } from '@/utils/order';
25 25 import {
26 26 DrawerForm,
27 27 FormListActionType,
... ... @@ -122,15 +122,8 @@ export default ({ onClose, data, subOrders, orderOptType }) => {
122 122 /**
123 123 * 获取销售代码枚举,在复制和编辑的时候判断是否为旧的代码
124 124 */
125   - const getSalesCodeOptions = async () => {
126   - const res = await postServiceOrderQuerySalesCode();
127   - let options = res.data?.map((item) => {
128   - return {
129   - label: item.userName,
130   - value: item.userName,
131   - number: item.number,
132   - };
133   - });
  125 + const loadSalesCodeOptions = async () => {
  126 + let options = await getSalesCodeOptions();
134 127 setSalesCodeOptions(options);
135 128  
136 129 if (optType('copy') || optType('edit')) {
... ... @@ -667,7 +660,7 @@ export default ({ onClose, data, subOrders, orderOptType }) => {
667 660  
668 661 useEffect(() => {
669 662 checkHasLocalData();
670   - getSalesCodeOptions();
  663 + loadSalesCodeOptions();
671 664 if (optType('after-sales-check')) {
672 665 getOldOrderData(data.id);
673 666 } else {
... ...
src/pages/ResearchGroup/components/ResearchGroupAddModal.tsx 0 → 100644
  1 +import { RESPONSE_CODE } from '@/constants/enum';
  2 +import {
  3 + postCanrdApiUserAddressList,
  4 + postCanrdApiUserList,
  5 + postResearchGroupsAdd,
  6 +} from '@/services';
  7 +import { getDefaultString, isEmpty } from '@/utils/StringUtil';
  8 +import { getRandomNumber } from '@/utils/numberUtil';
  9 +import { getSalesCodeOptions } from '@/utils/order';
  10 +import { validatePhoneNumberBool } from '@/utils/validators';
  11 +import {
  12 + ModalForm,
  13 + ProCard,
  14 + ProForm,
  15 + ProFormSelect,
  16 + ProFormText,
  17 +} from '@ant-design/pro-components';
  18 +import { Button, Form, message } from 'antd';
  19 +import { useEffect, useState } from 'react';
  20 +import '../index.less';
  21 +
  22 +// import { cloneDeep } from 'lodash';
  23 +export default ({ setVisible, onClose }) => {
  24 + const [form] = Form.useForm();
  25 + const [salesCodeOptions, setSalesCodeOptions] = useState([]);
  26 + const [memberOptions, setMemberOptions] = useState<any[]>([]);
  27 + const [accountOptions, setAccountOptions] = useState<any[]>([]);
  28 +
  29 + /**
  30 + * 获取销售代码枚举,在复制和编辑的时候判断是否为旧的代码
  31 + */
  32 + const loadSalesCodeOptions = async () => {
  33 + let options = await getSalesCodeOptions();
  34 + setSalesCodeOptions(options);
  35 + };
  36 +
  37 + /**
  38 + * 对options去重
  39 + * @param options
  40 + * @returns
  41 + */
  42 + function deduplicateOptions(options: any) {
  43 + const seen = new Set();
  44 + const result: any[] = [];
  45 + options.forEach((option: any) => {
  46 + const uniqueKey = `${option.realName}-${option.phone}`;
  47 + if (!seen.has(uniqueKey)) {
  48 + seen.add(uniqueKey);
  49 + result.push(option);
  50 + }
  51 + });
  52 + return result;
  53 + }
  54 +
  55 + /**
  56 + * 自动填充客户信息
  57 + * @param option
  58 + */
  59 + function autoFillCustomerInfo(option: any) {
  60 + if (!option) {
  61 + return;
  62 + }
  63 + let realName = option.realName;
  64 + let id = option.value;
  65 + if (id === 3.1415926) {
  66 + message.warning(
  67 + '请填写下方的【客户名称】和【手机号】,填写完成确保信息无误后点击添加按钮。',
  68 + );
  69 + form.setFieldValue('realName', option.name);
  70 + return;
  71 + }
  72 + //判断当前客户信息是否已添加过:id匹配或者option的phone匹配说明添加过了
  73 + let memberIds = form.getFieldValue('members');
  74 + if (!memberIds) {
  75 + //表单项没值的时候默认是undefined。初始化为数组
  76 + memberIds = [];
  77 + }
  78 + if (memberIds.includes(id)) {
  79 + message.info(`${realName} 重复添加`);
  80 + return;
  81 + }
  82 + //表单项的value添加当前option的value
  83 + memberIds.push(id);
  84 + form.setFieldValue('members', memberIds);
  85 + message.success(`${realName} 添加成功`);
  86 + //判断options中是否已经有这个option
  87 + for (let memberOption of memberOptions) {
  88 + if (
  89 + memberIds.includes(memberOption.value) &&
  90 + memberOption.phone === option.phone
  91 + ) {
  92 + return;
  93 + }
  94 + }
  95 + //option添加到memberOptions中
  96 + let newMemberOptions = [...memberOptions];
  97 + newMemberOptions.push(option);
  98 + setMemberOptions(newMemberOptions);
  99 + }
  100 +
  101 + /**
  102 + * 保存account的options
  103 + * @param option
  104 + * @returns
  105 + */
  106 + function autoAccountSelectOptions(option: any) {
  107 + if (!option) {
  108 + return;
  109 + }
  110 + let id = option.value;
  111 + //判断当前客户信息是否已添加过:id匹配或者option的phone匹配说明添加过了
  112 + let accountIds = form.getFieldValue('accounts');
  113 + if (!accountIds) {
  114 + //表单项没值的时候默认是undefined。初始化为数组
  115 + accountIds = [];
  116 + }
  117 + if (accountIds.includes(id)) {
  118 + return;
  119 + }
  120 + //option添加到accountOptions中
  121 + setAccountOptions(option);
  122 + }
  123 +
  124 + /**
  125 + * 添加自定义成员
  126 + */
  127 + function addCustomMember() {
  128 + let realName = form.getFieldValue('realName');
  129 + let phone = form.getFieldValue('phone');
  130 + if (isEmpty(realName)) {
  131 + message.error('请填写客户名称');
  132 + }
  133 + if (isEmpty(phone)) {
  134 + message.error('请填写手机号');
  135 + }
  136 + if (!validatePhoneNumberBool(phone)) {
  137 + message.error('请填写正确格式的手机号');
  138 + return;
  139 + }
  140 + let customOption = {
  141 + value: getRandomNumber(10),
  142 + realName: realName,
  143 + phone: phone,
  144 + };
  145 + autoFillCustomerInfo(customOption);
  146 + }
  147 +
  148 + function parseFormValues(values: any) {
  149 + if (!values) {
  150 + return {};
  151 + }
  152 +
  153 + let memberIds = values.members;
  154 + let accountIds = values.accounts;
  155 +
  156 + //成员对象封装
  157 + if (memberIds) {
  158 + let memberObjs: any[] = [];
  159 + for (let memberOption of memberOptions) {
  160 + if (memberIds.includes(memberOption.value)) {
  161 + memberObjs.push({
  162 + memberName: memberOption.realName,
  163 + memberPhone: memberOption.phone,
  164 + });
  165 + }
  166 + }
  167 + values.members = memberObjs;
  168 + }
  169 +
  170 + //预存账号对象封装
  171 + if (accountIds) {
  172 + let accountObjs: any[] = [];
  173 + for (let accountOption of accountOptions) {
  174 + if (accountIds.includes(accountOption.uid)) {
  175 + accountObjs.push({
  176 + accountPhone: accountOption.phone,
  177 + accountId: accountOption.uid,
  178 + accountName: accountOption.realName,
  179 + });
  180 + }
  181 + }
  182 + values.accounts = accountObjs;
  183 + }
  184 +
  185 + return values;
  186 + }
  187 +
  188 + useEffect(() => {
  189 + loadSalesCodeOptions();
  190 + }, []);
  191 + return (
  192 + <div className="research-group-index">
  193 + <ModalForm
  194 + width={800}
  195 + open
  196 + title="新增/编辑课题组"
  197 + form={form}
  198 + autoFocusFirstInput
  199 + submitter={{}}
  200 + modalProps={{
  201 + okText: '提交',
  202 + cancelText: '关闭',
  203 + destroyOnClose: true,
  204 + onCancel: () => {
  205 + setVisible(false);
  206 + },
  207 + }}
  208 + onFinish={async (values) => {
  209 + let newValues = parseFormValues(values);
  210 + let res = await postResearchGroupsAdd({
  211 + data: newValues,
  212 + });
  213 +
  214 + if (res && res.result === RESPONSE_CODE.SUCCESS) {
  215 + message.success(res.message);
  216 + onClose();
  217 + }
  218 + }}
  219 + onOpenChange={setVisible}
  220 + >
  221 + <ProForm.Group>
  222 + <ProFormText
  223 + name="group"
  224 + label="课题组名称"
  225 + placeholder="请输入课题组名称"
  226 + rules={[{ required: true, message: '请输入课题组名称' }]}
  227 + />
  228 + <ProFormSelect
  229 + name="leader"
  230 + key="leader"
  231 + width="lg"
  232 + showSearch
  233 + label="负责人"
  234 + placeholder="请输入课题组负责人"
  235 + rules={[{ required: true, message: '请输入课题组负责人' }]}
  236 + options={salesCodeOptions}
  237 + />
  238 + </ProForm.Group>
  239 +
  240 + <ProFormSelect
  241 + name="accounts"
  242 + key="accounts"
  243 + width="lg"
  244 + showSearch
  245 + label="绑定预存账号(可多选)"
  246 + placeholder="请选择预存账号"
  247 + onChange={(_, option) => {
  248 + autoAccountSelectOptions(option);
  249 + }}
  250 + rules={[{ required: true, message: '请至少选择绑定一个预存账号' }]}
  251 + fieldProps={{
  252 + mode: 'multiple',
  253 + filterOption() {
  254 + return true;
  255 + },
  256 + optionItemRender(item: any) {
  257 + let name =
  258 + item.label +
  259 + ' | ' +
  260 + item.institution +
  261 + ' | ' +
  262 + item.nowMoney +
  263 + '¥' +
  264 + ' | ' +
  265 + item.phone;
  266 + return (
  267 + <div title={name}>
  268 + <span style={{ color: '#333333' }}>{name}</span>
  269 + </div>
  270 + );
  271 + },
  272 + }}
  273 + debounceTime={1000}
  274 + request={async (value, {}) => {
  275 + const keywords = value.keyWords;
  276 + const res = await postCanrdApiUserList({
  277 + data: { keywords: keywords, pageSize: 20 },
  278 + });
  279 + let options = res?.data?.data?.map((c: any) => {
  280 + return {
  281 + ...c,
  282 + label: c.realName,
  283 + value: c.uid,
  284 + key: c.uid,
  285 + };
  286 + });
  287 + return options;
  288 + }}
  289 + />
  290 +
  291 + <ProFormSelect
  292 + name="members"
  293 + key="members"
  294 + width="lg"
  295 + showSearch
  296 + label="课题组成员"
  297 + placeholder="请添加课题组成员"
  298 + fieldProps={{
  299 + mode: 'multiple',
  300 + filterOption() {
  301 + return true;
  302 + },
  303 + optionItemRender(item: any) {
  304 + let name = item.realName + ' | ' + item.phone;
  305 + return (
  306 + <div title={name}>
  307 + <span style={{ color: '#333333' }}>{name}</span>
  308 + </div>
  309 + );
  310 + },
  311 + }}
  312 + options={memberOptions}
  313 + />
  314 +
  315 + <ProCard
  316 + title="选择或自定义课题组成员信息"
  317 + bordered
  318 + tooltip="从【客户信息】选择框中可以直接搜索客户,选中后自动添加到【课题组成员】中。也可以自定义输入【客户名称】和【手机号】,点击添加按钮手动添加到【课题组成员】中。"
  319 + >
  320 + <ProForm.Group>
  321 + <ProFormSelect
  322 + key="customerName"
  323 + label="客户信息(选择)"
  324 + width="lg"
  325 + showSearch
  326 + name="customerName"
  327 + placeholder="请选择客户信息"
  328 + onChange={(_, option) => {
  329 + autoFillCustomerInfo(option);
  330 + }}
  331 + fieldProps={{
  332 + filterOption() {
  333 + return true;
  334 + },
  335 + optionItemRender(item: any) {
  336 + if (item.type === 'add') {
  337 + return (
  338 + <div title={item.name + '(新增客户)'}>
  339 + <span style={{ color: '#333333' }}>{item.name}</span>
  340 + {' | '}
  341 + <span style={{ color: 'orange' }}>自定义</span>
  342 + </div>
  343 + );
  344 + }
  345 +
  346 + let title = '';
  347 + let spanText = '';
  348 + let realName = item.realName;
  349 + let phone = item.phone;
  350 +
  351 + title =
  352 + getDefaultString(realName) + '|' + getDefaultString(phone);
  353 +
  354 + spanText =
  355 + getDefaultString(realName) + '|' + getDefaultString(phone);
  356 + return (
  357 + <div title={title}>
  358 + <span style={{ color: '#333333' }}>{spanText}</span>
  359 + </div>
  360 + );
  361 + },
  362 + }}
  363 + debounceTime={1000}
  364 + request={async (value, {}) => {
  365 + const keywords = value.keyWords;
  366 + if (keywords === '') {
  367 + return [];
  368 + }
  369 + const res = await postCanrdApiUserAddressList({
  370 + data: { keywords: keywords },
  371 + });
  372 + let options = res?.data?.map((c: any) => {
  373 + return {
  374 + ...c,
  375 + label: c.name,
  376 + value: c.id,
  377 + key: c.id,
  378 + };
  379 + });
  380 +
  381 + //对options去重,realName和phone唯一
  382 + options = deduplicateOptions(options);
  383 +
  384 + //第一个商品默认为要新增客户
  385 + if (keywords.trim() !== '') {
  386 + options.unshift({
  387 + name: keywords,
  388 + type: 'add',
  389 + label: keywords,
  390 + value: 3.1415926,
  391 + key: keywords,
  392 + });
  393 + }
  394 +
  395 + return options;
  396 + }}
  397 + />
  398 + </ProForm.Group>
  399 +
  400 + <ProForm.Group>
  401 + <ProFormText
  402 + name="realName"
  403 + label="客户名称(自定义)"
  404 + placeholder="请输入客户名称"
  405 + rules={[{ required: false, message: '请输入客户名称' }]}
  406 + />
  407 + <ProFormText
  408 + name="phone"
  409 + label="手机号(自定义)"
  410 + width="md"
  411 + placeholder="请输入手机号"
  412 + rules={[{ required: false, message: '请输入手机号' }]}
  413 + />
  414 + </ProForm.Group>
  415 + <Button
  416 + type="primary"
  417 + onClick={() => {
  418 + addCustomMember();
  419 + }}
  420 + >
  421 + 添加
  422 + </Button>
  423 + </ProCard>
  424 + </ModalForm>
  425 + </div>
  426 + );
  427 +};
... ...
src/pages/ResearchGroup/constant.tsx 0 → 100644
  1 +export const RESEARCH_GROUP_COLUMNS = [
  2 + {
  3 + title: '序号',
  4 + dataIndex: 'index',
  5 + valueType: 'index',
  6 + width: 70,
  7 + },
  8 + {
  9 + title: 'ID',
  10 + dataIndex: 'id',
  11 + key: 'id',
  12 + valueType: 'index',
  13 + hideInSearch: true,
  14 + hideInTable: true,
  15 + },
  16 + {
  17 + title: '课题组名称',
  18 + dataIndex: 'groupName',
  19 + key: 'groupName',
  20 + fieldProps: {
  21 + placeholder: '请输入课题组名称',
  22 + },
  23 + },
  24 + {
  25 + title: '预存账号',
  26 + dataIndex: 'accounts',
  27 + key: 'accounts',
  28 + },
  29 + {
  30 + title: '课题组成员',
  31 + dataIndex: 'members',
  32 + key: 'members',
  33 + },
  34 + {
  35 + title: '负责人',
  36 + dataIndex: 'leaderName',
  37 + key: 'leaderName',
  38 + fieldProps: {
  39 + placeholder: '请输入负责人姓名',
  40 + },
  41 + },
  42 + {
  43 + title: '创建时间',
  44 + dataIndex: 'createTime',
  45 + key: 'createTime',
  46 + valueType: 'dateTime',
  47 + fieldProps: {
  48 + placeholder: '请选择创建时间',
  49 + },
  50 + },
  51 +
  52 + {
  53 + title: '创建人',
  54 + dataIndex: 'createByName',
  55 + key: 'createByName',
  56 + fieldProps: {
  57 + placeholder: '请输入选择创建人',
  58 + },
  59 + },
  60 +];
... ...
src/pages/ResearchGroup/index.less 0 → 100644
  1 +.research-group-index td {
  2 + font-family: 'San Francisco', 'Helvetica Neue', Helvetica, Arial,
  3 + 'Microsoft YaHei', 'PingFang SC', 'Hiragino Sans GB', 'Heiti SC',
  4 + 'WenQuanYi Micro Hei', sans-serif;
  5 + font-size: 13px;
  6 +}
... ...
src/pages/ResearchGroup/index.tsx 0 → 100644
  1 +import ButtonConfirm from '@/components/ButtomConfirm';
  2 +import EllipsisDiv from '@/components/Div/EllipsisDiv';
  3 +import { RESPONSE_CODE } from '@/constants/enum';
  4 +import {} from '@/pages/Invoice/constant';
  5 +import {
  6 + postCanrdApiUserDetail,
  7 + postPrepaidDelete,
  8 + postResearchGroupsList,
  9 +} from '@/services';
  10 +import { formatDateTime } from '@/utils';
  11 +import { PlusOutlined } from '@ant-design/icons';
  12 +import { ActionType, ProTable } from '@ant-design/pro-components';
  13 +import {
  14 + Button,
  15 + Col,
  16 + Divider,
  17 + Image,
  18 + Popconfirm,
  19 + Row,
  20 + Spin,
  21 + Tabs,
  22 + Tag,
  23 + message,
  24 +} from 'antd';
  25 +import React, { useRef, useState } from 'react';
  26 +import ResearchGroupAddModal from './components/ResearchGroupAddModal';
  27 +import { RESEARCH_GROUP_COLUMNS } from './constant';
  28 +import './index.less';
  29 +const PrepaidPage = () => {
  30 + const researchGroupActionRef = useRef<ActionType>();
  31 + const accountActionRef = useRef<ActionType>();
  32 + const [researchGroupAddModalVisible, setResearchGroupAddModalVisible] =
  33 + useState(false);
  34 + // const [checkVisible, setCheckVisible] = useState(false);;
  35 + const [accountInfo, setAccountInfo] = useState({
  36 + realName: '',
  37 + phone: '',
  38 + nowMoney: '',
  39 + uid: '',
  40 + });
  41 + const [accountInfoLoading, setAccountInfoLoading] = useState(false);
  42 +
  43 + const reloadResearchGroupTable = () => {
  44 + researchGroupActionRef.current?.reload();
  45 + };
  46 +
  47 + const reloadAccountTable = () => {
  48 + accountActionRef.current?.reload();
  49 + };
  50 +
  51 + // const getTableCellText = (target: any) => {
  52 + // if (!target) {
  53 + // return '';
  54 + // }
  55 +
  56 + // if (target.props) {
  57 + // return target.props.text;
  58 + // }
  59 +
  60 + // return target;
  61 + // };
  62 +
  63 + const renderMembersCell = (value: any) => {
  64 + if (!value) {
  65 + return <span></span>;
  66 + }
  67 +
  68 + return (
  69 + <div>
  70 + {value.map((item: any) => {
  71 + let memberName = item.memberName;
  72 + let memberPhone = item.memberPhone;
  73 + return (
  74 + <Tag
  75 + className="mt-1 mb-0"
  76 + key={item.id}
  77 + color="cyan"
  78 + title={memberName + ' | ' + memberPhone}
  79 + >
  80 + {memberName}
  81 + </Tag>
  82 + );
  83 + })}
  84 + </div>
  85 + );
  86 + };
  87 +
  88 + /**
  89 + * 获取预存账号信息
  90 + * @param accountId
  91 + */
  92 + const loadAccountInfo = async (accountId: any) => {
  93 + setAccountInfoLoading(true);
  94 + let res = await postCanrdApiUserDetail({ data: { uid: accountId } });
  95 + if (res && res.result === RESPONSE_CODE.SUCCESS) {
  96 + setAccountInfo(res.data);
  97 + } else {
  98 + setAccountInfo({
  99 + realName: '加载失败',
  100 + phone: '加载失败',
  101 + nowMoney: '加载失败',
  102 + uid: '加载失败',
  103 + });
  104 + }
  105 + setAccountInfoLoading(false);
  106 + };
  107 +
  108 + const renderAccountsCell = (value: any) => {
  109 + if (!value) {
  110 + return <span></span>;
  111 + }
  112 +
  113 + return (
  114 + <div>
  115 + {value.map((item: any) => {
  116 + let accountPhone = item.accountPhone;
  117 + let accountName = item.accountName;
  118 + let accountId = item.accountId;
  119 + return (
  120 + <Popconfirm
  121 + key={item.id}
  122 + title="账号详情"
  123 + description={
  124 + <div className="w-[170px]">
  125 + {accountInfoLoading ? (
  126 + <div>
  127 + <Spin />
  128 + </div>
  129 + ) : (
  130 + <div>
  131 + <Row gutter={4}>
  132 + <Col span={10}>
  133 + <div>编号:</div>
  134 + </Col>
  135 + <Col span={14}>
  136 + <div>{accountInfo.uid}</div>
  137 + </Col>
  138 + </Row>
  139 + <Row gutter={4}>
  140 + <Col span={10}>
  141 + <div>名称:</div>
  142 + </Col>
  143 + <Col span={14}>
  144 + <div>{accountInfo.realName}</div>
  145 + </Col>
  146 + </Row>
  147 + <Row gutter={4}>
  148 + <Col span={10}>
  149 + <div>手机号:</div>
  150 + </Col>
  151 + <Col span={14}>
  152 + <EllipsisDiv text={accountInfo.phone} />
  153 + </Col>
  154 + </Row>
  155 + <Row gutter={4}>
  156 + <Col span={10}>
  157 + <div>余额:</div>
  158 + </Col>
  159 + <Col span={14}>
  160 + <div>{accountInfo.nowMoney}</div>
  161 + </Col>
  162 + </Row>
  163 + </div>
  164 + )}
  165 + </div>
  166 + }
  167 + cancelButtonProps={{
  168 + hidden: true,
  169 + }}
  170 + okButtonProps={{
  171 + hidden: true,
  172 + }}
  173 + >
  174 + <Tag
  175 + className="mt-1 mb-0 hover:cursor-pointer"
  176 + color="geekblue"
  177 + title={accountName + ' | ' + accountPhone}
  178 + onClick={() => {
  179 + loadAccountInfo(accountId);
  180 + }}
  181 + >
  182 + {accountName}
  183 + </Tag>
  184 + </Popconfirm>
  185 + );
  186 + })}
  187 + </div>
  188 + );
  189 + };
  190 +
  191 + /**
  192 + * 加载发票列表表格的各个列格式
  193 + */
  194 + const researchGroupColumnsInit = () => {
  195 + let columns = RESEARCH_GROUP_COLUMNS.map((item) => {
  196 + let newItem = { ...item };
  197 + let dataIndex = item.dataIndex;
  198 +
  199 + newItem.render = (text, record, index) => {
  200 + let textValue = record[dataIndex];
  201 +
  202 + if (dataIndex.endsWith('Time')) {
  203 + textValue = formatDateTime(textValue);
  204 + }
  205 +
  206 + if (dataIndex === 'members') {
  207 + return renderMembersCell(textValue);
  208 + }
  209 +
  210 + if (dataIndex === 'accounts') {
  211 + return renderAccountsCell(textValue);
  212 + }
  213 +
  214 + if (dataIndex === 'index') {
  215 + textValue = index + 1;
  216 + }
  217 +
  218 + if (
  219 + dataIndex === 'proofImages' &&
  220 + textValue !== null &&
  221 + textValue !== undefined
  222 + ) {
  223 + return (
  224 + <Image.PreviewGroup
  225 + className="mr-10"
  226 + preview={{
  227 + onChange: (current, prev) =>
  228 + console.log(`current index: ${current}, prev index: ${prev}`),
  229 + }}
  230 + >
  231 + {textValue.map((item, index) => (
  232 + <React.Fragment key={index}>
  233 + {index > 0 ? <Divider type="vertical" /> : ''}
  234 + <Image
  235 + className="max-h-[35px] max-w-[45px]"
  236 + src={item}
  237 + title={item}
  238 + />{' '}
  239 + </React.Fragment>
  240 + ))}
  241 + </Image.PreviewGroup>
  242 + );
  243 + }
  244 +
  245 + return <EllipsisDiv text={textValue} />;
  246 + };
  247 +
  248 + return newItem;
  249 + });
  250 +
  251 + columns.push({
  252 + title: '操作',
  253 + valueType: 'option',
  254 + key: 'option',
  255 + fixed: 'right',
  256 + width: 120,
  257 + render: (text, record) => {
  258 + let btns = [];
  259 + let opts = record.operations;
  260 + if (opts?.includes('modify')) {
  261 + btns.push(
  262 + <Button
  263 + className="p-0"
  264 + key="modify"
  265 + type="link"
  266 + onClick={() => {
  267 + // setRechargePrepaymentModalVisible(true);
  268 + // setCurrentOptPrepaymentObj(cloneDeep(record));
  269 + }}
  270 + >
  271 + 编辑
  272 + </Button>,
  273 + );
  274 + }
  275 +
  276 + if (opts?.includes('audit')) {
  277 + btns.push(
  278 + <Button
  279 + className="p-0"
  280 + key="view"
  281 + type="link"
  282 + onClick={() => {
  283 + // setCurrentOptPrepaymentObj(record);
  284 + // setCheckVisible(true);
  285 + }}
  286 + >
  287 + 审核
  288 + </Button>,
  289 + );
  290 + }
  291 +
  292 + if (opts?.includes('delete')) {
  293 + btns.push(
  294 + <ButtonConfirm
  295 + key="delete"
  296 + className="p-0"
  297 + title={'确认删除这条预存记录吗?'}
  298 + text="删除"
  299 + onConfirm={async () => {
  300 + let res = await postPrepaidDelete({
  301 + data: { ids: [record.id] },
  302 + });
  303 + if (res && res.result === RESPONSE_CODE.SUCCESS) {
  304 + message.success(res.message);
  305 + reloadResearchGroupTable();
  306 + }
  307 + }}
  308 + />,
  309 + );
  310 + }
  311 + return btns;
  312 + },
  313 + });
  314 +
  315 + return columns;
  316 + };
  317 +
  318 + const tabsItems = [
  319 + {
  320 + key: 1,
  321 + label: '课题组列表',
  322 + children: (
  323 + <ProTable
  324 + columns={researchGroupColumnsInit()}
  325 + actionRef={researchGroupActionRef}
  326 + cardBordered
  327 + pagination={{
  328 + pageSize: 10,
  329 + }}
  330 + request={async (params) => {
  331 + const res = await postResearchGroupsList({
  332 + data: { ...params },
  333 + });
  334 + return {
  335 + data: res?.data?.data || [],
  336 + total: res?.data?.total || 0,
  337 + };
  338 + }}
  339 + columnsState={{
  340 + persistenceKey: 'pro-table-singe-research-group',
  341 + persistenceType: 'localStorage',
  342 + defaultValue: {
  343 + option: { fixed: 'right', disable: true },
  344 + },
  345 + onChange(value) {
  346 + console.log('value: ', value);
  347 + },
  348 + }}
  349 + rowKey="id"
  350 + search={{
  351 + labelWidth: 'auto',
  352 + }}
  353 + options={{
  354 + setting: {
  355 + listsHeight: 400,
  356 + },
  357 + }}
  358 + form={{}}
  359 + dateFormatter="string"
  360 + headerTitle="课题组列表"
  361 + scroll={{ x: 1400 }}
  362 + toolBarRender={() => [
  363 + <Button
  364 + key="button"
  365 + icon={<PlusOutlined />}
  366 + onClick={() => {
  367 + setCurrentOptPrepaymentObj(null);
  368 + setResearchGroupAddModalVisible(true);
  369 + }}
  370 + type="primary"
  371 + >
  372 + 新建
  373 + </Button>,
  374 + ]}
  375 + />
  376 + ),
  377 + },
  378 + ];
  379 + return (
  380 + <div className="research-group-index">
  381 + <Tabs
  382 + defaultActiveKey="1"
  383 + items={tabsItems}
  384 + onChange={(value) => {
  385 + if (value === '1') {
  386 + reloadResearchGroupTable();
  387 + } else {
  388 + reloadAccountTable();
  389 + }
  390 + }}
  391 + />
  392 +
  393 + {researchGroupAddModalVisible && (
  394 + <ResearchGroupAddModal
  395 + setVisible={(val: boolean) => {
  396 + setResearchGroupAddModalVisible(val);
  397 + }}
  398 + onClose={() => {
  399 + setResearchGroupAddModalVisible(false);
  400 + }}
  401 + />
  402 + )}
  403 + </div>
  404 + );
  405 +};
  406 +
  407 +export default PrepaidPage;
... ...
src/services/definition.ts
... ... @@ -1668,6 +1668,177 @@ export interface ReissueInvoiceDto {
1668 1668 notes?: string;
1669 1669 }
1670 1670  
  1671 +export interface ResearchGroupAccountAddRequest {
  1672 + /**
  1673 + * @description
  1674 + * 关联的账号id
  1675 + * @format int64
  1676 + */
  1677 + accountId?: number;
  1678 + /**
  1679 + * @description
  1680 + * 关联的账号手机号
  1681 + */
  1682 + accountPhone?: string;
  1683 + /**
  1684 + * @description
  1685 + * 课题组id
  1686 + * @format int64
  1687 + */
  1688 + groupId?: number;
  1689 +}
  1690 +
  1691 +export interface ResearchGroupAccountEditRequest {
  1692 + /**
  1693 + * @description
  1694 + * 关联的账号id
  1695 + * @format int64
  1696 + */
  1697 + accountId?: number;
  1698 + /**
  1699 + * @description
  1700 + * 关联的账号手机号
  1701 + */
  1702 + accountPhone?: string;
  1703 + /**
  1704 + * @description
  1705 + * 课题组id
  1706 + * @format int64
  1707 + */
  1708 + groupId?: number;
  1709 + /**
  1710 + * @description
  1711 + * 主键id
  1712 + * @format int64
  1713 + */
  1714 + id?: number;
  1715 +}
  1716 +
  1717 +export interface ResearchGroupAddRequest {
  1718 + accounts?: Array<ResearchGroupAccountAddRequest>;
  1719 + /**
  1720 + * @description
  1721 + * 课题组名称
  1722 + */
  1723 + group?: string;
  1724 + /**
  1725 + * @description
  1726 + * 课题组负责人
  1727 + */
  1728 + leader?: string;
  1729 + members?: Array<ResearchGroupMemberAddRequest>;
  1730 +}
  1731 +
  1732 +export interface ResearchGroupDeleteRequest {
  1733 + /**
  1734 + * @description
  1735 + * 主键id
  1736 + */
  1737 + ids?: Array<number>;
  1738 +}
  1739 +
  1740 +export interface ResearchGroupEditRequest {
  1741 + /**
  1742 + * @description
  1743 + * 课题组预存账号
  1744 + */
  1745 + accounts?: Array<ResearchGroupAccountEditRequest>;
  1746 + /**
  1747 + * @description
  1748 + * 课题组名称
  1749 + */
  1750 + group?: string;
  1751 + /**
  1752 + * @description
  1753 + * 主键id
  1754 + * @format int64
  1755 + */
  1756 + id?: number;
  1757 + /**
  1758 + * @description
  1759 + * 课题组负责人
  1760 + */
  1761 + leader?: string;
  1762 + /**
  1763 + * @description
  1764 + * 课题组成员集合
  1765 + */
  1766 + members?: Array<ResearchGroupMemberEditRequest>;
  1767 +}
  1768 +
  1769 +export interface ResearchGroupListRequest {
  1770 + /** @format int32 */
  1771 + current?: number;
  1772 + /**
  1773 + * @description
  1774 + * 课题组名称
  1775 + */
  1776 + group?: string;
  1777 + /**
  1778 + * @description
  1779 + * 课题组负责人
  1780 + */
  1781 + leader?: string;
  1782 + /**
  1783 + * @description
  1784 + * 课题组成员名称
  1785 + */
  1786 + memberName?: string;
  1787 + /**
  1788 + * @description
  1789 + * 课题组成员手机号
  1790 + */
  1791 + memberPhone?: string;
  1792 + /** @format int32 */
  1793 + pageSize?: number;
  1794 + /** @format int32 */
  1795 + total?: number;
  1796 +}
  1797 +
  1798 +export interface ResearchGroupMemberAddRequest {
  1799 + /**
  1800 + * @description
  1801 + * 课题组ID
  1802 + * @format int64
  1803 + */
  1804 + groupId?: number;
  1805 + /**
  1806 + * @description
  1807 + * 成员名称
  1808 + */
  1809 + memberName?: string;
  1810 + /**
  1811 + * @description
  1812 + * 成员手机号
  1813 + */
  1814 + memberPhone?: string;
  1815 +}
  1816 +
  1817 +export interface ResearchGroupMemberEditRequest {
  1818 + /**
  1819 + * @description
  1820 + * 课题组ID
  1821 + * @format int64
  1822 + */
  1823 + groupId?: number;
  1824 + /**
  1825 + * @description
  1826 + * 主键id
  1827 + * @format int64
  1828 + */
  1829 + id?: number;
  1830 + /**
  1831 + * @description
  1832 + * 成员名称
  1833 + */
  1834 + memberName?: string;
  1835 + /**
  1836 + * @description
  1837 + * 成员手机号
  1838 + */
  1839 + memberPhone?: string;
  1840 +}
  1841 +
1671 1842 export interface ResetPwdVO {
1672 1843 /** @format int64 */
1673 1844 userId?: number;
... ... @@ -2284,6 +2455,38 @@ export interface StoreOrderInvoiceRequest {
2284 2455 updateTime?: string;
2285 2456 }
2286 2457  
  2458 +/**
  2459 + * @description
  2460 + * 保存用户地址请求对象
  2461 + */
  2462 +export interface UserAddressSaveRequest {
  2463 + /**
  2464 + * @description
  2465 + * 联系电话
  2466 + */
  2467 + customerContactNumber: string;
  2468 + /**
  2469 + * @description
  2470 + * 客户姓名
  2471 + */
  2472 + customerName: string;
  2473 + /**
  2474 + * @description
  2475 + * 收货地址
  2476 + */
  2477 + customerShippingAddress?: string;
  2478 + /**
  2479 + * @description
  2480 + * 客户单位
  2481 + */
  2482 + institution?: string;
  2483 + /**
  2484 + * @description
  2485 + * 课题组老师
  2486 + */
  2487 + institutionContactName?: string;
  2488 +}
  2489 +
2287 2490 export interface UploadPaymentReceiptDTO {
2288 2491 /**
2289 2492 * @description
... ...
src/services/request.ts
... ... @@ -74,6 +74,10 @@ import type {
74 74 QueryMainOrderDto,
75 75 QueryReportFormsDto,
76 76 ReissueInvoiceDto,
  77 + ResearchGroupAddRequest,
  78 + ResearchGroupDeleteRequest,
  79 + ResearchGroupEditRequest,
  80 + ResearchGroupListRequest,
77 81 ResetPwdVO,
78 82 SalOrderSaveDto,
79 83 SalesRechargePrepaymentAuditRequest,
... ... @@ -95,6 +99,7 @@ import type {
95 99 UpdatePwdVO,
96 100 UploadPaymentReceiptDTO,
97 101 UserAddressListRequest,
  102 + UserAddressSaveRequest,
98 103 UserCenterInfoRequest,
99 104 UserDetailRequest,
100 105 UserListRequest,
... ... @@ -1460,6 +1465,78 @@ export const postCanrdApiUserDetail = /* #__PURE__ */ (() =&gt; {
1460 1465 return request;
1461 1466 })();
1462 1467  
  1468 +/** @description request parameter type for postCanrdApiUserInnerOrderSystemAddressSave */
  1469 +export interface PostCanrdApiUserInnerOrderSystemAddressSaveOption {
  1470 + /**
  1471 + * @description
  1472 + * request
  1473 + */
  1474 + body: {
  1475 + /**
  1476 + @description
  1477 + request */
  1478 + request: UserAddressSaveRequest;
  1479 + };
  1480 +}
  1481 +
  1482 +/** @description response type for postCanrdApiUserInnerOrderSystemAddressSave */
  1483 +export interface PostCanrdApiUserInnerOrderSystemAddressSaveResponse {
  1484 + /**
  1485 + * @description
  1486 + * OK
  1487 + */
  1488 + 200: ServerResult;
  1489 + /**
  1490 + * @description
  1491 + * Created
  1492 + */
  1493 + 201: any;
  1494 + /**
  1495 + * @description
  1496 + * Unauthorized
  1497 + */
  1498 + 401: any;
  1499 + /**
  1500 + * @description
  1501 + * Forbidden
  1502 + */
  1503 + 403: any;
  1504 + /**
  1505 + * @description
  1506 + * Not Found
  1507 + */
  1508 + 404: any;
  1509 +}
  1510 +
  1511 +export type PostCanrdApiUserInnerOrderSystemAddressSaveResponseSuccess =
  1512 + PostCanrdApiUserInnerOrderSystemAddressSaveResponse[200];
  1513 +/**
  1514 + * @description
  1515 + * 查询地址信息
  1516 + * @tags canrd-mobile-api-controller
  1517 + * @produces *
  1518 + * @consumes application/json
  1519 + */
  1520 +export const postCanrdApiUserInnerOrderSystemAddressSave =
  1521 + /* #__PURE__ */ (() => {
  1522 + const method = 'post';
  1523 + const url = '/canrd/api/user/innerOrderSystem/address/save';
  1524 + function request(
  1525 + option: PostCanrdApiUserInnerOrderSystemAddressSaveOption,
  1526 + ): Promise<PostCanrdApiUserInnerOrderSystemAddressSaveResponseSuccess> {
  1527 + return requester(request.url, {
  1528 + method: request.method,
  1529 + ...option,
  1530 + }) as unknown as Promise<PostCanrdApiUserInnerOrderSystemAddressSaveResponseSuccess>;
  1531 + }
  1532 +
  1533 + /** http method */
  1534 + request.method = method;
  1535 + /** request url */
  1536 + request.url = url;
  1537 + return request;
  1538 + })();
  1539 +
1463 1540 /** @description request parameter type for postCanrdApiUserList */
1464 1541 export interface PostCanrdApiUserListOption {
1465 1542 /**
... ... @@ -7551,6 +7628,290 @@ export const postPrepaidUpdate = /* #__PURE__ */ (() =&gt; {
7551 7628 return request;
7552 7629 })();
7553 7630  
  7631 +/** @description request parameter type for postResearchGroupsAdd */
  7632 +export interface PostResearchGroupsAddOption {
  7633 + /**
  7634 + * @description
  7635 + * request
  7636 + */
  7637 + body: {
  7638 + /**
  7639 + @description
  7640 + request */
  7641 + request: ResearchGroupAddRequest;
  7642 + };
  7643 +}
  7644 +
  7645 +/** @description response type for postResearchGroupsAdd */
  7646 +export interface PostResearchGroupsAddResponse {
  7647 + /**
  7648 + * @description
  7649 + * OK
  7650 + */
  7651 + 200: ServerResult;
  7652 + /**
  7653 + * @description
  7654 + * Created
  7655 + */
  7656 + 201: any;
  7657 + /**
  7658 + * @description
  7659 + * Unauthorized
  7660 + */
  7661 + 401: any;
  7662 + /**
  7663 + * @description
  7664 + * Forbidden
  7665 + */
  7666 + 403: any;
  7667 + /**
  7668 + * @description
  7669 + * Not Found
  7670 + */
  7671 + 404: any;
  7672 +}
  7673 +
  7674 +export type PostResearchGroupsAddResponseSuccess =
  7675 + PostResearchGroupsAddResponse[200];
  7676 +/**
  7677 + * @description
  7678 + * 新增课题组信息
  7679 + * @tags research-groups-controller
  7680 + * @produces *
  7681 + * @consumes application/json
  7682 + */
  7683 +export const postResearchGroupsAdd = /* #__PURE__ */ (() => {
  7684 + const method = 'post';
  7685 + const url = '/research/groups/add';
  7686 + function request(
  7687 + option: PostResearchGroupsAddOption,
  7688 + ): Promise<PostResearchGroupsAddResponseSuccess> {
  7689 + return requester(request.url, {
  7690 + method: request.method,
  7691 + ...option,
  7692 + }) as unknown as Promise<PostResearchGroupsAddResponseSuccess>;
  7693 + }
  7694 +
  7695 + /** http method */
  7696 + request.method = method;
  7697 + /** request url */
  7698 + request.url = url;
  7699 + return request;
  7700 +})();
  7701 +
  7702 +/** @description request parameter type for postResearchGroupsDelete */
  7703 +export interface PostResearchGroupsDeleteOption {
  7704 + /**
  7705 + * @description
  7706 + * request
  7707 + */
  7708 + body: {
  7709 + /**
  7710 + @description
  7711 + request */
  7712 + request: ResearchGroupDeleteRequest;
  7713 + };
  7714 +}
  7715 +
  7716 +/** @description response type for postResearchGroupsDelete */
  7717 +export interface PostResearchGroupsDeleteResponse {
  7718 + /**
  7719 + * @description
  7720 + * OK
  7721 + */
  7722 + 200: ServerResult;
  7723 + /**
  7724 + * @description
  7725 + * Created
  7726 + */
  7727 + 201: any;
  7728 + /**
  7729 + * @description
  7730 + * Unauthorized
  7731 + */
  7732 + 401: any;
  7733 + /**
  7734 + * @description
  7735 + * Forbidden
  7736 + */
  7737 + 403: any;
  7738 + /**
  7739 + * @description
  7740 + * Not Found
  7741 + */
  7742 + 404: any;
  7743 +}
  7744 +
  7745 +export type PostResearchGroupsDeleteResponseSuccess =
  7746 + PostResearchGroupsDeleteResponse[200];
  7747 +/**
  7748 + * @description
  7749 + * 删除课题组信息
  7750 + * @tags research-groups-controller
  7751 + * @produces *
  7752 + * @consumes application/json
  7753 + */
  7754 +export const postResearchGroupsDelete = /* #__PURE__ */ (() => {
  7755 + const method = 'post';
  7756 + const url = '/research/groups/delete';
  7757 + function request(
  7758 + option: PostResearchGroupsDeleteOption,
  7759 + ): Promise<PostResearchGroupsDeleteResponseSuccess> {
  7760 + return requester(request.url, {
  7761 + method: request.method,
  7762 + ...option,
  7763 + }) as unknown as Promise<PostResearchGroupsDeleteResponseSuccess>;
  7764 + }
  7765 +
  7766 + /** http method */
  7767 + request.method = method;
  7768 + /** request url */
  7769 + request.url = url;
  7770 + return request;
  7771 +})();
  7772 +
  7773 +/** @description request parameter type for postResearchGroupsEdit */
  7774 +export interface PostResearchGroupsEditOption {
  7775 + /**
  7776 + * @description
  7777 + * request
  7778 + */
  7779 + body: {
  7780 + /**
  7781 + @description
  7782 + request */
  7783 + request: ResearchGroupEditRequest;
  7784 + };
  7785 +}
  7786 +
  7787 +/** @description response type for postResearchGroupsEdit */
  7788 +export interface PostResearchGroupsEditResponse {
  7789 + /**
  7790 + * @description
  7791 + * OK
  7792 + */
  7793 + 200: ServerResult;
  7794 + /**
  7795 + * @description
  7796 + * Created
  7797 + */
  7798 + 201: any;
  7799 + /**
  7800 + * @description
  7801 + * Unauthorized
  7802 + */
  7803 + 401: any;
  7804 + /**
  7805 + * @description
  7806 + * Forbidden
  7807 + */
  7808 + 403: any;
  7809 + /**
  7810 + * @description
  7811 + * Not Found
  7812 + */
  7813 + 404: any;
  7814 +}
  7815 +
  7816 +export type PostResearchGroupsEditResponseSuccess =
  7817 + PostResearchGroupsEditResponse[200];
  7818 +/**
  7819 + * @description
  7820 + * 编辑课题组信息
  7821 + * @tags research-groups-controller
  7822 + * @produces *
  7823 + * @consumes application/json
  7824 + */
  7825 +export const postResearchGroupsEdit = /* #__PURE__ */ (() => {
  7826 + const method = 'post';
  7827 + const url = '/research/groups/edit';
  7828 + function request(
  7829 + option: PostResearchGroupsEditOption,
  7830 + ): Promise<PostResearchGroupsEditResponseSuccess> {
  7831 + return requester(request.url, {
  7832 + method: request.method,
  7833 + ...option,
  7834 + }) as unknown as Promise<PostResearchGroupsEditResponseSuccess>;
  7835 + }
  7836 +
  7837 + /** http method */
  7838 + request.method = method;
  7839 + /** request url */
  7840 + request.url = url;
  7841 + return request;
  7842 +})();
  7843 +
  7844 +/** @description request parameter type for postResearchGroupsList */
  7845 +export interface PostResearchGroupsListOption {
  7846 + /**
  7847 + * @description
  7848 + * request
  7849 + */
  7850 + body: {
  7851 + /**
  7852 + @description
  7853 + request */
  7854 + request: ResearchGroupListRequest;
  7855 + };
  7856 +}
  7857 +
  7858 +/** @description response type for postResearchGroupsList */
  7859 +export interface PostResearchGroupsListResponse {
  7860 + /**
  7861 + * @description
  7862 + * OK
  7863 + */
  7864 + 200: ServerResult;
  7865 + /**
  7866 + * @description
  7867 + * Created
  7868 + */
  7869 + 201: any;
  7870 + /**
  7871 + * @description
  7872 + * Unauthorized
  7873 + */
  7874 + 401: any;
  7875 + /**
  7876 + * @description
  7877 + * Forbidden
  7878 + */
  7879 + 403: any;
  7880 + /**
  7881 + * @description
  7882 + * Not Found
  7883 + */
  7884 + 404: any;
  7885 +}
  7886 +
  7887 +export type PostResearchGroupsListResponseSuccess =
  7888 + PostResearchGroupsListResponse[200];
  7889 +/**
  7890 + * @description
  7891 + * 课题组列表
  7892 + * @tags research-groups-controller
  7893 + * @produces *
  7894 + * @consumes application/json
  7895 + */
  7896 +export const postResearchGroupsList = /* #__PURE__ */ (() => {
  7897 + const method = 'post';
  7898 + const url = '/research/groups/list';
  7899 + function request(
  7900 + option: PostResearchGroupsListOption,
  7901 + ): Promise<PostResearchGroupsListResponseSuccess> {
  7902 + return requester(request.url, {
  7903 + method: request.method,
  7904 + ...option,
  7905 + }) as unknown as Promise<PostResearchGroupsListResponseSuccess>;
  7906 + }
  7907 +
  7908 + /** http method */
  7909 + request.method = method;
  7910 + /** request url */
  7911 + request.url = url;
  7912 + return request;
  7913 +})();
  7914 +
7554 7915 /** @description request parameter type for postServiceBankStatementDeleteBankStatement */
7555 7916 export interface PostServiceBankStatementDeleteBankStatementOption {
7556 7917 /**
... ...
src/utils/numberUtil.ts 0 → 100644
  1 +export function getRandomNumber(numDigits: number) {
  2 + if (numDigits <= 0) {
  3 + throw new Error('Number of digits must be greater than 0');
  4 + }
  5 +
  6 + const min = Math.pow(10, numDigits - 1);
  7 + const max = Math.pow(10, numDigits) - 1;
  8 + return Math.floor(Math.random() * (max - min + 1)) + min;
  9 +}
... ...
src/utils/order.ts
  1 +import { postServiceOrderQuerySalesCode } from '@/services';
1 2 import { cloneDeep } from 'lodash';
2 3 import { getUserInfo } from '.';
3 4 export function getReceivingCompanyOptions(PAYEE_OPTIONS: any) {
... ... @@ -63,3 +64,17 @@ export function isFinance() {
63 64 }
64 65 return false;
65 66 }
  67 +/**
  68 + * 获取销售代码枚举,在复制和编辑的时候判断是否为旧的代码
  69 + */
  70 +export const getSalesCodeOptions = async () => {
  71 + const res = await postServiceOrderQuerySalesCode();
  72 + let options = res.data?.map((item) => {
  73 + return {
  74 + label: item.userName,
  75 + value: item.userName,
  76 + number: item.number,
  77 + };
  78 + });
  79 + return options;
  80 +};
... ...
src/utils/validators.ts
... ... @@ -5,3 +5,8 @@ export const validatePhoneNumber = (_: any, value: any) =&gt; {
5 5 }
6 6 return Promise.reject('请输入正确的电话号码格式(例如:13789758969)');
7 7 };
  8 +
  9 +export const validatePhoneNumberBool = (phoneNumber: any) => {
  10 + const regex = /^1[3456789]\d{9}$/;
  11 + return regex.test(phoneNumber);
  12 +};
... ...