提交 61d5d9f5 作者: ZhangLingKun

Merge branch 'develop'

# Conflicts:
#	src/router/index.ts
...@@ -27,10 +27,10 @@ npm-debug.log* ...@@ -27,10 +27,10 @@ npm-debug.log*
yarn-debug.log* yarn-debug.log*
yarn-error.log* yarn-error.log*
pnpm-debug.log* pnpm-debug.log*
pnpm-lock.yaml* #pnpm-lock.yaml*
yarn-lock.yaml* yarn-lock.yaml*
package-lock.yaml* package-lock.yaml*
#package-lock.json* package-lock.json*
#yarn.lock* yarn.lock*
tsconfig.tsbuildinfo* tsconfig.tsbuildinfo*
...@@ -2,14 +2,18 @@ FROM node:18-alpine as builder ...@@ -2,14 +2,18 @@ FROM node:18-alpine as builder
ARG PROFILES_ACTIVE ARG PROFILES_ACTIVE
ENV PROFILES_ACTIVE=$PROFILES_ACTIVE ENV PROFILES_ACTIVE=$PROFILES_ACTIVE
WORKDIR /app WORKDIR /app
COPY package.json . COPY package.json yarn.lock* package-lock.json* pnpm-lock.yaml* ./
COPY package-lock.json . RUN \
RUN npm ci if [ -f pnpm-lock.yaml ]; then yarn global add pnpm && pnpm i --frozen-lockfile; \
elif [ -f yarn.lock ]; then yarn --frozen-lockfile; \
elif [ -f package-lock.json ]; then npm ci; \
else echo "Lockfile not found." && exit 1; \
fi
COPY . . COPY . .
RUN \ RUN \
if [ "${PROFILES_ACTIVE}" = "development" ]; then echo "env PROFILES_ACTIVE=development. exec npm run buildDev" && npm run buildDev; \ if [ "${PROFILES_ACTIVE}" = "development" ]; then echo "env PROFILES_ACTIVE=development. exec yarn run build:dev" && yarn run build:dev; \
else echo "env PROFILES_ACTIVE !=development. exec npm run build" && npm run build; \ else echo "env PROFILES_ACTIVE !=development. exec yarn run build" && yarn run build; \
fi fi
# nginx # nginx
......
...@@ -9,5 +9,10 @@ ...@@ -9,5 +9,10 @@
<body> <body>
<div id="root"></div> <div id="root"></div>
<script type="module" src="/src/main.tsx"></script> <script type="module" src="/src/main.tsx"></script>
<script type="text/javascript" >
window._AMapSecurityConfig = {
securityJsCode:'a9cd5c6e4eb563b65884efc14759d6a1',
}
</script>
</body> </body>
</html> </html>
...@@ -14,4 +14,4 @@ patches: ...@@ -14,4 +14,4 @@ patches:
images: images:
- name: REGISTRY/NAMESPACE/IMAGE:TAG - name: REGISTRY/NAMESPACE/IMAGE:TAG
newName: mmc-registry.cn-shenzhen.cr.aliyuncs.com/sharefly-dev/admin newName: mmc-registry.cn-shenzhen.cr.aliyuncs.com/sharefly-dev/admin
newTag: 01280aac6badac09fd839261006483b7d09bb7d4 newTag: 2bc3f5681467023eaf7d732d8bffde2e434fe72a
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
"scripts": { "scripts": {
"dev": "vite", "dev": "vite",
"build": "vite build", "build": "vite build",
"buildDev": "vite build --mode development", "build:dev": "vite build --mode development",
"build:tsc": "tsc && vite build", "build:tsc": "tsc && vite build",
"preview": "vite preview", "preview": "vite preview",
"lint": "npx eslint src", "lint": "npx eslint src",
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
"format": "npm run prettier:fix && npm run lint:fix" "format": "npm run prettier:fix && npm run lint:fix"
}, },
"dependencies": { "dependencies": {
"@amap/amap-jsapi-loader": "^1.0.1",
"@ant-design/icons": "^5.0.1", "@ant-design/icons": "^5.0.1",
"@reduxjs/toolkit": "^1.9.2", "@reduxjs/toolkit": "^1.9.2",
"@wangeditor/editor": "^5.1.23", "@wangeditor/editor": "^5.1.23",
...@@ -31,6 +32,7 @@ ...@@ -31,6 +32,7 @@
"match-sorter": "^6.3.1", "match-sorter": "^6.3.1",
"moment": "^2.29.4", "moment": "^2.29.4",
"pinyin-pro": "^3.14.0", "pinyin-pro": "^3.14.0",
"prop-types": "^15.8.1",
"qs": "^6.10.3", "qs": "^6.10.3",
"query-string": "^8.1.0", "query-string": "^8.1.0",
"react": "^18.1.0", "react": "^18.1.0",
...@@ -66,4 +68,4 @@ ...@@ -66,4 +68,4 @@
"vite": "^4.3.9", "vite": "^4.3.9",
"vite-tsconfig-paths": "^3.5.0" "vite-tsconfig-paths": "^3.5.0"
} }
} }
\ No newline at end of file
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -12,6 +12,7 @@ import { CustomManageAPI } from './modules/customManage'; ...@@ -12,6 +12,7 @@ import { CustomManageAPI } from './modules/customManage';
import { MallManageAPI } from './modules/mallManage'; import { MallManageAPI } from './modules/mallManage';
import { ResourceManageAPI } from './modules/resourceManageAPI'; import { ResourceManageAPI } from './modules/resourceManageAPI';
import { ForumManageAPI } from './modules/forumManageAPI'; import { ForumManageAPI } from './modules/forumManageAPI';
import { PilotTrainAPI } from './modules/pilotTrainAPI';
export { export {
CommonAPI, CommonAPI,
...@@ -28,4 +29,5 @@ export { ...@@ -28,4 +29,5 @@ export {
MallManageAPI, MallManageAPI,
ResourceManageAPI, ResourceManageAPI,
ForumManageAPI, ForumManageAPI,
PilotTrainAPI,
}; };
...@@ -37,6 +37,16 @@ export type listAppUserType = InterListFunction< ...@@ -37,6 +37,16 @@ export type listAppUserType = InterListFunction<
tagName: string; tagName: string;
tagRequire: string; tagRequire: string;
}[]; }[];
userRcdVO: {
createTime: string;
id: number;
rcdNickname: string;
rcdUserId: number;
rcdUserName: string;
remark: string;
userAccountId: number;
};
inviteCount: number;
} }
>; >;
// 加盟标签列表 // 加盟标签列表
...@@ -107,6 +117,7 @@ export type listUserApplyTag = InterListFunction< ...@@ -107,6 +117,7 @@ export type listUserApplyTag = InterListFunction<
{ {
applyStatus?: number; applyStatus?: number;
cooperationTagId?: number; cooperationTagId?: number;
companyName?: string;
endTime?: string; endTime?: string;
startTime?: string; startTime?: string;
}, },
...@@ -115,11 +126,17 @@ export type listUserApplyTag = InterListFunction< ...@@ -115,11 +126,17 @@ export type listUserApplyTag = InterListFunction<
applyPhone: string; applyPhone: string;
applyTime: string; applyTime: string;
approvalStatus: number; approvalStatus: number;
attachmentList: null; attachmentList: Array<{
type: number;
url: string;
}>;
companyName: string;
content: string;
cooperationTagId: number; cooperationTagId: number;
cooperationTagName: string; cooperationTagName: string;
id: number; id: number;
remark: string; remark: string;
score: number;
userAccountId: number; userAccountId: number;
} }
>; >;
...@@ -158,3 +175,61 @@ export type deleteApplyTag = InterFunction< ...@@ -158,3 +175,61 @@ export type deleteApplyTag = InterFunction<
}, },
NonNullable<unknown> NonNullable<unknown>
>; >;
// 后台-编辑详情信息
export type editUserApplyTagDetails = InterFunction<
{
id: number;
},
{
address: string;
content: string;
cooperationTagId: number;
id: number;
lat: number;
lon: number;
name: string;
score: number;
}
>;
// 后台-编辑服务商信息
export type editUserApplyTag = InterFunction<
{
address?: string;
content?: string;
cooperationTagId?: number;
id: number;
lat?: number;
lon?: number;
name?: string;
score?: number;
},
NonNullable<unknown>
>;
// 裂变-邀请列表
export type listUserRcdType = InterListFunction<
{
userAccountId: number;
},
{
accountStatus: null;
accountType: null;
companyAuthStatus: number;
companyName: null;
cooperationTagVOS: null;
createTime: string;
deleted: null;
email: null;
id: number;
inviteCount: null;
nickName: string;
phoneNum: string;
portType: null;
remark: null;
source: null;
uid: null;
userImg: string;
userName: null;
userRcdVO: null;
userSex: null;
}
>;
import { InterFunction, InterItemFunction } from '~/api/interface';
//执照等级下拉
export type licenceGradeListType = InterFunction<any, { id: number; name: string }[]>;
//执照机型下拉
export type licenceModelsListType = InterFunction<any, { id: number; name: string }[]>;
//规模下拉
export type licenceScaleList = InterFunction<any, { id: number; name: string }[]>;
//执照类型下拉
export type licenceTypeListType = InterFunction<any, { id: number; name: string }[]>;
//机构列表
export type listOrgPageType = InterItemFunction<
{
statTime?: string;
endTime?: string;
gradeId?: number;
modelsId?: number;
name?: string;
region?: number;
typeId?: number;
id?: number;
},
{
auxiliaryPicture: string;
description: string;
detail: string;
detailedAddress: string;
id: number;
latitude: number;
longitude: number;
mainImage: string;
name: string;
programsDOList: Array<{
gradeId: number;
gradeName: number;
id: number;
mainImage: string;
modelsId: number;
modelsName: number;
orgId: string;
place: string;
price: number;
typeId: number;
typeName: number;
}>;
region: string;
regionName: string;
scaleId: number;
scaleName: number;
testCenter: number;
video: string;
createTime: string;
}[]
>;
//机构上传
export type insertOrgType = InterFunction<
{
auxiliaryPicture: string;
description: string;
detail: string;
detailedAddress: string;
latitude: number;
longitude: number;
mainImage: string;
name: string;
region: string;
regionName: string;
scaleId: number;
testCenter: number;
trainingProgramsVOS: Array<{
gradeId: number;
id: number;
mainImage: string;
modelsId: number;
place: string;
price: number;
typeId: number;
}>;
video: string;
},
any
>;
//机构删除
export type removeOrgType = InterFunction<{ id: number }, any>;
//机构修改
export type updateOrgType = InterFunction<
{
auxiliaryPicture: string;
description: string;
detail: string;
detailedAddress: string;
latitude: number;
longitude: number;
mainImage: string;
name: string;
region: string;
regionName: string;
scaleId: number;
testCenter: number;
trainingProgramsVOS: Array<{
gradeId: number;
id: number;
mainImage: string;
modelsId: number;
place: string;
price: number;
typeId: number;
}>;
video: string;
id: number;
},
any
>;
...@@ -7,8 +7,11 @@ import { ...@@ -7,8 +7,11 @@ import {
CompanyListTag, CompanyListTag,
cooperationListTag, cooperationListTag,
deleteApplyTag, deleteApplyTag,
editUserApplyTag,
editUserApplyTagDetails,
listAppUserType, listAppUserType,
listUserApplyTag, listUserApplyTag,
listUserRcdType,
userAccountUpdateType, userAccountUpdateType,
} from '~/api/interface/customManageType'; } from '~/api/interface/customManageType';
...@@ -43,4 +46,13 @@ export class CustomManageAPI { ...@@ -43,4 +46,13 @@ export class CustomManageAPI {
// 强制删除 // 强制删除
static deleteApplyTag: deleteApplyTag = (params) => static deleteApplyTag: deleteApplyTag = (params) =>
axios.get('/userapp/cooperation/deleteApplyTag', { params }); axios.get('/userapp/cooperation/deleteApplyTag', { params });
// 后台-编辑详情信息
static editUserApplyTagDetails: editUserApplyTagDetails = (params) =>
axios.get('/userapp/cooperation/editUserApplyTagDetails', { params });
// 后台-编辑服务商信息
static editUserApplyTag: editUserApplyTag = (params) =>
axios.post('/userapp/cooperation/editUserApplyTag', params);
// 裂变-邀请列表
static listUserRcd: listUserRcdType = (data) =>
axios.post('/userapp/user-account/listUserRcd', data);
} }
import {
insertOrgType,
licenceGradeListType,
licenceModelsListType,
licenceScaleList,
licenceTypeListType,
listOrgPageType,
removeOrgType,
updateOrgType,
} from '~/api/interface/pilotTrainType';
import axios from '~/api/request';
export class PilotTrainAPI {
// 获取执照等级下拉
static getLicenceGradeList: licenceGradeListType = () =>
axios.get('/release/licence/pullDown/licenceGradeList');
//执照机型下拉
static getLicenceModelsList: licenceModelsListType = () =>
axios.get('/release/licence/pullDown/licenceModelsList');
// 机构规模下拉
static getLicenceScaleList: licenceScaleList = () =>
axios.get('/release/licence/pullDown/licenceScaleList');
// 执照类型下拉
static getLicenceTypeList: licenceTypeListType = () =>
axios.get('/release/licence/pullDown/licenceTypeList');
// 机构上传
static insertOrg: insertOrgType = (data) =>
axios.post('/release/licence/background/insertOrg', data);
// 机构列表
static getListOrgPage: listOrgPageType = (data) =>
axios.post('/release/licence/background/listOrgPage', data);
// 机构删除
static removeOrg: removeOrgType = (params) =>
axios.get('/release/licence/background/removeOrg', { params });
// 机构更新
static updateOrg: updateOrgType = (data) =>
axios.post('/release/licence/background/updateOrg', data);
}
...@@ -51,3 +51,12 @@ ...@@ -51,3 +51,12 @@
-moz-border-radius: 2em; -moz-border-radius: 2em;
border-radius: 2em; border-radius: 2em;
} }
.ant-input-disabled{
color: rgba(0, 0, 0, 0.68) !important;
}
.ant-select-disabled{
.ant-select-selection-item{
color: rgba(0, 0, 0, 0.68) !important;
}
}
import { Form, InputNumber, Input } from 'antd'; import { Form, InputNumber, Input, Select } from 'antd';
import React from 'react'; import React from 'react';
import { Uploader } from '~/components/uploader';
import { UploadOutlined } from '@ant-design/icons';
// 表格可编辑单元格 // 表格可编辑单元格
interface EditableCellProps extends React.HTMLAttributes<HTMLElement> { export interface EditableCellProps extends React.HTMLAttributes<HTMLElement> {
editing: boolean; editing: boolean;
dataIndex: string; dataIndex: string;
title: any; title: any;
inputType: 'number' | 'text'; inputType: 'number' | 'text' | 'select' | 'uploader';
record: any; record: any;
index: number; index: number;
children: React.ReactNode; children: React.ReactNode;
} }
const EditableCell: React.FC<EditableCellProps> = ({ const EditableCell: React.FC<
EditableCellProps & {
selectOption?: { name: string; id: number }[];
uploadSuccess?: (record: any, result: any) => void;
}
> = ({
editing, editing,
dataIndex, dataIndex,
title, title,
inputType, inputType,
record, record,
index, index,
selectOption,
uploadSuccess,
children, children,
...restProps ...restProps
}) => { }) => {
const inputNode = const inputNode = () => {
inputType === 'number' ? <InputNumber /> : <Input placeholder={`请输入${title}`} />; switch (inputType) {
case 'number':
return <InputNumber />;
case 'select':
return (
<Select placeholder={`请选择${title}`} style={{ textAlign: 'start' }}>
{selectOption &&
selectOption.map((v) => (
<Select.Option value={v.id} key={v.id}>
{v.name}
</Select.Option>
))}
</Select>
);
case 'uploader':
return (
<Uploader
fileUpload
listType='picture-card'
onChange={(value) => uploadSuccess?.(record, value)}
defaultFileList={record.fileList}
>
<UploadOutlined />
</Uploader>
);
default:
return <Input placeholder={`请输入${title}`} />;
}
};
const getMessage = () => {
switch (inputType) {
case 'number':
case 'text':
return `请输入${title}`;
case 'select':
return `请选择${title}`;
case 'uploader':
return `请上传${title}`;
default:
return `请输入${title}`;
}
};
return ( return (
<td {...restProps}> <td {...restProps}>
{editing ? ( {editing ? (
...@@ -33,11 +82,11 @@ const EditableCell: React.FC<EditableCellProps> = ({ ...@@ -33,11 +82,11 @@ const EditableCell: React.FC<EditableCellProps> = ({
rules={[ rules={[
{ {
required: true, required: true,
message: `请输入${title}`, message: getMessage(),
}, },
]} ]}
> >
{inputNode} {inputNode()}
</Form.Item> </Form.Item>
) : ( ) : (
children children
......
import { FC, useEffect, useRef, useState } from 'react';
import { Select, Input, Modal } from 'antd';
import MapComponent from '~/components/select-map/map';
import { debounce } from 'lodash';
// 传参类型
interface propType {
title?: string;
open: boolean;
closed: any;
submit: any;
}
const SelectMapModal: FC<propType> = (props) => {
SelectMapModal.defaultProps = {
title: '选择地点',
};
// 参数
const { title, open, closed, submit } = props;
// 子组件事件
const childRef = useRef<{
onSearch: (e: string) => void;
addMarker: (e: { lat: number; lng: number }) => void;
clearMarker: () => void;
}>(null);
// 位置信息
const [position, setPosition] = useState<{
lat: number;
lon: number;
address: string;
adCode: number;
}>();
// 搜索地点
const [addressList, setAddressList] = useState<{ label: string; value: number; data: any }[]>();
// 取消事件
const handleCancel = () => {
setPosition(undefined);
setAddressList([]);
closed();
};
// 确认事件
const handleOk = () => {
submit(position);
};
// 搜索地点
const handleSearch = (e: string) => {
if (e) {
childRef.current?.onSearch(e);
} else {
setAddressList([]);
}
};
// 防抖
const handleSearchDebounced = debounce(handleSearch, 500);
// 选择了地址
const handleSearchAddress = (e: number) => {
if (e) {
console.log(addressList?.[e].data);
// eslint-disable-next-line no-unsafe-optional-chaining
const { lat, lng } = addressList?.[e].data.location;
childRef.current?.addMarker({ lat, lng });
setPosition({
lat: lat,
lon: lng,
address: `${addressList?.[e].data.name}`,
adCode: addressList?.[e].data.adcode,
});
} else {
childRef.current?.clearMarker();
setPosition(undefined);
}
};
// componentDidMount
useEffect(() => {
if (!open) return;
return () => {
setPosition(undefined);
};
}, [open]);
return (
<Modal open={open} title={title} onCancel={handleCancel} onOk={handleOk} destroyOnClose>
<div
style={{
display: 'flex',
justifyContent: 'flex-start',
alignItems: 'center',
marginBottom: '10px',
}}
>
<div style={{ width: '60px' }}>搜索地点:</div>
<Select
showSearch
placeholder={'请输入地点'}
optionFilterProp='children'
style={{ width: '80%', marginRight: '20px' }}
allowClear
onSearch={handleSearchDebounced}
filterOption={(input, option) =>
(option?.label ?? '').toLowerCase().includes(input.toLowerCase())
}
options={addressList}
onChange={handleSearchAddress}
/>
</div>
<MapComponent
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
ref={childRef}
onSelectAddress={(e) => {
setPosition({
lat: e.lat,
lon: e.lng,
address: e.formattedAddress,
adCode: Number(e.adcode),
});
}}
onSearchAddress={(e) => {
setAddressList(e.map((i, j) => ({ label: i.name, value: j, data: i })));
}}
></MapComponent>
<div
style={{
display: 'flex',
justifyContent: 'flex-start',
alignItems: 'center',
marginTop: '10px',
marginBottom: '20px',
}}
>
<div style={{ width: '60px' }}>选择地点:</div>
<Input
value={position?.address}
placeholder={'请选择地点'}
maxLength={25}
allowClear
style={{ width: '80%', marginRight: '20px' }}
disabled
/>
</div>
</Modal>
);
};
export default SelectMapModal;
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-nocheck
import AMapLoader from '@amap/amap-jsapi-loader';
import { Component } from 'react';
interface MapComponentProps {
onSelectAddress: (e: {
adcode: string;
building: string;
buildingType: string;
city: string;
citycode: string;
district: string;
formattedAddress: string;
neighborhood: string;
neighborhoodType: string;
province: string;
street: string;
streetNumber: string;
towncode: string;
township: string;
lat: number;
lng: number;
}) => void;
onSearchAddress: (
e: {
id: string;
name: string;
district: string;
adcode: string;
location: Array<number>;
address: string;
typecode: string;
}[],
) => void;
}
class MapComponent extends Component<MapComponentProps> {
constructor(props) {
super(props);
this.map = {};
this.autoComplete = {};
}
// dom渲染成功后进行map对象的创建
componentDidMount() {
AMapLoader.load({
key: '7a3a24e85672c06ab466d790fb5d38a3', // 申请好的Web端开发者Key,首次调用 load 时必填
version: '2.0', // 指定要加载的 JSAPI 的版本,缺省时默认为 1.4.15
plugins: [], // 需要使用的的插件列表,如比例尺'AMap.Scale'等
})
.then((AMap) => {
this.map = new AMap.Map('container', {
// 设置地图容器id
viewMode: '3D', // 是否为3D地图模式
zoom: 10, // 初始化地图级别
// center: [105.602725, 37.076636], // 初始化地图中心点位置
});
AMap.plugin(
['AMap.ToolBar', 'AMap.AutoComplete', 'AMap.Scale', 'AMap.Geocoder', 'AMap.Marker'],
() => {
// 缩放
const scale = new AMap.Scale();
this.map.addControl(scale);
// 工具栏
const toolbar = new AMap.ToolBar();
this.map.addControl(toolbar);
// 位置搜索
const autoOptions = {
//city 限定城市,默认全国
city: '全国',
};
// 实例化AutoComplete
this.autoComplete = new AMap.AutoComplete(autoOptions);
},
);
this.map.on('click', (e) => {
this.map.clearMap();
const { lat, lng } = e.lnglat;
// 新建marker实例
const marker = new AMap.Marker({
position: new AMap.LngLat(lng, lat), // 经纬度对象,也可以是经纬度构成的一维数组[116.39, 39.9]
title: '选择的位置',
});
// 添加marker
this.map.add(marker);
// 获取地理信息
const geocoder = new AMap.Geocoder({
city: '全国',
});
// console.log('点击 --->', e);
geocoder.getAddress([lng, lat], (status, result) => {
if (status === 'complete' && result.info === 'OK') {
// result为对应的地理位置详细信息
const { formattedAddress, addressComponent } = result.regeocode;
console.log('点击选择-->', status, result);
this.props.onSelectAddress({
lat,
lng,
formattedAddress,
...addressComponent,
});
}
});
});
})
.catch((e) => {
console.log(e);
});
}
componentWillUnmount() {
this.map.destroy();
}
// 搜索数据
onSearch(keyword: string) {
// 根据关键字进行搜索
this.autoComplete.search(keyword, (status, result) => {
// 搜索成功时,result即是对应的匹配数据
if (status === 'complete' && result.info === 'OK') {
this.props.onSearchAddress(result.tips);
}
});
}
// 添加点标记
addMarker(e: { lat: number; lng: number }) {
const { lat, lng } = e;
this.map.clearMap();
// 新建marker实例
const marker = new AMap.Marker({
position: new AMap.LngLat(lng, lat), // 经纬度对象,也可以是经纬度构成的一维数组[116.39, 39.9]
title: '选择的位置',
});
// 添加marker
this.map.add(marker);
// 设置中心点
this.map.setCenter([lng, lat]);
}
// 清除地图上的点标记
clearMarker() {
this.map.clearMap();
}
render() {
// 初始化创建地图容器,div标签作为地图容器,同时为该div指定id属性;
return <div id='container' className='map' style={{ height: '400px' }}></div>;
}
}
// 导出地图组建类
export default MapComponent;
...@@ -44,9 +44,7 @@ function LoginView() { ...@@ -44,9 +44,7 @@ function LoginView() {
} else { } else {
message.warning('请先配置权限'); message.warning('请先配置权限');
} }
//获取第一个路由
}); });
// 获取第一个路由
} else { } else {
message.error('登录失败,请检查账号信息'); message.error('登录失败,请检查账号信息');
} }
......
import { FC, useEffect, useState } from 'react'; import { FC, useEffect, useState } from 'react';
import { Button, message, Modal } from 'antd';
import { InterDataType, InterListType, InterReqType } from '~/api/interface';
import { CustomManageAPI } from '~/api';
import { import {
applyTagDetails, editUserApplyTag,
approvalApplyTag, editUserApplyTagDetails,
listUserApplyTag, listUserApplyTag,
} from '~/api/interface/customManageType'; } from '~/api/interface/customManageType';
import './index.scss'; import { InterDataType, InterListType, InterReqType } from '~/api/interface';
import { PlusOutlined } from '@ant-design/icons'; import { Button, Form, Input, message, Modal, Rate, Select, Space } from 'antd';
import { Uploader } from '~/components/uploader'; import { CustomManageAPI } from '~/api';
import SelectMapModal from '~/components/select-map';
// 列表的类型 // 数据类型
type DataType = InterDataType<applyTagDetails>; type DataType = InterDataType<editUserApplyTagDetails>;
// 列表的类型 // 列表的类型
type TableType = InterListType<listUserApplyTag>; type TableType = InterListType<listUserApplyTag>;
// 请求的表单类型 // 请求的表单类型
type ReqType = InterReqType<approvalApplyTag>; type ReqType = InterReqType<editUserApplyTag>;
// 传参类型 // 传参类型
interface propType { interface propType {
title: string; title: string;
...@@ -26,111 +24,157 @@ interface propType { ...@@ -26,111 +24,157 @@ interface propType {
} }
const AddEditModal: FC<propType> = (props) => { const AddEditModal: FC<propType> = (props) => {
AddEditModal.defaultProps = {
data: undefined,
};
// 参数 // 参数
const { title, open, closed, data } = props; const { title, open, closed, data } = props;
const [applyTagDetail, setApplyTagDetail] = useState<DataType>(); // 表单数据
const [form] = Form.useForm<ReqType>();
// 详情数据
const [detail, setDetail] = useState<DataType>();
// 是否选择地址弹窗
const [openAddress, setOpenAddress] = useState<boolean>(false);
// 加盟列表
const [cooperationList, setCooperationList] = useState<{ label: string; value: number }[]>([]);
// 选择的地址
const [address, setAddress] = useState<{ lat: number; lon: number; address: string }>();
// 关闭弹窗 // 关闭弹窗
const handleCancel = () => { const handleCancel = () => {
form.resetFields();
closed(); closed();
}; };
// 点击事件 // 获取审批详情
const handleOk = async (status: boolean) => { const getApplyTagDetails = async () => {
await handleSubmit({ id: Number(data?.id), status }); const res = await CustomManageAPI.editUserApplyTagDetails({
id: Number(data?.id),
});
if (res && res.code === '200') {
form.setFieldsValue({
...res.result,
name: res.result.name || data?.companyName,
});
setDetail(res.result);
// console.log('获取审批详情 -->', res.result);
}
};
// 获取加盟列表
const getCooperationList = async () => {
const res = await CustomManageAPI.cooperationListTag({});
if (res && res.code === '200') {
const list = res.result || [];
setCooperationList(list.map((i) => ({ label: i.tagName, value: i.id })));
}
};
// 确认事件
const handleOk = () => {
form
.validateFields()
.then(async (values) => {
await handleSubmit(values);
})
.catch((err) => {
message
.warning({
content: err.errorFields[0].errors[0],
})
.then();
});
}; };
// 提交事件 // 提交事件
const handleSubmit = async (values: ReqType) => { const handleSubmit = async (values: ReqType) => {
const res = await CustomManageAPI.approvalApplyTag(values); const res = await CustomManageAPI.editUserApplyTag({
id: Number(data?.id),
...detail,
...values,
...address,
});
if (res && res.code === '200') { if (res && res.code === '200') {
message.success('操作成功'); message.success('操作成功');
handleCancel(); handleCancel();
} }
}; };
// 获取审批详情
const getApplyTagDetails = async () => {
const res = await CustomManageAPI.applyTagDetails({
id: data?.id,
userAccountId: data?.userAccountId,
});
if (res && res.code === '200') {
const { result } = res;
setApplyTagDetail(result);
}
};
// componentDidMount // componentDidMount
useEffect(() => { useEffect(() => {
if (!open) return; if (!open) return;
getCooperationList().then();
if (!data) return; if (!data) return;
getApplyTagDetails().then(); getApplyTagDetails().then();
// console.log('data --->', data); // console.log('data --->', data);
}, [open]); }, [open]);
return ( return (
<Modal open={open} title={title} onCancel={handleCancel} destroyOnClose footer={null}> <>
<div className='apply-detail'> <Modal open={open} title={title} onCancel={handleCancel} onOk={handleOk} destroyOnClose>
<div className='detail-text'>确定通过用户提交的加盟申请成为加盟商吗?</div> <Form form={form} labelCol={{ span: 5 }} wrapperCol={{ span: 16 }}>
<div className='detail-action'> <Form.Item
<Button type={'default'} onClick={() => handleOk(false)}> label='网点名称'
驳回 name='name'
</Button> rules={[{ required: true, message: '请输入网点名称' }]}
<Button type={'primary'} onClick={() => handleOk(true)}> >
通过 <Input placeholder={'请输入企业名称'} maxLength={25} allowClear />
</Button> </Form.Item>
</div> <Form.Item
<div className='detail-title'>企业认证信息</div> label='加盟类型'
<div className='detail-item'> name='cooperationTagId'
<div className='item-label'>企业名称:</div> rules={[{ required: true, message: '请选择加盟类型' }]}
<div className='item-value'>{applyTagDetail?.companyName || '无'}</div> >
</div> <Select placeholder='请选择加盟类型' allowClear options={cooperationList} disabled />
<div className='detail-item'> </Form.Item>
<div className='item-label'>社会信用代码:</div> <Form.Item
<div className='item-value'>{applyTagDetail?.creditCode || '无'}</div> label='网点地址'
</div> name='address'
<div className='detail-item'> rules={[{ required: true, message: '请选择网点地址' }]}
<div className='item-label'>工商营业执照:</div> >
<div className='item-value'> <Space.Compact style={{ width: '100%' }}>
<Uploader <Input
listType={'picture-card'} placeholder='请选择网点地址'
fileUpload maxLength={50}
fileLength={1} allowClear
fileSize={10} disabled
fileType={['image/png', 'image/jpeg', 'image/jpg', 'image/gif', 'image/bmp']} value={form.getFieldValue('address') || detail?.address}
defaultFileList={ />
applyTagDetail?.licenseImg ? [{ url: applyTagDetail?.licenseImg }] : [] <Button
} type='primary'
disabled={true} onClick={() => {
> setOpenAddress(true);
<PlusOutlined /> }}
</Uploader> >
</div> 选择位置
</div> </Button>
<div className='detail-item'> </Space.Compact>
<div className='item-label'>附件信息:</div> </Form.Item>
<div className='item-value'> <Form.Item
<Uploader label='服务资质'
listType={'picture-card'} name='content'
fileUpload rules={[{ required: true, message: '请输入服务资质' }]}
fileLength={1} >
fileSize={10} <Input.TextArea
fileType={['image/png', 'image/jpeg', 'image/jpg', 'image/gif', 'image/bmp']} placeholder={'请输入服务资质(“;”号换行)'}
defaultFileList={ maxLength={140}
applyTagDetail?.attachmentList?.length allowClear
? applyTagDetail?.attachmentList.map((i) => ({ url: i.url })) showCount
: [] />
} </Form.Item>
disabled={true} <Form.Item
> label='服务评分'
<PlusOutlined /> name='score'
</Uploader> initialValue={5}
</div> rules={[{ required: true, message: '请选择服务评分' }]}
</div> >
<div className='detail-item'> <Rate allowClear />
<div className='item-label'>备注:</div> </Form.Item>
<div className='item-value'>{applyTagDetail?.remark || '无'}</div> </Form>
</div> </Modal>
</div> <SelectMapModal
</Modal> title={'选择位置'}
open={openAddress}
closed={() => {
setOpenAddress(false);
}}
submit={(e: { lat: number; lon: number; address: string }) => {
form.setFieldValue('address', e.address);
setAddress(e);
setOpenAddress(false);
}}
/>
</>
); );
}; };
......
import { FC, useEffect, useState } from 'react';
import { Button, message, Modal } from 'antd';
import { InterDataType, InterListType, InterReqType } from '~/api/interface';
import { CustomManageAPI } from '~/api';
import {
applyTagDetails,
approvalApplyTag,
listUserApplyTag,
} from '~/api/interface/customManageType';
import './index.scss';
import { PlusOutlined } from '@ant-design/icons';
import { Uploader } from '~/components/uploader';
// 列表的类型
type DataType = InterDataType<applyTagDetails>;
// 列表的类型
type TableType = InterListType<listUserApplyTag>;
// 请求的表单类型
type ReqType = InterReqType<approvalApplyTag>;
// 传参类型
interface propType {
title: string;
open: boolean;
closed: any;
data?: TableType[0];
}
const ApprovalModal: FC<propType> = (props) => {
ApprovalModal.defaultProps = {
data: undefined,
};
// 参数
const { title, open, closed, data } = props;
const [applyTagDetail, setApplyTagDetail] = useState<DataType>();
// 关闭弹窗
const handleCancel = () => {
closed();
};
// 点击事件
const handleOk = async (status: boolean) => {
await handleSubmit({ id: Number(data?.id), status });
};
// 提交事件
const handleSubmit = async (values: ReqType) => {
const res = await CustomManageAPI.approvalApplyTag(values);
if (res && res.code === '200') {
message.success('操作成功');
handleCancel();
}
};
// 获取审批详情
const getApplyTagDetails = async () => {
const res = await CustomManageAPI.applyTagDetails({
id: data?.id,
userAccountId: data?.userAccountId,
});
if (res && res.code === '200') {
const { result } = res;
setApplyTagDetail(result);
}
};
// componentDidMount
useEffect(() => {
if (!open) return;
if (!data) return;
getApplyTagDetails().then();
// console.log('data --->', data);
}, [open]);
return (
<Modal open={open} title={title} onCancel={handleCancel} destroyOnClose footer={null}>
<div className='apply-detail'>
<div className='detail-text'>确定通过用户提交的加盟申请成为加盟商吗?</div>
<div className='detail-action'>
<Button type={'default'} onClick={() => handleOk(false)}>
驳回
</Button>
<Button type={'primary'} onClick={() => handleOk(true)}>
通过
</Button>
</div>
<div className='detail-title'>企业认证信息</div>
<div className='detail-item'>
<div className='item-label'>企业名称:</div>
<div className='item-value'>{applyTagDetail?.companyName || '无'}</div>
</div>
<div className='detail-item'>
<div className='item-label'>社会信用代码:</div>
<div className='item-value'>{applyTagDetail?.creditCode || '无'}</div>
</div>
<div className='detail-item'>
<div className='item-label'>工商营业执照:</div>
<div className='item-value'>
<Uploader
listType={'picture-card'}
fileUpload
fileLength={1}
fileSize={10}
fileType={['image/png', 'image/jpeg', 'image/jpg', 'image/gif', 'image/bmp']}
defaultFileList={
applyTagDetail?.licenseImg ? [{ url: applyTagDetail?.licenseImg }] : []
}
disabled={true}
>
<PlusOutlined />
</Uploader>
</div>
</div>
<div className='detail-item'>
<div className='item-label'>附件信息:</div>
<div className='item-value'>
<Uploader
listType={'picture-card'}
fileUpload
fileLength={1}
fileSize={10}
fileType={['image/png', 'image/jpeg', 'image/jpg', 'image/gif', 'image/bmp']}
defaultFileList={
applyTagDetail?.attachmentList?.length
? applyTagDetail?.attachmentList.map((i) => ({ url: i.url }))
: []
}
disabled={true}
>
<PlusOutlined />
</Uploader>
</div>
</div>
<div className='detail-item'>
<div className='item-label'>备注:</div>
<div className='item-value'>{applyTagDetail?.remark || '无'}</div>
</div>
</div>
</Modal>
);
};
export default ApprovalModal;
import { useEffect, useState } from 'react'; import { useEffect, useState } from 'react';
import SearchBox from '~/components/search-box'; import SearchBox from '~/components/search-box';
import { CustomManageAPI } from '~/api'; import { CustomManageAPI } from '~/api';
import { Button, message, Modal, Table } from 'antd'; import { Button, message, Modal, Rate, Table } from 'antd';
import { ColumnsType } from 'antd/es/table'; import { ColumnsType } from 'antd/es/table';
import { InterListType, InterReqListType } from '~/api/interface'; import { InterListType, InterReqListType } from '~/api/interface';
import { listUserApplyTag } from '~/api/interface/customManageType'; import { listUserApplyTag } from '~/api/interface/customManageType';
import AddEditModal from './comp/addEditModal'; import ApprovalModal from './comp/approvalModal';
import AddEditModal from '~/pages/customManage/customIdentity/comp/addEditModal';
// 列表类型 // 列表类型
type TableType = InterListType<listUserApplyTag>; type TableType = InterListType<listUserApplyTag>;
...@@ -24,8 +25,10 @@ const CustomIdentityView = () => { ...@@ -24,8 +25,10 @@ const CustomIdentityView = () => {
const { confirm } = Modal; const { confirm } = Modal;
// 加盟列表 // 加盟列表
const [cooperationList, setCooperationList] = useState<{ label: string; value: number }[]>([]); const [cooperationList, setCooperationList] = useState<{ label: string; value: number }[]>([]);
// 新增弹窗 // 新增编辑弹窗
const [addModalVisible, setAddModalVisible] = useState<boolean>(false); const [addModalVisible, setAddModalVisible] = useState<boolean>(false);
// 审批弹窗
const [approvalModalVisible, setApprovalModalVisible] = useState<boolean>(false);
// 需要编辑的数据 // 需要编辑的数据
const [editData, setEditData] = useState<TableType[0]>(); const [editData, setEditData] = useState<TableType[0]>();
// 表格数据 // 表格数据
...@@ -112,6 +115,13 @@ const CustomIdentityView = () => { ...@@ -112,6 +115,13 @@ const CustomIdentityView = () => {
render: (text) => cooperationList.find((i) => i.value === text)?.label || text, render: (text) => cooperationList.find((i) => i.value === text)?.label || text,
}, },
{ {
title: '企业认证名称',
dataIndex: 'companyName',
align: 'center',
width: '200px',
ellipsis: true,
},
{
title: '联系人', title: '联系人',
dataIndex: 'applyName', dataIndex: 'applyName',
align: 'center', align: 'center',
...@@ -122,6 +132,20 @@ const CustomIdentityView = () => { ...@@ -122,6 +132,20 @@ const CustomIdentityView = () => {
align: 'center', align: 'center',
}, },
{ {
title: '服务资质',
dataIndex: 'content',
align: 'center',
width: '200px',
ellipsis: true,
},
{
title: '服务评价',
dataIndex: 'score',
align: 'center',
width: '120px',
render: (text) => text && <Rate disabled value={Number(text)} />,
},
{
title: '申请时间', title: '申请时间',
dataIndex: 'applyTime', dataIndex: 'applyTime',
align: 'center', align: 'center',
...@@ -137,21 +161,31 @@ const CustomIdentityView = () => { ...@@ -137,21 +161,31 @@ const CustomIdentityView = () => {
dataIndex: 'action', dataIndex: 'action',
align: 'center', align: 'center',
fixed: 'right', fixed: 'right',
width: '120px', width: '150px',
render: (_text, record) => ( render: (_text, record) => (
<> <>
<Button <Button
type={'link'} type={'link'}
onClick={() => { onClick={() => {
setAddModalVisible(true); setApprovalModalVisible(true);
setEditData(JSON.parse(JSON.stringify(record))); setEditData(JSON.parse(JSON.stringify(record)));
}} }}
disabled={record.approvalStatus !== 0} disabled={record.approvalStatus !== 0}
> >
审批 审批
</Button> </Button>
<Button
type={'link'}
onClick={() => {
setAddModalVisible(true);
setEditData(JSON.parse(JSON.stringify(record)));
}}
disabled={[0, 2].includes(record.approvalStatus)}
>
编辑
</Button>
<Button type={'link'} danger onClick={() => handleDelete(record)}> <Button type={'link'} danger onClick={() => handleDelete(record)}>
强制删除 删除
</Button> </Button>
</> </>
), ),
...@@ -162,6 +196,12 @@ const CustomIdentityView = () => { ...@@ -162,6 +196,12 @@ const CustomIdentityView = () => {
<SearchBox <SearchBox
search={[ search={[
{ {
name: 'companyName',
label: '企业名称',
type: 'input',
placeholder: '请输入企业名称',
},
{
name: 'cooperationTagId', name: 'cooperationTagId',
label: '申请加盟类型', label: '申请加盟类型',
type: 'Select', type: 'Select',
...@@ -189,7 +229,7 @@ const CustomIdentityView = () => { ...@@ -189,7 +229,7 @@ const CustomIdentityView = () => {
dataSource={tableData} dataSource={tableData}
columns={columns} columns={columns}
rowKey='id' rowKey='id'
// scroll={{ x: 1500 }} scroll={{ x: 1200 }}
bordered bordered
pagination={{ pagination={{
total: pagination.total, total: pagination.total,
...@@ -201,9 +241,21 @@ const CustomIdentityView = () => { ...@@ -201,9 +241,21 @@ const CustomIdentityView = () => {
showTotal: (total, range) => `当前 ${range[0]}-${range[1]} 条记录 / 共 ${total} 条数据`, showTotal: (total, range) => `当前 ${range[0]}-${range[1]} 条记录 / 共 ${total} 条数据`,
}} }}
/> />
{/*审批弹窗*/}
<ApprovalModal
open={approvalModalVisible}
title={editData?.id ? '审批' : '新增'}
data={editData}
closed={() => {
setApprovalModalVisible(false);
setEditData(undefined);
paginationChange(pagination.current, pagination.pageSize);
}}
/>
{/*编辑弹窗*/}
<AddEditModal <AddEditModal
open={addModalVisible} open={addModalVisible}
title={editData?.id ? '审批' : '新增'} title={editData?.id ? '编辑' : '新增'}
data={editData} data={editData}
closed={() => { closed={() => {
setAddModalVisible(false); setAddModalVisible(false);
......
import React, { useEffect, useState } from 'react';
import { useLocation, useNavigate } from 'react-router-dom';
import qs from 'query-string';
import SearchBox from '~/components/search-box';
import { Button, Table } from 'antd';
import { ArrowLeftOutlined } from '@ant-design/icons';
import { InterListType } from '~/api/interface';
import { listUserRcdType } from '~/api/interface/customManageType';
import { CustomManageAPI } from '~/api';
import { ColumnsType } from 'antd/es/table';
// 表格类型
type TableType = InterListType<listUserRcdType>;
function CustomListDetail() {
// 路由钩子
const location = useLocation();
// 导航钩子
const navigate = useNavigate();
// 表格数据
const [tableData, setTableData] = useState<TableType>([]);
// 表格分页配置
const [pagination, setPagination] = useState({
total: 0,
pageSize: 5,
current: 1,
totalPage: 0,
});
// 加载列表
const getTableList = async (value = {}) => {
// 只需要修改这个地方的接口即可
const res = await CustomManageAPI.listUserRcd({
userAccountId: Number(qs.parse(location.search).id),
pageNo: pagination.current,
pageSize: pagination.pageSize,
...value,
});
if (res && res.code === '200') {
const { list, pageNo, totalCount, pageSize, totalPage } = res.result; // 解构
setPagination({
total: totalCount,
current: pageNo,
pageSize,
totalPage,
});
setTableData(list);
}
};
// 翻页
const paginationChange = (pageNo: number, pageSize: number) => {
getTableList({ pageNo, pageSize }).then();
};
// 返回上一页
const handleBack = () => {
navigate(-1);
};
// componentDidMount
useEffect(() => {
getTableList().then();
}, []);
// 表格结构
const columns: ColumnsType<TableType[0]> = [
{
title: '序号',
dataIndex: 'accountNo',
align: 'center',
width: '50px',
render: (_text, _record, index) => (pagination.current - 1) * pagination.pageSize + index + 1,
},
{
title: '用户名称',
dataIndex: 'userName',
align: 'center',
render: (text, record) => text || record.nickName || '游客用户',
},
{
title: '手机号',
dataIndex: 'phoneNum',
align: 'center',
},
{
title: '注册时间',
dataIndex: 'createTime',
align: 'center',
},
];
return (
<>
<SearchBox
child={
<Button type={'primary'} icon={<ArrowLeftOutlined />} onClick={() => handleBack()}>
返回
</Button>
}
/>
<Table
size='small'
dataSource={tableData}
columns={columns}
rowKey='id'
// scroll={{ x: 1500 }}
bordered
pagination={{
total: pagination.total,
pageSize: pagination.pageSize,
current: pagination.current,
showSizeChanger: true,
showQuickJumper: true,
onChange: (page: number, pageSize: number) => paginationChange(page, pageSize),
showTotal: (total, range) => `当前 ${range[0]}-${range[1]} 条记录 / 共 ${total} 条数据`,
}}
/>
</>
);
}
export default CustomListDetail;
...@@ -6,6 +6,8 @@ import { ChangeModal } from '~/pages/customManage/customList/comp/changeModal'; ...@@ -6,6 +6,8 @@ import { ChangeModal } from '~/pages/customManage/customList/comp/changeModal';
import { InterListType, InterReqType } from '~/api/interface'; import { InterListType, InterReqType } from '~/api/interface';
import { listAppUserType } from '~/api/interface/customManageType'; import { listAppUserType } from '~/api/interface/customManageType';
import { CustomManageAPI, SystemManageAPI } from '~/api'; import { CustomManageAPI, SystemManageAPI } from '~/api';
import qs from 'query-string';
import { useNavigate } from 'react-router-dom';
// 表格数据类型 // 表格数据类型
type TableType = InterListType<listAppUserType>; type TableType = InterListType<listAppUserType>;
...@@ -25,6 +27,8 @@ const portTypeList = [ ...@@ -25,6 +27,8 @@ const portTypeList = [
function CustomListView() { function CustomListView() {
const { confirm } = Modal; const { confirm } = Modal;
// 路由钩子
const navigate = useNavigate();
// 是否打开变更弹窗 // 是否打开变更弹窗
const [isChangeVisModal, setIsChangeVisModal] = useState<boolean>(false); const [isChangeVisModal, setIsChangeVisModal] = useState<boolean>(false);
// 表格分页配置 // 表格分页配置
...@@ -86,6 +90,13 @@ function CustomListView() { ...@@ -86,6 +90,13 @@ function CustomListView() {
}, },
}); });
}; };
// 跳转详情
const handleInvite = (record: TableType[0]) => {
const search = {
id: record.id,
};
navigate(`/customManage/customList/detail?${qs.stringify(search)}`);
};
// componentDidMount // componentDidMount
useEffect(() => { useEffect(() => {
query = {}; query = {};
...@@ -97,7 +108,7 @@ function CustomListView() { ...@@ -97,7 +108,7 @@ function CustomListView() {
const columns: ColumnsType<TableType[0]> = [ const columns: ColumnsType<TableType[0]> = [
{ {
title: '用户UID', title: '用户UID',
dataIndex: 'uid', dataIndex: 'id',
align: 'center', align: 'center',
width: '100px', width: '100px',
}, },
...@@ -150,6 +161,7 @@ function CustomListView() { ...@@ -150,6 +161,7 @@ function CustomListView() {
title: '加盟身份', title: '加盟身份',
dataIndex: 'cooperationTagVOS', dataIndex: 'cooperationTagVOS',
align: 'center', align: 'center',
width: '100px',
render: (_text, record) => render: (_text, record) =>
record.cooperationTagVOS?.map((i, j) => ( record.cooperationTagVOS?.map((i, j) => (
<Tag color='processing' key={j} style={{ marginBottom: '10px' }}> <Tag color='processing' key={j} style={{ marginBottom: '10px' }}>
...@@ -159,15 +171,23 @@ function CustomListView() { ...@@ -159,15 +171,23 @@ function CustomListView() {
}, },
{ {
title: '上级推荐人', title: '上级推荐人',
dataIndex: 'remark',
align: 'center', align: 'center',
render: (_text) => `--`, render: (_text, record) =>
record?.userRcdVO?.id &&
`${record?.userRcdVO?.rcdUserName || record?.userRcdVO?.rcdNickname}(${
record?.userRcdVO?.rcdUserId
})`,
}, },
{ {
title: '推荐伙伴', title: '推荐伙伴',
dataIndex: 'remark', dataIndex: 'inviteCount',
align: 'center', align: 'center',
render: (_text) => `--`, render: (text, record) =>
!!text && (
<Button type={'link'} onClick={() => handleInvite(record)}>
{text}
</Button>
),
}, },
{ {
title: '相关运营', title: '相关运营',
......
/* eslint-disable */
// @ts-nocheck
import { useState } from 'react'; import { useState } from 'react';
import { Form, Input, message, Modal, Upload, UploadProps } from 'antd'; import { Form, Input, message, Modal, Upload, UploadProps } from 'antd';
import { PlusOutlined } from '@ant-design/icons'; import { PlusOutlined } from '@ant-design/icons';
......
.base-info{ .base-info{
&-header{ &-header{
font-weight: bold; font-weight: bold;
margin-bottom: 10px;
line-height: 20px;
}
.info-video-wrap{
position: relative;
width: 200px;
img{
position: absolute;
right: 0;
top: 0;
transform: translate(50%,-25%);
}
}
.region-info{
display: flex;
align-items: center;
div{
margin-right: 10px;
word-break: break-all;
}
} }
} }
...@@ -2,56 +2,248 @@ import { Button, Form, Input, Radio, Select } from 'antd'; ...@@ -2,56 +2,248 @@ import { Button, Form, Input, Radio, Select } from 'antd';
import { Uploader } from '~/components/uploader'; import { Uploader } from '~/components/uploader';
import { EnvironmentOutlined, UploadOutlined } from '@ant-design/icons'; import { EnvironmentOutlined, UploadOutlined } from '@ant-design/icons';
import './index.scss'; import './index.scss';
import React, { FC, forwardRef, useEffect, useImperativeHandle, useState } from 'react';
import deletePng from '~/assets/image/delete.png';
import SelectMapModal from '~/components/select-map';
import { PilotTrainAPI } from '~/api';
import { InterDataType, InterReqType } from '~/api/interface';
import { insertOrgType, licenceScaleList } from '~/api/interface/pilotTrainType';
const BaseInfo = () => { //规模下拉返回类型
type scaleListType = InterDataType<licenceScaleList>;
interface selfProps {
ref: any;
}
//上传机构请求类型
type insertOrgParametersType = Omit<InterReqType<insertOrgType>, 'trainingProgramsVOS'>;
const BaseInfo: FC<selfProps> = forwardRef((props, ref) => {
const [baseInfoForm] = Form.useForm<insertOrgParametersType>();
//地图地点选择
const [selectMapShow, setSelectMapShow] = useState<boolean>(false);
// 位置信息
const [position, setPosition] = useState<{
lat: number;
lon: number;
address: string;
adCode: number;
}>();
const [mainImgList, setMainImgList] = useState<
{
id: number;
name: string;
uid: number;
url: string;
}[]
>([]);
const [subImgList, setSubImgList] = useState<
{
id: number;
name: string;
uid: number;
url: string;
}[]
>([]);
const [videoList, setVideoList] = useState<
{
id: number;
name: string;
uid: number;
url: string;
}[]
>([]);
//规模下拉列表
const [scaleList, setScaleList] = useState<scaleListType>([]);
useImperativeHandle(ref, () => ({
getForm: () => baseInfoForm,
getDefaultDataEvent: () => ({
setPosition,
setMainImgList,
setSubImgList,
setVideoList,
}),
getPosition: () => position,
}));
//上传结果
const uploaderChange = (
value: {
id: number;
name: string;
uid: number;
url: string;
}[],
type: string,
) => {
switch (type) {
case 'mainImg':
baseInfoForm.setFieldValue('mainImage', value[0].url || undefined);
setMainImgList(value);
break;
case 'subImg':
baseInfoForm.setFieldValue(
'auxiliaryPicture',
value.length ? value.map((v) => v.url).join(',') : undefined,
);
setSubImgList(value);
break;
case 'video':
baseInfoForm.setFieldValue('video', value[0].url);
setVideoList(value);
break;
default:
}
};
//视频删除
const deleteVideo = () => {
setVideoList([]);
baseInfoForm.setFieldValue('video', undefined);
};
//地图选点
const showSelectMap = () => [setSelectMapShow(true)];
const selectMapSubmit = (value: {
lat: number;
lon: number;
address: string;
adCode: number;
}) => {
baseInfoForm.setFieldsValue({
region: [
value.adCode.toString().substring(0, 2) + '0000',
value.adCode.toString().substring(0, 4) + '00',
].join(','),
});
setPosition(value);
setSelectMapShow(false);
};
const selectMapClose = () => {
setSelectMapShow(false);
};
//机构规模
const getLicenceScaleList = () => {
PilotTrainAPI.getLicenceScaleList().then(({ result }) => {
setScaleList(result || []);
});
};
useEffect(() => {
getLicenceScaleList();
}, []);
return ( return (
<div className='base-info'> <div className='base-info'>
<div className='base-info-header'>基本信息:</div> <div className='base-info-header'>基本信息:</div>
<div className='base-info-form'> <div className='base-info-form'>
<Form labelCol={{ span: 2 }} wrapperCol={{ span: 7 }}> <Form
<Form.Item label='机构主图'> labelCol={{ span: 2 }}
<Uploader fileUpload listType='picture-card'> wrapperCol={{ span: 7 }}
form={baseInfoForm}
initialValues={{ testCenter: 1 }}
>
<Form.Item
label='机构主图'
name='mainImage'
rules={[{ required: true, message: '请上传机构主图' }]}
>
<Uploader
fileUpload
listType='picture-card'
onChange={(result) => uploaderChange(result, 'mainImg')}
fileLength={1}
fileSize={5}
fileType={['image/jpg', 'image/jpeg', 'image/png']}
defaultFileList={mainImgList}
>
<UploadOutlined /> <UploadOutlined />
</Uploader> </Uploader>
</Form.Item> </Form.Item>
<Form.Item label='机构副图'> <Form.Item
<Uploader fileUpload listType='picture-card'> label='机构副图'
name='auxiliaryPicture'
rules={[{ required: true, message: '请上传机构副图' }]}
>
<Uploader
fileUpload
listType='picture-card'
onChange={(result) => uploaderChange(result, 'subImg')}
fileLength={5}
fileSize={5}
fileType={['image/jpg', 'image/jpeg', 'image/png']}
defaultFileList={subImgList}
>
<UploadOutlined /> <UploadOutlined />
</Uploader> </Uploader>
</Form.Item> </Form.Item>
<Form.Item label='机构视频'> <Form.Item label='机构视频' name='video'>
<Uploader fileUpload listType='text'> {videoList.length ? (
<Button icon={<UploadOutlined />} type='primary'> <div className='info-video-wrap'>
上传视频 {/* eslint-disable-next-line jsx-a11y/media-has-caption */}
</Button> <video
</Uploader> src={videoList[0].url}
style={{ width: '200px', height: '200px' }}
controls
/>
{<img src={deletePng} alt='删除' onClick={deleteVideo} />}
</div>
) : (
<Uploader
fileUpload
listType='text'
onChange={(result) => uploaderChange(result, 'video')}
fileSize={1024}
fileType={['video/mp4', 'video/avi', 'video/wmv', 'video/rmvb']}
fileLength={1}
defaultFileList={videoList}
>
<Button icon={<UploadOutlined />} type='primary'>
上传视频
</Button>
</Uploader>
)}
</Form.Item> </Form.Item>
<Form.Item label='机构名称'> <Form.Item
<Input placeholder='请输入机构名称' /> label='机构名称'
name='name'
rules={[{ required: true, message: '请输入机构名称' }]}
>
<Input placeholder='请输入机构名称' maxLength={30} />
</Form.Item> </Form.Item>
<Form.Item label='机构地区'> <Form.Item
<Button icon={<EnvironmentOutlined />} type='primary'></Button> label='机构地区'
name='region'
rules={[{ required: true, message: '请选择机构地区' }]}
>
<div className='region-info'>
{position?.address ? <div>{position?.address}</div> : ''}
<Button
icon={<EnvironmentOutlined />}
type='primary'
onClick={showSelectMap}
></Button>
</div>
</Form.Item> </Form.Item>
<Form.Item label='考点机构'> <Form.Item label='考点机构' name='testCenter'>
<Radio.Group> <Radio.Group>
<Radio value={1}></Radio> <Radio value={1}></Radio>
<Radio value={0}></Radio> <Radio value={0}></Radio>
</Radio.Group> </Radio.Group>
</Form.Item> </Form.Item>
<Form.Item label='机构规模'> <Form.Item label='机构规模' name='scaleId'>
<Select placeholder='请选择机构规模'> <Select placeholder='请选择机构规模'>
<Select.Option>2-4名</Select.Option> {scaleList.map((scale) => (
<Select.Option>4-6名</Select.Option> <Select.Option value={scale.id} key={scale.id}>
<Select.Option>6-8名</Select.Option> {scale.name}
<Select.Option>10名以上</Select.Option> </Select.Option>
))}
</Select> </Select>
</Form.Item> </Form.Item>
<Form.Item label='机构描述'> <Form.Item label='机构描述' name='description'>
<Input.TextArea placeholder='请选择机构描述' /> <Input.TextArea placeholder='请选择机构描述' maxLength={225} rows={4} showCount />
</Form.Item> </Form.Item>
</Form> </Form>
</div> </div>
<SelectMapModal submit={selectMapSubmit} closed={selectMapClose} open={selectMapShow} />
</div> </div>
); );
}; });
export default BaseInfo; export default BaseInfo;
.introduce-info{
margin-top: 20px;
&-header{
font-weight: bold;
margin-bottom: 10px;
line-height: 20px;
}
&-rich{
}
}
import RichText from '~/components/richText';
import './index.scss';
import { Col, Row } from 'antd';
import { FC } from 'react';
interface selfProps {
setIntroduceInfoEvent: (html: string) => void;
introduceInfo: string;
}
const IntroduceInfo: FC<selfProps> = ({ setIntroduceInfoEvent, introduceInfo }) => {
const onChange = (html?: string) => {
setIntroduceInfoEvent(html || '');
};
return (
<div className='introduce-info'>
<div className='introduce-info-header'>机构介绍:</div>
<div className='introduce-info-rich'>
<Row>
<Col span={1}></Col>
<Col span={18}>
<RichText richTextContent={introduceInfo} onChange={onChange} />
</Col>
</Row>
</div>
</div>
);
};
export default IntroduceInfo;
.sku-info{
margin-top: 20px;
&-header{
font-weight: bold;
margin-bottom: 10px;
line-height: 20px;
}
&-table{
}
}
const SkuInfo = () => { import './index.scss';
return <div className='sku-info'></div>; import { Button, Col, Form, Row, Table } from 'antd';
import { MinusOutlined, PlusOutlined } from '@ant-design/icons';
import EditableCell from '~/components/EditableCell';
import React, { FC, forwardRef, useEffect, useImperativeHandle, useState } from 'react';
import { PilotTrainAPI } from '~/api';
import { InterDataType } from '~/api/interface';
import {
licenceGradeListType,
licenceModelsListType,
licenceTypeListType,
} from '~/api/interface/pilotTrainType';
type EditableTableProps = Parameters<typeof Table>[0];
type ColumnTypes = Exclude<EditableTableProps['columns'], undefined>;
type tableDataType = {
gradeId: number;
id: number;
mainImage: string;
modelsId: number;
price: number;
typeId: number;
fileList: any[];
}; };
//机型下拉返回类型
type modelsListType = InterDataType<licenceModelsListType>;
//等级下拉返回类型
type gradeListType = InterDataType<licenceGradeListType>;
//执照类型返回类型
type typeListType = InterDataType<licenceTypeListType>;
interface selfProps {
ref: any;
}
const SkuInfo: FC<selfProps> = forwardRef((props, ref) => {
const [skuForm] = Form.useForm<any>();
//机型下拉列表
const [modelsList, setModelsList] = useState<modelsListType>([]);
//等级下拉列表
const [gradeList, setGradeList] = useState<gradeListType>([]);
//执照类型列表
const [typeList, setTypeList] = useState<typeListType>([]);
const defaultColumns: (ColumnTypes[number] & {
editable?: boolean;
dataIndex?: string;
selectOption?: { name: string; id: number }[];
inputType?: string;
})[] = [
{
title: '序号',
align: 'center',
render: (_text: string, _record, index: number) => index + 1,
width: '10%',
},
{
title: '培训主图',
align: 'center',
dataIndex: 'mainImage',
width: '10%',
inputType: 'uploader',
editable: true,
},
{
title: '培训机型',
align: 'center',
editable: true,
dataIndex: 'modelsId',
inputType: 'select',
width: '15%',
selectOption: modelsList,
},
{
title: '培训等级',
align: 'center',
editable: true,
dataIndex: 'gradeId',
inputType: 'select',
width: '15%',
selectOption: gradeList,
},
{
title: '培训类型',
align: 'center',
editable: true,
dataIndex: 'typeId',
inputType: 'select',
width: '15%',
selectOption: typeList,
},
{
title: '培训价格',
align: 'center',
editable: true,
dataIndex: 'price',
width: '12%',
},
{
title: '操作',
width: '10%',
onHeaderCell: () => {
return {
style: {
textAlign: 'center',
},
};
},
render: (_text: string, record: any, index) => (
<>
{index === tableData.length - 1 ? (
<Button
icon={<PlusOutlined />}
type='primary'
onClick={addTrainSku}
style={{ marginRight: '10px' }}
></Button>
) : (
''
)}
{index ? (
<Button icon={<MinusOutlined />} danger onClick={() => deleteTrainSku(record)}></Button>
) : (
''
)}
</>
),
},
];
const columns = defaultColumns.map((col) => {
if (!col.editable) {
return col;
}
return {
...col,
onCell: (record: any) => ({
record,
editable: col.editable,
dataIndex: col.dataIndex,
title: col.title,
editing: true,
selectOption: col.selectOption,
inputType: col.inputType,
uploadSuccess: col.inputType === 'uploader' ? uploadSuccess : undefined,
}),
};
});
const [tableData, setTableData] = useState<tableDataType[]>([
{
id: Math.random(),
gradeId: -1,
mainImage: '',
modelsId: -1,
price: -1,
typeId: -1,
fileList: [],
},
]);
useImperativeHandle(ref, () => ({
getForm: () => skuForm,
getTableData: () => tableData,
setDefaultDataEvent: () => ({
setDefaultTableData: (value: any) => setTableData(value),
}),
}));
//加一条培训项目
const addTrainSku = () => {
setTableData([
...tableData,
{
id: Math.random(),
gradeId: -1,
mainImage: '',
modelsId: -1,
price: -1,
typeId: -1,
fileList: [],
},
]);
};
//删除一条培训项目
const deleteTrainSku = (record: tableDataType) => {
const index: number = tableData.findIndex((v) => v.id === record.id);
tableData.splice(index, 1);
setTableData([...tableData]);
};
//主图上传
const uploadSuccess = (record: tableDataType, result: any) => {
const index: number = tableData.findIndex((v) => v.id === record.id);
skuForm.setFieldValue('mainImage' + record.id, result[0].url);
tableData[index].mainImage = result[0].url;
tableData[index].fileList = result;
setTableData([...tableData]);
};
//培训机型下拉
const getLicenceModelsList = () => {
PilotTrainAPI.getLicenceModelsList().then(({ result }) => {
setModelsList(result || []);
});
};
//培训等级下拉
const getLicenceGradeList = () => {
PilotTrainAPI.getLicenceGradeList().then(({ result }) => {
setGradeList(result || []);
});
};
//培训类型下拉
const getLicenceTypeList = () => {
PilotTrainAPI.getLicenceTypeList().then(({ result }) => {
setTypeList(result || []);
});
};
useEffect(() => {
getLicenceModelsList();
getLicenceGradeList();
getLicenceTypeList();
}, []);
return (
<div className='sku-info'>
<div className='sku-info-header'>培训项目:</div>
<div className='sku-info-table'>
<Row>
<Col span={1}></Col>
<Col span={18}>
<Form form={skuForm} component={false}>
<Table
size='small'
rowKey='id'
bordered
columns={columns as ColumnTypes}
components={{
body: {
cell: EditableCell,
},
}}
dataSource={tableData}
pagination={false}
/>
</Form>
</Col>
</Row>
</div>
</div>
);
});
export default SkuInfo; export default SkuInfo;
.institution-form{
&-operate{
height: 100px;
display: flex;
align-items: center;
justify-content: center;
button{
width: 100px;
height: 50px;
}
button:first-child{
margin-right: 50px;
}
}
}
import BaseInfo from './components/baseInfo'; import BaseInfo from './components/baseInfo';
import SkuInfo from './components/skuInfo';
import IntroduceInfo from './components/introduceInfo';
import './index.scss';
import { Button, message } from 'antd';
import { useNavigate, useSearchParams } from 'react-router-dom';
import { useEffect, useRef, useState } from 'react';
import { PilotTrainAPI } from '~/api';
import { InterDataType } from '~/api/interface';
import { listOrgPageType } from '~/api/interface/pilotTrainType';
//sku类型
type tableDataType = {
gradeId: number;
id: number;
mainImage: string;
modelsId: number;
price: number;
typeId: number;
fileList: any[];
};
//机构列表返回类型
type institutionListType = InterDataType<listOrgPageType>['list'];
const AddOrEditInstitution = () => { const AddOrEditInstitution = () => {
const baseRef = useRef<any>();
const skuRef = useRef<any>();
const navigate = useNavigate();
const [searchParams] = useSearchParams();
//机构介绍
const [introduceInfo, setIntroduceInfo] = useState<string>('');
//机构id
const [institutionId, setInstitutionId] = useState<number | undefined>(-1);
//机构详情
const [institutionDetail, setInstitutionDetail] = useState<institutionListType[0]>();
const setIntroduceInfoEvent = (html: string) => {
setIntroduceInfo(html);
};
//保存
const saveDataClick = () => {
Promise.all([
baseRef.current.getForm().validateFields(),
skuRef.current.getForm().validateFields(),
])
.then((value) => {
const skuReqData = skuRef.current.getTableData().map((v: tableDataType) => {
return Object.getOwnPropertyNames(v).reduce((pre: any, cur: string) => {
if (Object.getOwnPropertyNames(value[1]).includes(cur + v.id)) {
pre[cur] = value[1][cur + v.id];
}
return pre;
}, {});
});
PilotTrainAPI[institutionId ? 'updateOrg' : 'insertOrg']({
...value[0],
trainingProgramsVOS: skuReqData,
detail: introduceInfo,
longitude: baseRef.current.getPosition().lon,
latitude: baseRef.current.getPosition().lat,
detailedAddress: baseRef.current.getPosition().address,
id: institutionId || undefined,
}).then(({ code }) => {
if (code === '200') {
message.success(institutionId ? '编辑机构成功' : '上传机构成功');
navigate(-1);
}
});
})
.catch((error) => {
message.warning(error.errorFields[0].errors[0]);
});
};
//机构详情
const getOrgPageDetail = (id: number) => {
PilotTrainAPI.getListOrgPage({ pageNo: 1, pageSize: 10, id }).then(({ result }) => {
if (result.list) {
setInstitutionDetail({ ...result.list[0] });
}
});
};
//返回
const backRoute = () => {
navigate(-1);
};
useEffect(() => {
if (searchParams.get('id')) {
getOrgPageDetail(Number(searchParams.get('id')));
setInstitutionId(Number(searchParams.get('id')));
} else {
setInstitutionId(undefined);
}
}, []);
useEffect(() => {
if (institutionDetail) {
baseRef.current.getForm().setFieldsValue({
mainImage: institutionDetail.mainImage,
auxiliaryPicture: institutionDetail.auxiliaryPicture,
video: institutionDetail.video,
name: institutionDetail.name,
region: institutionDetail.region,
testCenter: institutionDetail.testCenter,
scaleId: institutionDetail.scaleId || undefined,
description: institutionDetail.description || undefined,
});
baseRef.current.getDefaultDataEvent().setPosition({
lat: institutionDetail.latitude,
lon: institutionDetail.longitude,
address: institutionDetail.detailedAddress,
adCode: institutionDetail.region.split(',')[1],
});
baseRef.current.getDefaultDataEvent().setMainImgList([
{
id: Math.random(),
uid: Math.random(),
url: institutionDetail.mainImage,
name: 'mainImage',
},
]);
baseRef.current.getDefaultDataEvent().setSubImgList(
institutionDetail.auxiliaryPicture.split(',').map((v: string) => ({
id: Math.random(),
uid: Math.random(),
url: v,
name: 'auxiliaryPicture',
})),
);
baseRef.current.getDefaultDataEvent().setVideoList([
{
id: Math.random(),
uid: Math.random(),
url: institutionDetail.video,
name: 'video',
},
]);
const programsList = institutionDetail.programsDOList.map((v) => ({
...v,
fileList: [
{
id: Math.random(),
uid: Math.random(),
name: 'img',
url: v.mainImage,
},
],
}));
skuRef.current.setDefaultDataEvent().setDefaultTableData(programsList);
const skuObj = institutionDetail.programsDOList.reduce((pre: any, cur: any) => {
Object.getOwnPropertyNames(cur)
.filter((key: string) => key !== 'id')
.forEach((v: string) => {
pre[v + cur.id] = cur[v];
});
return pre;
}, {});
skuRef.current.getForm().setFieldsValue(skuObj);
setIntroduceInfo(institutionDetail.detail);
}
}, [institutionDetail]);
return ( return (
<div className='institution-form'> <div className='institution-form'>
<BaseInfo /> <BaseInfo ref={baseRef} />
<SkuInfo ref={skuRef} />
<IntroduceInfo setIntroduceInfoEvent={setIntroduceInfoEvent} introduceInfo={introduceInfo} />
<div className='institution-form-operate'>
<Button type='primary' onClick={saveDataClick}>
保存
</Button>
<Button onClick={backRoute}>返回</Button>
</div>
</div> </div>
); );
}; };
......
import SearchBox, { searchColumns } from '~/components/search-box'; import SearchBox, { searchColumns } from '~/components/search-box';
import { Button, Table } from 'antd'; import { Button, message, Modal, Table, Tag } from 'antd';
import { ColumnsType } from 'antd/es/table'; import { ColumnsType } from 'antd/es/table';
import { PlusOutlined } from '@ant-design/icons'; import { PlusOutlined } from '@ant-design/icons';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
import { PilotTrainAPI } from '~/api';
import { useEffect, useState } from 'react';
import { InterDataType, PaginationProps } from '~/api/interface';
import { listOrgPageType } from '~/api/interface/pilotTrainType';
//机构列表返回类型
type institutionListType = InterDataType<listOrgPageType>['list'];
const InstitutionsList = () => { const InstitutionsList = () => {
const navigate = useNavigate(); const navigate = useNavigate();
//培训类型下拉
const search: searchColumns[] = [ const search: searchColumns[] = [
{ label: '机构名称', name: '', placeholder: '请输入机构名称', type: 'input' }, { label: '机构名称', name: '', placeholder: '请输入机构名称', type: 'input' },
{ label: '培训类型', name: '', placeholder: '请选择培训类型', type: 'select', options: [] }, { label: '培训类型', name: '', placeholder: '请选择培训类型', type: 'select', options: [] },
{ label: '选择日期', name: '', placeholder: '请选择日期', type: 'rangePicker', options: [] }, { label: '选择日期', name: '', placeholder: '请选择日期', type: 'rangePicker', options: [] },
]; ];
const tableColumns: ColumnsType<any> = [ const tableColumns: ColumnsType<institutionListType[0]> = [
{ {
title: '序号', title: '序号',
align: 'center', align: 'center',
render: (_text: string, _record, index: number) =>
(pagination.pageNo - 1) * pagination.pageSize + index + 1,
}, },
{ {
title: '机构名称', title: '机构名称',
align: 'center', align: 'center',
dataIndex: 'name',
}, },
{ {
title: '培训类型', title: '培训类型',
align: 'center', align: 'center',
render: (_text: string, record) =>
record.programsDOList.map((v) => <Tag key={v.id}>{v.typeName}</Tag>),
width: '20%',
}, },
{ {
title: '创建日期', title: '创建日期',
dataIndex: 'createTime',
align: 'center', align: 'center',
}, },
{ {
title: '操作', title: '操作',
align: 'center', align: 'center',
render: (_text: string, record) => (
<>
<Button type='link' onClick={() => editInstitutionsClick(record)}>
编辑
</Button>
<Button type='link' danger onClick={() => deleteInstitutionsClick(record)}>
删除
</Button>
</>
),
}, },
]; ];
const [tableData, setTableData] = useState<institutionListType>([]);
const [pagination, setPagination] = useState<PaginationProps & { totalCount: number }>({
pageNo: 1,
pageSize: 10,
totalCount: 0,
});
const toAddInstitutions = () => { const toAddInstitutions = () => {
navigate('/pilotTraining/institutionsList/add'); navigate('/pilotTraining/institutionsList/add');
}; };
//机构列表
const getListOrgPage = () => {
PilotTrainAPI.getListOrgPage({ pageNo: pagination.pageNo, pageSize: pagination.pageSize }).then(
({ result }) => {
setTableData(result.list || []);
pagination.totalCount = result.totalCount;
setPagination(pagination);
},
);
};
//分页-监听
const paginationChange = (pageNo: number, pageSize: number) => {
pagination.pageNo = pageNo;
pagination.pageSize = pageSize;
getListOrgPage();
};
//机构删除
const deleteInstitutionsClick = (record: institutionListType[0]) => {
Modal.confirm({
title: '删除机构',
content: '确认删除该机构吗?',
onOk: () => {
PilotTrainAPI.removeOrg({ id: record.id }).then(({ code }) => {
if (code === '200') {
message.success('删除成功');
if (pagination.pageNo !== 1 && tableData.length === 1) {
pagination.pageNo -= 1;
}
getListOrgPage();
}
});
},
});
};
//机构编辑
const editInstitutionsClick = (record: institutionListType[0]) => {
navigate({ pathname: '/pilotTraining/institutionsList/edit', search: `id=${record.id}` });
};
useEffect(() => {
getListOrgPage();
}, []);
return ( return (
<div className='institutions-list'> <div className='institutions-list'>
<SearchBox <SearchBox
...@@ -46,7 +120,20 @@ const InstitutionsList = () => { ...@@ -46,7 +120,20 @@ const InstitutionsList = () => {
</Button> </Button>
} }
/> />
<Table bordered columns={tableColumns} /> <Table
bordered
columns={tableColumns}
dataSource={tableData}
pagination={{
total: pagination.totalCount,
pageSize: pagination.pageSize,
current: pagination.pageNo,
showSizeChanger: true,
showQuickJumper: true,
onChange: (page: number, pageSize: number) => paginationChange(page, pageSize),
showTotal: (total, range) => `当前 ${range[0]}-${range[1]} 条记录 / 共 ${total} 条数据`,
}}
/>
</div> </div>
); );
}; };
......
...@@ -34,6 +34,7 @@ const bannerType = [ ...@@ -34,6 +34,7 @@ const bannerType = [
// { label: '红包', value: 7 }, // { label: '红包', value: 7 },
{ label: '链接', value: 8 }, { label: '链接', value: 8 },
{ label: '富文本', value: 11 }, { label: '富文本', value: 11 },
{ label: '分享', value: 12 },
]; ];
const AddEditModal: React.FC<propType> = (props) => { const AddEditModal: React.FC<propType> = (props) => {
...@@ -234,6 +235,8 @@ const AddEditModal: React.FC<propType> = (props) => { ...@@ -234,6 +235,8 @@ const AddEditModal: React.FC<propType> = (props) => {
wrapperCol={{ span: 20 }} wrapperCol={{ span: 20 }}
> >
<RichText <RichText
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
value={form.getFieldValue('textContent')} value={form.getFieldValue('textContent')}
onChange={(e) => form.setFieldValue('textContent', e)} onChange={(e) => form.setFieldValue('textContent', e)}
height={250} height={250}
......
...@@ -37,6 +37,7 @@ const bannerType = [ ...@@ -37,6 +37,7 @@ const bannerType = [
// { label: '红包', value: 7 }, // { label: '红包', value: 7 },
{ label: '链接', value: 8 }, { label: '链接', value: 8 },
{ label: '富文本', value: 11 }, { label: '富文本', value: 11 },
{ label: '分享', value: 12 },
]; ];
// 全部数据 // 全部数据
// let tableDataAll: TableType = []; // let tableDataAll: TableType = [];
......
...@@ -110,13 +110,13 @@ function AccountManageView() { ...@@ -110,13 +110,13 @@ function AccountManageView() {
width: '150px', width: '150px',
fixed: 'left', fixed: 'left',
}, },
{ // {
title: '账号类型', // title: '账号类型',
dataIndex: 'companyInfoVO', // dataIndex: 'companyInfoVO',
align: 'center', // align: 'center',
width: '10%', // width: '10%',
render: (_text, record) => (record?.companyInfoVO?.companyType === 1 ? '合伙人' : '员工'), // render: (_text, record) => (record?.companyInfoVO?.companyType === 1 ? '合伙人' : '员工'),
}, // },
{ title: '姓名', dataIndex: 'userName', align: 'center', width: '10%' }, { title: '姓名', dataIndex: 'userName', align: 'center', width: '10%' },
{ {
title: '所属单位', title: '所属单位',
...@@ -125,12 +125,12 @@ function AccountManageView() { ...@@ -125,12 +125,12 @@ function AccountManageView() {
width: '150px', width: '150px',
ellipsis: true, ellipsis: true,
}, },
{ // {
title: '渠道等级', // title: '渠道等级',
dataIndex: 'channelLevel', // dataIndex: 'channelLevel',
align: 'center', // align: 'center',
width: '150px', // width: '150px',
}, // },
{ {
title: '角色', title: '角色',
align: 'center', align: 'center',
...@@ -157,12 +157,12 @@ function AccountManageView() { ...@@ -157,12 +157,12 @@ function AccountManageView() {
width: '10%', width: '10%',
render: (text) => (text === 1 ? '可用' : '停用'), render: (text) => (text === 1 ? '可用' : '停用'),
}, },
{ // {
title: '企业实名认证', // title: '企业实名认证',
dataIndex: 'companyAuthStatus', // dataIndex: 'companyAuthStatus',
align: 'center', // align: 'center',
width: '10%', // width: '10%',
}, // },
{ {
title: '操作', title: '操作',
width: '160px', width: '160px',
...@@ -212,16 +212,16 @@ function AccountManageView() { ...@@ -212,16 +212,16 @@ function AccountManageView() {
type: 'input', type: 'input',
placeholder: '请输入姓名或账号', placeholder: '请输入姓名或账号',
}, },
{ // {
label: '账号类型', // label: '账号类型',
name: 'userType', // name: 'userType',
type: 'Select', // type: 'Select',
placeholder: '请选择账号类型', // placeholder: '请选择账号类型',
options: [ // options: [
{ value: 1, label: '员工' }, // { value: 1, label: '员工' },
{ value: 0, label: '合伙人' }, // { value: 0, label: '合伙人' },
], // ],
}, // },
{ {
label: '角色', label: '角色',
name: 'roleId', name: 'roleId',
......
...@@ -7,26 +7,38 @@ import Cookies from 'js-cookie'; ...@@ -7,26 +7,38 @@ import Cookies from 'js-cookie';
//菜单类型 //菜单类型
type menuType = InterDataType<listMenuInfoType>; type menuType = InterDataType<listMenuInfoType>;
// 缓存路由列表
let routerListStore: any[] = [];
// 获取用户权限路由列表 // 获取用户权限路由列表
export const authRouterList = async () => { export const authRouterList = async () => {
if (localStorage.getItem('roleId') && Cookies.get('SHAREFLY-TOKEN')) { if (localStorage.getItem('roleId') && Cookies.get('SHAREFLY-TOKEN')) {
const { result } = await SystemManageAPI.getListRoleMenuInfo({ // 如果缓存中没有数据
roleId: Number(localStorage.getItem('roleId')), if (routerListStore.length === 0) {
}); // 加载路由数据
const ids: number[] = getAllKeys([result]); const { result } = await SystemManageAPI.getListRoleMenuInfo({
const getRouteList = (data: RouteObjectType[]) => { roleId: Number(localStorage.getItem('roleId')),
return data.reduce((pre: RouteObjectType[], cur) => { });
const Obj: RouteObjectType = { ...cur }; const ids: number[] = getAllKeys([result]);
if (ids.includes(Obj.meta.id) || Obj.meta.hidden) { const getRouteList = (data: RouteObjectType[]) => {
if (Obj.children) { return data.reduce((pre: RouteObjectType[], cur) => {
Obj.children = [...getRouteList(Obj.children)]; const Obj: RouteObjectType = { ...cur };
if (ids.includes(Obj.meta.id) || Obj.meta.hidden || Obj.path?.includes('pilotTraining')) {
if (Obj.children) {
Obj.children = [...getRouteList(Obj.children)];
}
pre.push(Obj);
} }
pre.push(Obj); return pre;
} }, []);
return pre; };
}, []); const arr = [...getRouteList(routerList)];
}; // 将路由数据存到store中
return Promise.resolve([...getRouteList(routerList)]); routerListStore = arr;
// 完成后返回路由数据
return Promise.resolve(arr);
} else {
return Promise.resolve(routerListStore);
}
} }
return Promise.resolve([]); return Promise.resolve([]);
}; };
......
...@@ -102,14 +102,14 @@ const CategoryDetail = React.lazy(() => import('~/pages/categoryManage/category/ ...@@ -102,14 +102,14 @@ const CategoryDetail = React.lazy(() => import('~/pages/categoryManage/category/
// 目录管理 // 目录管理
const DirectoryManage = React.lazy(() => import('~/pages/categoryManage/directoryManage')); const DirectoryManage = React.lazy(() => import('~/pages/categoryManage/directoryManage'));
//飞手培训 // //飞手培训
const InstitutionsListView = React.lazy( // const InstitutionsListView = React.lazy(
() => import('~/pages/pilotTraining/ licensureExamination/institutionsList'), // () => import('~/pages/pilotTraining/ licensureExamination/institutionsList'),
); // );
//机构上传 // //机构上传
const AddInstitutionsView = React.lazy( // const AddInstitutionsView = React.lazy(
() => import('~/pages/pilotTraining/ licensureExamination/addOrEditInstitution'), // () => import('~/pages/pilotTraining/ licensureExamination/addOrEditInstitution'),
); // );
// 系统管理 // 系统管理
import AccountManageView from '~/pages/systemManage/accountManage'; import AccountManageView from '~/pages/systemManage/accountManage';
...@@ -120,7 +120,8 @@ import BusinessCaseManage from '~/pages/resourceManage/businessCaseManage'; ...@@ -120,7 +120,8 @@ import BusinessCaseManage from '~/pages/resourceManage/businessCaseManage';
import CustomIdentityView from '~/pages/customManage/customIdentity'; import CustomIdentityView from '~/pages/customManage/customIdentity';
import CompanyManageView from '~/pages/systemManage/companyManage'; import CompanyManageView from '~/pages/systemManage/companyManage';
import AccountLimit from '~/pages/systemManage/limitManage/roleList'; //账号权限 import AccountLimit from '~/pages/systemManage/limitManage/roleList'; //账号权限
import LimitInfo from '~/pages/systemManage/limitManage/limitInfo'; //权限信息 import LimitInfo from '~/pages/systemManage/limitManage/limitInfo';
import CustomListDetail from '~/pages/customManage/customList/detail'; //权限信息
// const IndustryListView = React.lazy(() => import('~/pages/mallManage/industryManage/industryList')); //行业列表 // const IndustryListView = React.lazy(() => import('~/pages/mallManage/industryManage/industryList')); //行业列表
// const IndustryDetailView = React.lazy( // const IndustryDetailView = React.lazy(
...@@ -198,6 +199,17 @@ export const routerList: Array<RouteObjectType> = [ ...@@ -198,6 +199,17 @@ export const routerList: Array<RouteObjectType> = [
}, },
}, },
{ {
path: '/customManage/customList/detail',
element: withLoadingComponent(<CustomListDetail />),
errorElement: <ErrorPage />,
meta: {
id: 220,
title: '邀请列表',
icon: <SolutionOutlined />,
hidden: true,
},
},
{
path: '/customManage/customMoney', path: '/customManage/customMoney',
element: withLoadingComponent(<CustomMoneyView />), element: withLoadingComponent(<CustomMoneyView />),
errorElement: <ErrorPage />, errorElement: <ErrorPage />,
...@@ -883,39 +895,50 @@ export const routerList: Array<RouteObjectType> = [ ...@@ -883,39 +895,50 @@ export const routerList: Array<RouteObjectType> = [
// }, // },
// ], // ],
// }, // },
{ // {
path: '/pilotTraining', // path: '/pilotTraining',
element: <LayoutView />, // element: <LayoutView />,
errorElement: <ErrorPage />, // errorElement: <ErrorPage />,
meta: { // meta: {
id: 1500, // id: 1500,
icon: <SettingOutlined />, // icon: <BankOutlined />,
title: '飞手培训', // title: '飞手培训',
}, // },
children: [ // children: [
{ // {
path: '/pilotTraining/institutionsList', // path: '/pilotTraining/institutionsList',
element: withLoadingComponent(<InstitutionsListView />), // element: withLoadingComponent(<InstitutionsListView />),
errorElement: <ErrorPage />, // errorElement: <ErrorPage />,
meta: { // meta: {
id: 1510, // id: 1510,
title: '执照考试', // title: '执照考试',
icon: <UserOutlined />, // icon: <VerifiedOutlined />,
}, // },
}, // },
{ // {
path: '/pilotTraining/institutionsList/add', // path: '/pilotTraining/institutionsList/add',
element: withLoadingComponent(<AddInstitutionsView />), // element: withLoadingComponent(<AddInstitutionsView />),
errorElement: <ErrorPage />, // errorElement: <ErrorPage />,
meta: { // meta: {
id: 1520, // id: 1520,
title: '机构上传', // title: '机构上传',
icon: <UserOutlined />, // icon: <UserOutlined />,
hidden: true, // hidden: true,
}, // },
}, // },
], // {
}, // path: '/pilotTraining/institutionsList/edit',
// element: withLoadingComponent(<AddInstitutionsView />),
// errorElement: <ErrorPage />,
// meta: {
// id: 1530,
// title: '机构编辑',
// icon: <UserOutlined />,
// hidden: true,
// },
// },
// ],
// },
{ {
path: '/systemManage', path: '/systemManage',
element: <LayoutView />, element: <LayoutView />,
...@@ -943,7 +966,7 @@ export const routerList: Array<RouteObjectType> = [ ...@@ -943,7 +966,7 @@ export const routerList: Array<RouteObjectType> = [
meta: { meta: {
id: 1420, id: 1420,
title: '权限角色', title: '权限角色',
icon: <UserOutlined />, icon: <TeamOutlined />,
}, },
}, },
{ {
......
...@@ -89,7 +89,7 @@ video { ...@@ -89,7 +89,7 @@ video {
border: 0; border: 0;
font-size: 100%; font-size: 100%;
//font: inherit; //font: inherit;
vertical-align: baseline; //vertical-align: baseline;
} }
/* HTML5 display-role reset for older browsers */ /* HTML5 display-role reset for older browsers */
article, article,
......
This source diff could not be displayed because it is too large. You can view the blob instead.
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论