diff --git a/src/pages/ResearchGroup/components/ResearchGroupAddModal.tsx b/src/pages/ResearchGroup/components/ResearchGroupAddModal.tsx index 8affc20..c0f340e 100644 --- a/src/pages/ResearchGroup/components/ResearchGroupAddModal.tsx +++ b/src/pages/ResearchGroup/components/ResearchGroupAddModal.tsx @@ -3,6 +3,7 @@ import { postCanrdApiUserAddressList, postCanrdApiUserList, postResearchGroupsAdd, + postResearchGroupsDetail, } from '@/services'; import { getDefaultString, isEmpty } from '@/utils/StringUtil'; import { getRandomNumber } from '@/utils/numberUtil'; @@ -15,16 +16,34 @@ import { ProFormSelect, ProFormText, } from '@ant-design/pro-components'; -import { Button, Form, message } from 'antd'; +import { Button, Form, Spin, message } from 'antd'; import { useEffect, useState } from 'react'; import '../index.less'; // import { cloneDeep } from 'lodash'; -export default ({ setVisible, onClose }) => { +export default ({ setVisible, researchGroupId, onClose }) => { const [form] = Form.useForm(); const [salesCodeOptions, setSalesCodeOptions] = useState([]); const [memberOptions, setMemberOptions] = useState<any[]>([]); const [accountOptions, setAccountOptions] = useState<any[]>([]); + const [researchGroupInfo, setResearchGroupInfo] = useState<any>(null); + const [modalLoading, setModalLoading] = useState(false); + + /** + * 获取课题组信息 + * @returns + */ + const loadResearchGroupInfo = async () => { + if (researchGroupId === null) { + return; + } + setModalLoading(true); + let res = await postResearchGroupsDetail({ data: { id: researchGroupId } }); + if (res && res.result === RESPONSE_CODE.SUCCESS) { + setResearchGroupInfo(res.data); + } + setModalLoading(false); + }; /** * 获取销售代码枚举,在复制和编辑的时候判断是否为旧的代码 @@ -185,9 +204,62 @@ export default ({ setVisible, onClose }) => { return values; } + /** + * 设置表单默认信息 + * @returns + */ + const loadFormDefaultValue = async () => { + if (!researchGroupInfo) { + return; + } + + let members = researchGroupInfo.members; + if (members !== null) { + let newMemberOptions = []; + for (let member of members) { + let name = member.memberName; + let phone = member.memberPhone; + let id = member.id; + newMemberOptions.push({ realName: name, phone: phone, value: id }); + } + setMemberOptions(newMemberOptions); + form.setFieldValue( + 'members', + members?.map((item: any) => { + return item.id; + }), + ); + } + + let accounts = researchGroupInfo.accounts; + if (accounts !== null) { + let accountIds = accounts.map((item: any) => { + return item.id; + }); + let res = await postCanrdApiUserList({ data: { uids: accountIds } }); + if (res && res.result === RESPONSE_CODE.SUCCESS && res.data) { + let newAccountOptions = res?.data?.map((item) => { + item.value = item.id; + return item; + }); + setAccountOptions(newAccountOptions); + form.setFieldValue('accounts', accountIds); + } + } + + form.setFieldValue('group', researchGroupInfo.groupName); + form.setFieldValue('leader', researchGroupInfo.leaderName); + }; + useEffect(() => { loadSalesCodeOptions(); + loadResearchGroupInfo(); }, []); + + useEffect(() => { + loadFormDefaultValue(); + }, [researchGroupInfo]); + return ( <div className="research-group-index"> <ModalForm @@ -218,209 +290,215 @@ export default ({ setVisible, onClose }) => { }} onOpenChange={setVisible} > - <ProForm.Group> - <ProFormText - name="group" - label="课题组名称" - placeholder="请输入课题组名称" - rules={[{ required: true, message: '请输入课题组名称' }]} + <Spin spinning={modalLoading} tip="加载中..."> + <ProForm.Group> + <ProFormText + name="group" + label="课题组名称" + placeholder="请输入课题组名称" + rules={[{ required: true, message: '请输入课题组名称' }]} + /> + <ProFormSelect + name="leader" + key="leader" + width="lg" + showSearch + label="负责人" + placeholder="请输入课题组负责人" + rules={[{ required: true, message: '请输入课题组负责人' }]} + options={salesCodeOptions} + /> + </ProForm.Group> + + <ProFormSelect + name="accounts" + key="accounts" + width="lg" + showSearch + label="绑定预存账号(可多选)" + placeholder="请选择预存账号" + onChange={(_, option) => { + autoAccountSelectOptions(option); + }} + rules={[{ required: true, message: '请至少选择绑定一个预存账号' }]} + fieldProps={{ + mode: 'multiple', + filterOption() { + return true; + }, + optionItemRender(item: any) { + let name = + item.label + + ' | ' + + item.institution + + ' | ' + + item.nowMoney + + '¥' + + ' | ' + + item.phone; + return ( + <div title={name}> + <span style={{ color: '#333333' }}>{name}</span> + </div> + ); + }, + }} + debounceTime={1000} + request={async (value, {}) => { + const keywords = value.keyWords; + const res = await postCanrdApiUserList({ + data: { keywords: keywords, pageSize: 20 }, + }); + let options = res?.data?.data?.map((c: any) => { + return { + ...c, + label: c.realName, + value: c.uid, + key: c.uid, + }; + }); + return options; + }} /> + <ProFormSelect - name="leader" - key="leader" + name="members" + key="members" width="lg" showSearch - label="负责人" - placeholder="请输入课题组负责人" - rules={[{ required: true, message: '请输入课题组负责人' }]} - options={salesCodeOptions} + label="课题组成员" + placeholder="请添加课题组成员" + fieldProps={{ + mode: 'multiple', + filterOption() { + return true; + }, + optionItemRender(item: any) { + let name = item.realName + ' | ' + item.phone; + return ( + <div title={name}> + <span style={{ color: '#333333' }}>{name}</span> + </div> + ); + }, + }} + options={memberOptions} /> - </ProForm.Group> - <ProFormSelect - name="accounts" - key="accounts" - width="lg" - showSearch - label="绑定预存账号(可多选)" - placeholder="请选择预存账号" - onChange={(_, option) => { - autoAccountSelectOptions(option); - }} - rules={[{ required: true, message: '请至少选择绑定一个预存账号' }]} - fieldProps={{ - mode: 'multiple', - filterOption() { - return true; - }, - optionItemRender(item: any) { - let name = - item.label + - ' | ' + - item.institution + - ' | ' + - item.nowMoney + - '¥' + - ' | ' + - item.phone; - return ( - <div title={name}> - <span style={{ color: '#333333' }}>{name}</span> - </div> - ); - }, - }} - debounceTime={1000} - request={async (value, {}) => { - const keywords = value.keyWords; - const res = await postCanrdApiUserList({ - data: { keywords: keywords, pageSize: 20 }, - }); - let options = res?.data?.data?.map((c: any) => { - return { - ...c, - label: c.realName, - value: c.uid, - key: c.uid, - }; - }); - return options; - }} - /> + <ProCard + title="选择或自定义课题组成员信息" + bordered + tooltip="从【客户信息】选择框中可以直接搜索客户,选中后自动添加到【课题组成员】中。也可以自定义输入【客户名称】和【手机号】,点击添加按钮手动添加到【课题组成员】中。" + > + <ProForm.Group> + <ProFormSelect + key="customerName" + label="客户信息(选择)" + width="lg" + showSearch + name="customerName" + placeholder="请选择客户信息" + onChange={(_, option) => { + autoFillCustomerInfo(option); + }} + fieldProps={{ + filterOption() { + return true; + }, + optionItemRender(item: any) { + if (item.type === 'add') { + return ( + <div title={item.name + '(新增客户)'}> + <span style={{ color: '#333333' }}>{item.name}</span> + {' | '} + <span style={{ color: 'orange' }}>自定义</span> + </div> + ); + } - <ProFormSelect - name="members" - key="members" - width="lg" - showSearch - label="课题组成员" - placeholder="请添加课题组成员" - fieldProps={{ - mode: 'multiple', - filterOption() { - return true; - }, - optionItemRender(item: any) { - let name = item.realName + ' | ' + item.phone; - return ( - <div title={name}> - <span style={{ color: '#333333' }}>{name}</span> - </div> - ); - }, - }} - options={memberOptions} - /> + let title = ''; + let spanText = ''; + let realName = item.realName; + let phone = item.phone; - <ProCard - title="选择或自定义课题组成员信息" - bordered - tooltip="从【客户信息】选择框中可以直接搜索客户,选中后自动添加到【课题组成员】中。也可以自定义输入【客户名称】和【手机号】,点击添加按钮手动添加到【课题组成员】中。" - > - <ProForm.Group> - <ProFormSelect - key="customerName" - label="客户信息(选择)" - width="lg" - showSearch - name="customerName" - placeholder="请选择客户信息" - onChange={(_, option) => { - autoFillCustomerInfo(option); - }} - fieldProps={{ - filterOption() { - return true; - }, - optionItemRender(item: any) { - if (item.type === 'add') { + title = + getDefaultString(realName) + + '|' + + getDefaultString(phone); + + spanText = + getDefaultString(realName) + + '|' + + getDefaultString(phone); return ( - <div title={item.name + '(新增客户)'}> - <span style={{ color: '#333333' }}>{item.name}</span> - {' | '} - <span style={{ color: 'orange' }}>自定义</span> + <div title={title}> + <span style={{ color: '#333333' }}>{spanText}</span> </div> ); + }, + }} + debounceTime={1000} + request={async (value, {}) => { + const keywords = value.keyWords; + if (keywords === '') { + return []; } + const res = await postCanrdApiUserAddressList({ + data: { keywords: keywords }, + }); + let options = res?.data?.map((c: any) => { + return { + ...c, + label: c.name, + value: c.id, + key: c.id, + }; + }); - let title = ''; - let spanText = ''; - let realName = item.realName; - let phone = item.phone; - - title = - getDefaultString(realName) + '|' + getDefaultString(phone); + //对options去重,realName和phone唯一 + options = deduplicateOptions(options); - spanText = - getDefaultString(realName) + '|' + getDefaultString(phone); - return ( - <div title={title}> - <span style={{ color: '#333333' }}>{spanText}</span> - </div> - ); - }, - }} - debounceTime={1000} - request={async (value, {}) => { - const keywords = value.keyWords; - if (keywords === '') { - return []; - } - const res = await postCanrdApiUserAddressList({ - data: { keywords: keywords }, - }); - let options = res?.data?.map((c: any) => { - return { - ...c, - label: c.name, - value: c.id, - key: c.id, - }; - }); + //第一个商品默认为要新增客户 + if (keywords.trim() !== '') { + options.unshift({ + name: keywords, + type: 'add', + label: keywords, + value: 3.1415926, + key: keywords, + }); + } - //对options去重,realName和phone唯一 - options = deduplicateOptions(options); + return options; + }} + /> + </ProForm.Group> - //第一个商品默认为要新增客户 - if (keywords.trim() !== '') { - options.unshift({ - name: keywords, - type: 'add', - label: keywords, - value: 3.1415926, - key: keywords, - }); - } - - return options; + <ProForm.Group> + <ProFormText + name="realName" + label="客户名称(自定义)" + placeholder="请输入客户名称" + rules={[{ required: false, message: '请输入客户名称' }]} + /> + <ProFormText + name="phone" + label="手机号(自定义)" + width="md" + placeholder="请输入手机号" + rules={[{ required: false, message: '请输入手机号' }]} + /> + </ProForm.Group> + <Button + type="primary" + onClick={() => { + addCustomMember(); }} - /> - </ProForm.Group> - - <ProForm.Group> - <ProFormText - name="realName" - label="客户名称(自定义)" - placeholder="请输入客户名称" - rules={[{ required: false, message: '请输入客户名称' }]} - /> - <ProFormText - name="phone" - label="手机号(自定义)" - width="md" - placeholder="请输入手机号" - rules={[{ required: false, message: '请输入手机号' }]} - /> - </ProForm.Group> - <Button - type="primary" - onClick={() => { - addCustomMember(); - }} - > - 添加 - </Button> - </ProCard> + > + 添加 + </Button> + </ProCard> + </Spin> </ModalForm> </div> ); diff --git a/src/pages/ResearchGroup/index.tsx b/src/pages/ResearchGroup/index.tsx index c61e473..f5ab16d 100644 --- a/src/pages/ResearchGroup/index.tsx +++ b/src/pages/ResearchGroup/index.tsx @@ -4,7 +4,7 @@ import { RESPONSE_CODE } from '@/constants/enum'; import {} from '@/pages/Invoice/constant'; import { postCanrdApiUserDetail, - postPrepaidDelete, + postResearchGroupsDelete, postResearchGroupsList, } from '@/services'; import { formatDateTime } from '@/utils'; @@ -31,7 +31,7 @@ const PrepaidPage = () => { const accountActionRef = useRef<ActionType>(); const [researchGroupAddModalVisible, setResearchGroupAddModalVisible] = useState(false); - // const [checkVisible, setCheckVisible] = useState(false);; + // const [checkVisible, setCheckVisible] = useState(false); const [accountInfo, setAccountInfo] = useState({ realName: '', phone: '', @@ -39,6 +39,8 @@ const PrepaidPage = () => { uid: '', }); const [accountInfoLoading, setAccountInfoLoading] = useState(false); + const [perms, setPerms] = useState<string[]>([]); + const [optRecordId, setOptRecordId] = useState<any>(null); const reloadResearchGroupTable = () => { researchGroupActionRef.current?.reload(); @@ -256,16 +258,15 @@ const PrepaidPage = () => { width: 120, render: (text, record) => { let btns = []; - let opts = record.operations; - if (opts?.includes('modify')) { + if (perms?.includes('modify')) { btns.push( <Button className="p-0" key="modify" type="link" onClick={() => { - // setRechargePrepaymentModalVisible(true); - // setCurrentOptPrepaymentObj(cloneDeep(record)); + setResearchGroupAddModalVisible(true); + setOptRecordId(record?.id); }} > 编辑 @@ -273,31 +274,15 @@ const PrepaidPage = () => { ); } - if (opts?.includes('audit')) { - btns.push( - <Button - className="p-0" - key="view" - type="link" - onClick={() => { - // setCurrentOptPrepaymentObj(record); - // setCheckVisible(true); - }} - > - 审核 - </Button>, - ); - } - - if (opts?.includes('delete')) { + if (perms?.includes('delete')) { btns.push( <ButtonConfirm key="delete" className="p-0" - title={'确认删除这条预存记录吗?'} + title={'确认删除这个课题组吗?'} text="删除" onConfirm={async () => { - let res = await postPrepaidDelete({ + let res = await postResearchGroupsDelete({ data: { ids: [record.id] }, }); if (res && res.result === RESPONSE_CODE.SUCCESS) { @@ -331,6 +316,7 @@ const PrepaidPage = () => { const res = await postResearchGroupsList({ data: { ...params }, }); + setPerms(res.data.specialPath); return { data: res?.data?.data || [], total: res?.data?.total || 0, @@ -359,19 +345,25 @@ const PrepaidPage = () => { dateFormatter="string" headerTitle="课题组列表" scroll={{ x: 1400 }} - toolBarRender={() => [ - <Button - key="button" - icon={<PlusOutlined />} - onClick={() => { - setCurrentOptPrepaymentObj(null); - setResearchGroupAddModalVisible(true); - }} - type="primary" - > - 新建 - </Button>, - ]} + toolBarRender={() => { + let btns = []; + if (perms.includes('add')) { + btns.push( + <Button + key="button" + icon={<PlusOutlined />} + onClick={() => { + setResearchGroupAddModalVisible(true); + }} + type="primary" + > + 新建 + </Button>, + ); + } + + return btns; + }} /> ), }, @@ -394,9 +386,12 @@ const PrepaidPage = () => { <ResearchGroupAddModal setVisible={(val: boolean) => { setResearchGroupAddModalVisible(val); + setOptRecordId(null); }} + researchGroupId={optRecordId} onClose={() => { setResearchGroupAddModalVisible(false); + setOptRecordId(null); }} /> )} diff --git a/src/services/definition.ts b/src/services/definition.ts index 3c51efd..da42e0c 100644 --- a/src/services/definition.ts +++ b/src/services/definition.ts @@ -1677,6 +1677,11 @@ export interface ResearchGroupAccountAddRequest { accountId?: number; /** * @description + * 关联的账号名称 + */ + accountName?: string; + /** + * @description * 关联的账号手机号 */ accountPhone?: string; @@ -1697,6 +1702,11 @@ export interface ResearchGroupAccountEditRequest { accountId?: number; /** * @description + * 关联的账号名称 + */ + accountName?: string; + /** + * @description * 关联的账号手机号 */ accountPhone?: string; @@ -1737,6 +1747,15 @@ export interface ResearchGroupDeleteRequest { ids?: Array<number>; } +export interface ResearchGroupDetailRequest { + /** + * @description + * 主键id + * @format int64 + */ + id?: number; +} + export interface ResearchGroupEditRequest { /** * @description @@ -1767,6 +1786,11 @@ export interface ResearchGroupEditRequest { } export interface ResearchGroupListRequest { + /** + * @description + * 预存账号手机号 + */ + accountPhone?: string; /** @format int32 */ current?: number; /** diff --git a/src/services/request.ts b/src/services/request.ts index a6ef356..c00c360 100644 --- a/src/services/request.ts +++ b/src/services/request.ts @@ -53,6 +53,7 @@ import type { MaterialUnitListRes, MeasureUnitListRes, MessageQueryDTO, + ModelAndView, OrderAddVO, OrderAuditLogQueryVO, OrderBaseInfoQueryVO, @@ -76,6 +77,7 @@ import type { ReissueInvoiceDto, ResearchGroupAddRequest, ResearchGroupDeleteRequest, + ResearchGroupDetailRequest, ResearchGroupEditRequest, ResearchGroupListRequest, ResetPwdVO, @@ -1614,9 +1616,7 @@ export interface GetErrorResponse { * @description * OK */ - 200: { - [propertyName: string]: any; - }; + 200: ModelAndView; /** * @description * Unauthorized @@ -1637,9 +1637,9 @@ export interface GetErrorResponse { export type GetErrorResponseSuccess = GetErrorResponse[200]; /** * @description - * error + * errorHtml * @tags basic-error-controller - * @produces * + * @produces text/html */ export const getError = /* #__PURE__ */ (() => { const method = 'get'; @@ -1663,9 +1663,7 @@ export interface PutErrorResponse { * @description * OK */ - 200: { - [propertyName: string]: any; - }; + 200: ModelAndView; /** * @description * Created @@ -1691,9 +1689,9 @@ export interface PutErrorResponse { export type PutErrorResponseSuccess = PutErrorResponse[200]; /** * @description - * error + * errorHtml * @tags basic-error-controller - * @produces * + * @produces text/html * @consumes application/json */ export const putError = /* #__PURE__ */ (() => { @@ -1718,9 +1716,7 @@ export interface PostErrorResponse { * @description * OK */ - 200: { - [propertyName: string]: any; - }; + 200: ModelAndView; /** * @description * Created @@ -1746,9 +1742,9 @@ export interface PostErrorResponse { export type PostErrorResponseSuccess = PostErrorResponse[200]; /** * @description - * error + * errorHtml * @tags basic-error-controller - * @produces * + * @produces text/html * @consumes application/json */ export const postError = /* #__PURE__ */ (() => { @@ -1773,9 +1769,7 @@ export interface DeleteErrorResponse { * @description * OK */ - 200: { - [propertyName: string]: any; - }; + 200: ModelAndView; /** * @description * No Content @@ -1796,9 +1790,9 @@ export interface DeleteErrorResponse { export type DeleteErrorResponseSuccess = DeleteErrorResponse[200]; /** * @description - * error + * errorHtml * @tags basic-error-controller - * @produces * + * @produces text/html */ export const deleteError = /* #__PURE__ */ (() => { const method = 'delete'; @@ -1822,9 +1816,7 @@ export interface OptionsErrorResponse { * @description * OK */ - 200: { - [propertyName: string]: any; - }; + 200: ModelAndView; /** * @description * No Content @@ -1845,9 +1837,9 @@ export interface OptionsErrorResponse { export type OptionsErrorResponseSuccess = OptionsErrorResponse[200]; /** * @description - * error + * errorHtml * @tags basic-error-controller - * @produces * + * @produces text/html * @consumes application/json */ export const optionsError = /* #__PURE__ */ (() => { @@ -1872,9 +1864,7 @@ export interface HeadErrorResponse { * @description * OK */ - 200: { - [propertyName: string]: any; - }; + 200: ModelAndView; /** * @description * No Content @@ -1895,9 +1885,9 @@ export interface HeadErrorResponse { export type HeadErrorResponseSuccess = HeadErrorResponse[200]; /** * @description - * error + * errorHtml * @tags basic-error-controller - * @produces * + * @produces text/html * @consumes application/json */ export const headError = /* #__PURE__ */ (() => { @@ -1922,9 +1912,7 @@ export interface PatchErrorResponse { * @description * OK */ - 200: { - [propertyName: string]: any; - }; + 200: ModelAndView; /** * @description * No Content @@ -1945,9 +1933,9 @@ export interface PatchErrorResponse { export type PatchErrorResponseSuccess = PatchErrorResponse[200]; /** * @description - * error + * errorHtml * @tags basic-error-controller - * @produces * + * @produces text/html * @consumes application/json */ export const patchError = /* #__PURE__ */ (() => { @@ -7770,6 +7758,77 @@ export const postResearchGroupsDelete = /* #__PURE__ */ (() => { return request; })(); +/** @description request parameter type for postResearchGroupsDetail */ +export interface PostResearchGroupsDetailOption { + /** + * @description + * request + */ + body: { + /** + @description + request */ + request: ResearchGroupDetailRequest; + }; +} + +/** @description response type for postResearchGroupsDetail */ +export interface PostResearchGroupsDetailResponse { + /** + * @description + * OK + */ + 200: ServerResult; + /** + * @description + * Created + */ + 201: any; + /** + * @description + * Unauthorized + */ + 401: any; + /** + * @description + * Forbidden + */ + 403: any; + /** + * @description + * Not Found + */ + 404: any; +} + +export type PostResearchGroupsDetailResponseSuccess = + PostResearchGroupsDetailResponse[200]; +/** + * @description + * 查询课题组信息 + * @tags research-groups-controller + * @produces * + * @consumes application/json + */ +export const postResearchGroupsDetail = /* #__PURE__ */ (() => { + const method = 'post'; + const url = '/research/groups/detail'; + function request( + option: PostResearchGroupsDetailOption, + ): Promise<PostResearchGroupsDetailResponseSuccess> { + return requester(request.url, { + method: request.method, + ...option, + }) as unknown as Promise<PostResearchGroupsDetailResponseSuccess>; + } + + /** http method */ + request.method = method; + /** request url */ + request.url = url; + return request; +})(); + /** @description request parameter type for postResearchGroupsEdit */ export interface PostResearchGroupsEditOption { /**