diff --git a/config/routers/contract.ts b/config/routers/contract.ts index 177d15e..bc9291d 100644 --- a/config/routers/contract.ts +++ b/config/routers/contract.ts @@ -59,4 +59,12 @@ export default [ path: "/contract/kt/itemamount/config", //事项款设置 component: "./contract/ItemAmountSetting", }, + { + path: "/contract/kt/authorization/setting", //合同授权 + component: "./contract/AuthorizationSetting", + }, + { + path: "/contract/kt/expressChargingStandard/setting", //快递收费标准 + component: "./contract/ExpressChargingStandardSetting", + }, ]; diff --git a/config/routers/fvm.ts b/config/routers/fvm.ts index 84017f8..bf90b10 100644 --- a/config/routers/fvm.ts +++ b/config/routers/fvm.ts @@ -330,4 +330,9 @@ export default [ path: "/fvm/plan/ticket/execution", component: "./stock/Plan/TicketExecution", }, + // 加装车配置 + { + path: "/fvm/vehicle/additional", + component: "./stock/VehicleAdditional", + }, ]; diff --git a/config/routers/order3.ts b/config/routers/order3.ts index 1513f6b..bfffcb0 100644 --- a/config/routers/order3.ts +++ b/config/routers/order3.ts @@ -206,8 +206,12 @@ export default [ path: "/order3/retailTaskConfiguration", component: "./order3/RetailTaskConfiguration", }, - { // 附加值任务配置 + { // 附加值任务配置 path: "/order3/addValueTaskConfig", component: "./order3/AddValueTaskConfig", }, + {//分期优惠券抵扣设置 + path: "/order3/orderSetting/loanDiscountSetting", + component: "./order3/OrderSetting/LoanDiscountSetting", + }, ]; \ No newline at end of file diff --git a/config/routers/performance.ts b/config/routers/performance.ts index 5458fff..588dd9f 100755 --- a/config/routers/performance.ts +++ b/config/routers/performance.ts @@ -70,6 +70,31 @@ export default [ component: "./performance/SalarySystemSetting", }, + /** 考评指标 */ + { + path: "/morax/evaSetting", //考评指标库设置 + component: "./performance/EvaSetting", + }, + { + path: "/morax/evaGroupSetting", //考评组设置 + component: "./performance/EvaGroupSetting", + }, + /** 考评组设置==》编辑新增 */ + { + path: "/morax/evaGroupSetting/edit/:id?/:read?/:type?", + component: "./performance/EvaGroupSetting/EditComfirm/index", + }, + /** 考评数据导入 */ + { + path: "/morax/evaDataImport", + component: "./performance/EvaDataImport", + }, + /** 考评数据导入==> 查看数据清单 */ + { + path: "/morax/evaDataImport/edit/:id?/:num?", + component: "./performance/EvaDataImport/EditComfirm/index", + }, + /** 旧 */ { path: "/performance/salaryManage/salaryGroupSetting", //薪酬组设置 diff --git a/package.json b/package.json index 486bef9..11428f7 100644 --- a/package.json +++ b/package.json @@ -54,6 +54,7 @@ "copy-to-clipboard": "^3.3.1", "cos-js-sdk-v5": "0.5.26", "currency.js": "^2.0.3", + "dayjs": "^1.11.7", "global": "^4.4.0", "image-conversion": "^2.1.1", "immer": "^7.0.5", diff --git a/src/components/FeeweeUploadAttachment/index.tsx b/src/components/FeeweeUploadAttachment/index.tsx index 1a9a13f..4cdcbbf 100644 --- a/src/components/FeeweeUploadAttachment/index.tsx +++ b/src/components/FeeweeUploadAttachment/index.tsx @@ -89,7 +89,7 @@ export default function FeeweeUploadAttachment({ })) ); }) - .catch((error: any) => {}) + .catch((error: any) => { }) .finally(() => { // hide(); setLoading(false); @@ -217,9 +217,9 @@ export default function FeeweeUploadAttachment({ return (
{file?.status === "uploading" ? ( @@ -300,9 +299,8 @@ const ListTypeOfText = ({
{file?.name}({file?.size ? getFileSize(file?.size) : ""}) @@ -405,9 +403,8 @@ const ListTypeOfPictureCard = ({ } >
{file?.status === "uploading" ? ( @@ -434,9 +431,8 @@ const ListTypeOfPictureCard = ({ src={IMGURL.showImage( file?.thumbUrl || file?.response?.data )} - alt={`${file?.name}(${ - file?.size ? getFileSize(file?.size) : "" - })`} + alt={`${file?.name}(${file?.size ? getFileSize(file?.size) : "" + })`} className="ant-upload-list-item-image" /> ) : ( @@ -448,9 +444,8 @@ const ListTypeOfPictureCard = ({ style={{ display: file?.type?.includes("image") ? "none" : undefined, }} - title={`${file?.name}(${ - file?.size ? getFileSize(file?.size) : "" - })`} + title={`${file?.name}(${file?.size ? getFileSize(file?.size) : "" + })`} > {file?.name}({file?.size ? getFileSize(file?.size) : ""}) @@ -517,11 +512,9 @@ const ListTypeOfPicture = ({ } >
{file?.status === "uploading" ? ( @@ -531,9 +524,8 @@ const ListTypeOfPicture = ({
{file?.name}({file?.size ? getFileSize(file?.size) : ""}) @@ -563,9 +555,8 @@ const ListTypeOfPicture = ({ {file?.type?.includes("image") ? ( {`${file?.name}(${ ) : ( @@ -576,9 +567,8 @@ const ListTypeOfPicture = ({ target="_blank" rel="noopener noreferrer" className="ant-upload-list-item-name" - title={`${file?.name}(${ - file?.size ? getFileSize(file?.size) : "" - })`} + title={`${file?.name}(${file?.size ? getFileSize(file?.size) : "" + })`} href={ file?.status === "error" ? undefined diff --git a/src/pages/admin/Role/entity.ts b/src/pages/admin/Role/entity.ts index 53493c1..a46c150 100644 --- a/src/pages/admin/Role/entity.ts +++ b/src/pages/admin/Role/entity.ts @@ -1,46 +1,53 @@ /* * @Date: 2021-07-14 10:54:47 * @LastEditors: wangqiang@feewee.cn - * @LastEditTime: 2021-07-29 14:50:55 + * @LastEditTime: 2023-02-27 17:18:17 */ export enum RoleTypeEnum { - '系统角色' = 1, - '流程角色', - '功能角色' + "系统角色" = 1, + "流程角色", + "功能角色", } export const roleTypeTag = { - 1: 'geekblue', - 2: 'purple', - 3: 'orange' + 1: "geekblue", + 2: "purple", + 3: "orange", }; export const roleRange = [1, 2, 3, 4]; export const roleRangeType = { - 1: '展厅', - 2: '服务站', - 3: '二手车店', - 4: '租赁店', + 1: "展厅", + 2: "服务站", + 3: "二手车店", + 4: "租赁店", }; +export enum EnumRoleRangeType { + "展厅" = 1, + "服务站", + "二手车店", + "租赁店", +} + /** 角色输入类型 */ export enum RoleRangeTypeEnum { - '允许' = 1, - '不允许' + "允许" = 1, + "不允许", } /** 角色用途枚举 */ export enum UseTypeEnum { - '默认' = 1, - '业务', - '审批', - '管理' + "默认" = 1, + "业务", + "审批", + "管理", } /** 角色用途颜色枚举 */ export enum UseTypeColorEnum { - '#4189FD' = 1, - '#20C688', - '#FF921C', - '#F93939' -} \ No newline at end of file + "#4189FD" = 1, + "#20C688", + "#FF921C", + "#F93939", +} diff --git a/src/pages/admin/Stand/StandGroup/components/EditModal.tsx b/src/pages/admin/Stand/StandGroup/components/EditModal.tsx index c4ba61b..a1e7c74 100644 --- a/src/pages/admin/Stand/StandGroup/components/EditModal.tsx +++ b/src/pages/admin/Stand/StandGroup/components/EditModal.tsx @@ -20,20 +20,19 @@ export default function DetailModal() { const [loading, setLoading] = useState(false); const [staffList, setStaffList] = useState([]); const [roleShop, setRoleShop] = useState({}); - const [staffSelect, setStaffSelect] = useState([]); const [form] = Form.useForm(); const resetRef = useRef(true); - const [shopValue, setShopValue] = useState(); + // const [shopValue, setShopValue] = useState(); useEffect(() => { if (visible && currentItem.id) { - const _staff = currentItem?.staffList?.map((i:any) => i.staffId); - setShopValue([currentItem.shopId]); + const _staff = currentItem?.staffList?.map((i:any) => ({value: i.staffId, label: i.staffName})); + // setShopValue([{value: currentItem.shopId, label: currentItem.shopName}]); form.setFieldsValue({ name: currentItem.name, roleCode: currentItem.roleCode, roleName: currentItem.roleName, - shop: [currentItem.shopId], + shop: [{value: currentItem.shopId, label: currentItem.shopName}], staff: _staff, }); setRoleShop({roleCode: currentItem.roleCode, roleName: currentItem.roleName, shopId: currentItem.shopId, shopName: currentItem.shopName}); @@ -51,7 +50,6 @@ export default function DetailModal() { } else { setStaffList([]); form.setFieldsValue({staff: []}); - setStaffSelect([]); } }, [roleShop.roleCode, roleShop.shopId]); @@ -75,24 +73,22 @@ export default function DetailModal() { setStaffList([]); setRoleShop({}); setCurrentItem({}); - setStaffSelect([]); resetRef.current = true; } async function onFinish() { const params = await form.validateFields(); - console.log('params', params); setLoading(true); - const _staff = staffSelect.map((v:any) => { + const _staff = params.staff.map((v:any) => { const k = { staffId: v.value, - staffName: v.children + staffName: v.label }; return k; }); const _params: List = { - shopId: params.shop.value, - shopName: params.shop.label, + shopId: Array.isArray(params.shop)? params.shop[0].value: params.shop.value, + shopName: Array.isArray(params.shop)? params.shop[0].label: params.shop.label, roleCode: params.roleCode, roleName: roleShop.roleName, staffList: _staff, @@ -167,7 +163,7 @@ export default function DetailModal() { shopId: item.value || undefined, shopName: item.label || undefined, })} - value={shopValue} + // value={shopValue} /> setStaffSelect(value)} + labelInValue > {staffList.length && staffList.map((item: any) => ( diff --git a/src/pages/capital/ReceiveRules/component/SelectGoodsTable.tsx b/src/pages/capital/ReceiveRules/component/SelectGoodsTable.tsx index cd414e0..dd4fed8 100644 --- a/src/pages/capital/ReceiveRules/component/SelectGoodsTable.tsx +++ b/src/pages/capital/ReceiveRules/component/SelectGoodsTable.tsx @@ -74,6 +74,8 @@ const SelectGoodsTable = (props: Props) => { }; function saveDate() { + console.log("🚀 ~ file: SelectGoodsTable.tsx:80 ~ saveDate ~ selectedRow:", selectedRow); + onChange && onChange(selectedRow); onCancel(); } @@ -87,8 +89,12 @@ const SelectGoodsTable = (props: Props) => { selectedRowKeys: selectedRow.map(row => row.code), onSelect: (row: any, _selected: boolean) => { const index = selectedRow.findIndex((_row) => _row.code == row.code); + if (!multiple) { + setSelectedRow([row]); + return; + } if (_selected) { - selectedRow.unshift(row); + selectedRow.unshift(row); } else if (index > -1) { selectedRow.splice(index, 1); } diff --git a/src/pages/capital/ReceiveRules/subPages/GoodsDimension/components/RenderSelectGoos.tsx b/src/pages/capital/ReceiveRules/subPages/GoodsDimension/components/RenderSelectGoos.tsx index fa066dd..bacad01 100644 --- a/src/pages/capital/ReceiveRules/subPages/GoodsDimension/components/RenderSelectGoos.tsx +++ b/src/pages/capital/ReceiveRules/subPages/GoodsDimension/components/RenderSelectGoos.tsx @@ -2,14 +2,17 @@ import SelectGoodsTable from '@/pages/capital/ReceiveRules/component/SelectGoods import { Button, Card, Popconfirm, Row, Table } from 'antd'; import React, { useState } from 'react'; import { PlusOutlined } from '@ant-design/icons'; +import RenderGoodsSpec from '@/pages/capital/components/RenderGoodsSpec'; const Column = Table.Column; interface GoodsProps { onChange?: Function; value?: any; + multiple?: boolean; + disabled?: boolean; } -function RenderSelectGoos({ onChange, value = [] }: GoodsProps) { +function RenderSelectGoos({ onChange, value = [], multiple, disabled }: GoodsProps) { const [goodsModal, setGoodsModal] = useState({ visible: false }); function deleteItem(code: string) { const newData = value.filter((i: any) => i.code !== code); @@ -18,11 +21,14 @@ function RenderSelectGoos({ onChange, value = [] }: GoodsProps) { return ( - - - + {!disabled ? ( + + + + ) : null} text && } + /> + deleteItem(value.code)}> - + {!disabled && ( + + )} ); @@ -48,6 +63,7 @@ function RenderSelectGoos({ onChange, value = [] }: GoodsProps) { />
setGoodsModal({ visible: false })} onChange={(v) => onChange && onChange(v)} diff --git a/src/pages/contract/AuthorizationSetting/api.ts b/src/pages/contract/AuthorizationSetting/api.ts new file mode 100644 index 0000000..6c2d94f --- /dev/null +++ b/src/pages/contract/AuthorizationSetting/api.ts @@ -0,0 +1,94 @@ +import { http } from "@/typing/http"; +import request from "@/utils/request"; +import qs from 'qs'; +import { CONTRACT_HOST, HOST } from "@/utils/host"; +import { Any } from "currency.js"; + +type PrResArr = http.PromiseResp; + +export interface Item { + id?:number, //授权ID + typeName?:string, //合同类型名称 + createTime?:number, //创建时间 + updateTime?:number, //更新时间 + enabled?:boolean, //是否启用 + roles?:Roles[],//授权角色 +} +export interface Roles { + roleCode?:string, //角色编码 + roleName?:string, //角色名称 +} +export interface TypesItem { + id?: number; // id + name?: string; + fixedAmount?: boolean; + contractableTradeCompCategories?: number[]; + feeType?: string; + feeTypeValue?: string; + bizType?: string; + bizTypeValue?: number; + subjectType?: string; + subjectTypeValue?: string; + servicePlaceTypes?: number[]; +} + +export interface PageParams { + current?: number; + pageSize?: number; + contractTypeName?:string //合同类型名称 +} +export interface SaveParams { + contractAuthId?: number; + typeId: number;//合同类型id + typeName:string //合同类型名称 + roles?:Roles[],//授权角色 +} +interface DelParams { + contractAuthId?: number; //合同授权id +} + +export interface DisableParams { + contractAuthId?: number;//合同授权id + enabled?: boolean;//是否启用 +} + +/** + * 查询所有角色列表 + */ +export function getAllRoleCodeApi(params: CommonApi.RoleParams): PrResArr { + return request.get(`${HOST}/role/listAll`, { params }); +} +/** + * 查询合同类型列表 + */ +export function getContractTypes(params: PageParams): http.PromisePageResp { + return request.get(`${CONTRACT_HOST}/erp/contract/type/page`, { params }); +} + +/** + * 分页查询合同授权 + */ +export function getContractAuthPage(params?: PageParams): http.PromisePageResp { + return request.get(`${CONTRACT_HOST}/erp/contractAuth/page`, {params}); +} + +/** + * 新增合同授权/编辑合同授权 + */ +export function addContractAuth(params?: SaveParams): http.PromisePageResp { + return request.post(`${CONTRACT_HOST}/erp/contractAuth/save`, {...params}); +} + +/** + * 删除合同授权 + */ + export function delContractAuth(params?: DelParams): http.PromisePageResp { + return request.post(`${CONTRACT_HOST}/erp/contractAuth/delete`, {...params}); +} + +/** + * 启用或禁用 + */ + export function disableContractAuth(params?: DisableParams): http.PromisePageResp { + return request.post(`${CONTRACT_HOST}/erp/contractAuth/enableOrDisable`, {...params}); +} \ No newline at end of file diff --git a/src/pages/contract/AuthorizationSetting/components/AddModel/index.tsx b/src/pages/contract/AuthorizationSetting/components/AddModel/index.tsx new file mode 100644 index 0000000..1a47a9f --- /dev/null +++ b/src/pages/contract/AuthorizationSetting/components/AddModel/index.tsx @@ -0,0 +1,132 @@ +import React, { useCallback, useEffect, useState } from "react"; +import { Modal, Skeleton, Select, Form, message } from "antd"; +import * as API from '../../api'; + +interface Props{ + visible:boolean; + row?:API.Item; + contractTypesList:any[], + roleList:any[], + onRefresh: () => void; + onCancel?: () => void; +} + +function AddModel({visible, row, contractTypesList, roleList, onCancel, onRefresh}:Props) { + const [form] = Form.useForm(); + const [loading, setLoading] = useState(false); + const {id, roles, typeName } = row || {}; + useEffect(() => { + if (id) { + form.setFieldsValue({ + contractType: contractTypesList.filter((item:API.TypesItem) => item.name === typeName).map((i:any) => ({label: i.name, value: i.id}))[0], + roleCode: roles?.length && roles.map((i:any) => ({label: i.roleName, value: i.roleCode})), + }); + } + }, [row]); + + /** + * @description: 表单提交 + * @param {any} feildValue + * @return {*} + */ + const handleSave = (feildValue: any) => { + setLoading(true); + const { roleCode, contractType } = feildValue; + const _roleCode = roleCode.length && roleCode.map((item:any) => ({roleCode: item.value, roleName: item.label })); + const params = {roles: _roleCode, typeId: contractType.value, typeName: contractType.label }; + API.addContractAuth({ ...params, contractAuthId: id }) + .then(res => { + message.success("操作成功"); + _onCancel(); + setLoading(false); + onRefresh(); + }) + .catch(err => { + message.error(err?.message); + setLoading(false); + }); + }; + /** + * @description: 关闭弹框 + * @param {*} + * @return {*} + */ + const _onCancel = () => { + onCancel && onCancel(); + form.resetFields(); + }; + + return ( + + +
+ + + + + + +
+
+
+ ); +} + +export default AddModel; \ No newline at end of file diff --git a/src/pages/contract/AuthorizationSetting/components/Filter/index.tsx b/src/pages/contract/AuthorizationSetting/components/Filter/index.tsx new file mode 100644 index 0000000..65f444c --- /dev/null +++ b/src/pages/contract/AuthorizationSetting/components/Filter/index.tsx @@ -0,0 +1,43 @@ +import React, { useCallback, useState } from "react"; +import { Row, Col, Select } from "antd"; +import * as common from "@/typing/common"; +import _ from "lodash"; +import * as API from '../../api'; + +interface Props{ + contractTypesList?:any[], + setParams:any, + innerParams?:any, +} + +function Filter({ contractTypesList, innerParams, setParams }:Props) { + const onChange = _.debounce((contractTypeName: string) => { + setParams({...innerParams, contractTypeName}, true); + }, 350); + return ( + + + + + + ); +} + +export default Filter; \ No newline at end of file diff --git a/src/pages/contract/AuthorizationSetting/components/RolesModel/index.tsx b/src/pages/contract/AuthorizationSetting/components/RolesModel/index.tsx new file mode 100644 index 0000000..ccb2012 --- /dev/null +++ b/src/pages/contract/AuthorizationSetting/components/RolesModel/index.tsx @@ -0,0 +1,32 @@ +import React, { useCallback, useEffect, useState } from "react"; +import { Modal, Form, message, Table } from "antd"; +import * as API from '../../api'; + +interface Props{ + visible:boolean; + roles?:API.Roles[]; + onRefresh: () => void; + onCancel?: () => void; +} +const { Column } = Table; + +function RolesModel({visible, roles, onRefresh, onCancel}:Props) { + return ( + + `${item.roleCode}`} + + > + t || "-"} /> + t || "-"} /> +
+
+ ); +} + +export default RolesModel; \ No newline at end of file diff --git a/src/pages/contract/AuthorizationSetting/index.tsx b/src/pages/contract/AuthorizationSetting/index.tsx new file mode 100644 index 0000000..902ad2b --- /dev/null +++ b/src/pages/contract/AuthorizationSetting/index.tsx @@ -0,0 +1,202 @@ +import React, { useCallback, useState } from "react"; +import { Button, Card, ConfigProvider, Divider, Input, message, Popconfirm, Select, Table } from "antd"; +import { PageHeaderWrapper } from "@ant-design/pro-layout"; +import zhCN from "antd/lib/locale-provider/zh_CN"; +import usePagination from "@/hooks/usePagination"; +import useInitial from "@/hooks/useInitail"; +import { PlusOutlined } from "@ant-design/icons"; +import AddModel from './components/AddModel'; +import RolesModel from './components/RolesModel'; +import Filter from './components/Filter'; +import * as API from './api'; +import _ from "lodash"; +import moment from 'moment'; +import st from "./style.less"; + +const { Column } = Table; +function AuthorizationSetting() { + const [visible, setVisible] = useState(false); + const [searchValue, setSearchValue] = useState({}); + const [rolesVisible, setRolesVisible] = useState(false); + const [row, setRow] = useState(); + const [roles, setRoles] = useState(); + const {data: roleList} = useInitial(API.getAllRoleCodeApi, [], {}); + const { + list: authList, + paginationConfig, + loading, + innerParams, + setParams, + } = usePagination(API.getContractAuthPage, {current: 1, pageSize: 10}); + const { + list: contractTypesList, + } = usePagination(API.getContractTypes, {current: 1, pageSize: 999}); + /** + * @description: 删除 + * @param {*} + * @return {*} + * + */ + const _delete = (row:API.Item) => { + const {id} =row; + API.delContractAuth({contractAuthId: id}) + .then((res) => { + message.success("操作成功"); + setParams({ ...innerParams }, true); + }) + .catch((e) => { + message.error(e.message); + }); + }; + + /** + * @description: 编辑 + * @param {API} row + * @return {*} + */ + const edit = async (row:API.Item) => { + await setRow(row); + setVisible(true); + }; + + /** + * @description: 禁用启用 + * @param {API} row + * @return {*} + */ + const handleDisable = (row:API.Item) => { + const { id, enabled } = row; + API.disableContractAuth({contractAuthId: id, enabled: !enabled}) + .then((res) => { + message.success("操作成功"); + setParams({ ...innerParams }, true); + }) + .catch((err) => { + message.error(err.message); + }); + }; + + const showRoles = async (row:API.Item) => { + const {roles} = row; + try { + await setRoles(roles); + } finally { + setRolesVisible(true); + } + }; + + return ( + + + +
+ + +
+ `${item.id}`} + onChange={(_pagination) => setParams({ ..._pagination }, true)} + > + t || "-"} /> + ( + + )} + /> + (t?'启用':'禁用')} /> + {/* (t ? moment(t).format('YYYY-MM-DD HH:mm') : "-")} /> + (t ? moment(t).format('YYYY-MM-DD HH:mm') : "-")} /> */} + ( + + handleDisable(row)} okText="确定" cancelText="取消"> + { + e.preventDefault(); + }} + style={{ color: "#FAAD14" }} + > + {`${row.enabled ? '禁用' :'启用'}`} + + + + edit(row)} okText="确定" cancelText="取消"> + { + e.preventDefault(); + }} + style={{ color: "#FAAD14" }} + > + 编辑 + + + + _delete(row)} okText="确定" cancelText="取消"> + { + e.preventDefault(); + }} + style={{ color: "red" }} + > + 删除 + + + + + )} + /> +
+ { + setVisible(false); + setRow(undefined); + }} + onRefresh={() => setParams({ ...innerParams }, true)} + /> + { + setRolesVisible(false); + setRoles(undefined); + }} + onRefresh={() => setParams({ ...innerParams }, true)} + /> +
+
+
+ ); +} +export default AuthorizationSetting; diff --git a/src/pages/contract/AuthorizationSetting/style.css b/src/pages/contract/AuthorizationSetting/style.css new file mode 100644 index 0000000..54cc5b3 --- /dev/null +++ b/src/pages/contract/AuthorizationSetting/style.css @@ -0,0 +1,40 @@ +.page { + position: relative; +} +.page .header { + margin-bottom: 10px; + height: 32px; + display: flex; + flex-direction: row; + justify-content: space-between; +} +.page .header .add { + position: absolute; + right: 28px; + top: 24px; + z-index: 10; +} +.table :global .ant-table table { + width: 100%; + border-collapse: collapse; + text-align: center; + border-radius: 4px 4px 0 0; +} +.table :global .ant-table-thead > tr > th, +.table :global .ant-table-tbody > tr > td { + padding: 16px 16px; + word-break: break-word; + text-align: center; + -ms-word-break: break-all; +} +.table .cover { + align-items: center; + height: 68px; +} +.table .cover img { + border-radius: 4%; + height: 100%; + width: auto; + min-width: 100px; + max-width: 100px; +} diff --git a/src/pages/contract/AuthorizationSetting/style.less b/src/pages/contract/AuthorizationSetting/style.less new file mode 100644 index 0000000..e4df1e1 --- /dev/null +++ b/src/pages/contract/AuthorizationSetting/style.less @@ -0,0 +1,48 @@ +//@import '~antd/lib/style/themes/default.less'; + +.page { + position: relative; + + .header { + margin-bottom: 10px; + height: 32px; + display: flex; + flex-direction: row; + justify-content: space-between; + .add { + position: absolute; + right: 28px; + top: 24px; + z-index: 10; + } + } + + } + .table { + :global { + .ant-table table { + width: 100%; + border-collapse: collapse; + text-align: center; + border-radius: 4px 4px 0 0; + } + .ant-table-thead > tr > th, .ant-table-tbody > tr > td { + padding: 16px 16px; + word-break: break-word; + text-align: center; + -ms-word-break: break-all; + } + } + .cover { + align-items: center; + height: 68px; + img { + border-radius: 4%; + height: 100%; + width: auto; + min-width: 100px; + max-width: 100px; + } + } + } + \ No newline at end of file diff --git a/src/pages/contract/BearCostSetting/components/BearModal/index.tsx b/src/pages/contract/BearCostSetting/components/BearModal/index.tsx index 2e29c96..46a8964 100644 --- a/src/pages/contract/BearCostSetting/components/BearModal/index.tsx +++ b/src/pages/contract/BearCostSetting/components/BearModal/index.tsx @@ -34,7 +34,7 @@ const BearModal = ({visible, onCancel, item = {} as BearCostSetting.Item}:Props) dataSource={item.shareRateItemList || []} rowKey={(item) => `${item.id}`} > - t || "-"} /> + t || "-"} /> (t && `${(t*100).toFixed(2)}%`) || "-"} /> diff --git a/src/pages/contract/BearCostSetting/components/ShareRateItemlist/index.tsx b/src/pages/contract/BearCostSetting/components/ShareRateItemlist/index.tsx index 3ddfae7..3a51f56 100644 --- a/src/pages/contract/BearCostSetting/components/ShareRateItemlist/index.tsx +++ b/src/pages/contract/BearCostSetting/components/ShareRateItemlist/index.tsx @@ -128,7 +128,7 @@ const ShareRateItemlist = ({onChange, value=[]}:Props) => { size="small" > t || "-"} @@ -176,7 +176,7 @@ const ShareRateItemlist = ({onChange, value=[]}:Props) => { onCancel={closeModal} onOk={form.submit} > -
+ { @@ -241,7 +241,7 @@ const ShareRateItemlist = ({onChange, value=[]}:Props) => { name="shareRate" rules={[{ required: true, message: '请输入缴费标识' }]} > - + = http.PromiseResp; + +export interface PageParams { + current?: number; + pageSize?: number; + tradeCompId?:number; //合同类型名称 + sendAreaNo?:string; //寄件地区编号 + arriveAreaNo?:string; //到达地区编号 +} + +export interface SaveParams { + expressChargeStandardId?:number; //id,提供该参数将执行编辑操作 + tradeCompId:number; //往来单位id + tradeCompName:string; //往来单位名称 + sendAreaNo:string; //寄件地区编号 + sendAreaName:string; //寄件地区名称 + firstWeight:number; //首重 + continuedWeight:number; //续重 + arriveAreas:ArriveAreas[]; //到达地区 +} + +export interface DelParams { + expressChargeStandardId:number; //快递收费标准id +} + +export interface ArriveAreas { + arriveAreaNo:string; //到达地区编号 + arriveAreaName:string; //到达地区名称 +} + +export interface Item { + id?:number; + tradeCompName?:string; //往来单位名称 + tradeCompShortName?:string; //往来单位简称 + sendAreaName?:string; //寄件地区名称 + arriveAreaName?:string; //到达地区名称 + firstWeight?:number; //首重 + continuedWeight?:number; //续重 +} + +/** + * 分页查询快递收费标准 + */ + export function getStandardPage(params?: PageParams): http.PromisePageResp { + return request.get(`${CONTRACT_HOST}/erp/express/charge/standard/page`, { params }); +} + +/** + * 新增/编辑快递收费标准 + */ + export function addStandardSave(params: SaveParams): http.PromiseResp { + return request.post(`${CONTRACT_HOST}/erp/express/charge/standard/save`, { ...params }); +} + +/** + * 删除快递收费标准 + */ + export function delStandard(params: DelParams): http.PromiseResp { + return request.post(`${CONTRACT_HOST}/erp/express/charge/standard/delete`, { ...params }); +} + +/**获取往来单位列表*/ +export function fetchComps(params?: any): http.PromiseResp { + return request.get(`${FINANCE2_HOST}/common/trade/company/list`, {params }); +} + +/** + * 城市列表 + */ + export function getCityLsit(): http.PromiseResp { + const params = { pbh: 0 }; + return request.get(`/oop/select/region`, { params }); +} \ No newline at end of file diff --git a/src/pages/contract/ExpressChargingStandardSetting/components/AddModel/index.tsx b/src/pages/contract/ExpressChargingStandardSetting/components/AddModel/index.tsx new file mode 100644 index 0000000..bca7683 --- /dev/null +++ b/src/pages/contract/ExpressChargingStandardSetting/components/AddModel/index.tsx @@ -0,0 +1,187 @@ +import React, { useCallback, useEffect, useState } from "react"; +import { Modal, Skeleton, Select, Form, message, InputNumber } from "antd"; +import * as API from '../../api'; +import _ from "lodash"; + +interface Props { + visible:boolean; + row?:API.Item; + compList:any[]; + cityList:any[]; + onCancel:()=>void; + onRefresh:() => void; + +} + +function AddModel({visible, row, compList, cityList, onCancel, onRefresh}:Props) { + const [form] = Form.useForm(); + const [loading, setLoading] = useState(false); + const { id } = row || {}; + useEffect(() => { + if (id) { + const { tradeCompName, sendAreaName, firstWeight, continuedWeight, arriveAreaName } = row || {}; + form.setFieldsValue({ + tradeComp: compList.filter(it => tradeCompName === it.name).map(item => ({value: item.id, label: item.name}))[0], + sendArea: cityList.filter(it => sendAreaName === it.fullName).map(item => ({value: item.bh, label: item.fullName}))[0], + firstWeight, + continuedWeight, + arriveAreas: cityList.filter(it => arriveAreaName === it.fullName).map(item => ({value: item.bh, label: item.fullName}))[0] + + }); + } + }, [row]); + + /** + * @description: 确定 + * @param {*} + * @return {*} + */ + const handleSave = (feildValue:any) => { + setLoading(true); + const {tradeComp, sendArea, arriveAreas, firstWeight, continuedWeight} = feildValue; + const _arriveAreas = id ? [{ ...arriveAreas }].map(item => ({arriveAreaNo: item.value, arriveAreaName: item.label})) + : arriveAreas.length && arriveAreas.map((item:any) => ({arriveAreaNo: item.value, arriveAreaName: item.label})); + + const params = { + expressChargeStandardId: id, + tradeCompId: tradeComp.value, + tradeCompName: tradeComp.label, + tradeCompShortName: compList && compList.filter(item => item.id == tradeComp.value)[0].shortName, + sendAreaNo: sendArea.value, + sendAreaName: sendArea.label, + firstWeight, + continuedWeight, + arriveAreas: _arriveAreas + }; + API.addStandardSave({ ...params }) + .then(res => { + message.success("操作成功"); + _onCancel(); + setLoading(false); + onRefresh(); + }).catch(err => { + message.error(err?.message); + setLoading(false); + }); + }; + /** + * @description: 关闭弹框 + * @param {*} + * @return {*} + */ + const _onCancel = () => { + onCancel && onCancel(); + form.resetFields(); + }; + + return ( + + + + + + + + + + + + + + + + + + + + + + ); +} + +export default AddModel; \ No newline at end of file diff --git a/src/pages/contract/ExpressChargingStandardSetting/components/Filter/index.tsx b/src/pages/contract/ExpressChargingStandardSetting/components/Filter/index.tsx new file mode 100644 index 0000000..d5f3db6 --- /dev/null +++ b/src/pages/contract/ExpressChargingStandardSetting/components/Filter/index.tsx @@ -0,0 +1,89 @@ +import React, { useCallback, useState } from "react"; +import { Row, Col, Select } from "antd"; +import _ from "lodash"; + +interface Props { + setParams:any; + innerParams:any; + cityList:any[]; + compList:BearCostSetting.Comp[]; +} + +interface SearchData { + tradeCompId?:number;//往来单位id + sendAreaNo?:string;//寄件地区编号 + arriveAreaNo?:string;//到达地区编号 +} + +function Filter({ compList, cityList, setParams, innerParams }:Props) { + const [searchData, setSearchData] = useState({}); + return ( + + + + + + + + + + + + ); +} + +export default Filter; \ No newline at end of file diff --git a/src/pages/contract/ExpressChargingStandardSetting/index.tsx b/src/pages/contract/ExpressChargingStandardSetting/index.tsx new file mode 100644 index 0000000..1a08992 --- /dev/null +++ b/src/pages/contract/ExpressChargingStandardSetting/index.tsx @@ -0,0 +1,149 @@ +import React, { useState } from "react"; +import { Button, Card, ConfigProvider, Divider, message, Popconfirm, Table } from "antd"; +import { PageHeaderWrapper } from "@ant-design/pro-layout"; +import zhCN from "antd/lib/locale-provider/zh_CN"; +import usePagination from "@/hooks/usePagination"; +import useInitial from "@/hooks/useInitail"; +import { PlusOutlined } from "@ant-design/icons"; +import AddModel from './components/AddModel'; +import Filter from './components/Filter'; +import * as API from './api'; +import _ from "lodash"; +import st from "./style.less"; + +interface Props { +} + +const { Column } = Table; + +function expressChargingStandard(props:Props) { + const [visible, setVisible] = useState(false); + const { + list: standardList, + loading, + paginationConfig, + innerParams, + setParams, + setLoading + } = usePagination(API.getStandardPage, {current: 1, pageSize: 10}); + const { data: cityList, loading: cityLoading } = useInitial(API.getCityLsit, [], {}); + const { data: compList, loading: compLoading } = useInitial(API.fetchComps, [], {types: '88'}); + const [row, setRow] = useState(); + /** + * @description: 编辑 + * @param {*} _ + * @return {*} + */ + const edit = _.debounce(async (row:API.Item) => { + await setRow({...row}); + setVisible(true); + }, 800); + + /** + * @description: 删除 + * @param {*} _ + * @return {*} + */ + const _delete = _.debounce((row:API.Item) => { + const {id} = row; + if (!id) return; + setLoading(true); + API.delStandard({expressChargeStandardId: id}) + .then(res => { + message.success("操作成功"); + setParams({...innerParams}, true); + setLoading(false); + }).catch(err => { + message.error(err?.message); + setLoading(false); + }); + }, 800); + + return ( + + + +
+ + +
+ `${item.id}`} + onChange={(_pagination) => setParams({ ..._pagination }, true)} + > + t || "-"} /> + t || '-'} /> + t || '-'} /> + t || '-'} /> + t || '-'} /> + ( + + edit(row)} okText="确定" cancelText="取消"> + { + e.preventDefault(); + }} + style={{ color: "#FAAD14" }} + > + 编辑 + + + + _delete(row)} okText="确定" cancelText="取消"> + { + e.preventDefault(); + }} + style={{ color: "red" }} + > + 删除 + + + + + )} + /> +
+ { + setVisible(false); + setRow(undefined); + }} + onRefresh={() => setParams({ ...innerParams }, true)} + /> +
+
+
+ ); +} + +export default expressChargingStandard; \ No newline at end of file diff --git a/src/pages/contract/ExpressChargingStandardSetting/style.less b/src/pages/contract/ExpressChargingStandardSetting/style.less new file mode 100644 index 0000000..e4df1e1 --- /dev/null +++ b/src/pages/contract/ExpressChargingStandardSetting/style.less @@ -0,0 +1,48 @@ +//@import '~antd/lib/style/themes/default.less'; + +.page { + position: relative; + + .header { + margin-bottom: 10px; + height: 32px; + display: flex; + flex-direction: row; + justify-content: space-between; + .add { + position: absolute; + right: 28px; + top: 24px; + z-index: 10; + } + } + + } + .table { + :global { + .ant-table table { + width: 100%; + border-collapse: collapse; + text-align: center; + border-radius: 4px 4px 0 0; + } + .ant-table-thead > tr > th, .ant-table-tbody > tr > td { + padding: 16px 16px; + word-break: break-word; + text-align: center; + -ms-word-break: break-all; + } + } + .cover { + align-items: center; + height: 68px; + img { + border-radius: 4%; + height: 100%; + width: auto; + min-width: 100px; + max-width: 100px; + } + } + } + \ No newline at end of file diff --git a/src/pages/coupon/CouponConfig/components/FullReduce.tsx b/src/pages/coupon/CouponConfig/components/FullReduce.tsx index 948f3b3..08e295e 100644 --- a/src/pages/coupon/CouponConfig/components/FullReduce.tsx +++ b/src/pages/coupon/CouponConfig/components/FullReduce.tsx @@ -8,6 +8,7 @@ import ShopLimit from "./ShopLimit"; import useInitail from "@/hooks/useInitail"; import { PaymentTypeEnum } from '@/pages/coupon/CashChange/api'; import { RightOutlined } from '@ant-design/icons'; +import RenderSelectGoos from '@/pages/capital/ReceiveRules/subPages/GoodsDimension/components/RenderSelectGoos'; const Option = Select.Option; interface Props { @@ -20,6 +21,7 @@ interface Props { limitCoupon?: string[]; // 优惠券类型限制 carSelectApi?: Function expires?: boolean; + changeEditKeys?: string[]; } export default function FullReduce({ @@ -30,8 +32,8 @@ export default function FullReduce({ confNo, limitCoupon, carSelectApi, - expires - + expires, + changeEditKeys, }: Props) { const [classifyInfo, setClassifyInfo] = useState({ code: "" }); const { data: ClassifyList } = useInitail(api.fetchClassifyList, [], {}); @@ -136,7 +138,7 @@ export default function FullReduce({ extra={ 示例:至高6500元鲸喜基金; -
setVisible(true)} > @@ -146,12 +148,12 @@ export default function FullReduce({ } > - + {!!expires && ( )} + {/* 实物兑换券选择兑换物品 */} + {classifyInfo.code === "dhyhq" && ( + *兑换物品仅限一个} rules={[{ required: true, message: '请选择' }]}> + + + )} { - const changedKeys = changeRows.map(row => row.partCode); + const changedKeys = changeRows.map(row => row[rowKey]); let newData = [...selected]; // 全选 if (onSelected) { @@ -120,7 +120,7 @@ export default function TableSelect(props: TableSelectProps) { ))} diff --git a/src/pages/coupon/CouponConfig/components/WareLimitType/index.tsx b/src/pages/coupon/CouponConfig/components/WareLimitType/index.tsx index fb5cffe..22727f2 100644 --- a/src/pages/coupon/CouponConfig/components/WareLimitType/index.tsx +++ b/src/pages/coupon/CouponConfig/components/WareLimitType/index.tsx @@ -19,21 +19,22 @@ interface Props { schemes: MktConponSpace.ClassifyList; formItemLayout: {}; carSelectApi?: Function; + changeEditKeys?: string[]; } const WareLimitType = (props: Props) => { - const { form, info, schemes, readonly, carSelectApi } = props; + const { form, info, schemes, readonly, carSelectApi, changeEditKeys } = props; /**根据场景选择限制条件 */ - function externalRender(type: string) { + function externalRender(type: string, editDisabled: boolean) { const key = typeof type === 'string' ? type : String(type); switch (key) { - case '1': return (); - case '2': return (schemes.code === "zhyhq" ? : ); - case '3': return (); - case '4': return (); - case '5': return (); - case '7': return (); - case '6': return (); + case '1': return (); + case '2': return (schemes.code === "zhyhq" ? : ); + case '3': return (); + case '4': return (); + case '5': return (); + case '7': return (); + case '6': return (); default: return null; } } @@ -66,7 +67,8 @@ const WareLimitType = (props: Props) => { > {({ getFieldValue }): any => { const limits = getFieldValue("schemeList")[key]; - console.log(123, getFieldValue("schemeList")) + // console.log(123, getFieldValue("schemeList")); + const editDisabled = changeEditKeys ? readonly && limits.limitScheme && !changeEditKeys.includes("schemeList") : readonly; if (limits.limitScheme) { return ( <> @@ -103,7 +105,7 @@ const WareLimitType = (props: Props) => { }), ]} > - {externalRender(limits.schemeType)} + {externalRender(limits.schemeType, editDisabled)} )} diff --git a/src/pages/coupon/CouponConfig/index.tsx b/src/pages/coupon/CouponConfig/index.tsx index 70b540a..538fbf0 100644 --- a/src/pages/coupon/CouponConfig/index.tsx +++ b/src/pages/coupon/CouponConfig/index.tsx @@ -3,25 +3,11 @@ import { Button, Card, Form, message, Modal, Spin } from "antd"; import FullReduce from "@/pages/coupon/CouponConfig/components/FullReduce"; import * as api from "./api"; -interface Props { - visible: boolean; - onCancel: Function; - /**配置编码 */ - confNo?: string; - /**备注 表明是哪个系统嵌入创建的次优惠券配置 */ - remark: string; - disabled?: boolean; - onSave: Function; - limitCoupon?: string[] // 优惠券类型限制 - /**车辆选择自定义接口,不传默认查询oop全部车辆 */ - carSelectApi?: Function; - /**是否展示优惠券固定天数有效期时间限制 */ - expires?: boolean; - /**优惠券固定天数有效期时间限制(评价有礼) */ - expiresDay?: number; +interface Props extends MktConponSpace.CouponProps { + } -export default function UpsertCoupon({ visible, onCancel, onSave, remark, disabled, confNo, limitCoupon, carSelectApi, expires, expiresDay }: Props) { +export default function UpsertCoupon({ visible, onCancel, onSave, remark, disabled, confNo, limitCoupon, carSelectApi, expires, expiresDay, getCouponDetailsApi, ...others }: Props) { const [form] = Form.useForm(); const [info, setInfo] = useState({} as MktConponSpace.ConListParams); const [loading, setLoading] = useState(false); @@ -36,7 +22,8 @@ export default function UpsertCoupon({ visible, onCancel, onSave, remark, disabl function getDetails(no: string) { setLoading(true); - api.fetchCasView(no).then((res) => { + const detailApi = getCouponDetailsApi || api.fetchCasView; + detailApi(no).then((res) => { const data = res.data || {} as any; setInfo(data); form.setFieldsValue({ @@ -45,6 +32,7 @@ export default function UpsertCoupon({ visible, onCancel, onSave, remark, disabl classifyCode: data.classifyCode ? { value: data.classifyCode, label: data.classifyName } : undefined, exchangeTypeId: data.exchangeTypeId ? { value: data.exchangeTypeId, label: data.exchangeTypeName } : undefined, orgList: data.orgList ? data.orgList.map((i) => ({ value: i.orgId, label: i.orgName })) : undefined, + amsCode: data.amsCode ? [{ code: data.amsCode, name: data.amsName, spec: data.amsSpec }] : undefined, }); setLoading(false); }).catch((e) => { @@ -77,6 +65,7 @@ export default function UpsertCoupon({ visible, onCancel, onSave, remark, disabl form.validateFields().then((fields) => { const params = { id: info.id, + confNo: info.confNo, ...fields, orgList: fields.orgList ? fields.orgList.map((i: { value: any; label: any }) => ({ orgId: i.value, orgName: i.label })) : [], classifyCode: fields.classifyCode.value, @@ -84,15 +73,16 @@ export default function UpsertCoupon({ visible, onCancel, onSave, remark, disabl exchangeTypeId: fields.exchangeTypeId && fields.exchangeTypeId.value, exchangeTypeName: fields.exchangeTypeId && fields.exchangeTypeId.label, schemeList: fields.schemeList ? fields.schemeList.map((i: MktConponSpace.LimitList) => ({ ...i, externalRely: i.externalRely || false })) : [], + amsCode: fields.amsCode && fields.amsCode.map((i: { code: string; }) => i.code).join(','), remark, }; setSaveLoading(true); - api - .saveConpon(params) + const saveApi = others.saveChangeCouponApi || api.saveConpon; + saveApi(params) .then((res) => { const result = { ...res, - confNo: res.data && res.data.confNo, + confNo: res.data && res.data.confNo || info.confNo, classifyCode: res.data && res.data.classifyCode, classifyName: params.classifyName, exchangeTypeId: params.exchangeTypeId, @@ -119,10 +109,20 @@ export default function UpsertCoupon({ visible, onCancel, onSave, remark, disabl } return ( - form.resetFields()} confirmLoading={loading || saveLoading} onOk={formSubmit} footer={disabled ? false : undefined} onCancel={() => { onCancel(); setInfo({}); }}> + form.resetFields()} + confirmLoading={loading || saveLoading} + onOk={formSubmit} + footer={disabled && !others.changeEditKeys ? false : undefined} + onCancel={() => { onCancel(); setInfo({}); }} + > ; + } interface decParams { id?: number, // 商品ID name?: string, // 商品名称 // partCode?: string, // 备件编码[string] Keywords?: string, //商品名称/代码 brandId?: number, // 品牌ID[long] - seriesId?: number, + seriesId?: number, yn?: boolean, //是否有效 bizType?: number, //0,"装潢",1,"配件零售" current?: number, @@ -60,6 +84,7 @@ declare namespace MktConponSpace { }>; //适用机构列表 当机构类型为发券门店时,可以为空列表 schemeList: LimitList[]; //限制规则 discountsType?: number; //折扣类型 1立减2兑换 + giftItemId?: number; } interface LimitList { diff --git a/src/pages/coupon/CouponOperation/components/CouponLog.tsx b/src/pages/coupon/CouponOperation/components/CouponLog.tsx index 7f3affb..7d1bafd 100644 --- a/src/pages/coupon/CouponOperation/components/CouponLog.tsx +++ b/src/pages/coupon/CouponOperation/components/CouponLog.tsx @@ -109,7 +109,7 @@ function CouponLog({ couponLog, setCouponLog, onChange }: Props) { `id${record.type}`} + rowKey="id" > ("save"); const tempItem = useRef(); + const rangeRoleSelectorRef = useRef(null); useEffect(() => { if (visible) { @@ -354,6 +357,12 @@ export default function ProgramOfStudySettingsModal() { type?: number; list?: { value?: string; label?: string }[]; }) => { + // 如果选择的是 1 按品牌 或 2 按车系 则角色的 authRange 必须包含 1 展厅 3 二手车店 + if (value?.type === 1 || value?.type === 2) { + rangeRoleSelectorRef.current?.setIncludesPreSale(true); + } else { + rangeRoleSelectorRef.current?.setIncludesPreSale(false); + } questionBankInitial.setParams( { adapterType: value?.type, @@ -390,7 +399,12 @@ export default function ProgramOfStudySettingsModal() { return value; }} > - + void; +} + /** * @description: 根据授权查询角色选择器-适用于表单 */ -export default function StandardAuthRoleSelector({ - value, - onChange, - style, - disabled = false, - mode, - labelInValue, - useFilter, -}: Props) { +export default forwardRef(StandardAuthRoleSelector); + +function StandardAuthRoleSelector( + { + value, + onChange, + style, + disabled = false, + mode, + labelInValue, + useFilter, + }: Props, + ref: Ref +) { + const [includesPreSale, setIncludesPreSale] = useState(false); const { data } = useInitail(getAllRoleCodeApi, [], { roleType: 2 }); const roleList = useMemo( - () => data.filter((role) => [CommonUseType.业务, CommonUseType.管理].includes(role.useType!) + () => data.filter((role) => ([CommonUseType.业务, CommonUseType.管理].includes(role.useType!) && + includesPreSale + ? role.authRange?.includes("" + EnumRoleRangeType.展厅) || + role.authRange?.includes("" + EnumRoleRangeType.二手车店) + : true) ), - [data] + [data, includesPreSale] ); + useImperativeHandle(ref, () => ({ + setIncludesPreSale, + })); + return !useFilter ? (
onChange && onChange({ type: value?.type, list })} + onChange={(selected, list: any) => { + onChange && onChange({ type: value?.type, list }); + }} style={{ flex: 1, width: "100%" }} getPopupContainer={(triggerNode) => triggerNode.parentNode} > {(roleList || []).map((role) => ( - + {role.roleName} ))} diff --git a/src/pages/finance/FinanceInvestor/components/Filter.tsx b/src/pages/finance/FinanceInvestor/components/Filter.tsx index 224207b..c7c7e77 100644 --- a/src/pages/finance/FinanceInvestor/components/Filter.tsx +++ b/src/pages/finance/FinanceInvestor/components/Filter.tsx @@ -8,26 +8,11 @@ const { Option } = Select; const Search = Input.Search; export default function AccountList() { - // const { setVisible, setParams, innerParams, dealerLoading, dealerList } = useStore(); const { triggerModal, brands, financeList, setInvestList, companys, dealers } = useStore(); - // investList, - // setInvestList, // 存储删选条件 const [filterParams, setFilterParams] = useState({}); - console.log("投资主体11列表", financeList); - - // function searchType(accountType: number) { - // setParams({ accountType }, true); - // } - - // _onSelectSubject; - // const fetchListByName = debounce(value => { - // setParams({ keywords: value }, true); - // }, 500); - useEffect(() => { - console.log("筛选参数filterParams", filterParams); let originList = financeList; let res = []; if (filterParams.brandId) { @@ -41,7 +26,6 @@ export default function AccountList() { if (filterParams.includeId) { //删选包含商家 includeId originList = originList.filter((item) => item.includeDealers?.find((y) => y.id === filterParams.includeId)); - console.log("筛选输入:", originList); } if (filterParams.creditDealerId) { //删选授信商家 creditDealerId diff --git a/src/pages/finance/Reimburse/FieldService/api.ts b/src/pages/finance/Reimburse/FieldService/api.ts index 6eff4cd..29f0351 100644 --- a/src/pages/finance/Reimburse/FieldService/api.ts +++ b/src/pages/finance/Reimburse/FieldService/api.ts @@ -1,6 +1,6 @@ import { http } from "@/typing/http"; import request from "@/utils/request"; -import { FINANCE2_HOST } from "@/utils/host"; +import { FINANCE2_HOST, ATTENDANCE_HOST } from "@/utils/host"; type P = http.PromiseResp; @@ -20,8 +20,8 @@ export interface Item { dinner?: number //晚餐 } export interface outType{ - id?:number, - name?:string + outsideType?:number, + outsideTypeName?:string } /**查询外勤报销设置列表*/ export function fetchList(): P { @@ -45,5 +45,5 @@ export function updataApi(params?: Item): P { /**外勤类型列表*/ export function fetchOutsideTypeList(): P { - return request.get(`${FINANCE2_HOST}/reimburse/setting/way/outside/type`); + return request.get(`${ATTENDANCE_HOST}/reason/setting/getOutsideTypeList`); } \ No newline at end of file diff --git a/src/pages/finance/Reimburse/FieldService/components/Modal.tsx b/src/pages/finance/Reimburse/FieldService/components/Modal.tsx index 5d3e94c..3456383 100644 --- a/src/pages/finance/Reimburse/FieldService/components/Modal.tsx +++ b/src/pages/finance/Reimburse/FieldService/components/Modal.tsx @@ -35,7 +35,7 @@ function CreateModal(props: Props) { const params = { id: current?.id || undefined, outsideType: item.outsideType, - outsideTypeName: data.find(i => i.id == item.outsideType)?.name, + outsideTypeName: data.find(i => i.outsideType == item.outsideType)?.outsideTypeName, isAllowReimburse: item.isAllowReimburse, breakfast: item.breakfast, lunch: item.lunch, @@ -94,8 +94,8 @@ function CreateModal(props: Props) { filterOption={(input: any, option: any) => option.children.toLowerCase().indexOf(input.toLowerCase()) >= 0} > {data.map((item: any) => ( - - {item.name} + + {item.outsideTypeName} ))} diff --git a/src/pages/finance/SpecialAccount/FactoryBill/components/Filter.tsx b/src/pages/finance/SpecialAccount/FactoryBill/components/Filter.tsx index 4bf5841..472b987 100644 --- a/src/pages/finance/SpecialAccount/FactoryBill/components/Filter.tsx +++ b/src/pages/finance/SpecialAccount/FactoryBill/components/Filter.tsx @@ -1,5 +1,5 @@ import React, { useCallback } from "react"; -import { Button, Col, Row, Select } from "antd"; +import { Button, Row, Select } from "antd"; import { useStore } from "../index"; const { Option } = Select; @@ -10,61 +10,47 @@ export default function Filter() { const searchDealer = useCallback((dealerId) => { setDealerId(dealerId); }, []); - + const searchBrand = useCallback((brandId) => { setBrandId(brandId); }, []); return ( -
- -
商家:
-
- - -
品牌:
- - - + + + + + - + ); } diff --git a/src/pages/identify/IdentifyAudit/components/List.tsx b/src/pages/identify/IdentifyAudit/components/List.tsx index ad7d513..83d9d8a 100644 --- a/src/pages/identify/IdentifyAudit/components/List.tsx +++ b/src/pages/identify/IdentifyAudit/components/List.tsx @@ -27,11 +27,21 @@ export default function IdentifyAuditList() { > - {pagination.innerParams.type === Type.会员认证 ? ( - + {pagination.innerParams.type !== Type.员工认证 ? ( + memberId ?? "-"} + /> ) : null} - {pagination.innerParams.type === Type.员工认证 ? ( - + {pagination.innerParams.type !== Type.会员认证 ? ( + staffId ?? "-"} + /> ) : null} {pagination.innerParams.type === Type.车辆认证 ? ( diff --git a/src/pages/identify/IdentifyAudit/components/Modal.tsx b/src/pages/identify/IdentifyAudit/components/Modal.tsx index 318bc14..69b5246 100644 --- a/src/pages/identify/IdentifyAudit/components/Modal.tsx +++ b/src/pages/identify/IdentifyAudit/components/Modal.tsx @@ -2,7 +2,7 @@ * @Author: wangqiang@feewee.cn * @Date: 2023-02-10 17:52:44 * @LastEditors: wangqiang@feewee.cn - * @LastEditTime: 2023-02-11 16:46:04 + * @LastEditTime: 2023-03-01 14:04:28 */ import { Button, @@ -139,12 +139,12 @@ export default function IdentifyAuditModal() { {current?.identifyName || "-"} - {pagination.innerParams?.type === Type.会员认证 ? ( + {pagination.innerParams?.type !== Type.员工认证 ? ( {current?.memberId || "-"} ) : null} - {pagination.innerParams?.type === Type.员工认证 ? ( + {pagination.innerParams?.type !== Type.会员认证 ? ( {current?.staffId || "-"} diff --git a/src/pages/mkt/ActivityCreate/BasicInformation/components/ImageUploader/index.tsx b/src/pages/mkt/ActivityCreate/BasicInformation/components/ImageUploader/index.tsx index 8aa936a..011c272 100644 --- a/src/pages/mkt/ActivityCreate/BasicInformation/components/ImageUploader/index.tsx +++ b/src/pages/mkt/ActivityCreate/BasicInformation/components/ImageUploader/index.tsx @@ -161,7 +161,7 @@ export default function Detail({ form, readOnly, bizType }: Props) { return e && e.fileList; }} > - + {uploadButton} diff --git a/src/pages/mkt/ActivityCreate/BasicInformation/index.tsx b/src/pages/mkt/ActivityCreate/BasicInformation/index.tsx index 31c1c25..fc6d09e 100644 --- a/src/pages/mkt/ActivityCreate/BasicInformation/index.tsx +++ b/src/pages/mkt/ActivityCreate/BasicInformation/index.tsx @@ -86,7 +86,6 @@ function Index({ onNext }: Props) { // } // } params.bizType = undefined; - params.activityName = undefined; params.activityType = undefined; params.address = undefined; params.addressType = undefined; @@ -170,7 +169,7 @@ function Index({ onNext }: Props) { - + { + return request.post(`${MKT_HOST}/erp/activity/change/scope/up/save`, params); +} + +/** * 查询报名有礼配置信息 */ @@ -71,8 +78,8 @@ export function getMulLotteryDetail(params: { activityNo?: string, change?: bool * 查询活动外促范围信息 * erp/activity/sale/promotion/range/detail */ -export function getSalePromotionDetail(activityNo?: string): http.PromiseResp { - return request.get(`${MKT_HOST}/erp/activity/sale/promotion/range/detail`, { params: { activityNo } }); +export function getSalePromotionDetail(params: { activityNo?: string, change?: boolean }): http.PromiseResp { + return request.get(`${MKT_HOST}/erp/activity/sale/promotion/range/detail`, { params }); } /** @@ -91,8 +98,8 @@ export function setFlowDisable(params: ExternalPromotion.FlowDisablePramas): htt /** *活动授权品牌车系车型 */ -export function getAuthcarApi(activityNo?: string): http.PromiseRespA { - return request.get(`${MKT_HOST}/erp/activity/sale/promotion/auth/car`, { params: { activityNo } }); +export function getAuthcarApi(activityNo?: string, change?: boolean): http.PromiseRespA { + return request.get(`${MKT_HOST}/erp/activity/sale/promotion/auth/car`, { params: { activityNo, change } }); } /** @@ -122,6 +129,33 @@ export function fetchCustomerCount(params: ExternalPromotion.CustomerCountParams /** * 提交活动变更申请 */ -export function saveChangeApply(params: { activityNo: number, reason: string}): http.PromiseResp { +export function saveChangeApply(params: { activityNo: number, reason: string }): http.PromiseResp { return request.post(`${MKT_HOST}/erp/activity/change/apply`, params); -} \ No newline at end of file +} +/** + * 保存优惠券变更信息(活动变更) + */ +export function saveChangeCoupon(params: MktConponSpace.ConListParams): http.PromiseResp { + return request.post(`${MKT_HOST}/erp/activity/change/coupon/save`, params); +} + +/** + * 获取优惠券配置详情 + * @param confNo //优惠券配置编码 + */ +export function getCouponChangeDetails(params: { activityNo?: string, confNo?: string }): http.PromiseResp { + return request.get(`${MKT_HOST}/erp/activity/change/coupon/info`, { params }); +} +/** + * 保存奖品变更信息(优惠券) + */ +export function saveChangeGift(params: MktConponSpace.ConListParams): http.PromiseResp { + return request.post(`${MKT_HOST}/erp/activity/change/gift/save`, params); +} + +/** + * 变更奖项名称(礼包奖品名称) + */ +export function saveChangeAwardName(params: { giftId: number, awardName: string }): http.PromiseResp { + return request.post(`${MKT_HOST}/erp/activity/change/gift/award/name`, params); +} diff --git a/src/pages/mkt/ActivityCreate/ExternalPromotion/components/ActivityFlow/Coupons.tsx b/src/pages/mkt/ActivityCreate/ExternalPromotion/components/ActivityFlow/Coupons.tsx index d0e8ff5..8a5ff9c 100644 --- a/src/pages/mkt/ActivityCreate/ExternalPromotion/components/ActivityFlow/Coupons.tsx +++ b/src/pages/mkt/ActivityCreate/ExternalPromotion/components/ActivityFlow/Coupons.tsx @@ -11,12 +11,13 @@ import { Card, Popconfirm, } from "antd"; -import { PlusOutlined, DeleteOutlined } from "@ant-design/icons"; +import { PlusOutlined, DeleteOutlined, SwapOutlined } from "@ant-design/icons"; import UpsertCoupon from "@/pages/coupon/CouponConfig"; import { deleteConfigList, batchDeleteCoupon, } from "@/pages/coupon/CouponConfig/api"; //删除优惠券配置 +import { getCouponChangeDetails, saveChangeCoupon, saveChangeGift, saveChangeAwardName } from '../../api'; import { useStore } from "@/pages/mkt/ActivityCreate/index"; const { Column } = Table; @@ -35,6 +36,7 @@ interface Coupon { index?: number; itemIndex?: number; confNo?: string; + giftItemId?: number; } export default function Coupons({ @@ -48,6 +50,7 @@ export default function Coupons({ }: Props) { const [form] = Form.useForm(); const { readOnly, baseInfo, getACarList } = useStore(); + const { changeEnable, activityNo, bizType } = baseInfo; // 保存表格中的数据 const [savaList, setSaveList] = useState([]); /** 是否点击过无奖占位 */ @@ -61,11 +64,11 @@ export default function Coupons({ //优惠券Modal const [coupon, setCoupon] = useState({ visible: false, - index: undefined, confNo: undefined, }); - + /**优惠券创建状态 */ + const couponStatus = changeEnable && !coupon.giftItemId && coupon.confNo; // 保存当前选中的奖项 const [currentItem, SetCurrentItem] = useState({ awardName: undefined, @@ -82,6 +85,7 @@ export default function Coupons({ }); } }, [visible, currentItem]); + useEffect(() => { if (value && value.length) { setSaveList([...value]); @@ -94,7 +98,7 @@ export default function Coupons({ const _onOk = () => { form .validateFields() - .then((fields) => { + .then(async (fields) => { /** * 新增时,判断奖项名称是否重复; * 编辑时,直接将中奖名额/中奖概率进行替换 @@ -121,6 +125,20 @@ export default function Coupons({ savaList.push(pa); } } else if (itemIndex !== undefined) { + /**变更奖项名称 */ + if (changeEnable) { + const changePa = { + giftId: savaList[itemIndex].giftId, + awardName: fields.awardName, + activityNo + }; + try { + await saveChangeAwardName(changePa); + message.success("变更成功"); + } catch (err: any) { + message.error(err.message); + } + } savaList[itemIndex].awardName = fields.awardName; savaList[itemIndex].winningNum = fields.winningNum; } @@ -142,7 +160,7 @@ export default function Coupons({ const _onSava = (params?: any) => { const pa: ExternalPromotion.giftItems = { ...params, - relySchemeType: params.data.relySchemeList.length + relySchemeType: params.data && params.data.relySchemeList.length ? params.data.relySchemeList[0] : 0, couponCode: params.confNo, @@ -151,13 +169,26 @@ export default function Coupons({ discountsAmount: params.amount, }; const _savaList = savaList; - //判断编辑还是新增 if (coupon.confNo) { //编辑 if (!(coupon.index === undefined || coupon.itemIndex === undefined)) { _savaList[coupon.index].giftItems[coupon.itemIndex] = pa; } - } else { + } + /**优惠券变更 */ + if (coupon.giftItemId) { + //@ts-ignore + saveChangeGift({ ...pa, giftItemId: coupon.giftItemId, activityNo, giftId: value[0] && value[0].giftId }).then(res => { + message.success("奖品变更成功"); + if (!(coupon.index === undefined || coupon.itemIndex === undefined)) { + _savaList[coupon.index].giftItems[coupon.itemIndex] = { ...pa, giftItemId: coupon.giftItemId }; + } + onChange && onChange([..._savaList]); + }).catch(err => { + message.error(err); + }); + } + if (!coupon.giftItemId && !coupon.confNo) { //新增 if (coupon.index !== undefined) { _savaList[coupon.index].giftItems.push(pa); @@ -209,7 +240,7 @@ export default function Coupons({ (item) => item.awardName !== record.awardName ); // 删除谢谢惠顾,无奖占位按钮可以点击 - if (record.awardName === "谢谢惠顾!") { + if (record.awardName === "谢谢惠顾") { setNoRewadDisable(false); setNoRewad(false); } @@ -252,7 +283,7 @@ export default function Coupons({ setNoRewad(true); setVisible(true); form.setFieldsValue({ - awardName: "谢谢惠顾!", + awardName: "谢谢惠顾", }); }} disabled={disabled || noRewardDisable} @@ -282,28 +313,36 @@ export default function Coupons({ bordered > { - if (text === "谢谢惠顾!") { - setNoRewadDisable(true); + render={(text, record: any, index) => { + if (text === "谢谢惠顾" || !changeEnable) { + return {text}; + } else { + return ( + + ); } - return {text || "--"}; }} /> (!mulLottery ? `${text}%` : awardWay === 1 ? `${text}%` : text)} + render={(text) => (awardWay === 1 ? `${text}%` : text)} /> - text && - text.length > 0 && + ) => text && + text.length > 0 && text.map((item, itemIndex: number) => (
{item.aliasName && !readOnly && ( )} + {item.aliasName && changeEnable && item.giftItemId && ( + { + setCoupon({ + ...coupon, + giftItemId: item.giftItemId, + visible: true, + confNo: undefined, + index, + itemIndex, + }); + }} + > + + + )}
))} @@ -424,28 +484,28 @@ export default function Coupons({ onFinish={_onOk} autoComplete="off" // initialValues={{ - // awardName: (awardWay === 2 && noReward) ? "谢谢惠顾!" : "", + // awardName: (awardWay === 2 && noReward) ? "谢谢惠顾" : "", // }} > - + @@ -478,12 +538,15 @@ export default function Coupons({ {/* 优惠券配置 */} setCoupon({ ...coupon, visible: false, confNo: undefined })} onSave={_onSava} remark="市场活动" confNo={coupon.confNo} - carSelectApi={baseInfo.bizType == 1 ? getACarList : undefined} + carSelectApi={bizType == 1 ? getACarList : undefined} + changeEditKeys={couponStatus ? ["aliasName", "schemeList"] : undefined} + getCouponDetailsApi={couponStatus ? (v: string) => getCouponChangeDetails({ activityNo, confNo: v }) : undefined} + saveChangeCouponApi={couponStatus ? (values: any) => saveChangeCoupon({ ...values, activityNo }) : undefined} /> ); diff --git a/src/pages/mkt/ActivityCreate/ExternalPromotion/components/ActivityFlow/SignIn.tsx b/src/pages/mkt/ActivityCreate/ExternalPromotion/components/ActivityFlow/SignIn.tsx index 2ffea98..9607a7d 100644 --- a/src/pages/mkt/ActivityCreate/ExternalPromotion/components/ActivityFlow/SignIn.tsx +++ b/src/pages/mkt/ActivityCreate/ExternalPromotion/components/ActivityFlow/SignIn.tsx @@ -20,7 +20,6 @@ export default function index() { useEffect(() => { if (!errMsg) { - console.log("签到有礼结果:", data); form.setFieldsValue({ ...data, signInTime: data.startTime && data.endTime ? [moment(data.startTime), moment(data.endTime)] : [], @@ -83,7 +82,7 @@ export default function index() { /> - {distributeMethod.map((item) => (
record.classifyCode || record.couponCode} > ( - disabled ? () : ( + disabled ? ( + <> + + {record.giftItemId && ( + setCoupon({ ...coupon, visible: true, giftItemId: record.giftItemId })}> + {!!changeEnable && } + + )} + + ) : (
String(item.id)} - dataSource={isChange ? approveData.changeItemList : data} + dataSource={data} > { - return approveData.approval ? null : - readOnly && (moment(record.time) < moment().endOf('day')) ? null : ( + return (moment(record.time) < moment().endOf('day')) ? null : ( + !readOnly || changeEnable ? ( <> @@ -179,7 +146,8 @@ export default function MktOutsideConfig() { - ); + ) : null + ); }} />
@@ -194,7 +162,6 @@ export default function MktOutsideConfig() { activityNo={baseInfo.activityNo} fetchList={() => setLoading(true)} /> - {approveData.approvalNo && setApproveVisible(false)} />}
); } \ No newline at end of file diff --git a/src/pages/mkt/ActivityCreate/store.ts b/src/pages/mkt/ActivityCreate/store.ts index 235a66d..766b7e7 100644 --- a/src/pages/mkt/ActivityCreate/store.ts +++ b/src/pages/mkt/ActivityCreate/store.ts @@ -38,7 +38,7 @@ export default function useStore() { //获取授权车辆 function getACarList() { - return getAuthcarApi(baseInfo.activityNo); + return getAuthcarApi(baseInfo.activityNo, baseInfo.changeEnable); } return { diff --git a/src/pages/order3/AddValueTaskConfig/components/EditModal.tsx b/src/pages/order3/AddValueTaskConfig/components/EditModal.tsx index e1a03f7..85afc3d 100644 --- a/src/pages/order3/AddValueTaskConfig/components/EditModal.tsx +++ b/src/pages/order3/AddValueTaskConfig/components/EditModal.tsx @@ -12,27 +12,27 @@ const { RangePicker } = DatePicker; export default function DetailModal() { const {currentData, setCurrentData, setLoading} = useStore(); const [confirm, setConfirm] = useState(false); - const [type, setType] = useState(1); + const [type, setType] = useState(2); const [form] = Form.useForm(); useEffect(() => { if (currentData.visible && currentData.data.id) { handleSetValue(); } else { - form.setFieldsValue({addedValueType: 1}); + form.setFieldsValue({addedValueType: 2}); } }, [currentData.visible]); const handleChangeType = (value: number) => { setType(value); - if (value === 2) { + if (value === 1) { form.setFieldsValue({ tciOutputValueRatio: 100, vciOutputValueRatio: 100, jcxOutputValueRatio: 100, decoOutputValueRatio: 100, }); - } else if (value === 1) { + } else if (value === 2) { form.setFieldsValue({ tciOutputValueRatio: 0, vciOutputValueRatio: 0, @@ -45,7 +45,7 @@ export default function DetailModal() { const handleCancel = () => { form.resetFields(); setCurrentData({visible: false, data: {}, title: ""}); - setType(1); + setType(2); }; const handleSetValue = () => { @@ -59,12 +59,11 @@ export default function DetailModal() { rangeDate: [moment(currentData.data.beginTime), moment(currentData.data.endTime)], addedValueType: currentData?.data.addedValueType }); - setType(currentData.data?.addedValueType || 1); + setType(currentData.data?.addedValueType || 2); }; const onFinish = async () => { const params = await form.validateFields(); - console.log(params); setConfirm(true); const _params: ListResult = { id: currentData.data?.id, @@ -111,13 +110,13 @@ export default function DetailModal() { style={{marginLeft: 30, marginRight: 30}} > - handleChangeType(e.target.value)} defaultValue={1} buttonStyle="solid"> - 按毛利计算 - 按产值计算 + handleChangeType(e.target.value)} defaultValue={2} buttonStyle="solid"> + 按毛利计算 + 按产值计算 @@ -132,7 +131,7 @@ export default function DetailModal() {
产值构成:
商业险金额 x} @@ -150,7 +149,7 @@ export default function DetailModal() { `${value}%`} @@ -174,7 +173,7 @@ export default function DetailModal() { `${value}%`} @@ -198,7 +197,7 @@ export default function DetailModal() { `${value}%`} @@ -208,7 +207,7 @@ export default function DetailModal() { 2.{type === 1 ? "计算装潢毛利" : "计算装潢产值"}:装潢金额 x} + label={2.{type === 2 ? "计算装潢毛利" : "计算装潢产值"}:装潢金额 x} colon={false} name="decoOutputValueRatio" rules={[({ getFieldValue }) => ({ @@ -223,7 +222,7 @@ export default function DetailModal() { `${value}%`} diff --git a/src/pages/order3/AddValueTaskConfig/components/List.tsx b/src/pages/order3/AddValueTaskConfig/components/List.tsx index 0df3a5b..6b3a81b 100644 --- a/src/pages/order3/AddValueTaskConfig/components/List.tsx +++ b/src/pages/order3/AddValueTaskConfig/components/List.tsx @@ -50,7 +50,7 @@ export default function LargeList({addedValueType} : Props) { render={(_text) => (isNil(_text) ? '-' : {_text}元/台)} /> ( @@ -62,7 +62,7 @@ export default function LargeList({addedValueType} : Props) { )} /> `装潢产值*${_text}%`} diff --git a/src/pages/order3/AddValueTaskConfig/index.tsx b/src/pages/order3/AddValueTaskConfig/index.tsx index b07f3bf..addea3d 100644 --- a/src/pages/order3/AddValueTaskConfig/index.tsx +++ b/src/pages/order3/AddValueTaskConfig/index.tsx @@ -13,7 +13,7 @@ export const { Provider, useStore } = createStore(store); function AddValueTaskConfig() { const {setCurrentData, setParams, innerParams} = useStore(); - const [type, setType] = useState(1); + const [type, setType] = useState(2); useEffect(() => { setParams({...innerParams, addedValueType: type}, true); @@ -28,7 +28,7 @@ function AddValueTaskConfig() { }, 380); const handleChangeType = (value?: number) => { - setType(value || 1); + setType(value || 2); }; const handleChangeDate = (value?: any) => { @@ -39,9 +39,9 @@ function AddValueTaskConfig() { - handleChangeType(e.target.value)} defaultValue={1} buttonStyle="solid"> - 按毛利计算 - 按产值计算 + handleChangeType(e.target.value)} defaultValue={2} buttonStyle="solid"> + 按毛利计算 + 按产值计算 diff --git a/src/pages/order3/AddValueTaskConfig/store.ts b/src/pages/order3/AddValueTaskConfig/store.ts index 56aadf3..aa807b8 100644 --- a/src/pages/order3/AddValueTaskConfig/store.ts +++ b/src/pages/order3/AddValueTaskConfig/store.ts @@ -14,7 +14,7 @@ interface ShopData { } export default function useStore() { - const { list, setParams, setLoading, loading, paginationConfig, innerParams } = usePagination(getConfigListApi, {pageSize: 10, current: 1, addedValueType: 1}); + const { list, setParams, setLoading, loading, paginationConfig, innerParams } = usePagination(getConfigListApi, {pageSize: 10, current: 1, addedValueType: 2}); const [currentData, setCurrentData] = useState({visible: false, title: "新增", data: {}}); const [shopData, setShopData] = useState({visible: false, data: []}); return { diff --git a/src/pages/order3/Common/ApproveModal/index.tsx b/src/pages/order3/Common/ApproveModal/index.tsx new file mode 100644 index 0000000..dbf9934 --- /dev/null +++ b/src/pages/order3/Common/ApproveModal/index.tsx @@ -0,0 +1,52 @@ +import React, { useState } from 'react'; +import { Modal, Form, Input, Button } from 'antd'; +import FeeweeUploadAttachment from '@/components/FeeweeUploadAttachment'; +import { UploadOutlined } from '@ant-design/icons'; + +interface Props { + open: boolean, + setOpen: (bool: boolean) => void, + callback?: Function +} + +export default function Add({ open, setOpen, callback }: Props) { + const [form] = Form.useForm(); + const [confirmLoading, setConfirmLoading] = useState(false); + + function handleCancel() { + setOpen(false); + form.resetFields(); + } + + async function handleSave() { + const params = await form.validateFields(); + setConfirmLoading(true); + callback && callback(params); + setConfirmLoading(false); + setOpen(false); + } + + return ( + setOpen(false)} + maskClosable={false} + footer={[ + , + + ]} + > +
+ + + + + + + + +
+
+ ); +} \ No newline at end of file diff --git a/src/pages/order3/OrderSetting/LoanDiscountSetting/api.ts b/src/pages/order3/OrderSetting/LoanDiscountSetting/api.ts new file mode 100644 index 0000000..cee9dea --- /dev/null +++ b/src/pages/order3/OrderSetting/LoanDiscountSetting/api.ts @@ -0,0 +1,19 @@ +import { http } from '@/typing/http'; +import request from '@/utils/request'; +import { ORDER3 } from '@/utils/host'; + +interface Detail { + financeServiceFee?: boolean // 服务费抵扣 + mortgageRegisterFee?: boolean // 抵押上户费抵扣 + removeMortgageFee?: boolean // 解除抵押费抵扣 + gpsFee?: boolean // GPS费抵扣 +} +/** 查询分期优惠劵抵扣配置*/ +export function getSettingApi(): http.PromiseResp { + return request.get(`${ORDER3}/erp/system/loan/coupon/deduct/config`); +} + +/** 保存分期优惠劵抵扣配置*/ +export function saveSettingApi(params?: Detail): http.PromiseResp { + return request.post(`${ORDER3}/erp/system/loan/coupon/deduct/config/save`, params); +} \ No newline at end of file diff --git a/src/pages/order3/OrderSetting/LoanDiscountSetting/index.tsx b/src/pages/order3/OrderSetting/LoanDiscountSetting/index.tsx new file mode 100644 index 0000000..39190fd --- /dev/null +++ b/src/pages/order3/OrderSetting/LoanDiscountSetting/index.tsx @@ -0,0 +1,78 @@ +import React, { useState, useEffect } from 'react'; +import { Card, Button, message, Checkbox } from 'antd'; +import { PageHeaderWrapper } from '@ant-design/pro-layout'; +import { getSettingApi, saveSettingApi } from './api'; +import { debounce } from 'lodash'; + +export default function InsuranceSetting() { + const option = [ + {label: "服务费", value: 'financeServiceFee'}, + {label: "抵押上户费", value: 'mortgageRegisterFee'}, + {label: "解除抵押费", value: 'removeMortgageFee'}, + {label: "GPS费", value: 'gpsFee'}]; + const [checked, setChecked] = useState([]); + const [loading, setLoading] = useState(false); + const [disabled, setDisabled] = useState(false); + + useEffect(() => { + getData(); + }, []); + + function getData() { + setLoading(true); + getSettingApi() + .then(res => { + const data = res.data; + if (data) { + let _check = []; + for (let k in data) { + if (data[k]) { + _check.push(`${k}`); + } + } + setChecked(_check); + setLoading(false); + } + }) + .catch(e => { + message.error(e.message); + setLoading(false); + }); + } + + function onChange(value?: any) { + value && setChecked(value); + } + + const onSubmit = () => { + setDisabled(true); + const params = { + financeServiceFee: checked.includes('financeServiceFee'), + mortgageRegisterFee: checked.includes('mortgageRegisterFee'), + removeMortgageFee: checked.includes('removeMortgageFee'), + gpsFee: checked.includes('gpsFee') + }; + saveSettingApi(params) + .then(res => { + message.success(res.result); + getData(); + setDisabled(false); + }) + .catch(e => { + message.error(e.message); + setDisabled(false); + }); + } + return ( + + +
+ onChange(value)} /> +
+
+ +
+
+
+ ); +} \ No newline at end of file diff --git a/src/pages/order3/OrderSetting/OrderPermissionDiscount/index.tsx b/src/pages/order3/OrderSetting/OrderPermissionDiscount/index.tsx index 2328ba2..f63f1f0 100644 --- a/src/pages/order3/OrderSetting/OrderPermissionDiscount/index.tsx +++ b/src/pages/order3/OrderSetting/OrderPermissionDiscount/index.tsx @@ -18,7 +18,7 @@ export default function OrderPermissionDiscount() { const [superLoading, setSuperLoading] = useState(false); const [confirmLoading, setConfirmLoading] = useState(false); const [specVis, setSpecVis] = useState(false); - const superRole = useRef({}); + const superRole = useRef([]); const [spcList, setSpcList] = useState([]); const { data: role, loading } = useInitail(getRoleListApi, [], {}); const { data: List, loading: ListLoading, setLoading } = useInitail(ConInformation, {}, {}); @@ -27,6 +27,13 @@ export default function OrderPermissionDiscount() { useEffect(() => { setAmount(List.allocationRatio && List.allocationRatio.rewardRatio); setRatio(List.allocationRatio && List.allocationRatio.payoutRatio); + if (List.superAuthDiscount?.roleId) { + superRole.current = [{ + id: List.superAuthDiscount.roleId, + roleCode: List.superAuthDiscount.roleCode, + roleName: List.superAuthDiscount.roleName + }]; + } }, [List]); function changeAmount(value: any) { @@ -161,7 +168,7 @@ export default function OrderPermissionDiscount() { - )} - ); + ); }} /> diff --git a/src/pages/order3/RetailManualAdjust/api.ts b/src/pages/order3/RetailManualAdjust/api.ts index 0e9790f..0df887b 100644 --- a/src/pages/order3/RetailManualAdjust/api.ts +++ b/src/pages/order3/RetailManualAdjust/api.ts @@ -37,6 +37,12 @@ interface ListParams { autoAssign?: boolean } +export interface SaveParams { + id?: number // 任务id + remark?: string // 备注 + attachmentList?: string[] // 附件列表 +} + /** 获取列表 */ export function getRetailManualList(params?: ListParams): http.PromiseResp { return request.get(`${ORDER3}/erp/sales/task/detail`, { params }); @@ -46,6 +52,6 @@ export function autoAlloctionApi(params: saveParams) { return request.post(`${ORDER3}/erp/sales/task/auto/assign`, { ...params }); } /*提交 */ -export function save(id?: number) { - return request.post(`${ORDER3}/erp/sales/task/submit`, { id }, { contentType: 'form-urlencoded' }); +export function save(params?: SaveParams) { + return request.post(`${ORDER3}/erp/sales/task/submit`, params); } diff --git a/src/pages/order3/RetailManualAdjust/index.tsx b/src/pages/order3/RetailManualAdjust/index.tsx index d6393af..b31ed98 100644 --- a/src/pages/order3/RetailManualAdjust/index.tsx +++ b/src/pages/order3/RetailManualAdjust/index.tsx @@ -5,6 +5,7 @@ import { getRetailManualList, ListItem, autoAlloctionApi, ShopTaskList, save, sa import EModal from './component/Modal'; import moment from 'moment'; import currency from 'currency.js'; +import ApproveModal from '@/pages/order3/Common/ApproveModal'; const { Column } = Table; @@ -26,6 +27,7 @@ export default function TacklingCarModels() { const [list, setList] = useState({}); const [orginDara, setOrginDara] = useState({}); const index = useRef(); + const [approveOpen, setApproveOpen] = useState(false); // let index; useEffect(() => { @@ -98,11 +100,15 @@ export default function TacklingCarModels() { autoAllocationSave(params); } + function handleOpenApprove() { + setApproveOpen(true); + } + //提交审批 - function saveClick() { + function saveClick(params?: any) { setLoading(true); setSaveLoading(true); - save(list.id).then((res) => { + save({...params, id: list.id}).then((res) => { setSaveLoading(false); setLoading(false); setList({ ...list, canModified: false }); @@ -198,7 +204,7 @@ export default function TacklingCarModels() { <> {edit ? : - } + } {edit ? null : } {edit ? @@ -209,6 +215,7 @@ export default function TacklingCarModels() { : null}
+
); } \ No newline at end of file diff --git a/src/pages/order3/RetailTask/api.ts b/src/pages/order3/RetailTask/api.ts index 043af70..358d03b 100644 --- a/src/pages/order3/RetailTask/api.ts +++ b/src/pages/order3/RetailTask/api.ts @@ -38,6 +38,12 @@ interface ListParams { autoAssign?: boolean } +export interface SaveParams { + id?: number // 任务id + remark?: string // 备注 + attachmentList?: string[] // 附件列表 +} + /** 获取列表 */ export function getRetailList(params?: ListParams): http.PromiseResp { return request.get(`${ORDER3}/erp/sales/task/detail`, { params }); @@ -47,6 +53,6 @@ export function saveHandelTack(params: saveParams) { return request.post(`${ORDER3}/erp/sales/task/manual/assign`, { ...params }); } /*提交 */ -export function save(id?: number) { - return request.post(`${ORDER3}/erp/sales/task/submit`, { id }, { contentType: 'form-urlencoded' }); +export function save(params?: SaveParams) { + return request.post(`${ORDER3}/erp/sales/task/submit`, params); } \ No newline at end of file diff --git a/src/pages/order3/RetailTask/index.tsx b/src/pages/order3/RetailTask/index.tsx index 02db2fd..561ece9 100644 --- a/src/pages/order3/RetailTask/index.tsx +++ b/src/pages/order3/RetailTask/index.tsx @@ -5,6 +5,7 @@ import { getRetailList, ListItem, saveHandelTack, ShopTaskList, save, saveParams import EModal from './component/Modal'; import moment from 'moment'; import currency from 'currency.js'; +import ApproveModal from '@/pages/order3/Common/ApproveModal'; const { Column } = Table; @@ -26,6 +27,7 @@ export default function TacklingCarModels() { const [list, setList] = useState({}); const [orginDara, setOrginDara] = useState({}); const index = useRef(0); + const [approveOpen, setApproveOpen] = useState(false); useEffect(() => { getList(newDay); @@ -92,11 +94,15 @@ export default function TacklingCarModels() { handleSave(params); } } + + function handleOpenApprove() { + setApproveOpen(true); + } //提交审批 - function saveClick() { + function saveClick(parmas: any) { setLoading(true); setSaveLoading(true); - save(list.id).then((res) => { + save({...parmas, id: list.id}).then((res) => { setSaveLoading(false); setLoading(false); setList({ ...list, canModified: false }); @@ -194,7 +200,7 @@ export default function TacklingCarModels() { <> {edit ? : - } + } {edit ? : @@ -203,6 +209,7 @@ export default function TacklingCarModels() { ) : null}
+ ); } \ No newline at end of file diff --git a/src/pages/order3/TacklingCarModels/api.ts b/src/pages/order3/TacklingCarModels/api.ts index 11c3dbd..909f626 100644 --- a/src/pages/order3/TacklingCarModels/api.ts +++ b/src/pages/order3/TacklingCarModels/api.ts @@ -3,25 +3,25 @@ import request from '@/utils/request'; import { ORDER3 } from '@/utils/host'; export interface ListItem { - totalTaskCount?: number,//任务总数 + totalTaskCount?: number, //任务总数 shopTaskList?: ShopTaskList[], - year?: number,//年份 + year?: number, //年份 id?:number, - month?: number,//月份 + month?: number, //月份 canModified?: boolean//是否可调整 } export interface ShopTaskList { - shopId?: number,//门店id - shopName?: string,//门店名称 - taskCount?: number,//任务数量 + shopId?: number, //门店id + shopName?: string, //门店名称 + taskCount?: number, //任务数量 staffTaskList?: StaffTaskList[]//员工任务列表 } interface StaffTaskList { - staffId?: number,//员工id - staffName?: string,//员工名称 - taskCount?: number,//任务数量 + staffId?: number, //员工id + staffName?: string, //员工名称 + taskCount?: number, //任务数量 regularMonth?: number//转正几个月 } export interface saveParams { @@ -33,6 +33,12 @@ interface ListParams { autoAssign?: boolean } +export interface SaveParams { + id?: number // 任务id + remark?: string // 备注 + attachmentList?: string[] // 附件列表 +} + /** 获取列表 */ export function getTackList(params?: ListParams): http.PromiseResp { return request.get(`${ORDER3}/erp/tack/car/task/detail`, { params }); @@ -46,7 +52,6 @@ export function autoAlloctionApi(params: saveParams) { return request.post(`${ORDER3}/erp/tack/car/task/auto/assign`, { ...params }); } /*提交 */ -export function save(id?: number) { - return request.post(`${ORDER3}/erp/tack/car/task/submit`, { id }, { contentType: 'form-urlencoded' }); -} - +export function save(params?: SaveParams) { + return request.post(`${ORDER3}/erp/tack/car/task/submit`, params); +} \ No newline at end of file diff --git a/src/pages/order3/TacklingCarModels/index.tsx b/src/pages/order3/TacklingCarModels/index.tsx index 2458b8d..86d7c9e 100644 --- a/src/pages/order3/TacklingCarModels/index.tsx +++ b/src/pages/order3/TacklingCarModels/index.tsx @@ -4,6 +4,7 @@ import { Card, Table, Button, Row, DatePicker, Col, InputNumber, message } from import { getTackList, ListItem, saveHandelTack, ShopTaskList, save, saveParams } from './api'; import EModal from './component/Modal'; import moment from 'moment'; +import ApproveModal from '@/pages/order3/Common/ApproveModal'; const { Column } = Table; @@ -25,6 +26,7 @@ export default function TacklingCarModels() { const [list, setList] = useState({}); const [orginDara, setOrginDara] = useState({}); let index; + const [approveOpen, setApproveOpen] = useState(false); useEffect(() => { getList(newDay); @@ -74,10 +76,10 @@ export default function TacklingCarModels() { handleSave(params); } //提交审批 - function saveClick() { + function saveClick(params?: any) { setLoading(true); setSaveLoading(true); - save(list.id).then(() => { + save({...params, id: list.id}).then(() => { setSaveLoading(false); setLoading(false); setList({ ...list, canModified: false }); @@ -88,6 +90,7 @@ export default function TacklingCarModels() { setSaveLoading(false); }); } + //手动提交 function handleSave(params: saveParams) { setConfirmLoading(true); @@ -103,6 +106,10 @@ export default function TacklingCarModels() { }); } + function handleOpenApprove() { + setApproveOpen(true); + } + return ( @@ -121,54 +128,58 @@ export default function TacklingCarModels() { }); return ( <> - {total == 0 ? null : - + {total == 0 ? null : ( + 合计 {total} - + - } + )} ); }} > - { if (edit) { - return _onChange(e, index)} /> + return _onChange(e, index)} />; } else { - return {value} + return {value}; } }} /> - ( + ( <> - + )} /> - {list.canModified ? + {list.canModified ? ( <> {edit ? : - - } + } {edit ? : - null - } - : null - } + null} + + ) : null} - - ) + + + ); } \ No newline at end of file diff --git a/src/pages/order3/TacklingManualAdjust/api.ts b/src/pages/order3/TacklingManualAdjust/api.ts index 267fa47..e97f283 100644 --- a/src/pages/order3/TacklingManualAdjust/api.ts +++ b/src/pages/order3/TacklingManualAdjust/api.ts @@ -33,6 +33,12 @@ interface ListParams { autoAssign?: boolean } +export interface SaveParams { + id?: number // 任务id + remark?: string // 备注 + attachmentList?: string[] // 附件列表 +} + /** 获取列表 */ export function getTackMaunuaList(params?: ListParams): http.PromiseResp { return request.get(`${ORDER3}/erp/tack/car/task/detail`, { params }); @@ -46,7 +52,6 @@ export function autoAlloctionApi(params: saveParams) { return request.post(`${ORDER3}/erp/tack/car/task/auto/assign`, { ...params }); } /*提交 */ -export function save(id?: number) { - return request.post(`${ORDER3}/erp/tack/car/task/submit`, { id }, { contentType: 'form-urlencoded' }); +export function save(params?: SaveParams) { + return request.post(`${ORDER3}/erp/tack/car/task/submit`, params); } - diff --git a/src/pages/order3/TacklingManualAdjust/index.tsx b/src/pages/order3/TacklingManualAdjust/index.tsx index 3b58f17..165d0d0 100644 --- a/src/pages/order3/TacklingManualAdjust/index.tsx +++ b/src/pages/order3/TacklingManualAdjust/index.tsx @@ -4,6 +4,7 @@ import { Card, Table, Button, Row, DatePicker, Col, InputNumber, message } from import { getTackMaunuaList, ListItem, autoAlloctionApi, ShopTaskList, save, saveParams } from './api'; import EModal from './component/Modal'; import moment from 'moment'; +import ApproveModal from '@/pages/order3/Common/ApproveModal'; const { Column } = Table; @@ -24,6 +25,7 @@ export default function TacklingCarModels() { const [edit, setEdit] = useState(false); const [list, setList] = useState({}); const [orginDara, setOrginDara] = useState({}); + const [approveOpen, setApproveOpen] = useState(false); let index; useEffect(() => { @@ -73,10 +75,10 @@ export default function TacklingCarModels() { autoAllocationSave(params); } //提交审批 - function saveClick() { + function saveClick(params?: any) { setLoading(true); setSaveLoading(true); - save(list.id).then(() => { + save({...params, id: list.id}).then(() => { setSaveLoading(false); setLoading(false); setList({ ...list, canModified: false }); @@ -102,6 +104,10 @@ export default function TacklingCarModels() { }); } + function handleOpenApprove() { + setApproveOpen(true); + } + return ( @@ -120,56 +126,59 @@ export default function TacklingCarModels() { }); return ( <> - {total == 0 ? null : - + {total == 0 ? null : ( + 合计 {total} - + - } + )} ); }} > - { if (edit) { - return _onChange(e, index)} /> + return _onChange(e, index)} />; } else { - return {value} + return {value}; } }} /> - ( + ( <> - + )} /> - {list.canModified ? + {list.canModified ? ( <> {edit ? : - - } + } {edit ? null : - - } + } {edit ? : - null - } - : null - } + null} + + ) : null} - - ) + + + ); } \ No newline at end of file diff --git a/src/pages/performance/CompensateGroupConfig/components/DraftList.tsx b/src/pages/performance/CompensateGroupConfig/components/DraftList.tsx index 040a532..b47ed1e 100755 --- a/src/pages/performance/CompensateGroupConfig/components/DraftList.tsx +++ b/src/pages/performance/CompensateGroupConfig/components/DraftList.tsx @@ -89,7 +89,7 @@ export default ({ type }: Props) => { 新增 - `id${row.id}`} dataSource={list} pagination={paginationConfig}> +
`id${row.draftId}`} dataSource={list} pagination={paginationConfig}> name || ""} /> ([]); + const { match } = props; + const { id, num } = match.params; + useEffect(() => { + setId(id); + }, [id]); + useEffect(() => { + if (configId) { + setParams({ id: configId }, true); + setDelay(false); + } + }, [configId]); + console.log('num', num); + const { data, errMsg, setParams, loading } = useInitail(evaDataDetailApi, {}, {}, delay); + console.log(isArray(data)); + useEffect(() => { + if (isArray(data)) { + setNewData(data); + } + }, [data]); + + return ( + + +
`id${id}`} dataSource={newData} pagination={{ total: num }}> + {name || "--"}} /> + {name || "--"}} /> + {name || "--"}} + /> + ( + + {num !== undefined + ? `${num}${ + record.dataType == 1 ? "台" : record.dataType == 2 ? "%" : record.dataType == 3 ? "元" : "" + }` + : "--"} + + )} + /> + (time ? moment(time).format("YYYY-MM-DD") : "--")} + /> + {/* ""} /> */} + + record.errorType ?
未导入
:
已导入
+ } + /> + (record.errorType ? ReasonsEnum[record.errorType] : "--")} + /> +
+ + + + + + ); +} +export default (props: Props) => ( + + + +); diff --git a/src/pages/performance/EvaDataImport/EditComfirm/store.ts b/src/pages/performance/EvaDataImport/EditComfirm/store.ts new file mode 100644 index 0000000..46d0d95 --- /dev/null +++ b/src/pages/performance/EvaDataImport/EditComfirm/store.ts @@ -0,0 +1,13 @@ +import { useEffect, useState } from "react"; +import useInitail from "@/hooks/useInitail"; +import usePagination from "@/hooks/usePagination"; +import { getAllPostListApi, getManagerRoleListApi } from "@/common/api"; + +export default function useStore() { + const [configId, setId] = useState(0); + + return { + configId, + setId, + }; +} diff --git a/src/pages/performance/EvaDataImport/EditComfirm/style.less b/src/pages/performance/EvaDataImport/EditComfirm/style.less new file mode 100644 index 0000000..aabc8d9 --- /dev/null +++ b/src/pages/performance/EvaDataImport/EditComfirm/style.less @@ -0,0 +1,22 @@ +.no { + width: 47px; + height: 18px; + margin: 0 auto; + color: #f4333c; + font-weight: 500; + font-size: 12px; + line-height: 18px; + border: 1px solid #f8797f; + border-radius: 2px; +} +.yes { + width: 47px; + height: 18px; + margin: 0 auto; + color: #20c688; + font-weight: 500; + font-size: 12px; + line-height: 18px; + border: 1px solid #6ddab2; + border-radius: 2px; +} diff --git a/src/pages/performance/EvaDataImport/api.ts b/src/pages/performance/EvaDataImport/api.ts new file mode 100644 index 0000000..be5d784 --- /dev/null +++ b/src/pages/performance/EvaDataImport/api.ts @@ -0,0 +1,54 @@ +import request from "@/utils/request"; +import { DALARAN, MORAX_HOST, CRM_HOST } from "@/utils/host"; +import { http } from "@/typing/http"; + +evaDataListApi; + +export interface PageParams { + current?: number; + pageSize?: number; +} + +/** 考评指标库列表 + * http://testgate.feewee.cn/morax/erp/eval/indicator/page + */ +export function evaDataListApi(params: EvaData.EvaDataListParams): http.PromisePageResp { + return request.get(`${MORAX_HOST}/erp/eval-indicator/import-page`, { params }); +} + +/** + * @description: 第三方渠道导入人员 + */ +export function saveImportPersonApi(params: any) { + return request.post(`${MORAX_HOST}/erp/eval-indicator/staff-indicator`, params, { + contentType: "form-data", + }); +} + +/** + * 第三方渠道导入门店 + */ +export function saveImportShopApi(params: { file: any[] }): http.PromiseResp { + return request.post(`${MORAX_HOST}/erp/eval-indicator/shop-indicator`, params, { + contentType: "form-data", + }); +} + +/** 导入记录详情查询 + * http://testgate.feewee.cn/morax/erp/eval-indicator/import-detail + */ +export function evaDataDetailApi(params: { id: number }): http.PromisePageResp { + return request.get(`${MORAX_HOST}/erp/eval-indicator/import-detail`, { params }); +} + +export function evaDataIndApi(): http.PromiseResp { + return request.get(`${MORAX_HOST}/erp/eval-indicator/indicators`, {}); +} + +/** + * 保存上传人员数据 + * http://testgate.feewee.cn/morax/erp/eval-indicator/save-import + */ +export function saveEvaImportData(params: { key: string }) { + return request.get(`${MORAX_HOST}/erp/eval-indicator/save-import`, { params }); +} diff --git a/src/pages/performance/EvaDataImport/components/FileDatailsModal.tsx b/src/pages/performance/EvaDataImport/components/FileDatailsModal.tsx new file mode 100644 index 0000000..c87ce68 --- /dev/null +++ b/src/pages/performance/EvaDataImport/components/FileDatailsModal.tsx @@ -0,0 +1,120 @@ +import React, { useState, useEffect } from "react"; +import { + Table, + Input, + InputNumber, + Popconfirm, + Form, + Typography, + Button, + message, + Space, + Divider, + Modal, + Card, +} from "antd"; +import { cloneDeep } from "lodash"; +import { KpiGroupSetteing } from "@/pages/performance/KpiGroupSetting/interface"; +import { TargetType, TargetTypeEnum } from "@/pages/performance/entity"; +import { render } from "react-dom"; +import moment from "moment"; +import { ReasonsEnum } from "../entity"; +import { saveEvaImportData } from "../api"; +import { history } from "umi"; +import st from "./style.less"; + +const Column = Table.Column; + +interface Props { + visible: boolean; + fileData: any; + tarOnCancel: Function; + setParams: Function; + innerParams: any; +} +const TargetModal = ({ visible, fileData, tarOnCancel, setParams, innerParams }: Props) => { + const [loading, setLoading] = useState(false); + const onOk = async (key: string) => { + const pa = { key }; + setLoading(true); + try { + const { success } = await saveEvaImportData(pa); + if (success) { + setLoading(false); + message.success(`数据上传成功`, 5); + // 重新刷新列表 + setParams({ ...innerParams }, true); + tarOnCancel && tarOnCancel(); + } + } catch (error: any) { + setLoading(false); + message.error(error.message); + } + }; + return ( + <> + tarOnCancel()} + maskClosable={false} + width={1500} + onOk={() => onOk(fileData.key)} + confirmLoading={loading} + > + + {name || "--"}} /> + {name || "--"}} /> + {name || "--"}} + /> + {/* ( + + {num !== undefined + ? `${num}${ + record.dataType == 1 ? "台" : record.dataType == 2 ? "%" : record.dataType == 3 ? "元" : "" + }` + : "--"} + + )} + /> */} + (time ? moment(time).format("YYYY-MM-DD") : "--")} + /> + + record.errorType ?
未导入
:
已导入
+ } + /> + (record.errorType ? ReasonsEnum[record.errorType] : "--")} + /> +
+
+ 成功条数: {fileData.successNum} 条 +
+
+ 失败条数: {fileData.errorNum} 条 +
+
+ + ); +}; + +export default TargetModal; diff --git a/src/pages/performance/EvaDataImport/components/Filter.tsx b/src/pages/performance/EvaDataImport/components/Filter.tsx new file mode 100644 index 0000000..250d3d8 --- /dev/null +++ b/src/pages/performance/EvaDataImport/components/Filter.tsx @@ -0,0 +1,85 @@ +import React, { useState, useEffect, useCallback } from "react"; +import { Table, Row, Input, Select, DatePicker } from "antd"; +import type { DatePickerProps, RangePickerProps } from "antd/es/date-picker"; +// import { ApprovalType, Approval_Status } from "../entity"; +import _ from "lodash"; +import usePagination from "@/hooks/usePagination"; +import { systemListApi } from "@/pages/admin/Privilege/api"; +import { getStaffApi } from "@/common/api"; +import { evaDataIndApi } from "../api"; +import useInitial from "@/hooks/useInitail"; +import moment from "moment"; + +const { RangePicker } = DatePicker; + +const { Option } = Select; +interface Props { + setParams: any; +} + +export default function Filter({ setParams }: Props) { + // const { list: syslist } = usePagination(systemListApi, { + // current: 1, + // pageSize: 500, + // }); + const { list } = usePagination(getStaffApi, { current: 1, pageSize: 1000 }); + const { data } = useInitial(evaDataIndApi, [], {}); + + // const seachOnchange = useCallback( + // _.debounce((param) => { + // setParams({ ...param }, true); + // }, 800), + // [setParams] + // ); + const onChange = (value: RangePickerProps["value"], dateString: [string, string] | string) => { + console.log("Selected Time: ", value); + if (value) { + setParams({ startTime: moment(value[0]).unix() * 1000, endTime: moment(value[1]).unix() * 1000 }, true); + console.log(moment(value[0]).unix() * 1000); + console.log(moment(value[1]).unix() * 1000); + } + }; + + return ( + + + + + + ); +} diff --git a/src/pages/performance/EvaDataImport/components/style.less b/src/pages/performance/EvaDataImport/components/style.less new file mode 100644 index 0000000..aabc8d9 --- /dev/null +++ b/src/pages/performance/EvaDataImport/components/style.less @@ -0,0 +1,22 @@ +.no { + width: 47px; + height: 18px; + margin: 0 auto; + color: #f4333c; + font-weight: 500; + font-size: 12px; + line-height: 18px; + border: 1px solid #f8797f; + border-radius: 2px; +} +.yes { + width: 47px; + height: 18px; + margin: 0 auto; + color: #20c688; + font-weight: 500; + font-size: 12px; + line-height: 18px; + border: 1px solid #6ddab2; + border-radius: 2px; +} diff --git a/src/pages/performance/EvaDataImport/entity.ts b/src/pages/performance/EvaDataImport/entity.ts new file mode 100644 index 0000000..055d445 --- /dev/null +++ b/src/pages/performance/EvaDataImport/entity.ts @@ -0,0 +1,6 @@ +export enum ReasonsEnum { + "未匹配到人员" = 1, + "未匹配到门店" = 2, + "未匹配到指标" = 3, + "重复" = 4, +} diff --git a/src/pages/performance/EvaDataImport/index.tsx b/src/pages/performance/EvaDataImport/index.tsx new file mode 100644 index 0000000..ea81af6 --- /dev/null +++ b/src/pages/performance/EvaDataImport/index.tsx @@ -0,0 +1,160 @@ +import React, { useState } from "react"; +import { PageHeaderWrapper } from "@ant-design/pro-layout"; +import { Button, Card, Table, Row, message, Space, Typography, Divider, Switch, Upload } from "antd"; +import usePagination from "@/hooks/usePagination"; +import { evaDataListApi } from "./api"; +import { UploadOutlined } from "@ant-design/icons"; +import type { UploadProps } from "antd"; +import { history } from "umi"; +import moment from "moment"; +import Filter from './components/Filter'; +import FileDatailsModal from './components/FileDatailsModal'; + +const Column = Table.Column; + +export default () => { + const { loading, list, paginationConfig, setParams, innerParams } = usePagination(evaDataListApi, { + pageSize: 10, + }); + const [fileData, setFileData] = useState({}); + const [visible, setVisible] = useState(false); + const uploadPerson: UploadProps = { + name: "file", + action: "/api/morax/erp/eval-indicator/analysis-staff", + maxCount: 1, + showUploadList: false, + onChange(info) { + if (info.file.status !== "uploading") { + console.log(info.file, info.fileList); + } + if (info.file.status === "done") { + setFileData(info.file.response.data); + setVisible(true); + } else if (info.file.status === "error") { + message.error(`${info.file.name} 上传失败`); + } + }, + }; + const uploadShop: UploadProps = { + name: "file", + action: "/api/morax/erp/eval-indicator/analysis-shop", + maxCount: 1, + showUploadList: false, + onChange(info) { + if (info.file.status !== "uploading") { + console.log(info.file, info.fileList); + } + if (info.file.status === "done") { + setFileData(info.file.response.data); + setVisible(true); + } else if (info.file.status === "error") { + message.error(`${info.file.name} 上传失败`); + } + }, + }; + + return ( + + + + +
+ + + + + + + + +
+
+ `id${row.id}`} + dataSource={list} + pagination={paginationConfig} + > + (time ? moment(time).format("YYYY-MM-DD") : "--")} + /> + {name || "--"}} + /> + {name || "--"}} + /> + {num !== undefined ? `${num}条` : "--"}} + /> + {num !== undefined ? `${num}条` : "--"}} + /> + {num !== undefined ? `${num}条` : "--"}} + /> + ( + }> + { + history.push(`/morax/evaDataImport/edit/${record.id}/${record.num}`); + }} + > + 查看 + + + )} + /> +
+ setVisible(false)} + fileData={fileData} + setParams={setParams} + innerParams={innerParams} + /> +
+
+ ); +}; diff --git a/src/pages/performance/EvaDataImport/interface.ts b/src/pages/performance/EvaDataImport/interface.ts new file mode 100644 index 0000000..6373a04 --- /dev/null +++ b/src/pages/performance/EvaDataImport/interface.ts @@ -0,0 +1,67 @@ +declare namespace EvaData { + interface EvaDataListParams { + current?: number; + pageSize?: number; + indicatorCode?: number; + userId?: number; + startTime?: string; + endTime?: string; + groupId?: number; + } + /** + * 数据库列表项 + */ + interface EvaDataItems { + id: number; + importUserId: number; + importUserName: string; + shopId: number; + shopName: string; + dimensionType: number; + indicatorCode: string; + indicatorName: string; + valueType: number; + dataDate: string; + num: number; + successNum: number; + errorNum: number; + groupId: number; + yn: boolean; + } + /** + * 导入人员 + */ + interface ImportPerson { + staffName: string; + shopName: string; + indicatorName: string; + indicatorValue: string; + applyTime: string; + } + /** + * 导入门店 + */ + interface ImportShop { + shopName: string; + indicatorName: string; + indicatorValue: string; + } + interface ImportParams { + file: any; + } + interface EvaDataDetai { + evalIndicatorImportRecordId: number; + userId: number; + userName: string; + shopId: number; + shopName: string; + indicatorName: string; + indicatorCode: string; + indicatorValue: string; + valueType: number; + dataDate: string; + groupId: number; + yn: boolean; + errorMsg: string; + } +} \ No newline at end of file diff --git a/src/pages/performance/EvaGroupSetting/EditComfirm/api.ts b/src/pages/performance/EvaGroupSetting/EditComfirm/api.ts new file mode 100644 index 0000000..58095d9 --- /dev/null +++ b/src/pages/performance/EvaGroupSetting/EditComfirm/api.ts @@ -0,0 +1,47 @@ +import { http } from "@/typing/http"; +import request from "@/utils/request"; +import { EHR_HOST, MORAX_HOST } from "@/utils/host"; +import { EvaGroupSetteing } from "@/pages/performance/EvaGroupSetting/interface"; + +/** + * 考评详情 + * http://testgate.feewee.cn/morax/erp/eval/group + */ +export function queryDetailListApi(id: number): http.PromiseResp { + return request.get(`${MORAX_HOST}/erp/eval/group`, { params: { id } }); +} +/** + * 考评草稿详情 + * http://testgate.feewee.cn/morax/erp/setting-draft/eval-detail + */ +export function draftQueryDetailListApi(id: number): http.PromiseResp { + return request.get(`${MORAX_HOST}/erp/setting-draft/eval-detail`, { params: { id } }); +} + +/** + * 获取岗位下的绩效组指标 + * http://testgate.feewee.cn/morax/erp/eval/post/indicator + * @param postId + * @returns + */ +export function queryPostIndicatorApi(params?: { postId: number; }): http.PromiseResp { + return request.get(`${MORAX_HOST}/erp/eval/post/indicator`, { params }); +} + +/** + * 获取岗位下的绩效组指标 + * http://testgate.feewee.cn/morax/erp/eval/shop/indicator + * @param postId + * @returns + */ +export function queryShopIndicatorApi(params?: any): http.PromiseResp { + return request.get(`${MORAX_HOST}/erp/eval/shop/indicator`, { params }); +} + +/** + * 考评组保存 + * http://testgate.feewee.cn/morax/erp/eval/group/{submit} + */ +export function saveEvaGroupConfig(params: EvaGroupSetteing.EvaGroupSaveParams, submit: number): http.PromiseResp { + return request.post(`${MORAX_HOST}/erp/eval/group/${submit}`, params); +} diff --git a/src/pages/performance/EvaGroupSetting/EditComfirm/components/AddCommissionParamsModal.tsx b/src/pages/performance/EvaGroupSetting/EditComfirm/components/AddCommissionParamsModal.tsx new file mode 100755 index 0000000..0c2eb72 --- /dev/null +++ b/src/pages/performance/EvaGroupSetting/EditComfirm/components/AddCommissionParamsModal.tsx @@ -0,0 +1,264 @@ +import React, { useEffect, useState } from "react"; +import { Modal, Form, Select, InputNumber, message, Spin, Radio, Input, Button } from "antd"; +import { saveRewardsListApi } from "../RewardsList/api"; +import { useStore } from "../index"; +import { queryPostIndicatorApi, queryShopIndicatorApi } from "@/pages/performance/EvaGroupSetting/EditComfirm/api"; +import _ from "lodash"; +import useInitail from "@/hooks/useInitail"; +import { EvaGroupSetteing } from "@/pages/performance/EvaGroupSetting/interface"; +import { TargetType, TargetTypeEnum } from "@/pages/performance/entity"; + +const Option = Select.Option; +interface Props { + // visible: boolean; + // onCancel: Function; + // postId?: number; + // shopIds?: string; + // onOk: (vales: any) => void; + // currentItem: KpiGroupSetteing.Item; + // comItem: KpiGroupSetteing.CommissionParams; + addComVisible: boolean; + onCancel: Function; + postId?: number; + shopIds?: string; + onOk: (vales: any) => void; + comItem: Commission; + setItemId: Function; + scopeType: number; +} +type Commission = EvaGroupSetteing.CommissionParams; +export default function AddCommissionParamsModal(props: Props) { + const percent = /^\d\.([1-9]{1,2}|[0-9][1-9])$|^[1-9]\d{0,1}(\.\d{1,2}){0,1}$|^100(\.0{1,2}){0,1}$/; + const Momney = /^([1-9]\d*(\.\d{1,2})?|([0](\.([0][1-9]|[1-9]\d{0,1}))))$/; + const [form] = Form.useForm(); + const { selectedIndicators, setParamAlias, setSelectedIndicators } = useStore(); + + const [isTarget, setIsTarget] = useState(false); + // console.log(form); + const { addComVisible, onCancel, postId, shopIds, onOk, comItem, setItemId, scopeType } = props; + const [delay, setDelay] = useState(true); + // 保存选中绩效指标需要配置的绩效考核目标值类型 + const [targetType, setTargetType] = useState(); + // 保存选中指标是否考评类型 + const [codeType, setCodeType] = useState(); + const [dataType, setDataType] = useState(); + // 保存过滤后指标列表 + const [newIndicators, setNewIndicators] = useState([]); + const [indicatorName, setIndicatorName] = useState(""); + const [id, setId] = useState(0); + const { + data: indicatorsList, + setParams, + loading, + } = useInitail( + scopeType == 1 ? queryPostIndicatorApi : queryShopIndicatorApi, + [], + scopeType == 1 ? { postId } : {}, + delay + ); + useEffect(() => { + setParams(scopeType == 1 ? { postId } : {}, true); + setDelay(false); + setTargetType(1); + }, [addComVisible]); + // 修改 + + useEffect(() => { + if (indicatorsList && indicatorsList.length > 0 && !comItem.code) { + const res = indicatorsList.filter((item) => !selectedIndicators.find((y) => y === item.code)); + setNewIndicators([...res]); + console.log("selectedIndicators", selectedIndicators); + } + if (addComVisible && comItem.code) { + const indTar = indicatorsList.find((item) => item.code == comItem.code)?.targetType; + console.log("indTar", indTar); + console.log("comItem.targetType", comItem.targetType); + setTargetType(indTar); + setIndicatorName(comItem.name); + setDataType(comItem.dataType); + setCodeType(comItem.codeType); + form.setFieldsValue({ + ...comItem, + commissionParams: { + value: comItem.code, + label: comItem.name, + }, + }); + } + if (comItem.targetValue && comItem.targetCalcType) { + setIsTarget(true); + } + }, [indicatorsList]); + useEffect(() => { + if (targetType === TargetTypeEnum["无"]) { + setIsTarget(false); + } + }, [targetType]); + useEffect(() => { + setIsTarget(false); + }, [id]); + // 校验表单数据 + function transformDTO(formData: any) { + let detail = {}; + _.each(formData, (value: any, key: string) => { + switch (key) { + case "commissionParams": + const _options = value || {}; + console.log(_options); + detail.code = _options.key; + detail.name = _options.label[0]; + detail.code = _options.value; + break; + default: + detail[key] = value; + break; + } + }); + return detail; + } + function handSubmit(fieldsValue: any) { + const pa: any = transformDTO(fieldsValue); + pa.targetType = targetType; + pa.codeType = codeType; + pa.dataType = dataType; + console.log("100pa", pa); + const newItemId = pa.code; + // 编辑时,不需要push id + if (!comItem.code) { + const tmpIds = [...selectedIndicators]; + tmpIds.push(newItemId); + setSelectedIndicators([...tmpIds]); + } else { + pa.code = comItem.code; + pa.name = comItem.name; + } + onOk(pa); + onCancel && onCancel(); + } + return ( + { + form.resetFields(); + onCancel(); + }} + onCancel={() => onCancel()} + onOk={form.submit} + width={1000} + > + +
+ + + +
+ + + +
+ + + + + + + {(targetType === TargetTypeEnum["百分比"] || + targetType === TargetTypeEnum["金额"] || + targetType === TargetTypeEnum["数量"]) && ( +
+ + {isTarget && ( + + )} +
+ )} + {isTarget && ( + <> + + { + setTargetType(Option.targetType); + setItemId(Option.key); + setId(Option.key); + setIndicatorName(Option.children); + setCommissionParamAlias(Option.name); + setCodeType(Option.codeType); + setDataType(Option.dataType); + }} + showSearch + optionFilterProp="children" + > + {newIndicators.map((item) => ( + + ))} + + +
+ + + +
+ + + + + + + {(targetType === TargetTypeEnum["百分比"] || + targetType === TargetTypeEnum["金额"] || + targetType === TargetTypeEnum["数量"]) && ( +
+ + {isTarget && ( + + )} +
+ )} + {isTarget && ( + <> + + { + setTargetType(Option.targetType); + // 最外层id + setItemId(Option.key); + // 列表id + setId(Option.key); + setIndicatorName(Option.children); + setPreconditionAlias(Option.name); + setCodeType(Option.codeType); + setDataType(Option.dataType); + }} + showSearch + optionFilterProp="children" + > + {newIndicators.map((item) => ( + + ))} + + + {(targetType === TargetTypeEnum["百分比"] || + targetType === TargetTypeEnum["金额"] || + targetType === TargetTypeEnum["数量"]) && ( +
+ + {isTarget && ( + + )} +
+ )} + {isTarget && ( + <> + + { + setTargetType(Option.targetType); + // 最外层id + setItemId(Option.key); + // 列表id + setId(Option.key); + setIndicatorName(Option.children); + setPreconditionAliasSal(Option.name); + setCodeType(Option.codeType); + setDataType(Option.dataType); + }} + showSearch + optionFilterProp="children" + > + {newIndicators.map((item) => ( + + ))} + + + + + 满足目标 + 满足排名率 + + + prevValues.condType !== currentValues.condType} + > + {({ getFieldValue }) => { + const condType = getFieldValue("condType"); + return ( + + + + ); + }} + + {(targetType === TargetTypeEnum["百分比"] || + targetType === TargetTypeEnum["金额"] || + targetType === TargetTypeEnum["数量"]) && ( +
+ + {isTarget && ( + + )} +
+ )} + {isTarget && ( + <> + + + + + current && current < moment().add(-1, "days").endOf("day")} + /> + + + setScopeType(e.target.value)}> + 人员考评 + 门店考评 + + + prevValues.scopeType !== currentValues.scopeType} + > + {({ getFieldValue }) => + getFieldValue("scopeType") === 1 ? ( + + + + ) : null + } + + + prevValues.scopeType !== currentValues.scopeType} + > + {({ getFieldValue }) => { + const scopeType = getFieldValue("scopeType"); + return ( + + item.shopId) : []} + type={scopeType === 1 ? 2 : 1} + onChange={( + shops: { + key: number; + label: string; + value: number; + }[] + ) => { + const shopIds = shops.map((item) => item.value).join(","); + setPersonModal({ ...personModal, shopIds }); + }} + /> + + ); + }} + + prevValues.scopeType !== currentValues.scopeType} + > + {({ getFieldValue }) => + getFieldValue("scopeType") === 1 ? ( + + ) : null + } + + prevValues.scopeType !== currentValues.scopeType} + > + {({ getFieldValue }) => + getFieldValue("scopeType") === 2 ? ( + + + + ) : null + } + + + prevValues.rewards !== currentValues.rewards}> + {({ getFieldValue }) => { + const rewards = getFieldValue("rewards"); + return ( + 0) }]}> + + + ); + }} + + prevValues.indicators !== currentValues.indicators} + > + {({ getFieldValue }) => { + const indicators = getFieldValue("indicators"); + return ( + 0) }]}> + + + ); + }} + +
+ + +
+ ); +} diff --git a/src/pages/performance/EvaGroupSetting/EditComfirm/components/AddIndicatorsModal.tsx b/src/pages/performance/EvaGroupSetting/EditComfirm/components/AddIndicatorsModal.tsx new file mode 100755 index 0000000..a352d54 --- /dev/null +++ b/src/pages/performance/EvaGroupSetting/EditComfirm/components/AddIndicatorsModal.tsx @@ -0,0 +1,288 @@ +/* eslint-disable no-return-assign */ +/* eslint-disable no-return-assign */ +import React, { useEffect, useState } from "react"; +import { Modal, Form, Select, InputNumber, message, Spin, Radio, Input, Button } from "antd"; +import { saveRewardsListApi } from "../RewardsList/api"; +import { useStore } from "../index"; +import { queryPostIndicatorApi } from "@/pages/performance/KpiGroupSetting/EditComfirm/api"; +import _ from "lodash"; +import useInitail from "@/hooks/useInitail"; +import LadderTable from "@/pages/performance/EvaGroupSetting/EditComfirm/components/LadderTable"; +import CommissionParams from "@/pages/performance/EvaGroupSetting/EditComfirm/components/CommissionParams"; +import LadderParams from "@/pages/performance/EvaGroupSetting/EditComfirm/components/LadderParams"; +import Conds from "@/pages/performance/EvaGroupSetting/EditComfirm/components/Conds"; +import { EvaGroupSetteing } from "@/pages/performance/EvaGroupSetting/interface"; + +const Option = Select.Option; +interface Props { + visible: boolean; + onCancel: Function; + postId?: number; + shopIds?: string; + onOk: (vales: any) => void; + currentItem: EvaGroupSetteing.Indicators; + comItem: EvaGroupSetteing.CommissionParams; + scopeType: number; +} + +export default function AddIndicatorsModal(props: Props) { + const [form] = Form.useForm(); + // console.log(form); + const { paramAlias, setParamAlias, preconditionAlias, setPreconditionAlias } = useStore(); + + // 是否为百分比 + const { visible, onCancel, postId, shopIds, onOk, currentItem, comItem, scopeType } = props; + const [isPercent, setIsPercent] = useState(0); + const [delay, setDelay] = useState(true); + // 显示前置条件 + const [condsVisible, setCondsVisible] = useState(false); + // 判断占比相加是否为100 + const [isHundred, setIsHundred] = useState(false); + // 保存过滤后指标列表 + // const [newIndicators, setNewIndicators] = useState([]); + const [id, setItemId] = useState(); + + // 修改 + useEffect(() => { + if (visible && currentItem.name) { + setParamAlias(currentItem.paramAlias); + form.setFieldsValue({ + ...currentItem, + }); + } + if (currentItem.conds && currentItem.conds.length > 0) { + setPreconditionAlias(currentItem.preconditionAlias); + setCondsVisible(true); + } else { + setCondsVisible(false); + } + }, [visible]); + + // useEffect(() => { + // if (indicatorsList && indicatorsList.length > 0 && !currentItem.id) { + // const res = indicatorsList.filter((item) => !selectedIndicators.find((y) => Number(y) === item.id)); + // setNewIndicators([...res]); + // } + // }, [indicatorsList]); + // 校验表单数据 + function transformDTO(formData: any) { + console.log("InformData", formData); + let detail = {}; + _.each(formData, (value: any, key: string) => { + switch (key) { + case "commissionParams": + const _options = value || {}; + detail.indicatorId = _options.key; + detail.name = _options.label; + detail.code = _options.value; + break; + default: + detail[key] = value; + break; + } + }); + return formData; + } + function handSubmit(fieldsValue: any) { + console.log(fieldsValue); + const pa: any = transformDTO(fieldsValue); + // pa.targetType = targetType; + // pa.id = id; + pa.paramAlias = paramAlias; + if (pa?.ladderParams && pa?.ladderParams.length > 0) { + if (isPercent == 0) { + pa.laddersType = currentItem.laddersType; + } else { + pa.laddersType = isPercent; + } + } + console.log("大", pa); + let hundred = 0; + if (pa?.commissionParams) { + hundred = pa?.commissionParams.reduce((data: number, item: EvaGroupSetteing.CommissionParams) => { + return data + item.proportion; + }, 0); + } + if (pa?.ladderParams) { + hundred = pa?.ladderParams.reduce((data: number, item: EvaGroupSetteing.CommissionParams) => { + return data + item.proportion; + }, 0); + } + //设置conds的sort + if (pa?.conds && pa?.conds.length > 0) { + pa?.conds.forEach((item: any, index: number) => { + Object.assign(item, { sort: index + 1 }); + }); + pa.preconditionAlias = preconditionAlias; + } + console.log("cond", pa?.conds); + + // 校验标准分不能大于绩效分值 + const indicatorValue = pa.baseScore; + if (!!pa.ladders && pa.ladders.length > 0) { + const _indicatorLadders: any[] = pa.ladders; + const res = _indicatorLadders.every((x, index) => { + if (x.standardScore <= indicatorValue) { + return true; + } + message.error(`第${index + 1}组标准分不满足条件: 标准分不能大于绩效分值`, 3); + return false; + }); + const _result = verifySteps(_indicatorLadders); + if (!(res && _result)) { + return; + } + } + + const newItemId = pa.id; + // 编辑时,不需要push id + // if (currentItem.id) { + // const tmpIds = [...selectedIndicators]; + // tmpIds.push(newItemId); + // setSelectedIndicators([...tmpIds]); + // setSelectedIndicatorsConds([...tmpIds]); + // } + if (hundred === 100) { + setIsHundred(false); + onOk(pa); + console.log(pa); + onCancel && onCancel(); + } else { + setIsHundred(true); + } + } + + // 校验阶梯越小,标准分越小 + const verifySteps = (_indicatorLadders: any[]) => { + let res = true; + _indicatorLadders.forEach((item, index) => { + if (index > 0) { + const curScore = item.standardScore; + const lastScore = _indicatorLadders[index - 1].standardScore; + if (curScore < lastScore) { + message.error(`第${index + 1}组标准分不满足条件: 阶梯越小,标准分越小`, 3); + res = false; + } + } + }); + return res; + }; + return ( + { + form.resetFields(); + onCancel(); + }} + onCancel={() => onCancel()} + onOk={form.submit} + width={1200} + > +
+ + + + + + + + + + +
+ 是否添加前置条件设置: + { + setCondsVisible(e.target.value); + }} + value={condsVisible} + > + + + +
+ {condsVisible && ( + + + + )} + prevValues.scoreWay !== currentValues.scoreWay}> + {({ getFieldValue }) => + getFieldValue("scoreWay") === 1 ? ( + <> + + + + + + + + ) : getFieldValue("scoreWay") === 2 ? ( + + + + ) : null + } + + prevValues.ladderParams !== currentValues.ladderParams} + > + {({ getFieldValue }) => { + const ladderParams = getFieldValue("ladderParams"); + if (ladderParams && ladderParams.length > 0) { + console.log("ladderParams", ladderParams); + if (ladderParams.length > 1) { + setIsPercent(2); + } else if (ladderParams[0].targetValue) { + setIsPercent(2); + } else if (ladderParams[0].dataType === 2) { + setIsPercent(2); + } else if (ladderParams[0].dataType === 1 || ladderParams[0].dataType === 3) { + setIsPercent(1); + } + } + return null; + }} + +
+
+ ); +} diff --git a/src/pages/performance/EvaGroupSetting/EditComfirm/components/AddLadderParamsModal.tsx b/src/pages/performance/EvaGroupSetting/EditComfirm/components/AddLadderParamsModal.tsx new file mode 100755 index 0000000..f810437 --- /dev/null +++ b/src/pages/performance/EvaGroupSetting/EditComfirm/components/AddLadderParamsModal.tsx @@ -0,0 +1,261 @@ +/* eslint-disable no-return-assign */ +/* eslint-disable no-return-assign */ +import React, { useEffect, useState } from "react"; +import { Modal, Form, Select, InputNumber, message, Spin, Radio, Input, Button } from "antd"; +import { useStore } from "../index"; +import { queryPostIndicatorApi, queryShopIndicatorApi } from "../api"; +import _ from "lodash"; +import useInitail from "@/hooks/useInitail"; +import { EvaGroupSetteing } from "@/pages/performance/EvaGroupSetting/interface"; +import { TargetType, TargetTypeEnum } from "@/pages/performance/entity"; + +const Option = Select.Option; +interface Props { + addComVisible: boolean; + onCancel: Function; + postId?: number; + shopIds?: string; + onOk: (vales: any) => void; + comItem: Commission; + setItemId: Function; + scopeType: number; +} +type Commission = EvaGroupSetteing.CommissionParams; +export default function AddLadderParamsModal(props: Props) { + const percent = /^\d\.([1-9]{1,2}|[0-9][1-9])$|^[1-9]\d{0,1}(\.\d{1,2}){0,1}$|^100(\.0{1,2}){0,1}$/; + const Momney = /^([1-9]\d*(\.\d{1,2})?|([0](\.([0][1-9]|[1-9]\d{0,1}))))$/; + const [form] = Form.useForm(); + const { selectedIndicatorsLadder, setSelectedIndicatorsLadder, setParamAlias } = useStore(); + + const [isTarget, setIsTarget] = useState(false); + const [dataType, setDataType] = useState(2); + // console.log(form); + const { addComVisible, onCancel, postId, shopIds, onOk, comItem, setItemId, scopeType } = props; + const [delay, setDelay] = useState(true); + // 保存选中绩效指标需要配置的绩效考核目标值类型 + const [targetType, setTargetType] = useState(); + // 保存选中指标是否考评类型 + const [codeType, setCodeType] = useState(); + // 保存过滤后指标列表 + const [newIndicators, setNewIndicators] = useState([]); + const [name, setIndicatorName] = useState(""); + const [id, setId] = useState(0); + const { + data: indicatorsList, + setParams, + loading, + } = useInitail( + scopeType == 1 ? queryPostIndicatorApi : queryShopIndicatorApi, + [], + scopeType == 1 ? { postId } : {}, + delay + ); + useEffect(() => { + setParams(scopeType == 1 ? { postId } : {}, true); + setDelay(false); + setTargetType(1); + }, [addComVisible]); + // 修改 + + useEffect(() => { + if (indicatorsList && indicatorsList.length > 0 && !comItem.code) { + const res = indicatorsList.filter((item) => !selectedIndicatorsLadder.find((y) => y === item.code)); + setNewIndicators([...res]); + } + if (addComVisible && comItem.code) { + const indTar = indicatorsList.find((item) => item.code == comItem.code)?.targetType; + console.log("indTar", indTar); + console.log("comItem.targetType", comItem.targetType); + setTargetType(indTar); + setIndicatorName(comItem.name); + setCodeType(comItem.codeType); + form.setFieldsValue({ + ...comItem, + ladderParams: { + value: comItem.code, + label: comItem.name, + dataType: comItem.dataType, + }, + }); + } + if (comItem.targetValue && comItem.targetCalcType) { + setIsTarget(true); + } + }, [indicatorsList]); + useEffect(() => { + if (targetType === TargetTypeEnum["无"]) { + setIsTarget(false); + } + }, [targetType]); + useEffect(() => { + setIsTarget(false); + }, [id]); + // 校验表单数据 + function transformDTO(formData: any) { + let detail = {}; + _.each(formData, (value: any, key: string) => { + switch (key) { + case "ladderParams": + const _options = value || {}; + detail.name = _options.label[0]; + detail.code = _options.value; + break; + default: + detail[key] = value; + break; + } + }); + return detail; + } + function handSubmit(fieldsValue: any) { + const pa: any = transformDTO(fieldsValue); + pa.targetType = targetType; + pa.codeType = codeType; + if (comItem.dataType) { + pa.dataType = comItem.dataType; + } + if (!comItem.dataType) { + pa.dataType = dataType; + } + console.log("100pa", pa); + const newItemId = pa.code; + // 编辑时,不需要push id + if (!comItem.code) { + const tmpIds = [...selectedIndicatorsLadder]; + tmpIds.push(newItemId); + setSelectedIndicatorsLadder([...tmpIds]); + } else { + pa.code = comItem.code; + pa.name = comItem.name; + } + onOk(pa); + onCancel && onCancel(); + } + return ( + { + form.resetFields(); + onCancel(); + }} + onCancel={() => onCancel()} + onOk={form.submit} + width={1000} + > + +
+ + + +
+ + + +
+ + + + + + + {(targetType === TargetTypeEnum["百分比"] || + targetType === TargetTypeEnum["金额"] || + targetType === TargetTypeEnum["数量"]) && ( +
+ + {isTarget && ( + + )} +
+ )} + {isTarget && ( + <> + + { + setTargetType(Option.targetType); + setItemId(Option.key); + setId(Option.key); + setIndicatorName(Option.children); + setLadderParamAlias(Option.name); + setDataType(Option.dataType); + setCodeType(Option.codeType); + }} + showSearch + optionFilterProp="children" + > + {newIndicators.map((item) => ( + + ))} + + +
+ + + +
+ + + + + + + {(targetType === TargetTypeEnum["百分比"] || + targetType === TargetTypeEnum["金额"] || + targetType === TargetTypeEnum["数量"]) && ( +
+ + {isTarget && ( + + )} +
+ )} + {isTarget && ( + <> + + + + + prevValues.calMethod !== currentValues.calMethod} + > + {({ getFieldValue }) => { + return ( + + + + ); + }} + + +
+ 是否添加前置条件设置: + { + setCondsVisible(e.target.value); + }} + value={condsVisible} + > + + + +
+ {condsVisible && ( + + + + )} + prevValues.calMethod !== currentValues.calMethod} + > + {({ getFieldValue }) => { + const caculateType = getFieldValue("calMethod"); + if (caculateType !== 1) { + return ( + <> + + + + + ); + } else { + return null; + } + }} + + prevValues.calMethod !== currentValues.calMethod} + > + {({ getFieldValue }) => { + const caculateType = getFieldValue("calMethod"); + if (caculateType == 1) { + return ( + <> + + + + + + 按固定值 + 按比例 + + + {/* + + 正数 + 倒数 + + */} + prevValues.rankType !== currentValues.rankType} + > + {({ getFieldValue }) => { + const rankType = getFieldValue("rankType"); + if (rankType == 1) { + setIsPercent(1); + } else { + setIsPercent(2); + } + return null; + }} + + prevValues.rankType !== currentValues.rankType} + > + {({ getFieldValue }) => { + const rankType = getFieldValue("rankType"); + if (rankType == 1 && !currentItem.ladders) { + form.setFieldValue("ladders", [{ lower: 1, money: 0, key: 0, rankOrderType: 1 }]); + } else if (rankType == 2 && !currentItem.ladders) { + form.setFieldValue("ladders", [{ lower: 0, money: 0, key: 0, rankOrderType: 1 }]); + } + return ( + + + + ); + }} + + + ); + } else if (caculateType == 2 || caculateType == 4) { + return ( + <> + + + + + ); + } else if (caculateType == 3 || caculateType == 5) { + return ( + <> + + + + + ); + } + return null; + }} + + + prevValues.ladderParams !== currentValues.ladderParams} + > + {({ getFieldValue }) => { + const ladderParams = getFieldValue("ladderParams"); + const calMethod = getFieldValue("calMethod"); + if (ladderParams && ladderParams.length > 0 && (calMethod == 3 || calMethod == 5)) { + console.log("ladderParams", ladderParams); + if (ladderParams.length > 1) { + setIsPercent(2); + } else if (ladderParams[0].targetValue) { + setIsPercent(2); + } else if (ladderParams[0].dataType === 2) { + setIsPercent(2); + } else if (ladderParams[0].dataType === 1 || ladderParams[0].dataType === 3) { + console.log("hasvdhjasvhdj"); + setIsPercent(1); + } + } + return null; + }} + + prevValues.calMethod !== currentValues.calMethod} + > + {({ getFieldValue }) => { + const caculateType = getFieldValue("calMethod"); + //阶梯(总) + if (caculateType == 3 || caculateType == 5) { + if (caculateType == 3 && !currentItem.ladders) { + form.setFieldValue("ladders", [{ lower: 0, money: 0, key: 0 }]); + } else if (caculateType == 5 && !currentItem.ladders) { + form.setFieldValue("ladders", [{ lower: 0, money: 0, capMoney: 0, key: 0 }]); + } + return ( + <> + + + + + ); + } + return null; + }} + +
+
+ ); +} diff --git a/src/pages/performance/EvaGroupSetting/EditComfirm/components/CommissionParams.tsx b/src/pages/performance/EvaGroupSetting/EditComfirm/components/CommissionParams.tsx new file mode 100755 index 0000000..a23e081 --- /dev/null +++ b/src/pages/performance/EvaGroupSetting/EditComfirm/components/CommissionParams.tsx @@ -0,0 +1,185 @@ +import React, { useState, useEffect } from "react"; +import { + Table, + Input, + InputNumber, + Popconfirm, + Form, + Typography, + Button, + message, + Space, + Divider, + Modal, + Card, +} from "antd"; +import { cloneDeep } from "lodash"; +import { EvaGroupSetteing } from "@/pages/performance/EvaGroupSetting/interface"; +import { useStore } from "../index"; +import AddCommissionParamsModal from "@/pages/performance/EvaGroupSetting/EditComfirm/components/AddCommissionParamsModal"; +import { TargetType, TargetTypeEnum } from "@/pages/performance/entity"; + +interface Props { + postId?: number; + onChange?: Function; + shopIds?: string; + value?: any[]; + setItemId: Function; + isHundred?: boolean; + scopeType: number; + // currentItem?: KpiGroupSetteing.Item[]; +} +type Commission = EvaGroupSetteing.CommissionParams; +const CommissionParams = ({ postId, shopIds, value, onChange, setItemId, isHundred, scopeType }: Props) => { + const [addComVisible, setAddComVisible] = useState(false); + const { selectedIndicators, setSelectedIndicators, readOnly, paramAlias, setParamAlias } = useStore(); + const [tableData, setTableData] = useState(value || []); + const [targetType, setTargetType] = useState(); + // 非台阶参数 + const [comItem, setComItem] = useState({}); + // 编辑 + const onEdit = (record: Commission) => { + setAddComVisible(true); + setComItem({ ...record }); + }; + //删除 + const _onDelete = (record: Commission, index: number) => { + const tempData = [...(value || [])]; + // console.log("tempData", tempData); + const res = tempData.filter((item) => item.code !== record.code); + //已选指标项同步删除 + selectedIndicators.splice(index, 1); + console.log(selectedIndicators); + onChange && onChange([...res]); + }; + useEffect(() => { + if (Array.isArray(value)) { + setTableData([...value]); + } + }, [value]); + const addCommission = () => { + setAddComVisible(true); + }; + const onCancel = () => { + setAddComVisible(false); + setComItem({}); + }; + const columns = [ + { + title: "指标名称", + dataIndex: "name", + key: "name", + }, + { + title: "占比", + dataIndex: "proportion", + key: "proportion", + render: (val: any, record: Commission, index: number) => { + return `${val}%`; + }, + }, + { + title: "单项指标封顶", + dataIndex: "cap", + key: "cap", + render: (val: any, record: Commission, index: number) => { + return val === true ? "是" : "否"; + }, + }, + { + title: "考核目标设置", + dataIndex: "targetValue", + key: "targetValue", + render: (value: number, record: Commission) => { + if (record.targetValue !== undefined) { + return record.targetType === 2 + ? `${value}%` + : record.targetType === 3 + ? `${value}元` + : record.targetType === 4 + ? `${value}台` + : "--"; + } else { + return "--"; + } + }, + }, + { + title: "考核目标值类型", + dataIndex: "targetType", + key: "targetType", + render: (value: number, record: any) => { + if (record.targetValue) { + if (value === TargetTypeEnum["百分比"]) { + return "百分比"; + } else if (value === TargetTypeEnum["金额"]) { + return "金额"; + } else if (value === TargetTypeEnum["数量"]) { + return "数量"; + } else { + return "无"; + } + } else { + return "无"; + } + }, + }, + { + title: "操作", + key: "operation", + render: (_: any, record: Commission, index: number) => ( + }> + onEdit(record)}>编辑 + _onDelete(record, index)}>删除 + + ), + }, + ]; + return ( + <> + + +
+ } + title={ +
+ X= + setParamAlias(e.target.value)} /> +
+ } + > + String(record.code)} + /> + {isHundred &&
占比和必须为100,当只有一项占比时该项占比也必须为100
} + + { + if (!comItem.code) { + tableData.push(values); + onChange && onChange(tableData); + } else { + const res = tableData.map((item) => (item.code === comItem.code ? { ...values } : item)); + onChange && onChange(res); + } + }} + /> + + ); +}; + +export default CommissionParams; diff --git a/src/pages/performance/EvaGroupSetting/EditComfirm/components/CommissionParamsSal.tsx b/src/pages/performance/EvaGroupSetting/EditComfirm/components/CommissionParamsSal.tsx new file mode 100755 index 0000000..729a30e --- /dev/null +++ b/src/pages/performance/EvaGroupSetting/EditComfirm/components/CommissionParamsSal.tsx @@ -0,0 +1,185 @@ +import React, { useState, useEffect } from "react"; +import { + Table, + Input, + InputNumber, + Popconfirm, + Form, + Typography, + Button, + message, + Space, + Divider, + Modal, + Card, +} from "antd"; +import { cloneDeep } from "lodash"; +import { EvaGroupSetteing } from "@/pages/performance/EvaGroupSetting/interface"; +import { useStore } from "../index"; +import AddCommissionParamsModalSal from "@/pages/performance/EvaGroupSetting/EditComfirm/components/AddCommissionParamsModalSal"; +import { TargetType, TargetTypeEnum } from "@/pages/performance/entity"; + +interface Props { + postId?: number; + onChange?: Function; + shopIds?: string; + value?: any[]; + setItemId: Function; + isHundred?: boolean; + scopeType: number; + // currentItem?: KpiGroupSetteing.Item[]; +} +type Commission = EvaGroupSetteing.CommissionParams; +const CommissionParams = ({ postId, shopIds, value, onChange, setItemId, isHundred, scopeType }: Props) => { + const [addComVisible, setAddComVisible] = useState(false); + const { selectedIndicatorSal, readOnly, commissionParamAlias, setCommissionParamAlias } = useStore(); + const [tableData, setTableData] = useState(value || []); + // const [targetType, setTargetType] = useState(); + // 非台阶参数 + const [comItem, setComItem] = useState({}); + // 编辑 + const onEdit = (record: Commission) => { + setAddComVisible(true); + setComItem({ ...record }); + }; + //删除 + const _onDelete = (record: Commission, index: number) => { + const tempData = [...(value || [])]; + // console.log("tempData", tempData); + const res = tempData.filter((item) => item.code !== record.code); + //已选指标项同步删除 + selectedIndicatorSal.splice(index, 1); + console.log(selectedIndicatorSal); + onChange && onChange([...res]); + }; + useEffect(() => { + if (Array.isArray(value)) { + setTableData([...value]); + } + }, [value]); + const addCommission = () => { + setAddComVisible(true); + }; + const onCancel = () => { + setAddComVisible(false); + setComItem({}); + }; + const columns = [ + { + title: "指标名称", + dataIndex: "name", + key: "name", + }, + { + title: "占比", + dataIndex: "proportion", + key: "proportion", + render: (val: any, record: Commission, index: number) => { + return `${val}%`; + }, + }, + { + title: "单项指标封顶", + dataIndex: "cap", + key: "cap", + render: (val: any, record: Commission, index: number) => { + return val === true ? "是" : "否"; + }, + }, + { + title: "考核目标设置", + dataIndex: "targetValue", + key: "targetValue", + render: (value: number, record: Commission) => { + if (record.targetValue !== undefined) { + return record.targetType === 2 + ? `${value}%` + : record.targetType === 3 + ? `${value}元` + : record.targetType === 4 + ? `${value}台` + : "--"; + } else { + return "--"; + } + }, + }, + { + title: "考核目标值类型", + dataIndex: "targetType", + key: "targetType", + render: (value: number, record: any) => { + if (record.targetValue) { + if (value === TargetTypeEnum["百分比"]) { + return "百分比"; + } else if (value === TargetTypeEnum["金额"]) { + return "金额"; + } else if (value === TargetTypeEnum["数量"]) { + return "数量"; + } else { + return "无"; + } + } else { + return "无"; + } + }, + }, + { + title: "操作", + key: "operation", + render: (_: any, record: Commission, index: number) => ( + }> + onEdit(record)}>编辑 + _onDelete(record, index)}>删除 + + ), + }, + ]; + return ( + <> + + + + } + title={ +
+ X= + setCommissionParamAlias(e.target.value)} /> +
+ } + > +
String(record.code)} + /> + {isHundred &&
占比和必须为100,当只有一项占比时该项占比也必须为100
} + + { + if (!comItem.code) { + tableData.push(values); + onChange && onChange(tableData); + } else { + const res = tableData.map((item) => (item.code === comItem.code ? { ...values } : item)); + onChange && onChange(res); + } + }} + /> + + ); +}; + +export default CommissionParams; diff --git a/src/pages/performance/EvaGroupSetting/EditComfirm/components/CondLaddersTable.tsx b/src/pages/performance/EvaGroupSetting/EditComfirm/components/CondLaddersTable.tsx new file mode 100755 index 0000000..d30bf47 --- /dev/null +++ b/src/pages/performance/EvaGroupSetting/EditComfirm/components/CondLaddersTable.tsx @@ -0,0 +1,320 @@ +import React, { useState, useEffect } from "react"; +import { Table, Input, InputNumber, Popconfirm, Form, Typography, Button, message, Space, Divider, Modal } from "antd"; +import { cloneDeep } from "lodash"; + +interface Item { + key: string; + lower: number; + upper: number; + scorePercent: number; +} + +interface Props { + value?: any[]; + onChange?: Function; + readOnly?: boolean; + visible?: boolean; + type?: number; //2 查看得分阶梯 + setladderVisible?: Function; +} + +interface EditableCellProps extends React.HTMLAttributes { + editing: boolean; + dataIndex: string; + title: any; + inputType: "number" | "text"; + record: Item; + index: number; + children: React.ReactNode; +} + +const EditableCell: React.FC = ({ + editing, + dataIndex, + title, + inputType, + record, + index, + children, + ...restProps +}) => { + const inputNode = + inputType === "number" ? : ; + + return ( + + ); +}; + +const LadderTable = ({ value, onChange, readOnly, visible, type, setladderVisible }: Props) => { + const [form] = Form.useForm(); + // 添加阶梯 + const [disable, setDisable] = useState(false); + const [editingKey, setEditingKey] = useState(""); + const isEditing = (record: Item) => record.key === editingKey; + + const edit = (record: Partial & { key: React.Key }, index: number) => { + form.setFieldsValue({ + scorePercent: "", + address: "", + ...record, + upper: record.upper == 65536 ? "" : record.upper, + }); + // console.log(record); + record.key = index.toString(); + setEditingKey(record.key); + }; + + const cancel = () => { + setEditingKey(""); + }; + + // 添加阶梯 + const onAdd = (values: any[], index: number) => { + const preTableData: any[] = [...values.map((i) => ({ ...i }))]; + + // 编辑不是最后一行,不需要增加阶梯 + if (index !== preTableData.length - 1) { + return preTableData; + } + + // 如果最后一行没有输入最大值,不需要增加阶梯 + if (index === preTableData.length - 1) { + const endData = preTableData[index]; + if (!endData.upper) { + return preTableData; + } + } + const newObj: { lower?: number; key?: number } = {}; + const lastData = preTableData[preTableData.length - 1]; + newObj.lower = lastData.upper; + newObj.key = Number(lastData.key) + 1; + + const pa = { + ...newObj, + key: newObj.key?.toString(), + scorePercent: 0, + }; + + preTableData.push(pa); + return preTableData; + }; + + const checkRange = async (tempData, index) => { + const res = [...tempData.map((i) => ({ ...i }))]; + const _tempData = res.concat(); + + for (let i = 0; i < _tempData.length; i++) { + const item = res[i]; + if (item.upper && item.lower && item.lower >= item.upper) { + item.upper = item.lower + 1; + } + if (i >= index && i < res.length - 1) { + res[i + 1].lower = item.upper; + } + } + + return res; + }; + + const save = async (key: React.Key, record: Item) => { + try { + const row = (await form.validateFields()) as Item; + let newData = [...value.map((i) => ({ ...i }))]; + const index = newData.findIndex((item) => key === item.key); + + const tempData = [...newData].map((i) => (i.key == key ? { ...record, ...row } : { ...i })); + + const res = await checkRange([...tempData], index); + + const addRow = onAdd([...res], index); + + if (index > -1) { + const item = addRow[index]; + + addRow.splice(index, 1, { + ...row, + ...item, + }); + + onChange && onChange([...addRow.map((i) => ({ ...i }))]); + setEditingKey(""); + } else { + addRow.push(row); + onChange && onChange([...addRow.map((i) => ({ ...i }))]); + + setEditingKey(""); + } + } catch (errInfo) { + console.log("Validate Failed:", errInfo); + } + }; + + // 删除阶梯区间 + + const _onDelete = (record: Item, index: number) => { + const tmpData = [...(value || [])]; + const res = tmpData.filter((item) => item.key !== record.key); + if (index > 0 && index <= res.length - 1) { + res[index].lower = res[index - 1].upper; + } + + //校准区间 + res.forEach((item, ind) => { + if (ind === 0) { + res[0].lower = 0; + } + }); + onChange && onChange([...res]); + }; + const columns = [ + { + title: "区间下限(≥)", + dataIndex: "lower", + width: "20%", + render: (value: number) => value + "%", + }, + { + title: "区间上限(<)", + dataIndex: "upper", + width: "20%", + editable: true, + render: (value: number) => (value && value !== 65536 ? value + "%" : ""), + }, + { + title: "标准分", + dataIndex: "scorePercent", + width: "15%", + editable: true, + }, + { + title: "操作", + width: "40%", + dataIndex: "operation", + render: (_: any, record: Item, index: number) => { + const editable = isEditing(record); + return editable ? ( + }> + save(record.key, record)} style={{ marginRight: 8 }}> + 保存 + + + 取消 + + + ) : ( + }> + edit(record, index)}> + 编辑 + + {index !== 0 && index !== value?.length - 1 && ( + _onDelete(record, index)} + > + 删除 + + )} + + ); + }, + }, + ]; + const getColumns = () => { + const _columns = columns; + if (readOnly) { + _columns.pop(); + } + return _columns; + }; + // const mergedColumns = columns.map((col) => { + const mergedColumns = getColumns().map((col) => { + if (!col.editable) { + return col; + } + return { + ...col, + onCell: (record: Item) => ({ + record, + inputType: "number", + dataIndex: col.dataIndex, + title: col.title, + editing: isEditing(record), + }), + }; + }); + + return ( + <> + {type === 2 ? ( + setladderVisible(false)} + > +
+
+ {editing ? ( + + {inputNode} + + ) : ( + children + )} +
+ + + ) : ( + +
+ + )} + + ); +}; + +export default LadderTable; diff --git a/src/pages/performance/EvaGroupSetting/EditComfirm/components/Conds.tsx b/src/pages/performance/EvaGroupSetting/EditComfirm/components/Conds.tsx new file mode 100755 index 0000000..96b6992 --- /dev/null +++ b/src/pages/performance/EvaGroupSetting/EditComfirm/components/Conds.tsx @@ -0,0 +1,197 @@ +import React, { useState, useEffect } from "react"; +import { + Table, + Input, + InputNumber, + Popconfirm, + Form, + Typography, + Button, + message, + Space, + Divider, + Modal, + Card, +} from "antd"; +import { cloneDeep } from "lodash"; +import { EvaGroupSetteing } from "@/pages/performance/EvaGroupSetting/interface"; +import { useStore } from "../index"; +import AddCondModal from "@/pages/performance/EvaGroupSetting/EditComfirm/components/AddCondModal"; +import { TargetType, TargetTypeEnum } from "@/pages/performance/entity"; +import CondLaddersTable from "@/pages/performance/EvaGroupSetting/EditComfirm/components/CondLaddersTable"; + +interface Props { + postId?: number; + onChange?: Function; + shopIds?: string; + value?: any[]; + setItemId: Function; + isHundred?: boolean; + scopeType: number; + // currentItem?: KpiGroupSetteing.Item[]; +} +type Commission = EvaGroupSetteing.CommissionParams; +const Conds = ({ postId, shopIds, value, onChange, setItemId, scopeType, isHundred }: Props) => { + const [addComVisible, setAddComVisible] = useState(false); + const [one, setOne] = useState(0); + const { readOnly, selectedIndicatorsConds, preconditionAlias, setPreconditionAlias } = useStore(); + const [tableData, setTableData] = useState(value || []); + // 查看得分阶梯 + const [ladderVisible, setladderVisible] = useState(false); + // 查看得分阶梯值 + const [ladderList, setladderList] = useState([]); + // 非台阶参数 + const [comItem, setComItem] = useState({}); + // 编辑 + const onEdit = (record: Commission) => { + setAddComVisible(true); + setComItem({ ...record }); + console.log("record", record); + }; + //删除 + const _onDelete = (record: Commission, index: number) => { + const tempData = [...(value || [])]; + console.log("tempData", tempData); + const res = tempData.filter((item) => item.code !== record.code); + selectedIndicatorsConds.splice(index, 1); + onChange && onChange([...res]); + }; + // 查看前置条件台阶详情 + const onLookCondLadders = (record: any) => { + if (record.ladders && record.ladders.length > 0) { + setladderVisible(true); + setladderList([...record?.ladders]); + } + }; + useEffect(() => { + if (Array.isArray(value)) { + setTableData([...value]); + } + }, [value]); + const addCommission = () => { + setAddComVisible(true); + setOne(1); + }; + const onCancel = () => { + setAddComVisible(false); + setComItem({}); + }; + const columns = [ + { + title: "前置条件名称", + dataIndex: "name", + key: "name", + }, + { + title: "前置条件阶梯", + render: (_: any, record: any) => (record.ladders && record.ladders.length > 0 ? ( + + ) : ( + "--" + )), + }, + { + title: "考核目标设置", + dataIndex: "targetValue", + key: "targetValue", + render: (value: number, record: Commission) => { + if (record.targetValue !== undefined) { + return record.targetType === 2 + ? `${value}%` + : record.targetType === 3 + ? `${value}元` + : record.targetType === 4 + ? `${value}台` + : "--"; + } else { + return "--"; + } + }, + }, + { + title: "考核目标值类型", + dataIndex: "targetType", + key: "targetType", + render: (value: number, record: any) => { + if (record.targetValue) { + if (value === TargetTypeEnum["百分比"]) { + return "百分比"; + } else if (value === TargetTypeEnum["金额"]) { + return "金额"; + } else if (value === TargetTypeEnum["数量"]) { + return "数量"; + } else { + return "无"; + } + } else { + return "无"; + } + }, + }, + { + title: "操作", + key: "operation", + render: (_: any, record: Commission, index: number) => ( + }> + onEdit(record)}>编辑 + _onDelete(record, index)}>删除 + + ), + }, + ]; + return ( + <> + + + + } + title={ +
+ Y= + setPreconditionAlias(e.target.value)} /> +
+ } + > +
String(record.code)} + /> + + { + if (!comItem.code) { + tableData.push(values); + onChange && onChange(tableData); + } else { + const res = tableData.map((item) => (item.code === comItem.code ? { ...values } : item)); + onChange && onChange(res); + } + }} + /> + + + ); +}; + +export default Conds; diff --git a/src/pages/performance/EvaGroupSetting/EditComfirm/components/CondsSal.tsx b/src/pages/performance/EvaGroupSetting/EditComfirm/components/CondsSal.tsx new file mode 100755 index 0000000..be61f22 --- /dev/null +++ b/src/pages/performance/EvaGroupSetting/EditComfirm/components/CondsSal.tsx @@ -0,0 +1,171 @@ +import React, { useState, useEffect } from "react"; +import { + Table, + Input, + InputNumber, + Popconfirm, + Form, + Typography, + Button, + message, + Space, + Divider, + Modal, + Card, +} from "antd"; +import { cloneDeep } from "lodash"; +import { EvaGroupSetteing } from "@/pages/performance/EvaGroupSetting/interface"; +import { useStore } from "../index"; +import AddCondModalSal from "@/pages/performance/EvaGroupSetting/EditComfirm/components/AddCondModalSal"; +import { TargetType, TargetTypeEnum } from "@/pages/performance/entity"; + +interface Props { + postId?: number; + onChange?: Function; + shopIds?: string; + value?: any[]; + setItemId: Function; + isHundred?: boolean; + scopeType: number; +} +type Commission = EvaGroupSetteing.CommissionParams; +const Conds = ({ postId, shopIds, value, onChange, setItemId, scopeType, isHundred }: Props) => { + const [addComVisible, setAddComVisible] = useState(false); + const [one, setOne] = useState(0); + const { readOnly, selectedIndicatorsCondsSal, preconditionAliasSal, setPreconditionAliasSal } = useStore(); + const [tableData, setTableData] = useState(value || []); + // 查看得分阶梯 + const [ladderVisible, setladderVisible] = useState(false); + // 查看得分阶梯值 + const [ladderList, setladderList] = useState([]); + // 非台阶参数 + const [comItem, setComItem] = useState({}); + // 编辑 + const onEdit = (record: Commission) => { + setAddComVisible(true); + setComItem({ ...record }); + console.log("record", record); + }; + //删除 + const _onDelete = (record: Commission, index: number) => { + const tempData = [...(value || [])]; + console.log("tempData", tempData); + const res = tempData.filter((item) => item.code !== record.code); + selectedIndicatorsCondsSal.splice(index, 1); + onChange && onChange([...res]); + }; + useEffect(() => { + if (Array.isArray(value)) { + setTableData([...value]); + } + }, [value]); + const addCommission = () => { + setAddComVisible(true); + setOne(1); + }; + const onCancel = () => { + setAddComVisible(false); + setComItem({}); + }; + const columns = [ + { + title: "前置条件名称", + dataIndex: "name", + key: "name", + }, + { + title: "考核目标设置", + dataIndex: "targetValue", + key: "targetValue", + render: (value: number, record: Commission) => { + if (record.targetValue !== undefined) { + return record.targetType === 2 + ? `${value}%` + : record.targetType === 3 + ? `${value}元` + : record.targetType === 4 + ? `${value}台` + : "--"; + } else { + return "--"; + } + }, + }, + { + title: "考核目标值类型", + dataIndex: "targetType", + key: "targetType", + render: (value: number, record: any) => { + if (record.targetValue) { + if (value === TargetTypeEnum["百分比"]) { + return "百分比"; + } else if (value === TargetTypeEnum["金额"]) { + return "金额"; + } else if (value === TargetTypeEnum["数量"]) { + return "数量"; + } else { + return "无"; + } + } else { + return "无"; + } + }, + }, + { + title: "操作", + key: "operation", + render: (_: any, record: Commission, index: number) => ( + }> + onEdit(record)}>编辑 + _onDelete(record, index)}>删除 + + ), + }, + ]; + return ( + <> + + + + } + title={ +
+ Y= + setPreconditionAliasSal(e.target.value)} /> +
+ } + > +
String(record.code)} + /> + + { + if (!comItem.code) { + tableData.push(values); + onChange && onChange(tableData); + } else { + const res = tableData.map((item) => (item.code === comItem.code ? { ...values } : item)); + onChange && onChange(res); + } + }} + /> + + ); +}; + +export default Conds; diff --git a/src/pages/performance/EvaGroupSetting/EditComfirm/components/EvalGroups.tsx b/src/pages/performance/EvaGroupSetting/EditComfirm/components/EvalGroups.tsx new file mode 100644 index 0000000..00b7368 --- /dev/null +++ b/src/pages/performance/EvaGroupSetting/EditComfirm/components/EvalGroups.tsx @@ -0,0 +1,153 @@ +import React, { useState, useEffect } from "react"; +import { Table, Typography, Button, message, Card, Divider, Space } from "antd"; +import Column from "antd/lib/table/Column"; +import AddEvaGroupModal from "./AddEvaGroupModal"; +import { EvaGroupSetteing } from "@/pages/performance/EvaGroupSetting/interface"; +import { useStore } from "../index"; +import ShopModal from "@/pages/performance/KpiGroupSetting/components/ShopModal"; +import { transformFormData } from "../entity"; + +interface Props { + value?: any[]; + onChange?: Function; +} + +type Item = EvaGroupSetteing.EvalGroups; +const EvalGroups = ({ value, onChange }: Props) => { + const { readOnly, setReadOnly } = useStore(); + const [tableData, setTableData] = useState(value || []); + const [scopeType, setScopeType] = useState(2); + // 添加指标Modal + const [visible, setVisible] = useState(false); + // 当前对象参数 + const [evaItem, setEvaItem] = useState({}); + // 查看门店 + const [shopModal, setShopModal] = useState<{ + visible: boolean; + record?: EvaGroupSetteing.EvalGroups; + }>({ + visible: false, + record: {}, + }); + const shopOnCancel = () => { + setShopModal({ visible: false }); + }; + // 添加指标 + const addEvaGroups = () => { + setVisible(true); + }; + const onCancel = () => { + setVisible(false); + setEvaItem({}); + }; + useEffect(() => { + if (Array.isArray(value)) { + setTableData([...value]); + } + }, [value]); + + // 编辑 + const onEdit = (record: Item, index: number) => { + console.log("evarecord", record); + const res = transformFormData(record); + setScopeType(record.scopeType); + setVisible(true); + setEvaItem({ ...res, index }); + }; + // 查看 + const onLook = (record: Item, index: number) => { + console.log("evarecord", record); + const res = transformFormData(record); + setVisible(true); + setEvaItem({ ...res, index }); + }; + + // 删除 + const _onDelete = (record: Item, index: number) => { + const tempData = [...(value || [])]; + tempData.splice(index, 1); // splice直接修改原数组,不会返回新数组 + onChange && onChange([...tempData]); + }; + const columns = [ + { + title: "考评组名称", + dataIndex: "name", + key: "name", + }, + { + title: "考评范围", + dataIndex: "scopeType", + key: "baseScore", + render: (scopeType: number) => (scopeType ? (scopeType == 2 ? "门店考评" : "人员考评") : ""), + }, + { + title: "岗位", + dataIndex: "postName", + key: "postName", + render: (postName: string) => postName || "--", + }, + { + title: "适用门店", + dataIndex: "shopNames", + render: (_: any, record: EvaGroupSetteing.EvalGroups) => ( + + ), + }, + { + title: "操作", + key: "operation", + render: (_: any, record: Item, index: number) => ( + }> + {readOnly ? ( + onLook(record, index)}>查看 + ) : ( + <> + onEdit(record, index)}>编辑 + _onDelete(record, index)}>删除 + + )} + + ), + }, + ]; + return ( + <> + + + + } + > +
String(record.id)} columns={columns} /> + + { + if (!evaItem.name) { + tableData.push(values); + onChange && onChange(tableData); + } else { + const res = tableData.map((item, index) => (index === evaItem.index ? { ...values } : item)); + onChange && onChange(res); + } + } + } + /> + + + ); +}; + +export default EvalGroups; diff --git a/src/pages/performance/EvaGroupSetting/EditComfirm/components/IndivatorsTable.tsx b/src/pages/performance/EvaGroupSetting/EditComfirm/components/IndivatorsTable.tsx new file mode 100755 index 0000000..88a3a81 --- /dev/null +++ b/src/pages/performance/EvaGroupSetting/EditComfirm/components/IndivatorsTable.tsx @@ -0,0 +1,238 @@ +import React, { useState, useEffect } from "react"; +import { Table, Typography, Button, message, Card, Divider, Space } from "antd"; +import Column from "antd/lib/table/Column"; +import AddIndicatorsModal from "./AddIndicatorsModal"; +import { EvaGroupSetteing } from "@/pages/performance/EvaGroupSetting/interface"; +import LadderTable from "@/pages/performance/EvaGroupSetting/EditComfirm/components/LadderTable"; +import { useStore } from "../index"; +import TargetModal from './TargetModal'; + +interface Props { + value?: any[]; + onChange?: Function; + postId?: number; + personModal: EvaGroupSetteing.Person; + scopeType: number; +} + +type Item = EvaGroupSetteing.Indicators; +type CommissionParams = EvaGroupSetteing.CommissionParams; +const IndivatorsTable = ({ value, onChange, personModal, scopeType }: Props) => { + const { postId, shopIds } = personModal; + const { + selectedIndicators, + setSelectedIndicators, + readOnly, + setSelectedIndicatorsConds, + setSelectedIndicatorsLadder, + setParamAlias, + } = useStore(); + const [tableData, setTableData] = useState(value || []); + const [tarVisible, setTarVisible] = useState(false); + const [tarCommissionParams, setTarCommissionParams] = useState<[]>([]); + // 添加指标Modal + const [visible, setVisible] = useState(false); + // 存储当前编辑数据 + const [currentItem, setCurrentItem] = useState({}); + // 非台阶参数 + const [comItem, setComItem] = useState({}); + // 查看得分阶梯 + const [ladderVisible, setladderVisible] = useState(false); + // 查看得分阶梯值 + const [ladderList, setladderList] = useState([]); + // 添加指标 + const addIndicators = () => { + if (!shopIds) { + message.error("请先选择门店"); + return; + } + setVisible(true); + setSelectedIndicators([]); + setSelectedIndicatorsConds([]); + setSelectedIndicatorsLadder([]); + setParamAlias(""); + }; + const onCancel = () => { + setVisible(false); + setCurrentItem({}); + setComItem({}); + }; + const tarOnCancel = () => { + setTarVisible(false); + }; + useEffect(() => { + if (Array.isArray(value)) { + setTableData([...value]); + } + }, [value]); + + // 编辑 + const onEdit = (record: Item, index: number) => { + setVisible(true); + setCurrentItem({ ...record, index }); + console.log({ ...record, index }); + if (record.commissionParams) { + setSelectedIndicators((record.commissionParams || []).map((item) => item.code)); + } + if (record.conds) { + setSelectedIndicatorsConds((record.conds || []).map((item) => item.code)); + } + if (record.ladderParams) { + setSelectedIndicatorsLadder((record.ladderParams || []).map((item) => item.code)); + } + }; + + /** + * 查看得分阶梯 + * */ + const onLookLadders = (record: Item) => { + if (record.ladders && record.ladders.length > 0) { + setladderVisible(true); + setladderList([...record?.ladders]); + } + }; + const lookTar = (record: any) => { + setTarVisible(true); + setTarCommissionParams(record); + }; + // 删除 + const _onDelete = (record: Item, index: number) => { + const tempData = [...(value || [])]; + tempData.splice(index, 1); // splice直接修改原数组,不会返回新数组 + onChange && onChange([...tempData]); + }; + const columns = [ + { + title: "指标名称", + dataIndex: "name", + key: "name", + }, + { + title: "绩效分值", + dataIndex: "baseScore", + key: "baseScore", + }, + { + title: "得分设置", + render: (_: any, record: Item) => + record.ladders && record.ladders.length > 0 ? ( + + ) : ( + "--" + ), + }, + { + title: "考核目标设置", + render: (value: any, record: Item) => { + const targets: any = []; + if (record.targets && record.targets.length > 0) { + const newValue = record.targets.filter((item: any) => item.targetValue); + if (newValue.length === 1) { + return newValue[0].targetType === 2 + ? `${newValue[0].targetValue}%` + : newValue[0].targetType === 3 + ? `${newValue[0].targetValue}元` + : `${newValue[0].targetValue}台`; + } else if (newValue.length > 1) { + return ( + + ); + } else { + return "--"; + } + } else { + if (record.conds && record.conds.length > 0) { + record.conds.forEach((i) => targets.push(i)); + } + if (record.commissionParams && record.commissionParams.length > 0) { + record.commissionParams.forEach((i) => targets.push(i)); + } + if (record.ladderParams && record.ladderParams.length > 0) { + record.ladderParams.forEach((i) => targets.push(i)); + } + const newValue = targets.filter((item: any) => item.targetValue); + if (newValue.length === 1) { + return newValue[0].targetType === 2 + ? `${newValue[0].targetValue}%` + : newValue[0].targetType === 3 + ? `${newValue[0].targetValue}元` + : `${newValue[0].targetValue}台`; + } else if (newValue.length > 1) { + return ( + + ); + } else { + return "--"; + } + } + }, + }, + { + title: "操作", + key: "operation", + render: (_: any, record: Item, index: number) => ( + }> + onEdit(record, index)}>编辑 + _onDelete(record, index)}>删除 + + ), + }, + ]; + + const getColumns = () => { + const _columns = columns; + if (readOnly) { + _columns.pop(); + } + return _columns; + }; + return ( + <> + + + + } + > +
String(record.id)} columns={getColumns()} /> + + { + if (!currentItem.name) { + tableData.push(values); + onChange && onChange(tableData); + } else { + const res = tableData.map((item, index) => (index === currentItem.index ? { ...values } : item)); + onChange && onChange(res); + } + }} + /> + + + + ); +}; + +export default IndivatorsTable; diff --git a/src/pages/performance/EvaGroupSetting/EditComfirm/components/LadderParams.tsx b/src/pages/performance/EvaGroupSetting/EditComfirm/components/LadderParams.tsx new file mode 100755 index 0000000..a0ce6ef --- /dev/null +++ b/src/pages/performance/EvaGroupSetting/EditComfirm/components/LadderParams.tsx @@ -0,0 +1,183 @@ +import React, { useState, useEffect } from "react"; +import { + Table, + Input, + InputNumber, + Popconfirm, + Form, + Typography, + Button, + message, + Space, + Divider, + Modal, + Card, +} from "antd"; +import { cloneDeep } from "lodash"; +import { EvaGroupSetteing } from "@/pages/performance/EvaGroupSetting/interface"; +import { useStore } from "../index"; +import AddLadderParamsModal from "@/pages/performance/EvaGroupSetting/EditComfirm/components/AddLadderParamsModal"; +import { TargetType, TargetTypeEnum } from "@/pages/performance/entity"; + +interface Props { + postId?: number; + onChange?: Function; + shopIds?: string; + value?: any[]; + setItemId: Function; + isHundred?: boolean; + scopeType: number; + // currentItem?: KpiGroupSetteing.Item[]; +} +type Commission = EvaGroupSetteing.CommissionParams; +const LadderParams = ({ postId, shopIds, value, onChange, setItemId, isHundred, scopeType }: Props) => { + const [addComVisible, setAddComVisible] = useState(false); + const { selectedIndicatorsLadder, readOnly, paramAlias, setParamAlias } = useStore(); + const [tableData, setTableData] = useState(value || []); + // 参数 + const [comItem, setComItem] = useState({}); + // 编辑 + const onEdit = (record: Commission) => { + setAddComVisible(true); + setComItem({ ...record }); + }; + //删除 + const _onDelete = (record: Commission, index: number) => { + const tempData = [...(value || [])]; + // console.log("tempData", tempData); + const res = tempData.filter((item) => item.code !== record.code); + //已选指标项同步删除 + selectedIndicatorsLadder.splice(index, 1); + onChange && onChange([...res]); + }; + useEffect(() => { + if (Array.isArray(value)) { + setTableData([...value]); + } + }, [value]); + const addCommission = () => { + setAddComVisible(true); + }; + const onCancel = () => { + setAddComVisible(false); + setComItem({}); + }; + const columns = [ + { + title: "指标名称", + dataIndex: "name", + key: "name", + }, + { + title: "占比", + dataIndex: "proportion", + key: "proportion", + render: (val: any, record: Commission, index: number) => { + return `${val}%`; + }, + }, + { + title: "单项指标封顶", + dataIndex: "cap", + key: "cap", + render: (val: any, record: Commission, index: number) => { + return val === true ? "是" : "否"; + }, + }, + { + title: "考核目标设置", + dataIndex: "targetValue", + key: "targetValue", + render: (value: number, record: Commission) => { + if (record.targetValue !== undefined) { + return record.targetType === 2 + ? `${value}%` + : record.targetType === 3 + ? `${value}元` + : record.targetType === 4 + ? `${value}台` + : "--"; + } else { + return "--"; + } + }, + }, + { + title: "考核目标值类型", + dataIndex: "targetType", + key: "targetType", + render: (value: number, record: any) => { + if (record.targetValue) { + if (value === TargetTypeEnum["百分比"]) { + return "百分比"; + } else if (value === TargetTypeEnum["金额"]) { + return "金额"; + } else if (value === TargetTypeEnum["数量"]) { + return "数量"; + } else { + return "无"; + } + } else { + return "无"; + } + }, + }, + { + title: "操作", + key: "operation", + render: (_: any, record: Commission, index: number) => ( + }> + onEdit(record)}>编辑 + _onDelete(record, index)}>删除 + + ), + }, + ]; + return ( + <> + + + + } + title={ +
+ X= + setParamAlias(e.target.value)} /> +
+ } + > +
String(record.code)} + /> + {isHundred &&
占比和必须为100,当只有一项占比时该项占比也必须为100
} + + { + if (!comItem.code) { + tableData.push(values); + onChange && onChange(tableData); + } else { + const res = tableData.map((item) => (item.code === comItem.code ? { ...values } : item)); + onChange && onChange(res); + } + }} + /> + + ); +}; + +export default LadderParams; diff --git a/src/pages/performance/EvaGroupSetting/EditComfirm/components/LadderParamsSal.tsx b/src/pages/performance/EvaGroupSetting/EditComfirm/components/LadderParamsSal.tsx new file mode 100755 index 0000000..d67803b --- /dev/null +++ b/src/pages/performance/EvaGroupSetting/EditComfirm/components/LadderParamsSal.tsx @@ -0,0 +1,193 @@ +import React, { useState, useEffect } from "react"; +import { + Table, + Input, + InputNumber, + Popconfirm, + Form, + Typography, + Button, + message, + Space, + Divider, + Modal, + Card, +} from "antd"; +import { cloneDeep } from "lodash"; +import { EvaGroupSetteing } from "@/pages/performance/EvaGroupSetting/interface"; +import { useStore } from "../index"; +import AddLadderParamsModalSal from "@/pages/performance/EvaGroupSetting/EditComfirm/components/AddLadderParamsModalSal"; +import { TargetType, TargetTypeEnum } from "@/pages/performance/entity"; + +interface Props { + postId?: number; + onChange?: Function; + shopIds?: string; + value?: any[]; + setItemId: Function; + isHundred?: boolean; + scopeType: number; + isHundredLadder?: boolean; + // currentItem?: KpiGroupSetteing.Item[]; +} +type Commission = EvaGroupSetteing.CommissionParams; +const LadderParams = ({ + postId, + shopIds, + value, + onChange, + setItemId, + isHundred, + scopeType, + isHundredLadder, +}: Props) => { + const [addComVisible, setAddComVisible] = useState(false); + const { selectedIndicatorsLadderSal, readOnly, ladderParamAlias, setLadderParamAlias } = useStore(); + const [tableData, setTableData] = useState(value || []); + // 参数 + const [comItem, setComItem] = useState({}); + // 编辑 + const onEdit = (record: Commission) => { + setAddComVisible(true); + setComItem({ ...record }); + }; + //删除 + const _onDelete = (record: Commission, index: number) => { + const tempData = [...(value || [])]; + // console.log("tempData", tempData); + const res = tempData.filter((item) => item.code !== record.code); + //已选指标项同步删除 + selectedIndicatorsLadderSal.splice(index, 1); + onChange && onChange([...res]); + }; + useEffect(() => { + if (Array.isArray(value)) { + setTableData([...value]); + } + }, [value]); + const addCommission = () => { + setAddComVisible(true); + }; + const onCancel = () => { + setAddComVisible(false); + setComItem({}); + }; + const columns = [ + { + title: "指标名称", + dataIndex: "name", + key: "name", + }, + { + title: "占比", + dataIndex: "proportion", + key: "proportion", + render: (val: any, record: Commission, index: number) => { + return `${val}%`; + }, + }, + { + title: "单项指标封顶", + dataIndex: "cap", + key: "cap", + render: (val: any, record: Commission, index: number) => { + return val === true ? "是" : "否"; + }, + }, + { + title: "考核目标设置", + dataIndex: "targetValue", + key: "targetValue", + render: (value: number, record: Commission) => { + if (record.targetValue !== undefined) { + return record.targetType === 2 + ? `${value}%` + : record.targetType === 3 + ? `${value}元` + : record.targetType === 4 + ? `${value}台` + : "--"; + } else { + return "--"; + } + }, + }, + { + title: "考核目标值类型", + dataIndex: "targetType", + key: "targetType", + render: (value: number, record: any) => { + if (record.targetValue) { + if (value === TargetTypeEnum["百分比"]) { + return "百分比"; + } else if (value === TargetTypeEnum["金额"]) { + return "金额"; + } else if (value === TargetTypeEnum["数量"]) { + return "数量"; + } else { + return "无"; + } + } else { + return "无"; + } + }, + }, + { + title: "操作", + key: "operation", + render: (_: any, record: Commission, index: number) => ( + }> + onEdit(record)}>编辑 + _onDelete(record, index)}>删除 + + ), + }, + ]; + return ( + <> + + + + } + title={ +
+ X= + setLadderParamAlias(e.target.value)} /> +
+ } + > +
String(record.code)} + /> + {isHundredLadder &&
占比和必须为100,当只有一项占比时该项占比也必须为100
} + + { + if (!comItem.code) { + tableData.push(values); + onChange && onChange(tableData); + } else { + const res = tableData.map((item) => (item.code === comItem.code ? { ...values } : item)); + onChange && onChange(res); + } + }} + /> + + ); +}; + +export default LadderParams; diff --git a/src/pages/performance/EvaGroupSetting/EditComfirm/components/LadderTable.tsx b/src/pages/performance/EvaGroupSetting/EditComfirm/components/LadderTable.tsx new file mode 100755 index 0000000..609f30f --- /dev/null +++ b/src/pages/performance/EvaGroupSetting/EditComfirm/components/LadderTable.tsx @@ -0,0 +1,379 @@ +import React, { useState, useEffect } from "react"; +import { Table, Input, InputNumber, Popconfirm, Form, Typography, Button, message, Space, Divider, Modal } from "antd"; +import { cloneDeep } from "lodash"; + +interface Item { + key: string; + lower: number; + upper: number; + standardScore: number; +} + +interface Props { + value?: any[]; + onChange?: Function; + readOnly?: boolean; + visible?: boolean; + type?: number; //2 查看得分阶梯 + setladderVisible: Function; + isPercent?: number; + laddersType?: number; +} + +interface EditableCellProps extends React.HTMLAttributes { + editing: boolean; + dataIndex: string; + title: any; + inputType: "number" | "text"; + record: Item; + index: number; + children: React.ReactNode; +} + +const EditableCell: React.FC = ({ + editing, + dataIndex, + title, + inputType, + record, + index, + children, + ...restProps +}) => { + const inputNode = + inputType === "number" ? : ; + + return ( + + ); +}; + +const LadderTable = ({ value, onChange, readOnly, visible, type, setladderVisible, isPercent, laddersType }: Props) => { + const EditableCell: React.FC = ({ + editing, + dataIndex, + title, + inputType, + record, + index, + children, + ...restProps + }) => { + let precision = 0; + if (dataIndex == "upper" && isPercent == 2) { + precision = 2; + } + const inputNode = inputType === "number" ? : ; + + return ( + + ); + }; + const [form] = Form.useForm(); + // 添加阶梯 + const [disable, setDisable] = useState(false); + const [editingKey, setEditingKey] = useState(""); + const isEditing = (record: Item) => record.key === editingKey; + + const edit = (record: Partial & { key: React.Key }) => { + form.setFieldsValue({ + upper: "", + standardScore: "", + address: "", + ...record, + }); + console.log(record); + setEditingKey(record.key); + }; + + const cancel = () => { + setEditingKey(""); + }; + + // 添加阶梯 + const onAdd = (values: any[], index: number) => { + const preTableData: any[] = [...values.map((i) => ({ ...i }))]; + + // 编辑不是最后一行,不需要增加阶梯 + if (index !== preTableData.length - 1) { + return preTableData; + } + + // 如果最后一行没有输入最大值,不需要增加阶梯 + if (index === preTableData.length - 1) { + const endData = preTableData[index]; + if (!endData.upper) { + return preTableData; + } + } + const newObj: { lower?: number; key?: number } = {}; + const lastData = preTableData[preTableData.length - 1]; + newObj.lower = lastData.upper; + newObj.key = Number(lastData.key) + 1; + + const pa = { + ...newObj, + key: newObj.key?.toString(), + standardScore: 0, + }; + + preTableData.push(pa); + return preTableData; + }; + + const checkRange = async (tempData, index) => { + const res = [...tempData.map((i) => ({ ...i }))]; + const _tempData = res.concat(); + + for (let i = 0; i < _tempData.length; i++) { + const item = res[i]; + if (item.upper && item.lower && item.lower >= item.upper) { + item.upper = item.lower + 1; + } + if (i >= index && i < res.length - 1) { + res[i + 1].lower = item.upper; + } + } + + return res; + }; + + const save = async (key: React.Key, record: Item) => { + try { + const row = (await form.validateFields()) as Item; + let newData = [...value.map((i) => ({ ...i }))]; + const index = newData.findIndex((item) => key === item.key); + + const tempData = [...newData].map((i) => (i.key == key ? { ...record, ...row } : { ...i })); + + const res = await checkRange([...tempData], index); + + const addRow = onAdd([...res], index); + + if (index > -1) { + const item = addRow[index]; + + addRow.splice(index, 1, { + ...row, + ...item, + }); + + onChange && onChange([...addRow.map((i) => ({ ...i }))]); + setEditingKey(""); + } else { + addRow.push(row); + onChange && onChange([...addRow.map((i) => ({ ...i }))]); + + setEditingKey(""); + } + } catch (errInfo) { + console.log("Validate Failed:", errInfo); + } + }; + + // 删除阶梯区间 + + const _onDelete = (record: Item, index: number) => { + // const tmpData = [...value] || []; + const tmpData = [...(value || [])]; + const res = tmpData.filter((item) => item.key !== record.key); + if (index > 0 && index <= res.length - 1) { + res[index].lower = res[index - 1].upper; + } + + //校准区间 + res.forEach((item, ind) => { + if (ind === 0) { + res[0].lower = 0; + } + }); + onChange && onChange([...res]); + }; + const columns = [ + { + title: "区间下限(≥)", + dataIndex: "lower", + width: "20%", + render: (value: number) => { + if (isPercent == 2) { + return value + "%"; + } else if (isPercent == 1) { + return value; + } else if (isPercent == 0 && laddersType == 2) { + return value + "%"; + } else { + return value; + } + }, + }, + { + title: "区间上限(<)", + dataIndex: "upper", + width: "20%", + editable: true, + render: (value: number) => { + if (value) { + if (isPercent == 2) { + return value + "%"; + } else if (isPercent == 1) { + return value; + } else if (isPercent == 0 && laddersType == 2) { + return value + "%"; + } else { + return value; + } + } else { + return ""; + } + }, + }, + { + title: "标准分", + dataIndex: "standardScore", + width: "15%", + editable: true, + }, + { + title: "得分", + width: "15%", + render: (_: any, record: Item) => (typeof record.standardScore === "number" ? `${record.standardScore}*x` : ""), + }, + { + title: "操作", + width: "40%", + dataIndex: "operation", + render: (_: any, record: Item, index: number) => { + const editable = isEditing(record); + return editable ? ( + }> + save(record.key, record)} style={{ marginRight: 8 }}> + 保存 + + + 取消 + + + ) : ( + }> + edit(record)}> + 编辑 + + {index !== 0 && index !== value?.length - 1 && ( + _onDelete(record, index)} + > + 删除 + + )} + + ); + }, + }, + ]; + const getColumns = () => { + const _columns = columns; + if (readOnly) { + _columns.pop(); + } + return _columns; + }; + // const mergedColumns = columns.map((col) => { + const mergedColumns = getColumns().map((col) => { + if (!col.editable) { + return col; + } + return { + ...col, + onCell: (record: Item) => ({ + record, + inputType: "number", + dataIndex: col.dataIndex, + title: col.title, + editing: isEditing(record), + }), + }; + }); + + return ( + <> + {type === 2 ? ( + setladderVisible(false)} + > +
+
+ {editing ? ( + + {inputNode} + + ) : ( + children + )} + + {editing ? ( + + {inputNode} + + ) : ( + children + )} +
+ + + ) : ( + +
+ + )} + + ); +}; + +export default LadderTable; diff --git a/src/pages/performance/EvaGroupSetting/EditComfirm/components/RankModal.tsx b/src/pages/performance/EvaGroupSetting/EditComfirm/components/RankModal.tsx new file mode 100755 index 0000000..4f8ccf8 --- /dev/null +++ b/src/pages/performance/EvaGroupSetting/EditComfirm/components/RankModal.tsx @@ -0,0 +1,468 @@ +import React, { useState, useEffect } from "react"; +import { Table, Input, InputNumber, Popconfirm, Form, Typography, Space, Divider, Modal, Radio } from "antd"; +import { SalaryMapHeader } from "@/pages/performance/CompensateGroupConfig/entity"; + +interface Item { + key: string; + lower: number; + upper: number; + standardScore: number; +} + +interface Props { + value?: any[]; + onChange?: Function; + readOnly?: boolean; + visible?: boolean; + type?: number; //2 查看得分阶梯 + setladderVisible?: Function; + salaryCode?: string; + isPercent?: number; + laddersType?: number; + calType?: number; + rankType?: number; +} + +interface EditableCellProps extends React.HTMLAttributes { + editing: boolean; + dataIndex: string; + title: any; + inputType: "number" | "text"; + record: Item; + index: number; + children: React.ReactNode; +} + +const TotalAmount = ({ + laddersType, + value, + onChange, + readOnly, + visible, + type, + setladderVisible, + salaryCode, + isPercent, + calType, + rankType, +}: Props) => { + const EditableCell: React.FC = ({ + editing, + dataIndex, + title, + inputType, + record, + index, + children, + ...restProps + }) => { + let precision = 0; + if (dataIndex == "upper" && isPercent == 2) { + precision = 2; + } + let max = 0; + if ((dataIndex == "upper" || dataIndex == "lower") && isPercent == 2) { + max = 100; + } else { + max = 999999999999; + } + const inputNode = inputType === "number" ? : ; + const rankOrderType = ( + + 正数 + 倒数 + + ); + + return ( + + ); + }; + const [form] = Form.useForm(); + // 添加阶梯 + const [disable, setDisable] = useState(false); + const [editingKey, setEditingKey] = useState(""); + + const isEditing = (record: Item) => record.key === editingKey; + + const edit = (record: Partial & { key: React.Key }) => { + console.log(record); + form.setFieldsValue({ + upper: "", + money: "", + ...record, + }); + setEditingKey(record.key); + }; + + const cancel = () => { + setEditingKey(""); + }; + + // 添加阶梯 + const onAdd = (values: any[], index: number) => { + const preTableData: any[] = [...values.map((i) => ({ ...i }))]; + + // 编辑不是最后一行,不需要增加阶梯 + if (index !== preTableData.length - 1) { + return preTableData; + } + + // 如果最后一行没有输入最大值,不需要增加阶梯 + if (index === preTableData.length - 1) { + const endData = preTableData[index]; + if (!endData.upper) { + return preTableData; + } + } + const newObj: { lower?: number; key?: number } = {}; + const lastData = preTableData[preTableData.length - 1]; + if (rankType == 2) { + newObj.lower = lastData.upper; + } else if (rankType == 1) { + newObj.lower = lastData.upper + 1; + } else { + newObj.lower = lastData.upper + 1; + } + newObj.key = Number(lastData.key) + 1; + + const pa = { + ...newObj, + key: newObj.key?.toString(), + money: 0, + }; + + preTableData.push(pa); + return preTableData; + }; + + const checkRange = async (tempData: any, index: number) => { + const res = [...tempData.map((i: any) => ({ ...i }))]; + const _tempData = res.concat(); + + for (let i = 0; i < _tempData.length; i++) { + const item = res[i]; + if (item.upper && item.lower && item.lower > item.upper) { + item.upper = item.lower + 1; + } + if (i >= index && i < res.length - 1) { + if (rankType == 2) { + res[i + 1].lower = item.upper; + } else if (rankType == 1) { + res[i + 1].lower = item.upper + 1; + } + } + } + + return res; + }; + + const _add = async (key: React.Key, record: Item) => { + try { + const row = (await form.validateFields()) as Item; + let newData = [...value.map((i) => ({ ...i }))]; + const index = newData.findIndex((item) => key === item.key); + + const tempData = [...newData].map((i) => (i.key == key ? { ...record, ...row } : { ...i })); + + const res = await checkRange([...tempData], index); + + const addRow = onAdd([...res], index); + + if (index > -1) { + const item = addRow[index]; + + addRow.splice(index, 1, { + ...row, + ...item, + }); + + onChange && onChange([...addRow.map((i) => ({ ...i }))]); + setEditingKey(""); + } else { + addRow.push(row); + onChange && onChange([...addRow.map((i) => ({ ...i }))]); + setEditingKey(""); + } + } catch (errInfo) { + console.log("Validate Failed:", errInfo); + } + }; + + const save = async (key: React.Key, record: Item) => { + try { + const row = (await form.validateFields()) as Item; + let newData = [...value.map((i) => ({ ...i }))]; + const index = newData.findIndex((item) => key === item.key); + + const tempData = [...newData].map((i) => (i.key == key ? { ...record, ...row } : { ...i })); + + const res = await checkRange([...tempData], index); + + const addRow = [...res]; + + if (index > -1) { + const item = addRow[index]; + + addRow.splice(index, 1, { + ...row, + ...item, + }); + + onChange && onChange([...addRow.map((i) => ({ ...i }))]); + setEditingKey(""); + } else { + onChange && onChange([...addRow.map((i) => ({ ...i }))]); + setEditingKey(""); + } + } catch (errInfo) { + console.log("Validate Failed:", errInfo); + } + }; + + // 删除阶梯区间 + + const _onDelete = (record: Item, index: number) => { + console.log(record); + const tmpData = [...(value || [])]; + const res = tmpData.filter((item) => item.key !== record.key); + if (index > 0 && index <= res.length - 1) { + res[index].lower = res[index - 1].upper; + } + + //校准区间 + res.forEach((item, ind) => { + if (ind === 0) { + res[0].lower = rankType == 1 ? 1 : 0; + } + }); + onChange && onChange([...res]); + }; + const columns = [ + { + title: "区间", + editable: true, + children: [ + { + title: `初始排名${rankType == 1 ? "(≥)" : "(>)"}`, + editable: true, + dataIndex: "lower", + width: "15%", + render: (value: number) => { + if (isPercent == 2) { + return value + "%"; + } else if (isPercent == 1) { + return value; + } else if (isPercent == 0 && laddersType == 2) { + return value + "%"; + } else { + return value; + } + }, + }, + { + title: `结束排名${rankType == 1 ? "(≤)" : "(≤)"}`, + dataIndex: "upper", + width: "15%", + editable: true, + render: (value: number) => { + if (value) { + if (isPercent == 2) { + return value + "%"; + } else if (isPercent == 1) { + return value; + } else if (isPercent == 0 && laddersType == 2) { + return value + "%"; + } else { + return value; + } + } else { + return ""; + } + }, + }, + ], + }, + { + title: "金额 (元)", + dataIndex: "money", + width: "10%", + editable: true, + render: (text: number) => (typeof text === "number" ? `${text}` : "--"), + }, + { + title: "封顶金额 (元)", + dataIndex: "capMoney", + width: "20%", + editable: true, + render: (text: number) => (typeof text === "number" ? `${text}` : "--"), + }, + { + title: "排名顺序类型", + dataIndex: "rankOrderType", + width: "20%", + editable: true, + render: (rankOrderType: number) => (rankOrderType === 2 ? "倒数排序" : "正数排序"), + }, + { + title: "操作", + width: "40%", + dataIndex: "operation", + render: (_: any, record: Item, index: number) => { + const editable = isEditing(record); + return editable ? ( + }> + _add(record.key, record)} style={{ marginRight: 8 }}> + 保存并新增排名区间 + + save(record.key, record)} style={{ marginRight: 8 }}> + 保存 + + + 取消 + + + ) : ( + }> + edit(record)}> + 编辑 + + {index !== 0 && ( + _onDelete(record, index)} + > + 删除 + + )} + + ); + }, + }, + ]; + const getColumns = () => { + const _columns = columns; + if (readOnly) { + _columns.pop(); + } + return _columns; + }; + const calTypeColumns = () => { + const _columns = getColumns(); + if (calType == 5) { + return _columns; + } else { + return _columns.filter((item) => item.dataIndex !== "capMoney"); + } + }; + const mergedColumns = calTypeColumns().map((col) => { + if (!col.editable) { + return col; + } + if (col.children) { + return { + ...col, + children: [ + { + ...col.children[0], + onCell: (record: Item) => { + return { + record, + inputType: "number", + dataIndex: col.children[0].dataIndex, + title: col.children[0].title, + editing: isEditing(record), + }; + }, + }, + { + ...col.children[1], + onCell: (record: Item) => { + console.log("recordrecord", record); + return { + record, + inputType: "number", + dataIndex: col.children[1].dataIndex, + title: col.children[1].title, + editing: isEditing(record), + }; + }, + }, + ], + }; + } + return { + ...col, + onCell: (record: Item) => ({ + record, + inputType: "number", + dataIndex: col.dataIndex, + title: col.title, + editing: isEditing(record), + }), + }; + }); + + return ( + <> + {type === 2 ? ( + setladderVisible(false)} + > +
+
+ {editing ? ( + + {dataIndex == "rankOrderType" ? rankOrderType : inputNode} + + ) : ( + children + )} +
+ +
金额可为负数,负数为负激励
+ + ) : ( + <> + +
+ +
金额可为负数,负数为负激励
+ + )} + + ); +}; + +export default TotalAmount; diff --git a/src/pages/performance/EvaGroupSetting/EditComfirm/components/RewardsTableSal.tsx b/src/pages/performance/EvaGroupSetting/EditComfirm/components/RewardsTableSal.tsx new file mode 100755 index 0000000..c5cae83 --- /dev/null +++ b/src/pages/performance/EvaGroupSetting/EditComfirm/components/RewardsTableSal.tsx @@ -0,0 +1,208 @@ +import React, { useState, useEffect } from "react"; +import { Table, Typography, Button, message, Card, Divider, Space } from "antd"; +import AddRewardsModal from "./AddRewardsModal"; +import { useStore } from "../index"; +import { OptionalMethod_Enum } from "../../entity"; +import TargetModal from "./TargetModal"; +import { EvaGroupSetteing } from "@/pages/performance/EvaGroupSetting/interface"; + +interface Props { + value?: any[]; + onChange?: Function; + postId?: number; + shopIds?: string; + scopeType: number; + personModal: EvaGroupSetteing.Person; +} + +type Item = EvaGroupSetteing.Rewards; + +const IndivatorsTable = ({ value, onChange, scopeType, personModal }: Props) => { + const [delay, setDelay] = useState(true); + const { postId, shopIds } = personModal; + const { + readOnly, + setSelectedIndicatorsSal, + setSelectedIndicatorsCondsSal, + setSelectedIndicatorsLadderSal, + setCommissionParamAlias, + setLadderParamAlias, + setPreconditionAliasSal, + } = useStore(); + const [tableData, setTableData] = useState(value || []); + const [visible, setVisible] = useState(false); + const [currentItem, setCurrentItem] = useState({}); + const [tarVisible, setTarVisible] = useState(false); + const [tarCommissionParams, setTarCommissionParams] = useState<[]>([]); + + // 添加指标 + const addIndicators = () => { + if (!shopIds) { + message.error("请先选择门店"); + return; + } + setVisible(true); + setSelectedIndicatorsSal([]); + setSelectedIndicatorsCondsSal([]); + setSelectedIndicatorsLadderSal([]); + setCommissionParamAlias(""); + setLadderParamAlias(""); + setPreconditionAliasSal(""); + }; + const onCancel = () => { + setVisible(false); + setCurrentItem({}); + }; + useEffect(() => { + if (Array.isArray(value)) { + setTableData([...value]); + } + }, [value]); + + // 编辑 + const onEdit = (record: Item, index: number) => { + setVisible(true); + setCurrentItem({ ...record, index }); + console.log("编辑record", record); + console.log({ ...record, index }); + if (record.commissionParams) { + setSelectedIndicatorsSal((record.commissionParams || []).map((item) => item.code)); + } + if (record.conds) { + setSelectedIndicatorsCondsSal((record.conds || []).map((item) => item.code)); + } + if (record.ladderParams) { + setSelectedIndicatorsLadderSal((record.ladderParams || []).map((item) => item.code)); + } + }; + + // 删除 + const _onDelete = (record: Item, index: number) => { + const tempData = [...(value || [])]; + tempData.splice(index, 1); // splice直接修改原数组,不会返回新数组 + onChange && onChange([...tempData]); + }; + // 查看考核目标设置 + const lookTar = (record: any) => { + setTarVisible(true); + setTarCommissionParams(record); + }; + const tarOnCancel = () => { + setTarVisible(false); + }; + const columns = [ + { + title: "指标名称", + dataIndex: "name", + key: "name", + }, + { + title: "计算方式", + dataIndex: "calMethod", + key: "calMethod", + render: (text: number) => (text ? OptionalMethod_Enum[text] : "--"), + }, + { + title: "考核目标设置", + render: (value: any, record: Item) => { + const targets: any = []; + if (record.targets && record.targets.length > 0) { + const newValue = record.targets.filter((item: any) => item.targetValue); + if (newValue.length === 1) { + return newValue[0].targetType === 2 + ? `${newValue[0].targetValue}%` + : newValue[0].targetType === 3 + ? `${newValue[0].targetValue}元` + : `${newValue[0].targetValue}台`; + } else if (newValue.length > 1) { + return ( + + ); + } else { + return "--"; + } + } else { + if (record.conds && record.conds.length > 0) { + record.conds.forEach((i) => targets.push(i)); + } + if (record.commissionParams && record.commissionParams.length > 0) { + record.commissionParams.forEach((i) => targets.push(i)); + } + if (record.ladderParams && record.ladderParams.length > 0) { + record.ladderParams.forEach((i) => targets.push(i)); + } + const newValue = targets.filter((item: any) => item.targetValue); + if (newValue.length === 1) { + return newValue[0].targetType === 2 + ? `${newValue[0].targetValue}%` + : newValue[0].targetType === 3 + ? `${newValue[0].targetValue}元` + : `${newValue[0].targetValue}台`; + } else if (newValue.length > 1) { + return ( + + ); + } else { + return "--"; + } + } + }, + }, + { + title: "操作", + key: "operation", + render: (_: any, record: Item, index: number) => ( + }> + onEdit(record, index)}>编辑 + _onDelete(record, index)}>删除 + + ), + }, + ]; + + const getColumns = () => { + const _columns = columns; + if (readOnly) { + _columns.pop(); + } + return _columns; + }; + return ( + <> + + + + } + > +
String(record.id)} columns={getColumns()} /> + + { + if (!currentItem.name) { + tableData.push(values); + onChange && onChange(tableData); + } else { + const res = tableData.map((item, index) => (index === currentItem.index ? { ...values } : item)); + onChange && onChange(res); + } + }} + /> + + + ); +}; +export default IndivatorsTable; diff --git a/src/pages/performance/EvaGroupSetting/EditComfirm/components/TargetModal.tsx b/src/pages/performance/EvaGroupSetting/EditComfirm/components/TargetModal.tsx new file mode 100755 index 0000000..8e8ccb8 --- /dev/null +++ b/src/pages/performance/EvaGroupSetting/EditComfirm/components/TargetModal.tsx @@ -0,0 +1,60 @@ +import React, { useState, useEffect } from "react"; +import { + Table, + Input, + InputNumber, + Popconfirm, + Form, + Typography, + Button, + message, + Space, + Divider, + Modal, + Card, +} from "antd"; +import { cloneDeep } from "lodash"; +import { KpiGroupSetteing } from "@/pages/performance/KpiGroupSetting/interface"; +import { useStore } from "../index"; +import { TargetType, TargetTypeEnum } from "@/pages/performance/entity"; +import { render } from "react-dom"; + +interface Props { + visible: boolean; + tarCommissionParams: []; + tarOnCancel: Function; +} +const columns = [ + { + title: "目标名称", + dataIndex: "name", + key: "name", + }, + { + title: "目标值", + dataIndex: "targetValue", + key: "targetValue", + render: (value: Number, record: any) => { + return record.targetType === 2 ? `${value}%` : record.targetType === 3 ? `${value}元` : `${value}台`; + }, + }, +]; + +const TargetModal = ({ visible, tarCommissionParams, tarOnCancel }: Props) => { + console.log("tarCommissionParams", tarCommissionParams); + return ( + <> + tarOnCancel()} + maskClosable={false} + footer={null} + > +
+ + + ); +}; + +export default TargetModal; diff --git a/src/pages/performance/EvaGroupSetting/EditComfirm/components/TotalAmountSal.tsx b/src/pages/performance/EvaGroupSetting/EditComfirm/components/TotalAmountSal.tsx new file mode 100755 index 0000000..518c276 --- /dev/null +++ b/src/pages/performance/EvaGroupSetting/EditComfirm/components/TotalAmountSal.tsx @@ -0,0 +1,390 @@ +import React, { useState, useEffect } from "react"; +import { Table, Input, InputNumber, Popconfirm, Form, Typography, Space, Divider, Modal } from "antd"; +import { SalaryMapHeader } from "@/pages/performance/CompensateGroupConfig/entity"; + +interface Item { + key: string; + lower: number; + upper: number; + standardScore: number; +} + +interface Props { + value?: any[]; + onChange?: Function; + readOnly?: boolean; + visible?: boolean; + type?: number; //2 查看得分阶梯 + setladderVisible?: Function; + salaryCode?: string; + isPercent?: number; + laddersType?: number; + calType?: number; +} + +interface EditableCellProps extends React.HTMLAttributes { + editing: boolean; + dataIndex: string; + title: any; + inputType: "number" | "text"; + record: Item; + index: number; + children: React.ReactNode; +} + +const TotalAmount = ({ + laddersType, + value, + onChange, + readOnly, + visible, + type, + setladderVisible, + salaryCode, + isPercent, + calType, +}: Props) => { + const EditableCell: React.FC = ({ + editing, + dataIndex, + title, + inputType, + record, + index, + children, + ...restProps + }) => { + let precision = 0; + if (dataIndex == "upper" && isPercent == 2) { + precision = 2; + } + const inputNode = inputType === "number" ? : ; + + return ( + + ); + }; + const [form] = Form.useForm(); + // 添加阶梯 + const [disable, setDisable] = useState(false); + const [editingKey, setEditingKey] = useState(""); + + const isEditing = (record: Item) => record.key === editingKey; + + const edit = (record: Partial & { key: React.Key }, index: number) => { + form.setFieldsValue({ + upper: "", + money: "", + ...record, + }); + setEditingKey(record.key); + }; + + const cancel = () => { + setEditingKey(""); + }; + + // 添加阶梯 + const onAdd = (values: any[], index: number) => { + const preTableData: any[] = [...values.map((i) => ({ ...i }))]; + + // 编辑不是最后一行,不需要增加阶梯 + if (index !== preTableData.length - 1) { + return preTableData; + } + + // 如果最后一行没有输入最大值,不需要增加阶梯 + if (index === preTableData.length - 1) { + const endData = preTableData[index]; + if (!endData.upper) { + return preTableData; + } + } + const newObj: { lower?: number; key?: number } = {}; + const lastData = preTableData[preTableData.length - 1]; + newObj.lower = lastData.upper; + newObj.key = Number(lastData.key) + 1; + + const pa = { + ...newObj, + key: newObj.key?.toString(), + money: 0, + }; + + preTableData.push(pa); + return preTableData; + }; + + const checkRange = async (tempData:any, index:number) => { + const res = [...tempData.map((i:any) => ({ ...i }))]; + const _tempData = res.concat(); + + for (let i = 0; i < _tempData.length; i++) { + const item = res[i]; + if (item.upper && item.lower && item.lower >= item.upper) { + item.upper = item.lower + 1; + } + if (i >= index && i < res.length - 1) { + res[i + 1].lower = item.upper; + } + } + + return res; + }; + + const save = async (key: React.Key, record: Item) => { + try { + const row = (await form.validateFields()) as Item; + let newData = [...value.map((i) => ({ ...i }))]; + const index = newData.findIndex((item) => key === item.key); + + const tempData = [...newData].map((i) => (i.key == key ? { ...record, ...row } : { ...i })); + + const res = await checkRange([...tempData], index); + + const addRow = onAdd([...res], index); + + if (index > -1) { + const item = addRow[index]; + + addRow.splice(index, 1, { + ...row, + ...item, + }); + + onChange && onChange([...addRow.map((i) => ({ ...i }))]); + setEditingKey(""); + } else { + addRow.push(row); + onChange && onChange([...addRow.map((i) => ({ ...i }))]); + + setEditingKey(""); + } + } catch (errInfo) { + console.log("Validate Failed:", errInfo); + } + }; + + // 删除阶梯区间 + + const _onDelete = (record: Item, index: number) => { + console.log(record); + const tmpData = [...(value || [])]; + const res = tmpData.filter((item) => item.key !== record.key); + if (index > 0 && index <= res.length - 1) { + res[index].lower = res[index - 1].upper; + } + + //校准区间 + res.forEach((item, ind) => { + if (ind === 0) { + res[0].lower = 0; + } + }); + onChange && onChange([...res]); + }; + const columns = [ + { + title: "区间", + editable: true, + children: [ + { + title: "阶梯值下限(≥)", + dataIndex: "lower", + width: "25%", + render: (value: number) => { + if (isPercent == 2) { + return value + "%"; + } else if (isPercent == 1) { + return value; + } else if (isPercent == 0 && laddersType == 2) { + return value + "%"; + } else { + return value; + } + }, + }, + { + title: "阶梯值上限(<)", + dataIndex: "upper", + width: "25%", + editable: true, + render: (value: number) => { + if (value) { + if (isPercent == 2) { + return value + "%"; + } else if (isPercent == 1) { + return value; + } else if (isPercent == 0 && laddersType == 2) { + return value + "%"; + } else { + return value; + } + } else { + return ""; + } + }, + }, + ], + }, + { + title: "金额 (元)", + dataIndex: "money", + width: "20%", + editable: true, + render: (text: number) => (typeof text === "number" ? `${text}` : "--"), + }, + { + title: "封顶金额 (元)", + dataIndex: "capMoney", + width: "20%", + editable: true, + render: (text: number) => (typeof text === "number" ? `${text}` : "--"), + }, + { + title: "操作", + width: "40%", + dataIndex: "operation", + render: (_: any, record: Item, index: number) => { + const editable = isEditing(record); + return editable ? ( + }> + save(record.key, record)} style={{ marginRight: 8 }}> + 保存 + + + 取消 + + + ) : ( + }> + edit(record,index)}> + 编辑 + + {index !== 0 && index !== value?.length - 1 && ( + _onDelete(record, index)} + > + 删除 + + )} + + ); + }, + }, + ]; + const getColumns = () => { + const _columns = columns; + if (readOnly) { + _columns.pop(); + } + return _columns; + }; + const calTypeColumns = () => { + const _columns = getColumns(); + if (calType == 5) { + return _columns; + } else { + return _columns.filter((item) => item.dataIndex !== "capMoney"); + } + }; + const mergedColumns = calTypeColumns().map((col) => { + if (!col.editable) { + return col; + } + if (col.children) { + return { + ...col, + children: [ + { + ...col.children[0], + }, + { + ...col.children[1], + onCell: (record: Item) => ({ + record, + inputType: "number", + dataIndex: col.children[1].dataIndex, + title: col.children[1].title, + editing: isEditing(record), + }), + }, + ], + }; + } + return { + ...col, + onCell: (record: Item) => ({ + record, + inputType: "number", + dataIndex: col.dataIndex, + title: col.title, + editing: isEditing(record), + }), + }; + }); + + return ( + <> + {type === 2 ? ( + setladderVisible(false)} + > +
+
+ {editing ? ( + + {inputNode} + + ) : ( + children + )} +
+ +
金额可为负数,负数为负激励
+ + ) : ( + <> + +
+ +
金额可为负数,负数为负激励
+ + )} + + ); +}; + +export default TotalAmount; diff --git a/src/pages/performance/EvaGroupSetting/EditComfirm/entity.ts b/src/pages/performance/EvaGroupSetting/EditComfirm/entity.ts new file mode 100644 index 0000000..adf6c4e --- /dev/null +++ b/src/pages/performance/EvaGroupSetting/EditComfirm/entity.ts @@ -0,0 +1,211 @@ +import _ from "lodash"; +import { EvaGroupSetteing } from "../interface"; +import moment from "moment"; + +export interface formData { + post?: { value: number; label: string }; + shop?: { value: number; label: string }[]; + // role?: { value: string; label: string }[]; + role?: { value: string; label: string }; + indicators?: any[]; + [key: string]: any; +} + +/** + * 将form表单数据转换成接口需要的数据 + */ +export function transformDTO(formData: formData): any { + let detail: any = {}; + _.each(formData, (value: any, key: string) => { + switch (key) { + case "post": + const _options = value || {}; + detail.postId = _options.value; + detail.postName = _options.label; + break; + case "shop": + const _shopOptions: { label: string; value: number }[] = value || []; + detail.shopIds = _shopOptions.map((item) => item.value); + detail.shopNames = _shopOptions.map((item) => item.label); + break; + case "role": + // const _roleOptions: { label: string; value: number }[] = value || []; + // detail.roleCodes = _roleOptions.map((item) => item.value); + // detail.roleNames = _roleOptions.map((item) => item.label); + const _roleOptions = value || {}; + detail.roleCodes = [_roleOptions.value]; + detail.roleNames = [_roleOptions.label]; + break; + case "kpiAttachList": + const _attachOptions: { response: { fid: string } }[] = value || []; + detail.attachment = _attachOptions.map((item) => item.response.fid); + break; + + case "indicators": + const _indicatorsOptions: any[] = value || []; + const res = setMaxValue(_indicatorsOptions); + detail.indicators = res; + break; + case "rewards": + const _rewardsOptions: any[] = value || []; + const _res = setMaxValueRewards(_rewardsOptions); + detail.rewards = _res; + break; + case "time": + const time = value; + detail.beginTime = moment(time[0]).unix() * 1000; + detail.overTime = moment(time[1]).unix() * 1000; + break; + + default: + detail[key] = value; + break; + } + }); + return detail; +} +// 绩效指标最大值为65536 +const setMaxValue = (indicators: any[]) => { + if (indicators.length) { + indicators.forEach((item) => { + if (item.ladders) { + const _length = item.ladders.length; + if (_length > 0) { + item.ladders[_length - 1].upper = 65536; + } + } + if (item.conds) { + item.conds.forEach((i: any) => { + if (i.ladders) { + const _length = i.ladders.length; + if (_length > 0) { + i.ladders[_length - 1].upper = 65536; + } + } + }); + } + }); + } + return indicators; +}; +const setMaxValueRewards = (rewards: any[]) => { + if (rewards.length) { + rewards.forEach((item) => { + if (item.ladders && (item.calMethod == 3 || item.calMethod == 5)) { + const _length = item.ladders.length; + if (_length > 0) { + item.ladders[_length - 1].upper = 65536; + } + } + if (item.conds) { + item.conds.forEach((i: any) => { + if (i.ladders) { + const _length = i.ladders.length; + if (_length > 0) { + i.ladders[_length - 1].upper = 65536; + } + } + }); + } + }); + } + return rewards; +}; + +/** + * 将接口数据转换成表单数据 + * @param detail + * @returns + */ +export function transformFormData(detail: EvaGroupSetteing.EvalGroups): formData { + let formData: formData = {}; + _.each(detail, (value: any, key: string) => { + switch (key) { + case "postId": + formData.post = { value, label: detail.postName }; + break; + case "shopIds": + const _shopIdsOptions: number[] = value || []; + if (_shopIdsOptions.length) { + const _ShopIds = _shopIdsOptions.map((item, index) => ({ value: item, label: detail.shopNames[index] })); + formData.shop = _ShopIds; + } + break; + case "roleCodes": + const _roleCodesOptions: string[] = value || []; + if (_roleCodesOptions.length) { + // const _roleCodes = _roleCodesOptions.map((item, index) => ({ value: item, label: detail.roleNames[index] })); + // formData.role = _roleCodes; + const _roleCodes = { value: _roleCodesOptions[0], label: detail.roleNames[0] }; + formData.role = _roleCodes; + } + break; + case "indicators": + const res = maxValueTransform(value); + formData.indicators = res; + break; + case "rewards": + const resRewards = maxValueTransformRewards(value); + formData.rewards = resRewards; + break; + case "starLadders": + formData.starLadders = value; + break; + case "attachment": + const _res = value.map((item: string, index: number) => ({ + uid: `${index}`, + name: "", + status: "done", + url: "/api/file/show?fid=" + item, + thumbUrl: `/api/file/show?fid=${item}`, + response: { data: item, status: "success", fid: `${item}` }, + })); + formData.kpiAttachList = _res; + break; + case "beginTime": + formData.time = [moment(value), moment(detail.overTime)]; + break; + default: + formData[key] = value; + break; + } + }); + return formData; +} +// 绩效指标最大值为65536 +const maxValueTransform = (indicators: any[]) => { + if (indicators.length) { + indicators.forEach((item) => { + if (item.ladders) { + item.ladders.forEach((i: any, index: number) => { + item.ladders[index].key = String(index); + if (i.upper === 65536) { + item.ladders[index].upper = undefined; + } + }); + } + }); + } + return indicators; +}; + +const maxValueTransformRewards = (rewards: any[]) => { + if (rewards.length) { + rewards.forEach((item) => { + if (item.ladders && (item.calMethod == 3 || item.calMethod == 5)) { + item.ladders.forEach((i: any, index: number) => { + item.ladders[index].key = String(index); + if (i.upper === 65536) { + item.ladders[index].upper = undefined; + } + }); + } + if (item.ladders && (item.calMethod == 1)) { + item.ladders.forEach((i: any, index: number) => { + item.ladders[index].key = String(index); + }); + } + }); + } + return rewards; +}; diff --git a/src/pages/performance/EvaGroupSetting/EditComfirm/index.tsx b/src/pages/performance/EvaGroupSetting/EditComfirm/index.tsx new file mode 100644 index 0000000..27d85a7 --- /dev/null +++ b/src/pages/performance/EvaGroupSetting/EditComfirm/index.tsx @@ -0,0 +1,239 @@ +import React, { useEffect, useState } from "react"; +import { Card, Popconfirm, Row, Button, message, Result, Form, Select, Radio, Input } from "antd"; +import { FeeweeFileAccept, FeeweeFileChange } from "@/utils/getFidFile"; +import { common } from "@/typing/common"; +import { PlusOutlined } from "@ant-design/icons"; +import { IMGURL } from "@/utils"; +import { PageHeaderWrapper } from "@ant-design/pro-layout"; +import { createStore } from "@/hooks/moz"; +import { history } from "umi"; +import store from "./store"; +import EvalGroups from "./components/EvalGroups"; +// import PersonModal from "../components/PersonModal"; +import { EvaGroupSetteing } from "@/pages/performance/EvaGroupSetting/interface"; +import * as api from "./api"; +import { saveEvaGroupConfig } from "./api"; +import FeeweeUpload from "@/components/FeeweeUpload"; +import { transformDTO, transformFormData, formData } from "./entity"; +import _ from "lodash"; + +// 星级数据: +export const { Provider, useStore } = createStore(store); +const { Option } = Select; + +interface Props extends common.ConnectProps {} +function Index(props: Props) { + const { + postList, + detailError, + configId, + setId, + data, + readOnly, + setReadOnly, + setSelectedIndicators, + paramAlias, + setParamAlias, + setSubmit, + calType, + loading + } = useStore(); + + const [form] = Form.useForm(); + const { match } = props; + console.log(match); + const { id, read, type } = match.params; + const [saveLoading, setSaveLoading] = useState(false); + useEffect(() => { + setReadOnly(read === undefined ? false : read !== "false"); + }, [read]); + useEffect(() => { + setSubmit(type); + }, [type]); + useEffect(() => { + setId(id); + }, [id]); + + function outerDataToFrom(detail: EvaGroupSetteing.EvaGroupDetail): formData { + let formData: formData = {}; + _.each(detail, (value: any, key: string) => { + switch (key) { + case "attachment": + const _res = value.map((item: string, index: number) => ({ + uid: `${index}`, + name: "", + status: "done", + url: "/api/file/show?fid=" + item, + thumbUrl: `/api/file/show?fid=${item}`, + response: { data: item, status: "success", fid: `${item}` }, + })); + formData.kpiAttachList = _res; + break; + default: + formData[key] = value; + break; + } + }); + return formData; + } + // 控制回显 + useEffect(() => { + if (configId && data) { + const res = outerDataToFrom(data); + form.setFieldsValue({ + ...res, + }); + } + }, [configId, data]); + + function handSubmit(submit: number) { + form.validateFields().then((values) => { + const res = transformDTO(values); + let pa = null; + if (type == 1 || type == 2) { + if (data?.id && !data?.draftId) { + pa = { ...res, id: data?.id }; + } else if (data?.draftId && !data?.id) { + pa = { ...res, draftId: data?.draftId }; + } else if (data?.id && data?.draftId) { + pa = { ...res, id: data?.id, draftId: data?.draftId }; + } + } else { + pa = { ...res }; + } + console.log("总的提交表单pa", pa); + setSaveLoading(true); + saveEvaGroupConfig(pa, submit) + .then((res) => { + setSaveLoading(false); + message.success("操作成功"); + setSaveLoading(false); + history.goBack(); + }) + .catch((e) => { + setSaveLoading(false); + message.error(e.message); + }); + }); + } + + return ( + + + {detailError ? ( + + ) : ( +
+ {/* 选择岗位和门店 */} +
handSubmit} + > + + + 活动考评 + 其他考评 + + + prevValues.type !== currentValues.type}> + {({ getFieldValue }) => { + const type = getFieldValue("type"); + if (type == 1) { + return ( + + + + ); + } else if (type == 2) { + return ( + + + + ); + } else { + return null; + } + }} + + + + + + + + + + +
+ +
+
+
+ + + + + {!readOnly && ( + handSubmit(1)} + okText="确定" + cancelText="取消" + > + + + )} + {!readOnly && ( + handSubmit(2)} + okText="确定" + cancelText="取消" + > + + + )} + +
+ )} +
+
+ ); +} +export default (props: Props) => ( + + + +); diff --git a/src/pages/performance/EvaGroupSetting/EditComfirm/store.ts b/src/pages/performance/EvaGroupSetting/EditComfirm/store.ts new file mode 100644 index 0000000..60941c5 --- /dev/null +++ b/src/pages/performance/EvaGroupSetting/EditComfirm/store.ts @@ -0,0 +1,81 @@ +import { useEffect, useState } from "react"; +import useInitail from "@/hooks/useInitail"; +import * as api from "./api"; +import usePagination from "@/hooks/usePagination"; +import { getAllPostListApi, getManagerRoleListApi } from "@/common/api"; + +export default function useStore() { + const [configId, setId] = useState(0); + const [submit, setSubmit] = useState(1); + const { list: postList } = usePagination(getAllPostListApi, { pageSize: 999 }, {}); + const [delay, setDelay] = useState(true); + const { + data, + errMsg: detailError, + setParams, + loading, + } = useInitail(submit == 1 ? api.queryDetailListApi : api.draftQueryDetailListApi, {}, {}, delay); + const [readOnly, setReadOnly] = useState(false); + // 存储选择计算方式 + const [calType, setCalType] = useState(); + + // 保存已经配置过阶梯的指标的id + const [selectedIndicators, setSelectedIndicators] = useState([]); + const [selectedIndicatorsConds, setSelectedIndicatorsConds] = useState([]); + const [selectedIndicatorsLadder, setSelectedIndicatorsLadder] = useState([]); + // 奖惩 + const [selectedIndicatorSal, setSelectedIndicatorsSal] = useState([]); + const [selectedIndicatorsCondsSal, setSelectedIndicatorsCondsSal] = useState([]); + const [selectedIndicatorsLadderSal, setSelectedIndicatorsLadderSal] = useState([]); + // 别名 + const [paramAlias, setParamAlias] = useState(""); // 考评提成与台阶参数别名 + const [preconditionAlias, setPreconditionAlias] = useState(""); // 考评前置条件别名 + + // 奖惩别名 + const [ladderParamAlias, setLadderParamAlias] = useState(""); // 台阶参数别名 + const [commissionParamAlias, setCommissionParamAlias] = useState(""); // 提成参数别名 + const [preconditionAliasSal, setPreconditionAliasSal] = useState(""); // 前置条件别名 + + useEffect(() => { + if (configId) { + setParams(configId, true); + setDelay(false); + } + }, [configId]); + + return { + readOnly, + setReadOnly, + selectedIndicators, + setSelectedIndicators, //固定得分指标库 + postList, + data, + configId, + setId, + detailError, + paramAlias, + setParamAlias, + selectedIndicatorsConds, + setSelectedIndicatorsConds, //前置得分指标库 + selectedIndicatorsLadder, + setSelectedIndicatorsLadder, //台阶条件指标库 + setSubmit, + preconditionAlias, + setPreconditionAlias, + selectedIndicatorSal, + setSelectedIndicatorsSal, + selectedIndicatorsCondsSal, + setSelectedIndicatorsCondsSal, + selectedIndicatorsLadderSal, + setSelectedIndicatorsLadderSal, + ladderParamAlias, + setLadderParamAlias, + commissionParamAlias, + setCommissionParamAlias, + preconditionAliasSal, + setPreconditionAliasSal, + calType, + setCalType, + loading, + }; +} diff --git a/src/pages/performance/EvaGroupSetting/api.ts b/src/pages/performance/EvaGroupSetting/api.ts new file mode 100644 index 0000000..c853540 --- /dev/null +++ b/src/pages/performance/EvaGroupSetting/api.ts @@ -0,0 +1,46 @@ +import request from "@/utils/request"; +import { DALARAN, MORAX_HOST } from "@/utils/host"; +import { http } from "@/typing/http"; +import { EvaGroupSetteing } from "@/pages/performance/EvaGroupSetting/interface"; + +/** 考评组列表 + * http://testgate.feewee.cn/morax/erp/kpi/group-config/page + */ +export function evaGroupApi( + params: EvaGroupSetteing.EvaGroupListParams +): http.PromisePageResp { + return request.get(`${MORAX_HOST}/erp/eval/page`, { params }); +} + +/** 考评组列表(草稿) + * http://testgate.feewee.cn/morax/erp/setting-draft/kpi-page + */ +export function evaGroupDraftApi( + params: EvaGroupSetteing.EvaGroupListParams +): http.PromisePageResp { + return request.get(`${MORAX_HOST}/erp/setting-draft/eval-page`, { params }); +} + +/** + *删除草稿,审批不通过 + * http://testgate.feewee.cn/morax/erp/setting-draft/del + */ +export function deleteEvaGroup(params: EvaGroupSetteing.DeleteKpiGroup) { + return request.get(`${MORAX_HOST}/erp/setting-draft/del`, { params }); +} + +/** + *禁用考评组 + * http://testgate.feewee.cn/morax/erp/kpi/group-config/disable + */ +export function evaGroupEnable(params: EvaGroupSetteing.DeleteKpiGroup) { + return request.get(`${MORAX_HOST}/erp/eval/group-disable`, { params }); +} + +/** + *撤销审批 + * http://testgate.feewee.cn/morax/erp/setting-draft/cancel + */ +export function quashEvaGroup(params: EvaGroupSetteing.DeleteKpiGroup) { + return request.get(`${MORAX_HOST}/erp/setting-draft/cancel`, { params }); +} diff --git a/src/pages/performance/EvaGroupSetting/components/DetailModal.tsx b/src/pages/performance/EvaGroupSetting/components/DetailModal.tsx new file mode 100755 index 0000000..3cd4204 --- /dev/null +++ b/src/pages/performance/EvaGroupSetting/components/DetailModal.tsx @@ -0,0 +1,26 @@ +import React, { useState, useEffect, useMemo } from "react"; +import { Button, Modal } from "antd"; +import ApprovalProgress from "@/components/ApprovalProgress"; + +interface Props { + visible: boolean; + onCancel: Function; + item: any; +} + +export default function DetailModal(props: Props) { + const { visible, onCancel, item } = props; + + return ( + onCancel()} + footer={} + destroyOnClose + > + + + ); +} diff --git a/src/pages/performance/EvaGroupSetting/components/DraftFilter.tsx b/src/pages/performance/EvaGroupSetting/components/DraftFilter.tsx new file mode 100755 index 0000000..1c70894 --- /dev/null +++ b/src/pages/performance/EvaGroupSetting/components/DraftFilter.tsx @@ -0,0 +1,37 @@ +import React, { useCallback } from "react"; +import { Row, Select, Radio } from "antd"; +import _ from "lodash"; +import usePagination from "@/hooks/usePagination"; +import { systemListApi } from "@/pages/admin/Privilege/api"; +import { getAllPostListApi } from "@/common/api"; +import { StatusDraftData } from "@/pages/performance/entity"; + +const { Option } = Select; +interface Props { + setParams: any; + innerParams: any; +} +const RadioButton = Radio.Button; +const RadioGroup = Radio.Group; + +export default function Filter({ setParams, innerParams }: Props) { + return ( + + { + console.log("选中状态", e); + setParams({ status: e.target.value }, true); + }} + > + {StatusDraftData.map((item) => ( + + {item.label} + + ))} + + + ); +} diff --git a/src/pages/performance/EvaGroupSetting/components/DraftList.tsx b/src/pages/performance/EvaGroupSetting/components/DraftList.tsx new file mode 100644 index 0000000..4ac553c --- /dev/null +++ b/src/pages/performance/EvaGroupSetting/components/DraftList.tsx @@ -0,0 +1,164 @@ +import React, { useEffect, useState } from "react"; +import { PageHeaderWrapper } from "@ant-design/pro-layout"; +import { Button, Card, Table, Row, Space, Typography, Divider, Popconfirm, message } from "antd"; +import usePagination from "@/hooks/usePagination"; +import { history } from "umi"; +import { evaGroupDraftApi, deleteEvaGroup, quashEvaGroup } from "../api"; +import DraftFilter from "./DraftFilter"; +import DetailModal from "./DetailModal"; +import { StatusEnum } from "../entity"; +import { EvaGroupSetteing } from "@/pages/performance/EvaGroupSetting/interface"; +// import EmployeesModal from "./EmployeesModal"; +// import ShopModal from "./ShopModal"; +// import moment from "moment"; + +const Column = Table.Column; +interface Props { + type: number; +} + +export default ({ type }: Props) => { + const { loading, list, paginationConfig, setParams, innerParams } = usePagination(evaGroupDraftApi, { + status: 2, + type: 1, + }); + useEffect(() => { + console.log("list", list); + }, [list]); + const [visibleDetail, setVisibleDetail] = useState(false); + const [item, setItem] = useState({}); + //删除 + const onDelet = async (id: number) => { + const pa = { id }; + try { + const { success } = await deleteEvaGroup(pa); + if (success) { + message.success("删除成功", 5); + // 重新刷新列表 + setParams({ ...innerParams }, true); + } + } catch (error: any) { + message.error(error.message); + } + }; + + //撤销审批 + const onQuash = async (id: number) => { + const pa = { id }; + try { + const { success } = await quashEvaGroup(pa); + if (success) { + message.success("撤销审批成功", 5); + // 重新刷新列表 + setParams({ ...innerParams }, true); + } + } catch (error: any) { + message.error(error.message); + } + }; + return ( + <> + + + + + +
`id${row.draftId}`} + dataSource={list} + pagination={paginationConfig} + scroll={{ x: 500 }} + > + name || "--"} /> + (type ? (type == 1 ? "活动考评" : "其他考评") : "")} + /> + ( + { + history.push(`/morax/evaGroupSetting/edit/${record.draftId}/true/${type}`); + }} + > + 查看 + + )} + /> + (text ? StatusEnum[text] : "--")} + /> + { + return ( + }> + {record.draftStatus == 2 || record.draftStatus == 3 ? ( + { + setVisibleDetail(true); + setItem(record); + }} + > + 流程进度 + + ) : null} + {record.draftStatus == 3 || record.draftStatus == 1 || record.draftStatus == 5 ? ( + { + history.push(`/morax/evaGroupSetting/edit/${record.draftId}/false/${type}`); + }} + > + {`${record.draftStatus == 3 ? "重新" : ""}编辑`} + + ) : null} + + {record.draftStatus == 3 || record.draftStatus == 1 || record.draftStatus == 5 ? ( + onDelet(record.draftId)} + okText="确定" + cancelText="取消" + > + 删除 + + ) : null} + {record.draftStatus == 2 ? ( + onQuash(record.draftId)} + okText="确定" + cancelText="取消" + > + 撤销审批 + + ) : null} + + ); + }} + /> +
+ setVisibleDetail(false)} /> + + ); +}; diff --git a/src/pages/performance/EvaGroupSetting/components/Filter.tsx b/src/pages/performance/EvaGroupSetting/components/Filter.tsx new file mode 100755 index 0000000..8fd8e8b --- /dev/null +++ b/src/pages/performance/EvaGroupSetting/components/Filter.tsx @@ -0,0 +1,34 @@ +import React, { useCallback } from "react"; +import { Row, Select, Radio } from "antd"; +import _ from "lodash"; +import { StatusData } from "@/pages/performance/entity"; + +const { Option } = Select; +interface Props { + setParams: any; + innerParams: any; +} +const RadioButton = Radio.Button; +const RadioGroup = Radio.Group; + +export default function Filter({ setParams, innerParams }: Props) { + return ( + + { + console.log("选中状态", e); + setParams({ status: e.target.value }, true); + }} + > + {StatusData.map((item) => ( + + {item.label} + + ))} + + + ); +} diff --git a/src/pages/performance/EvaGroupSetting/components/NormalList.tsx b/src/pages/performance/EvaGroupSetting/components/NormalList.tsx new file mode 100644 index 0000000..6030503 --- /dev/null +++ b/src/pages/performance/EvaGroupSetting/components/NormalList.tsx @@ -0,0 +1,120 @@ +import React, { useState } from "react"; +import { PageHeaderWrapper } from "@ant-design/pro-layout"; +import { Button, Card, Table, Row, Space, Typography, Divider, Popconfirm, message } from "antd"; +import usePagination from "@/hooks/usePagination"; +import { history } from "umi"; +import { evaGroupApi, evaGroupEnable } from "../api"; +import Filter from "./Filter"; +// import DetailModal from "./DetailModal"; +import { StatusEnum } from "../entity"; +import { EvaGroupSetteing } from "@/pages/performance/EvaGroupSetting/interface"; +// import EmployeesModal from "./EmployeesModal"; +// import ShopModal from "./ShopModal"; +// import moment from "moment"; + +const Column = Table.Column; +interface Props { + type: number; +} +export default ({ type }: Props) => { + const { loading, list, paginationConfig, setParams, innerParams } = usePagination(evaGroupApi, { status: 3 }); + const [visibleDetail, setVisibleDetail] = useState(false); + const [item, setItem] = useState({}); + // 禁用 + const indicatorEnable = async (id: number) => { + const pa = { id }; + try { + const { success } = await evaGroupEnable(pa); + if (success) { + message.success("禁用成功", 5); + // 重新刷新列表 + setParams({ ...innerParams }, true); + } + } catch (error: any) { + message.error(error.message); + } + }; + return ( + <> + + + + + + `id${row.id}`} + dataSource={list} + pagination={paginationConfig} + scroll={{ x: 500 }} + > + name || "--"} /> + (type ? (type == 1 ? "活动考评" : "其他考评") : "")} + /> + ( + { + history.push(`/morax/evaGroupSetting/edit/${record.id}/true/${type}`); + }} + > + 查看 + + )} + /> + (text ? StatusEnum[text] : "--")} + /> + { + return ( + }> + {record.status === 2 || record.status === 3 ? ( + { + history.push(`/morax/evaGroupSetting/edit/${record.id}/false/${type}`); + }} + > + 编辑 + + ) : null} + {record.status == 2 || record.status == 3 ? ( + indicatorEnable(record.id)} + okText="确定" + cancelText="取消" + > + 禁用 + + ) : null} + + ); + }} + /> +
+ + ); +}; diff --git a/src/pages/performance/EvaGroupSetting/entity.ts b/src/pages/performance/EvaGroupSetting/entity.ts new file mode 100644 index 0000000..74ddf9a --- /dev/null +++ b/src/pages/performance/EvaGroupSetting/entity.ts @@ -0,0 +1,39 @@ +// import { KpiGroupSetteing } from "@/pages/performance/KpiGroupSetting/interface"; +import _ from "lodash"; + +/** + * 状态;1:审批中 2:待生效 3:生效中 4:已失效 + */ + +export enum StatusEnum { + "待审批" = 1, + "待生效" = 2, + "生效中" = 3, + "已失效" = 4, +} +export enum DraftStatusEnum { + "未发布" = 1, + "审批中" = 2, + "审批不通过" = 3, + "审批同意" = 4, + "撤销审批" = 5, +} + +export const Approval_Status = [ + { + label: "启用", + value: 1, + }, + { + label: "禁用", + value: 2, + }, +]; +// 可选计算方式; +export enum OptionalMethod_Enum { + "排名正负激励" = 1, + "固定值", + "阶梯", + "总金额占比", + "阶梯翻倍", +} diff --git a/src/pages/performance/EvaGroupSetting/index.tsx b/src/pages/performance/EvaGroupSetting/index.tsx new file mode 100644 index 0000000..07ef61e --- /dev/null +++ b/src/pages/performance/EvaGroupSetting/index.tsx @@ -0,0 +1,21 @@ +import React, { useState } from "react"; +import { PageHeaderWrapper } from "@ant-design/pro-layout"; +import { Card, Radio, Divider } from "antd"; +import NormalList from "./components/NormalList"; +import DraftList from "./components/DraftList"; + +export default () => { + const [type, setType] = useState(1); + return ( + + + setType(e.target.value)}> + 考评组 + 草稿 + + + {type == 1 ? : } + + + ); +}; diff --git a/src/pages/performance/EvaGroupSetting/interface.d.ts b/src/pages/performance/EvaGroupSetting/interface.d.ts new file mode 100644 index 0000000..9d88854 --- /dev/null +++ b/src/pages/performance/EvaGroupSetting/interface.d.ts @@ -0,0 +1,209 @@ +import Enum from "@/utils/enum"; + +declare namespace EvaGroupSetteing { + interface DeleteKpiGroup { + id: number; + } + /** + * 考评组列表请求参数 + */ + + interface EvaGroupListParams { + current?: number; + pageSize?: number; + postId?: number; //岗位id + status?: number; // 状态 + groupId?: number; //集团id + } + + /** + * 考评组列表项 + */ + interface EvaGroupListItems { + draftId: number; + draftStatus?: number; + id: number; //考评id + name: string; // 考评,活动名称 + type: number; // 考评类型; 1:活动考评 2:其他考评(See: 考评类型) + status?: number; + evalGroups: EvalGroups[]; + } + interface EvalGroups { + post: any; + shop: any[]; + roleNames: string[]; + roleCodes: string[]; + id?: number; // 考评组id + egc?: string; // 考评组编码 + name: string; // 考评,活动名称 + scopeType: number; // 考评范围; 1:门店考评 2:人员考评(See: 考评范围) + postId: number; // 岗位id + postName: string; // 岗位名称 + shopIds: number[]; // 适用门店ids + shopNames: string[]; // 适用门店名称 + status: number; // 状态; 1:审批中 2:待生效 3:生效中 4:已失效 5:草稿 + indicatorNum: number; // 包含指标数量 + groupId?: number; // 集团id + indicators: Indicators[]; // 考评指标 + rewards: Rewards[]; // 考评奖惩 + index?: number; + beginTime: number; + overTime: number; + } + + interface Indicators { + laddersType: number; + index: number; + id?: number; + evalGroupId?: number; // 考评组配置id + name: string; // 指标名称 + baseScore: number; // 基础绩效分 + scoreWay: number; // 得分方式;1: 阶梯得分 2:普通得分 + paramAlias: string; // 考评项别名 + preconditionAlias: string; // 前置考评项别名(目前预留) + commissionParams?: CommissionParams[]; // 提成参数 + ladderParams?: LadderParams[]; // 台阶参数 + conds?: Conds[]; // 前置条件 + ladders?: Ladders[]; // 指标阶梯 + targets?: Targets[]; // 目标 + } + interface CommissionParams { + condType: number; + id: number; + evalGroupId: number; // 考评组配置id + evalGroupIndicatorId: number; // 考评组指标id + paramType: number; // 条件类型(1.台阶条件,2,提成条件)(See: 指标参数类型) + codeType: number; // 指标类型(1.指标,2,考评指标)(See: 指标参数类型) + code: string; // 指标编码 + name: string; // 指标库名称 + proportion: number; // 占比 + cap: boolean; //是否封顶 + targetCalcType: number; // 目标计算类型;1: 目标值计算 2:最低要求计算(See: 目标计算类型) + targetType: number; // 绩效目标值类型; 1:无 2:百分比 3:金额 4:台数(See: 目标类型); + targetValue: number; // 目标值 + dataType?: number; // 数据类型;1:台数 2:百分比 3:金额(See: 数据类型) + money?: number; // 金额 + } + interface LadderParams { + id: number; + evalGroupId: number; // 考评组配置id + evalGroupIndicatorId: number; // 考评组指标id + paramType: number; // 条件类型(1.台阶条件,2,提成条件)(See: 指标参数类型) + codeType: number; // 指标类型(1.指标,2,考评指标)(See: 指标参数类型) + code: string; // 指标编码 + name: string; // 指标库名称 + proportion: number; // 占比 + cap: boolean; //是否封顶 + targetCalcType: number; // 目标计算类型;1: 目标值计算 2:最低要求计算(See: 目标计算类型) + targetType: number; // 绩效目标值类型; 1:无 2:百分比 3:金额 4:台数(See: 目标类型); + targetValue: number; // 目标值 + dataType?: number; // 数据类型;1:台数 2:百分比 3:金额(See: 数据类型) + money?: number; // 金额 + } + interface Conds { + id: number; + evalGroupId: number; // 考评组配置id + evalGroupIndicatorId: number; // 考评组指标id + codeType: number; // 指标类型(1.指标,2,考评指标)(See: 指标参数类型) + code: string; // 指标编码 + name: string; // 指标库名称 + targetCalcType: number; // 目标计算类型;1: 目标值计算 2:最低要求计算(See: 目标计算类型) + targetType: number; // 绩效目标值类型; 1:无 2:百分比 3:金额 4:台数(See: 目标类型); + targetValue: number; // 目标值 + sort: number; // 排序 + condType?: number; // 条件值类型; 1:满足目标 2:满足排名率 3:金额(See: 指标参数类型) + condValue?: number; // 条件值 + } + interface Ladders { + id?: number; + evalGroupIndicatorId?: number; // 考评组指标条件id + lower: number; // 阶梯下限;大于等于 + upper: number; // 阶梯上限;小于; 无上限的情况值为 2<<15 + scorePercent: number; // 得分百分比 + yn?: boolean; // 逻辑删除 + money?: number; // 金额 + capMoney?: number; // 封顶金额/台 + } + interface Targets { + indicatorId: number; // 指标库id + indicatorCode: string; // 指标编码 + indicatorName: string; // 指标库名称 + targetCalcType: number; // 目标计算类型;1: 目标值计算 2:最低要求计算(See: 目标计算类型) + targetType: number; // 绩效目标值类型; 1:无 2:百分比 3:金额 4:台数(See: 目标类型); + targetValue: number; // 目标值 + } + interface Rewards { + index: number; + preconditionAlias: string; + commissionParamAlias: string; + ladderParamAlias: string; + laddersType: number; + id: number; + evalGroupId: number; // 考评组配置id + name: string; // 考评,活动名称 + calMethod: number; // 计算方式; 1: 排名正负激励 2:阶梯奖励(翻倍) 3:总金额X达成率占比 4:固定值X达成率 5: 固定值+超额部分追加奖励(See: 考评周期类型) + rankType: number; // 排名方式;1:排名序号 2:排名人数百分比(See: 数据类型) + money: number; // 金额 + extraMoney: number; // 追加奖励 XX 元/台,超额奖励用 + commissionParams: CommissionParams[]; // 提成参数 + ladderParams: LadderParams[]; // 台阶参数 + conds: Conds[]; // 前置条件 + ladders: Ladders[]; // 指标阶梯 + targets: Targets[]; // 目标 + } + interface EvaGroupDetail { + draftId: number; + draftStatus?: number; + id: number; //考评id + name: string; // 考评,活动名称 + type: number; // 考评类型; 1:活动考评 2:其他考评(See: 考评类型) + status?: number; + reason: string; // 调整原因 + attachment: string[]; // 附件 + evalGroups: EvalGroups[]; + } + interface ShopList { + id: number; //组合id + postId: number; //岗位id + limitNum: number; //限制人数 + postNum: number; //在岗人数 + shopId: number; //门店id + shopName: string; //门店名称 + } + /**人员查看 */ + interface Person { + visible: boolean; + postId?: number; //岗位id + shopIds: string; //门店id + } + interface IndicatorByPost { + sid: string; + codeType: number; // 指标类型(1.指标,2,考评指标)(See: 指标参数类型) + dataType: number; + id: number; //指标id + code: string; // 指标编码 + name: string; //指标名称 + sysId: number; //归属系统id + sysPrefix: string; // 归属系统前缀 + sysName: string; // 归属系统名称 + roleCode: string; //导入操作人员角色码 + roleName: string; // 适用角色名称 + ruleType: number; // 频率类型; 1:按滚动天 2:按星期 3:按月指定日期 4:按滚动月(See: 考评周期类型) + rollValue: number; // 滚动天数 + ruleValues: number[]; // 频率值 ,号分隔(按星期、按月指定日期使用) + orderType: number; // 按滚动月计算顺序; 1:正序 2:倒序(See: 滚动月计算顺序) + startTime: string; // 开始日期 + enable: boolean; //启用/禁用; 0: 禁用 1: 启用 + targetType: number; // 绩效目标值类型 + } + interface EvaGroupSaveParams { + id?: number; + draftId?: number; + name: string; + type: number; + groupId?: number; + userName?: string; + userId?: number; + evalGroups: EvalGroups[]; + } +} diff --git a/src/pages/performance/EvaSetting/api.ts b/src/pages/performance/EvaSetting/api.ts new file mode 100644 index 0000000..7915249 --- /dev/null +++ b/src/pages/performance/EvaSetting/api.ts @@ -0,0 +1,31 @@ +import request from "@/utils/request"; +import { DALARAN, MORAX_HOST } from "@/utils/host"; +import { http } from "@/typing/http"; + +export interface PageParams { + current?: number; + pageSize?: number; +} + +/** 考评指标库列表 + * http://testgate.feewee.cn/morax/erp/eval/indicator/page + */ +export function evaConfigApi(params: EvaSetteing.EvaListParams): http.PromisePageResp { + return request.get(`${MORAX_HOST}/erp/eval/indicator/page`, { params }); +} + +/** + * 指标库保存 + * http://testgate.feewee.cn/morax/erp/eval/indicator + */ +export function saveEvaIndicators(params: EvaSetteing.EvaIndicatorsParams) { + return request.post(`${MORAX_HOST}/erp/eval/indicator`, params); +} + +/** + * 指标库禁用启用 + * http://testgate.feewee.cn/morax/erp/eval/indicator/enable + */ +export function evaIndicatorEnable(params: EvaSetteing.IndicatorEnable) { + return request.put(`${MORAX_HOST}/erp/eval/indicator/enable`, params); +} \ No newline at end of file diff --git a/src/pages/performance/EvaSetting/components/EditModal.tsx b/src/pages/performance/EvaSetting/components/EditModal.tsx new file mode 100644 index 0000000..c1646e5 --- /dev/null +++ b/src/pages/performance/EvaSetting/components/EditModal.tsx @@ -0,0 +1,216 @@ +import React, { useState, useEffect } from "react"; +import { Form, Modal, message, Input, Select, Radio, DatePicker, InputNumber, Checkbox } from "antd"; +import { saveEvaIndicators } from "../api"; +import usePagination from "@/hooks/usePagination"; +import { systemListApi } from "@/pages/admin/Privilege/api"; +import { transformDTO, transformFormData, DataType, TargetType, DatePick } from "../entity"; +import moment from "moment"; + +const FormItem = Form.Item; +const { Option } = Select; + +interface Props { + item: { visible: boolean; currentItem?: EvaSetteing.EvaListItems }; + onClose?: (refresh?: boolean) => any; + setItem?: Function; + roleList: CommonApi.RoleCodeVO[]; +} + +export default function EditModal({ onClose, setItem, item, roleList }: Props) { + const [form] = Form.useForm(); + const { visible, currentItem = {} } = item; + const [saveLoading, setSaveLoading] = useState(false); + // 存储系统列表 + const { list } = usePagination(systemListApi, { current: 1, pageSize: 500 }); + useEffect(() => { + if (visible && currentItem) { + const result = transformFormData(currentItem, roleList, list); + form.setFieldsValue({ ...result }); + } + }, [visible]); + function handleSave(values: any) { + const pa = transformDTO(values); + if (currentItem.id) { + pa.id = currentItem.id; + } + console.log("提交指标pa", pa); + setSaveLoading(true); + saveEvaIndicators(pa) + .then((res: any) => { + setSaveLoading(false); + message.success(res.result); + onClose?.(true); + }) + .catch((e: any) => { + setSaveLoading(false); + message.error(e.message); + }); + } + const options = [ + { label: "考评人", value: 1 }, + { label: "考评门店", value: 2 }, + ]; + + return ( + onClose?.(false)} + maskClosable={false} + getContainer={false} + confirmLoading={saveLoading} + afterClose={() => form.resetFields()} + > +
+ + + + + + + + + + + + + {/* + + */} + {/* 使用角色 */} + + + + + + 按滚动天数 + 按星期指定 + 按月指定日期 + 按滚动月 + + + prevValues.ruleType !== currentValues.ruleType}> + {({ getFieldValue }) => { + const _ruleType = getFieldValue("ruleType"); + if (_ruleType === 1) { + return ( + <> + + + + + + + + ); + } else if (_ruleType === 2) { + return ( + + + 星期一 + 星期二 + 星期三 + 星期四 + 星期五 + 星期六 + 星期天 + + + ); + } else if (_ruleType === 3) { + return ( + + + + ); + } else if (_ruleType === 4) { + return ( + <> + + + + + + + + + 月第X天 + 月倒数第X天 + + + + + + + ); + } + }} + +
+
+ ); +} diff --git a/src/pages/performance/EvaSetting/components/Filter.tsx b/src/pages/performance/EvaSetting/components/Filter.tsx new file mode 100644 index 0000000..754e522 --- /dev/null +++ b/src/pages/performance/EvaSetting/components/Filter.tsx @@ -0,0 +1,99 @@ +import React, { useState, useEffect, useCallback } from "react"; +import { Table, Row, Input, Select } from "antd"; +// import { ApprovalType, Approval_Status } from "../entity"; +import _ from "lodash"; +import usePagination from "@/hooks/usePagination"; +import { systemListApi } from "@/pages/admin/Privilege/api"; + +const { Option } = Select; +interface Props { + setParams: any; + // tempData: any; + roleList: CommonApi.RoleCodeVO[]; +} + +export default function Filter({ setParams, roleList }: Props) { + const { list: syslist } = usePagination(systemListApi, { + current: 1, + pageSize: 500, + }); + + const seachOnchange = useCallback( + _.debounce((param) => { + setParams({ ...param }, true); + }, 800), + [setParams] + ); + const enableList = [ + { value: 0, label: "禁用" }, + { value: 1, label: "启用" }, + ]; + + //根据系统名称搜索 + const _onChangeSys = (value: any) => { + setParams({ ...value, current: 1 }, true); + }; + + return ( + + { + setParams({ keyword: value }, true); + }} + onChange={(e) => { + seachOnchange({ keyword: e.target.value }); + }} + style={{ width: 250, marginRight: 10, marginBottom: 10 }} + /> + + + {/* */} + + + ); +} diff --git a/src/pages/performance/EvaSetting/entity.ts b/src/pages/performance/EvaSetting/entity.ts new file mode 100644 index 0000000..22820dc --- /dev/null +++ b/src/pages/performance/EvaSetting/entity.ts @@ -0,0 +1,193 @@ +import _ from "lodash"; +import moment from "moment"; + +// 指标类型 +export enum DataTypeEnum { + "--" = 1, + "百分比" = 2, + "金额" = 3, + "台数" = 4, +} +export enum WeekValueEnum { + "一" = 1, + "二" = 2, + "三" = 3, + "四" = 4, + "五" = 5, + "六" = 6, + "天" = 7, +} +export const DataType = [ + { + label: "数量", + value: 1, + }, + { + label: "百分比", + value: 2, + }, + { + label: "金额", + value: 3, + }, +]; + +export const TargetType = [ + { + label: "无目标", + value: 1, + }, + { + label: "百分比", + value: 2, + }, + { + label: "金额", + value: 3, + }, +]; +export const DatePick = [ + { label: "1号", value: 1 }, + { label: "2号", value: 2 }, + { label: "3号", value: 3 }, + { label: "4号", value: 4 }, + { label: "5号", value: 5 }, + { label: "6号", value: 6 }, + { label: "7号", value: 7 }, + { label: "8号", value: 8 }, + { label: "9号", value: 9 }, + { label: "10号", value: 10 }, + { label: "11号", value: 11 }, + { label: "12号", value: 12 }, + { label: "13号", value: 13 }, + { label: "14号", value: 14 }, + { label: "15号", value: 15 }, + { label: "16号", value: 16 }, + { label: "17号", value: 17 }, + { label: "18号", value: 18 }, + { label: "19号", value: 19 }, + { label: "20号", value: 20 }, + { label: "21号", value: 21 }, + { label: "22号", value: 22 }, + { label: "23号", value: 23 }, + { label: "24号", value: 24 }, + { label: "25号", value: 25 }, + { label: "26号", value: 26 }, + { label: "27号", value: 27 }, + { label: "28号", value: 28 }, + { label: "29号", value: 29 }, + { label: "30号", value: 30 }, + { label: "31号", value: 31 }, +]; + +/** + * 将form表单数据转换成接口需要的数据 + */ +export function transformDTO(formData: any): any { + let detail: any = {}; + _.each(formData, (value: any, key: string) => { + switch (key) { + case "belongSystem": + const _options = value || {}; + detail.sysId = _options.value; + detail.sysName = _options.label; + break; + case "role": + const _rolesOptions = value || {}; + detail.roleCode = _rolesOptions.value; + detail.roleName = _rolesOptions.label; + break; + case "rollValue1": + const _rollValue1 = value; + detail.rollValue = _rollValue1; + break; + case "rollValue4": + const _rollValue4 = value; + detail.rollValue = _rollValue4; + break; + case "startTime1": + const _startTime1 = value; + detail.startTime = moment(_startTime1).unix() * 1000; + break; + case "startTime4": + const _startTime4 = value; + detail.startTime = moment(_startTime4).unix() * 1000; + break; + case "ruleValues2": + const _ruleValues2 = value || []; + detail.ruleValues = _ruleValues2; + break; + case "ruleValues3": + const _ruleValues3 = value || []; + detail.ruleValues = _ruleValues3; + break; + case "ruleValues4": + const _ruleValues4 = value; + detail.ruleValues = [_ruleValues4]; + break; + default: + detail[key] = value; + break; + } + }); + return detail; +} + +/** + * 将接口数据转换成表单数据 + * @param detail + * @returns + */ +export function transformFormData( + detail: any, + roleList: CommonApi.RoleCodeVO[] = [], + list: Privilege.SystemListVO[] = [] +) { + let formData = {}; + _.each(detail, (value: any, key: string) => { + switch (key) { + case "roleCode": + const _roleCode = value; + const res = roleList + .filter((item) => item.roleCode === _roleCode) + .map((it) => ({ label: it.roleName, value: it.roleCode })); + formData.role = res[0]; + break; + case "sysId": + const _sysId = value; + const _res = list.filter((item) => item.id === _sysId).map((it) => ({ label: it.sysName, value: it.id })); + formData.belongSystem = _res[0]; + break; + case "rollValue": + const _rollValue = value; + if (detail.ruleType === 1) { + formData.rollValue1 = _rollValue; + } else if (detail.ruleType === 4) { + formData.rollValue4 = _rollValue; + } + break; + case "startTime": + const _startTime = value; + if (detail.ruleType === 1) { + formData.startTime1 = moment(_startTime); + } else if (detail.ruleType === 4) { + formData.startTime4 = moment(_startTime); + } + break; + case "ruleValues": + const _ruleValues = value; + if (detail.ruleType === 4) { + formData.ruleValues4 = _ruleValues[0]; + } else if (detail.ruleType === 3) { + formData.ruleValues3 = _ruleValues; + } else if (detail.ruleType === 2) { + formData.ruleValues2 = _ruleValues; + } + break; + default: + formData[key] = value; + break; + } + }); + return formData; +} diff --git a/src/pages/performance/EvaSetting/index.tsx b/src/pages/performance/EvaSetting/index.tsx new file mode 100644 index 0000000..04a1bcd --- /dev/null +++ b/src/pages/performance/EvaSetting/index.tsx @@ -0,0 +1,144 @@ +import React, { useState } from "react"; +import { PageHeaderWrapper } from "@ant-design/pro-layout"; +import { Button, Card, Table, Row, message, Space, Typography, Divider, Switch } from "antd"; +import usePagination from "@/hooks/usePagination"; +import { evaConfigApi, evaIndicatorEnable } from "./api"; +import { DataTypeEnum, WeekValueEnum } from "./entity"; +import { getAllRoleCodeApi } from "@/common/api"; +import useInitial from "@/hooks/useInitail"; +import EditModal from "./components/EditModal"; +import Filter from './components/Filter'; + +const Column = Table.Column; + +export default () => { + const { loading, list, paginationConfig, setParams, innerParams } = usePagination(evaConfigApi, { pageSize: 10, enable: true }); + + const { data: roleList } = useInitial(getAllRoleCodeApi, [], {}); + // console.log(roleList); + /** 新增/编辑 */ + const [item, setItem] = useState<{ + visible: boolean; + currentItem?: EvaSetteing.EvaListItems; + }>({ visible: false, currentItem: {} }); + // 禁用、启用 + const indicatorEnable = async (enable: boolean, record: EvaSetteing.EvaListItems) => { + const pa = { + indicatorId: record.id, + enable: !enable, + }; + try { + const { success } = await evaIndicatorEnable(pa); + if (success) { + message.success(`${enable ? "禁用" : "启用"}成功`, 5); + // 重新刷新列表 + setParams({ ...innerParams }, true); + } + } catch (error: any) { + message.error(error.message); + } + }; + // 编辑 + function _onEdit(record: any) { + setItem({ visible: true, currentItem: { ...record } }); + } + // 渲染更新周期 + const renderRule = (type: number, record: any) => { + if (type == 1) { + return record.rollValue == 1 ? "每天" : `每${record.rollValue}天`; + } else if (type == 2) { + return `每周${[...record.ruleValues] + .sort((a: any, b: any) => a - b) + .map((item: number) => WeekValueEnum[item]) + .join("、")}`; + } else if (type == 3) { + return `每月${[...record.ruleValues] + .sort((a: any, b: any) => a - b) + .map((item: number) => `${item}号`) + .join("、")}`; + } else if (type == 4) { + return `每${record.ruleValues[0]}个月,该月${record.orderType == 1 ? "第" : "倒数第"}${record.rollValue}天`; + } + }; + return ( + + + + + + + + + `id${row.code}`} dataSource={list} pagination={paginationConfig}> + + {name || "--"}} /> + { + if (dataScopeTypes) { + if (dataScopeTypes.length == 1) { + if (dataScopeTypes[0] == 1) { + return "考核人"; + } else { + return "考核门店"; + } + } else { + return "考核人;考核门店"; + } + } else { + return "--"; + } + }} + /> + (type == 1 ? "否" : "是")} + /> + DataTypeEnum[type]} /> + renderRule(type, record)} + /> + {name || "--"}} + /> + + ( + }> + _onEdit(record)}>编辑 + indicatorEnable(text, record)}> + {text ? "禁用" : "启用"} + + + )} + /> +
+ { + setItem({ visible: false, currentItem: {} }); + refresh && setParams({}, !!refresh); + }} + /> +
+
+ ); +}; diff --git a/src/pages/performance/EvaSetting/interface.ts b/src/pages/performance/EvaSetting/interface.ts new file mode 100644 index 0000000..131f431 --- /dev/null +++ b/src/pages/performance/EvaSetting/interface.ts @@ -0,0 +1,61 @@ +declare namespace EvaSetteing { + /** + * 指标库列表请求参数 + */ + interface EvaListParams { + current?: number; + pageSize?: number; + roleCode?: string; // 角色编码 + sysId?: number; //归属id + enable?: boolean; //禁用0 启用1 + keyword?: string; //指标名称或编码 + allRoleTypes?: number[]; + groupId?: number; //集团id + } + + /** + * 指标库列表项 + */ + interface EvaListItems { + id: number; + sysId: number; //归属系统id + sysPrefix: string; // 归属系统前缀 + sysName: string; //归属系统名称 + roleCode: string; // 导入操作人员角色码 + roleName: string; //导入操作人员角色名称 + ruleType: number; // 频率类型; 1:按滚动天 2:按星期 3:按月指定日期 4:按滚动月(See: 考评周期类型) + ruleValues: string[]; // 频率值 ,号分隔(按星期、按月指定日期使用) + rollMonths: number; // 滚动月数 + startTime: string; // 开始日期 + monthDayType: number; // 月天; 1:月第几天 2:月倒数第几天(See: 滚动月计算顺序) + monthDay: number; // 月天数 + code: string; // 考评指标编码 + name: string; // 考评指标名称 + targetType: number; // 目标值类型; 1:无 2:百分比 3:金额 4:台数 + enable: boolean; // 启用/禁用;0:禁用 1:启用 + yn: boolean; // 逻辑删除 + } + /** + * 添加编辑指标传的参数 + */ + interface EvaIndicatorsParams { + id?: number; + name: string; + sysId: number; //归属系统id + sysName: string; // 归属系统名称 + dataType: number; // 数据类型;1:数量 2:百分比 3:金额(See: 数据类型) + targetType: number; // 绩效目标值类型; 1:无 2:百分比 3:金额(See: 目标类型) + roleCode: string; // 导入操作角色编码 + roleName: string; // 导入操作角色名称 + ruleType: number; // 频率类型; 1:按滚动天 2:按星期 3:按月指定日期 4:按滚动月(See: 考评周期类型) + ruleValues?: number[]; // 频率值 ,号分隔(按星期、按月指定日期使用) + rollValue?: number; // 滚动天数 + startTime?: string; // 开始日期 + orderType?: number; // 月天; 1:月第几天 2:月倒数第几天(See: 滚动月计算顺序) + } + /**指标库禁用启用参数 */ + interface IndicatorEnable { + indicatorId: number; //指标id + enable: boolean; //启用禁用 + } +} diff --git a/src/pages/performance/KpiGroupSetting/EditComfirm/components/AddCommissionParamsModal.tsx b/src/pages/performance/KpiGroupSetting/EditComfirm/components/AddCommissionParamsModal.tsx index 4b37220..cc42f02 100755 --- a/src/pages/performance/KpiGroupSetting/EditComfirm/components/AddCommissionParamsModal.tsx +++ b/src/pages/performance/KpiGroupSetting/EditComfirm/components/AddCommissionParamsModal.tsx @@ -56,7 +56,7 @@ export default function AddCommissionParamsModal(props: Props) { setParams({ postId, shopIds }, true); setDelay(false); } - setTargetType(1); + setTargetType(1); }, [addComVisible]); // 修改 diff --git a/src/pages/performance/KpiGroupSetting/EditComfirm/index.tsx b/src/pages/performance/KpiGroupSetting/EditComfirm/index.tsx index 34f273c..971dbdb 100755 --- a/src/pages/performance/KpiGroupSetting/EditComfirm/index.tsx +++ b/src/pages/performance/KpiGroupSetting/EditComfirm/index.tsx @@ -39,6 +39,7 @@ function Index(props: Props) { paramAlias, setParamAlias, setSubmit, + loading } = useStore(); const [form] = Form.useForm(); @@ -156,7 +157,7 @@ function Index(props: Props) { }; return ( - + {detailError ? ( diff --git a/src/pages/performance/KpiGroupSetting/EditComfirm/store.ts b/src/pages/performance/KpiGroupSetting/EditComfirm/store.ts index 871e770..dd9cbe2 100755 --- a/src/pages/performance/KpiGroupSetting/EditComfirm/store.ts +++ b/src/pages/performance/KpiGroupSetting/EditComfirm/store.ts @@ -9,7 +9,7 @@ export default function useStore() { const [submit, setSubmit] = useState(1); const { list: postList } = usePagination(getAllPostListApi, { pageSize: 999 }, {}); const [delay, setDelay] = useState(true); - const { data, errMsg: detailError, setParams } = useInitail(submit == 1 ? api.queryDetailListApi : api.draftQueryDetailListApi, {}, {}, delay); + const { data, errMsg: detailError, setParams, loading } = useInitail(submit == 1 ? api.queryDetailListApi : api.draftQueryDetailListApi, {}, {}, delay); const [readOnly, setReadOnly] = useState(false); // 保存已经配置过阶梯的指标的id @@ -42,5 +42,6 @@ export default function useStore() { selectedIndicatorsLadder, setSelectedIndicatorsLadder, //台阶条件指标库 setSubmit, + loading, }; } diff --git a/src/pages/performance/KpiGroupSetting/components/DraftList.tsx b/src/pages/performance/KpiGroupSetting/components/DraftList.tsx index 197dff2..47edbe9 100755 --- a/src/pages/performance/KpiGroupSetting/components/DraftList.tsx +++ b/src/pages/performance/KpiGroupSetting/components/DraftList.tsx @@ -92,7 +92,7 @@ export default ({ type }: Props) => { `id${row.id}`} + rowKey={(row) => `id${row.draftId}`} dataSource={list} pagination={paginationConfig} scroll={{ x: 500 }} diff --git a/src/pages/performance/KpiGroupSetting/components/ShopModal.tsx b/src/pages/performance/KpiGroupSetting/components/ShopModal.tsx index d9a73b3..669357d 100755 --- a/src/pages/performance/KpiGroupSetting/components/ShopModal.tsx +++ b/src/pages/performance/KpiGroupSetting/components/ShopModal.tsx @@ -6,26 +6,21 @@ import useInitial from "@/hooks/useInitail"; const { Column } = Table; interface Props { - shopModal: { visible: boolean; record?: KpiGroupSetteing.KpiGroupListItems }; + shopModal: { visible: boolean; record?: any }; onCancel: Function; } export default function ShopModal({ shopModal, onCancel }: Props) { const { visible, record } = shopModal; - const [delay, setDelay] = useState(true); - - const { setParams, loading } = useInitial(fetchRealtimeStaffs, [], { postId: record?.postId }, delay); - - useEffect(() => { - if (visible && record?.shopIds && record?.shopIds.length > 0 && record.postId) { - setParams({ shopIds: record?.shopIds.join(","), postId: record?.postId }, true); - setDelay(false); - } - }, [visible]); return ( onCancel()} onOk={() => onCancel()}> -
({ shopName: item }))} loading={loading} rowKey="shopName"> - +
({ shopName: item }))} rowKey="shopName"> + shopName || ""} + />
); diff --git a/src/pages/performance/KpiGroupSetting/interface.d.ts b/src/pages/performance/KpiGroupSetting/interface.d.ts index ba54b2b..3340996 100755 --- a/src/pages/performance/KpiGroupSetting/interface.d.ts +++ b/src/pages/performance/KpiGroupSetting/interface.d.ts @@ -78,11 +78,6 @@ declare namespace KpiGroupSetteing { id: number; beginTime: number; //生效时间 kpiGroupId: number; // 绩效组配置id - // indicatorId: number; // 指标库id - // indicatorCode: string; // 指标编码 - // indicatorName: string; //指标库名称 - // baseScore: number; //基础绩效分 - // scoreWay: number; // 得分方式; 1: 阶梯得分 2: 普通得分 commissionParams?: CommissionParams[]; indicators: Item[]; indicatorLadderVos: IndicatorLadderVos[]; //星级阶梯 diff --git a/src/pages/performance/KpiSetting/components/EditModal.tsx b/src/pages/performance/KpiSetting/components/EditModal.tsx index 812c8fa..f4c25ca 100755 --- a/src/pages/performance/KpiSetting/components/EditModal.tsx +++ b/src/pages/performance/KpiSetting/components/EditModal.tsx @@ -1,5 +1,5 @@ import React, { useState, useEffect } from "react"; -import { Form, Modal, message, Input, Select, Radio } from "antd"; +import { Form, Modal, message, Input, Select, Radio, Checkbox } from "antd"; import { saveKpiIndicators } from "../api"; import usePagination from "@/hooks/usePagination"; import { systemListApi } from "@/pages/admin/Privilege/api"; @@ -46,6 +46,10 @@ export default function EditModal({ onClose, setItem, item, roleList }: Props) { message.error(e.message); }); } + const options = [ + { label: '考评人', value: 1 }, + { label: '考评门店', value: 2 }, +]; return ( form.resetFields()} >
- + - + + + + - _onChange(v?.currentTarget?.value)} + enterButton + onSearch={v => _onChange(v)} />
diff --git a/src/pages/pms/part/PartPriceCoefficient/api.ts b/src/pages/pms/part/PartPriceCoefficient/api.ts index 639ebd7..1a15154 100644 --- a/src/pages/pms/part/PartPriceCoefficient/api.ts +++ b/src/pages/pms/part/PartPriceCoefficient/api.ts @@ -105,6 +105,8 @@ interface Params{ file:any user?: string fixRemark?: string + shopIds?:any + shopNames?:any } export function uploadApi(params: Params) { return request.post(`${PMS_HOST}/erp/part/price/import/fix/price`, params, {contentType: 'form-data'}); diff --git a/src/pages/pms/part/PartPriceCoefficient/components/ChoosePart.tsx b/src/pages/pms/part/PartPriceCoefficient/components/ChoosePart.tsx index 5ab320a..656411c 100644 --- a/src/pages/pms/part/PartPriceCoefficient/components/ChoosePart.tsx +++ b/src/pages/pms/part/PartPriceCoefficient/components/ChoosePart.tsx @@ -23,7 +23,6 @@ export default function ChoosePart({ value = { partCode: '', partName: '' }, onC const { list, loading, paginationConfig, setParams } = usePagination(getPartPageListApi, { keywords: value.partCode, brandId }); const handleChangeKeywords = debounce((value: string) => { - // setParams({ current: 1, keywords: value }, true); setFilterPartCode(value); }, 500); @@ -60,7 +59,6 @@ export default function ChoosePart({ value = { partCode: '', partName: '' }, onC allowClear value={filterPartCode} placeholder="请输入配件名称/编码/件号" - onChange={e => handleChangeKeywords(e.target.value)} onSearch={value => setParams({ current: 1, keywords: value }, true)} style={{ maxWidth: 240, marginLeft: 10, marginBottom: 20 }} /> diff --git a/src/pages/pms/part/PartPriceCoefficient/components/FixedPriceModal.tsx b/src/pages/pms/part/PartPriceCoefficient/components/FixedPriceModal.tsx index 7bedde4..955db08 100644 --- a/src/pages/pms/part/PartPriceCoefficient/components/FixedPriceModal.tsx +++ b/src/pages/pms/part/PartPriceCoefficient/components/FixedPriceModal.tsx @@ -15,10 +15,9 @@ interface Props { } export default function FixedPriceModal({ visible, setVisible, currentFixedPrice, setParams }: Props) { - const { brands, shops } = useStore(); + const { shops } = useStore(); const [brandId, setBrandId] = useState(); const [form] = Form.useForm(); - // console.log(currentFixedPrice, 'currentFixedPrice'); useEffect(() => { if (visible) { @@ -49,7 +48,6 @@ export default function FixedPriceModal({ visible, setVisible, currentFixedPrice brandId: currentFixedPrice.brandId, partId: fields.part.partId }; - // console.log(params); saveFixedApi(params).then(res => { if (res.success) { message.success(res.result); diff --git a/src/pages/pms/part/PartPriceCoefficient/components/FixedPriceTab.tsx b/src/pages/pms/part/PartPriceCoefficient/components/FixedPriceTab.tsx index efaea79..e5471c4 100644 --- a/src/pages/pms/part/PartPriceCoefficient/components/FixedPriceTab.tsx +++ b/src/pages/pms/part/PartPriceCoefficient/components/FixedPriceTab.tsx @@ -5,7 +5,6 @@ import FixedPriceModal from './FixedPriceModal'; import { useStore } from '..'; import usePagination from '@/hooks/usePagination'; import { getFixedPageListApi, exportFixedPageListApi } from '../api'; -import { debounce } from 'lodash'; import UploadModal from './UploadModal'; import ShopModal from './ShopModal'; @@ -15,26 +14,17 @@ const { Search } = Input; export default function InsuranceTab() { const { list, loading, setParams, paginationConfig } = usePagination(getFixedPageListApi); - const { brands, shops } = useStore(); + const { shops } = useStore(); const [visible, setVisible] = useState(false); const [currentFixedPrice, setCurrentFixedPrice] = useState({}); const [uploadVisible, sertUploadVisible] = useState(false); const [shopVisible, setShopVisible] = useState(false); const [item, setItem] = useState(); - const handleChangeKeywords = debounce(value => { - setParams({ current: 1, keywords: value }, true); - }, 500); - return ( <>
- {/* */} - { - insurances.map(insurance => ) - } - */}
{ const params = { id: currentRetail.id, - // brandId: fields.brandId, - // brandName: brands.filter(brand => brand.id === fields.brandId)[0].name, - shopIds: fields.shopId, + shopIds: fields.shopIds, workTypeId: fields.workTypeId, scopes: fields.scopes }; @@ -74,7 +72,7 @@ export default function TabModal({ setParams, currentRetail= {}, setCurrentRetai scopes: currentRetail.scopes && currentRetail.scopes.length > 1 ? currentRetail.scopes : undefined }} > - + setUploadInfo({...uploadInfo, shopIds: v})} + > + {shops.map(shop => ( + + ))} + +
导入人员: - setUser(e.target.value)} style={{width: 200}} /> + setUploadInfo({ ...uploadInfo, user: e.target.value })} style={{width: 250}} />
导入原因: - setFixRemark(e.target.value)} style={{width: 200}} /> + setUploadInfo({ ...uploadInfo, fixRemark: e.target.value})} style={{width: 250}} />

diff --git a/src/pages/pms/part/PartSpec/index.tsx b/src/pages/pms/part/PartSpec/index.tsx index aa89cfa..dd3f52c 100644 --- a/src/pages/pms/part/PartSpec/index.tsx +++ b/src/pages/pms/part/PartSpec/index.tsx @@ -11,7 +11,7 @@ import { throttle } from 'lodash'; const { Column } = Table; const { Search } = Input; export default function PartPriceCoefficient() { - const { list, paginationConfig, loading, setParams, innerParams } = usePagination(getPageListApi, {}); + const { list, paginationConfig, loading, setParams } = usePagination(getPageListApi, {}); const [visible, setVisible] = useState(false); const [confirmLoading, setConfirmLoading] = useState(false); const [item, setItem] = useState({}); @@ -38,9 +38,7 @@ export default function PartPriceCoefficient() { setParams({ current: 1, keywords: e.target.value }, true)} onSearch={value => setParams({ current: 1, keywords: value }, true)} style={{ maxWidth: 240 }} /> diff --git a/src/pages/pms/part/PartSplit/components/RetailModal.tsx b/src/pages/pms/part/PartSplit/components/RetailModal.tsx index 2a98b49..0b5172e 100644 --- a/src/pages/pms/part/PartSplit/components/RetailModal.tsx +++ b/src/pages/pms/part/PartSplit/components/RetailModal.tsx @@ -35,9 +35,7 @@ export default function TabModal({ setParams, currentRetail= {}, setCurrentRetai form.validateFields().then(fields => { const params = { id: currentRetail.id, - // brandId: fields.brandId, - // brandName: brands.filter(brand => brand.id === fields.brandId)[0].name, - shopIds: fields.shopId, + shopIds: fields.shopIds, workTypeId: fields.workTypeId, scopes: fields.scopes }; @@ -75,7 +73,7 @@ export default function TabModal({ setParams, currentRetail= {}, setCurrentRetai scopes: currentRetail.scopes && currentRetail.scopes.length > 1 ? currentRetail.scopes : undefined }} > - + handleChangeBrand({ keywords: e.target.value })} - style={{ maxWidth: 240 }} - value={innerParams.keywords} + onSearch={e => handleChangeBrand({ keywords: e })} + style={{ maxWidth: 260 }} /> option.children.toLowerCase().indexOf(input.toLowerCase()) >= 0} > {partTypeData.map((item: any) => ( diff --git a/src/pages/pms/part/Repertory/components/SpecEpcModal.tsx b/src/pages/pms/part/Repertory/components/SpecEpcModal.tsx index 0ddf52b..9f2e19d 100644 --- a/src/pages/pms/part/Repertory/components/SpecEpcModal.tsx +++ b/src/pages/pms/part/Repertory/components/SpecEpcModal.tsx @@ -43,7 +43,6 @@ export default function specEcpModal() { visible={specVisible} maskClosable={false} onCancel={() => setSpecVisible(false)} - // forceRender footer={

diff --git a/src/pages/pms/part/Repertory/components/UploadExcel.tsx b/src/pages/pms/part/Repertory/components/UploadExcel.tsx index 3da090f..2981847 100644 --- a/src/pages/pms/part/Repertory/components/UploadExcel.tsx +++ b/src/pages/pms/part/Repertory/components/UploadExcel.tsx @@ -52,23 +52,30 @@ export default function UploadExcel() { message.error(e.message); }); } + const cancel = () => { + setImportVisible(false); + setUploadResult(null); + }; + return ( { setImportVisible(false); setUploadResult(null); }} + onCancel={cancel} footer={
- - - - + + {uploadResult ? : ( + + + + )}
} > diff --git a/src/pages/pms/part/Repertory/interface.d.ts b/src/pages/pms/part/Repertory/interface.d.ts index 8833dee..931fa64 100644 --- a/src/pages/pms/part/Repertory/interface.d.ts +++ b/src/pages/pms/part/Repertory/interface.d.ts @@ -33,6 +33,7 @@ declare namespace PartRepertorySpace { canEdit?: boolean, // 能否编辑 epcs?: Epc[], // EPC信息集合 out?: boolean, + type?:number[] } /** 车型列表 */ diff --git a/src/pages/pms/partPlan/AppointPart/api.ts b/src/pages/pms/partPlan/AppointPart/api.ts index 6840713..81994cf 100644 --- a/src/pages/pms/partPlan/AppointPart/api.ts +++ b/src/pages/pms/partPlan/AppointPart/api.ts @@ -118,6 +118,14 @@ export interface detailGroups{ statusName?:string // 审批状态 parts?: detailParts[] } + +export interface editItem{ + partId?:number + partName?: string, + partCode?: string, + price?: number, + partCnt?: number +} export interface detailItem extends Item { groups: detailGroups[] } @@ -132,4 +140,9 @@ export function savePartPlan(params: groups[]): http.PromiseResp { export function partPlanDetailApi(params: queryDetail) { return request.get(`${PMS_HOST}/erp/purchase/task/detail`, {params}); +} + +// 批量导入 +export function importApi(params: {file: any}): http.PromiseResp { + return request.post(`${PMS_HOST}/erp/purchase/task/importData`, params, { contentType: "form-data" }); } \ No newline at end of file diff --git a/src/pages/pms/partPlan/AppointPart/comonents/EditModal.tsx b/src/pages/pms/partPlan/AppointPart/comonents/EditModal.tsx new file mode 100644 index 0000000..dc3d519 --- /dev/null +++ b/src/pages/pms/partPlan/AppointPart/comonents/EditModal.tsx @@ -0,0 +1,96 @@ +import React, { useEffect } from 'react'; +import { Modal, Button, Input, Form } from 'antd'; +import { editItem } from '../api'; + +const Item = Form.Item; +interface Props { + visible: boolean, + onCancel: Function, + item: editItem, + onOk: (_: any) => any, +} +export default function Index(props: Props) { + const {visible, onCancel, item, onOk} = props; + const [form] = Form.useForm(); + + useEffect(() => { + if (visible) { + form.setFieldsValue({ + partName: item.partName, + partCode: item.partCode, + price: item.price, + partCnt: item.partCnt, + }); + } else { + form.resetFields(); + } + }, [visible]); + + const save = () => { + form.validateFields().then(files => { + const _item = { + ...item, + price: files.price, + partCnt: files.partCnt, + }; + onOk(_item); + onCancel(); + }); + }; + + return ( + onCancel()} + footer={[ + , + + ]} + > + + + + + + + + ({ + validator(_, value) { + if (value >= 0) { + return Promise.resolve(); + } + return Promise.reject(new Error('配件价格必须大于0')); + }, + }), + ]} + > + + + ({ + validator(_, value) { + if (value >= 0) { + return Promise.resolve(); + } + return Promise.reject(new Error('配件数量必须大于0')); + }, + }), + ]} + > + + + + + ); +} \ No newline at end of file diff --git a/src/pages/pms/partPlan/AppointPart/comonents/PartModal.tsx b/src/pages/pms/partPlan/AppointPart/comonents/PartModal.tsx index d3f4e11..8255a86 100644 --- a/src/pages/pms/partPlan/AppointPart/comonents/PartModal.tsx +++ b/src/pages/pms/partPlan/AppointPart/comonents/PartModal.tsx @@ -92,7 +92,6 @@ export default function Index({ value = { partCode: '', partName: '', price: und enterButton allowClear placeholder="请输入配件名称/编码" - onChange={e => handleChange(e.target.value)} onSearch={handleChange} style={{ maxWidth: 240, marginRight: 10 }} /> diff --git a/src/pages/pms/partPlan/AppointPart/comonents/PartStorageModal.tsx b/src/pages/pms/partPlan/AppointPart/comonents/PartStorageModal.tsx index 606e595..f7e1d4f 100644 --- a/src/pages/pms/partPlan/AppointPart/comonents/PartStorageModal.tsx +++ b/src/pages/pms/partPlan/AppointPart/comonents/PartStorageModal.tsx @@ -1,9 +1,11 @@ import React, { useEffect, useState } from 'react'; -import { Modal, Button, Table, Form, message } from 'antd'; +import { Modal, Button, Table, Form, message, Divider } from 'antd'; import ChoosePartModal from './ChoosePartModal'; import {useStore} from '../index'; -import {partPlan} from '../api'; +import { partPlan, editItem } from '../api'; import PmsSelect from '@/pages/pms/comonents/PmsSelect'; +import EditModal from './EditModal'; +import UploadExcel from './UploadExcel'; const {Item} = Form; const {Column} = Table; @@ -22,6 +24,8 @@ export default function PartStorageModal({ onCancel, visible, onOk, itemData, se const [form] = Form.useForm(); const [storageid, setStorageid] = useState(); const [partParams, setPartParams] = useState<{stId?:number, spId?: number}>(); + const [editInfo, setEditInfo] = useState<{ visible: boolean, item: editItem }>({visible: false, item: {}}); + const [upload, setUpload] = useState(false); useEffect(() => { if (itemData?.id) { @@ -93,6 +97,7 @@ export default function PartStorageModal({ onCancel, visible, onOk, itemData, se
+
@@ -109,9 +114,13 @@ export default function PartStorageModal({ onCancel, visible, onOk, itemData, se ( - setSelectedParts(selectedParts.filter(i => i.partCode != _item.partCode))}> - 删除 - + <> + setEditInfo({visible: true, item: _item})}>编辑 + + setSelectedParts(selectedParts.filter(i => i.partCode != _item.partCode))}> + 删除 + + )} />
@@ -128,6 +137,31 @@ export default function PartStorageModal({ onCancel, visible, onOk, itemData, se } }} /> + setEditInfo({visible: false, item: {}})} + onOk={(part) => { + setSelectedParts(selectedParts.map(i => { + if (i.partId == part.partId) { + return ({ + partId: part.partId, + partName: part.partName, + partCode: part.partCode, + partCnt: part.partCnt, + price: part.price, + }); + } else { + return i; + } + })); + }} + /> + setUpload(false)} + onOk={(parts) => setSelectedParts([...selectedParts, ...parts])} + /> ); } diff --git a/src/pages/pms/partPlan/AppointPart/comonents/UploadExcel.tsx b/src/pages/pms/partPlan/AppointPart/comonents/UploadExcel.tsx new file mode 100644 index 0000000..67e0a5d --- /dev/null +++ b/src/pages/pms/partPlan/AppointPart/comonents/UploadExcel.tsx @@ -0,0 +1,88 @@ +import React, { useState } from 'react'; +import { InboxOutlined } from '@ant-design/icons'; +import { Button, Modal, Upload, message, Popconfirm } from 'antd'; +import { importApi } from '../api'; +import _ from 'lodash'; +import type { UploadFile, UploadProps } from 'antd/es/upload/interface'; + +interface Props { + visible: boolean, + onCancel: Function, + onOk: (_: any) => any, +} + +const Dragger = Upload.Dragger; + +export default function UploadExcel(props: Props) { + const { visible, onCancel, onOk } = props; + const [fileList, setFileList] = useState([]); + const [confirmLoading, setConfirmLoading] = useState(false); + + function beforeUpload(file: any) { + const isLt2M = file.size / 1024 / 1024 < 20; + if (!isLt2M) { + message.error('文件不能超过20MB!'); + return false; + } + setFileList([...fileList, file]); + return false; + } + + function submit() { + setConfirmLoading(true); + importApi({file: fileList[0]}).then((res) => { + setConfirmLoading(false); + onOk(res.data); + setFileList([]); + message.success('导入成功'); + onCancel(); + }).catch((e: any) => { + setConfirmLoading(false); + message.error(e.message); + setFileList([]); + }); + } + const uploadProps: UploadProps = { + onRemove: (file) => { + const index = fileList.indexOf(file); + const newFileList = fileList.slice(); + newFileList.splice(index, 1); + setFileList(newFileList); + }, + beforeUpload, + fileList, + }; + + return ( + onCancel()} + footer={[ + , + + + + ]} + > + +

+ +

+

将文件拖到此处上传

+
+
+ ); +} diff --git a/src/pages/pms/partPlan/CustBuyPlan/api.ts b/src/pages/pms/partPlan/CustBuyPlan/api.ts index cbd5208..f9fd7f9 100644 --- a/src/pages/pms/partPlan/CustBuyPlan/api.ts +++ b/src/pages/pms/partPlan/CustBuyPlan/api.ts @@ -37,6 +37,7 @@ export interface Item { serviceTypes?: string, // 接车类型 mileIn?: number, // 进站里程 totalActualPrice?: number, // 装潢收款金额 + sourceType?:string // 来源类型 } /** diff --git a/src/pages/pms/partPlan/CustBuyPlan/subpages/First/components/CasTable.tsx b/src/pages/pms/partPlan/CustBuyPlan/subpages/First/components/CasTable.tsx index 772a781..43376ad 100644 --- a/src/pages/pms/partPlan/CustBuyPlan/subpages/First/components/CasTable.tsx +++ b/src/pages/pms/partPlan/CustBuyPlan/subpages/First/components/CasTable.tsx @@ -68,16 +68,17 @@ export default function Index() { - - onPress(it.remark)}>查看} /> - - - - + + + + + + (r.serviceTypes?.map((i:any) => serviceTypeEnum[i]).join(','))} /> + onPress(it.remark)}>查看} /> {fw && onFinish(record)}>完成} />} ); diff --git a/src/pages/pms/partPlan/CustBuyPlan/subpages/First/components/DecoTable.tsx b/src/pages/pms/partPlan/CustBuyPlan/subpages/First/components/DecoTable.tsx index 05a5023..b8d36d9 100644 --- a/src/pages/pms/partPlan/CustBuyPlan/subpages/First/components/DecoTable.tsx +++ b/src/pages/pms/partPlan/CustBuyPlan/subpages/First/components/DecoTable.tsx @@ -1,5 +1,4 @@ import React, { useEffect, useState } from 'react'; -import moment from 'moment'; import { message, Table } from 'antd'; import usePagination from '@/hooks/usePagination'; import { fetchList, Item } from '@/pages/pms/partPlan/CustBuyPlan/api'; @@ -43,15 +42,16 @@ export default function Index() { > - onPress(it.remark)}>查看} /> - - - - t && moment(t).format('YYYY-MM-DD HH:mm')} /> - + + + + + + t.toFixed(2) || 0} /> + onPress(it.remark)}>查看} /> ); } diff --git a/src/pages/pms/partPlan/CustBuyPlan/subpages/Second/index.tsx b/src/pages/pms/partPlan/CustBuyPlan/subpages/Second/index.tsx index 9c05cb7..be643d0 100644 --- a/src/pages/pms/partPlan/CustBuyPlan/subpages/Second/index.tsx +++ b/src/pages/pms/partPlan/CustBuyPlan/subpages/Second/index.tsx @@ -77,9 +77,10 @@ export default function Index() {
setDfParam({...dfParam, keywords: e.target.value || ''})} + style={{width: 220, marginRight: 10}} + onSearch={e => setDfParam({...dfParam, keywords: e})} /> (getStoragePage, {pageSize: 1000}); const { data: shops } = useInitial(getShopApi, [], {}); const [selectedParts, setSelectedParts] = useState([]); + const { data: partTypeData } = useInitial(getPartTypeApi, [], {}); const [item, setItem] = useState({}); const [detailModal, setDetailModal] = useState(false); @@ -71,9 +73,9 @@ export default function Index() { handleKeywords(v)} - onChange={e => handleKeywords(e.target.value)} /> + { - setDfParam({...dfParam, partType}); + onChange={(v) => { + setDfParam({...dfParam, partTypeName: partTypeData.find(i => i.value == v)?.label}); }} placeholder="请选择配件类型" showSearch @@ -216,7 +216,7 @@ export default function Index({ onCancel, visible, parts=[], onOk, setParams }: - partTypeData.find(it => it.value == t)?.label} /> + diff --git a/src/pages/pms/partPlan/PlanManage/subpages/Apply/index.tsx b/src/pages/pms/partPlan/PlanManage/subpages/Apply/index.tsx index 339799d..5ddad07 100644 --- a/src/pages/pms/partPlan/PlanManage/subpages/Apply/index.tsx +++ b/src/pages/pms/partPlan/PlanManage/subpages/Apply/index.tsx @@ -134,12 +134,12 @@ export default function Index() { })); } - useEffect(() => { - if (dfParams.brandId) { - setParams(dfParams, true); - setDelay(false); - } - }, [dfParams.brandId]); + // useEffect(() => { + // if (dfParams.brandId) { + // setParams(dfParams, true); + // setDelay(false); + // } + // }, [dfParams.brandId]); const onSubmit = throttle(() => { setLoading(true); @@ -179,6 +179,8 @@ export default function Index() { value={dfParams.brandId} onChange={brandId => { setDfParams({ ...dfParams, brandId }); + setParams({}, true); + setDelay(false); setDealerList([]); }} > diff --git a/src/pages/pms/partPlan/PlanManage/subpages/Detail/index.tsx b/src/pages/pms/partPlan/PlanManage/subpages/Detail/index.tsx index 5887828..9ee1395 100644 --- a/src/pages/pms/partPlan/PlanManage/subpages/Detail/index.tsx +++ b/src/pages/pms/partPlan/PlanManage/subpages/Detail/index.tsx @@ -1,4 +1,4 @@ -import {Card, ConfigProvider} from 'antd'; +import {Card, ConfigProvider, Spin} from 'antd'; import { PageHeaderWrapper } from '@ant-design/pro-layout'; import React, {useState} from "react"; import useInitial from "@/hooks/useInitail"; @@ -14,18 +14,19 @@ import PartDetailModal from './components/PartDetailModal'; export default function Index({ match }: common.ConnectProps) { const { planId } = match.params; - const { data } = useInitial(getDetail, [], {planId}); + const { data, loading } = useInitial(getDetail, [], {planId}); const [visiblePart, setVisiblePart] = useState(false); const [parts, setParts] = useState([]); return ( - - - {data.map((dealer: DetailVO = {}) => ( -
-
{`商家: ${dealer.settleDealerName || ''}`}
- {(dealer.suppliers || []).map((supplier: SupplierVO = {}) => { + + + + {data.map((dealer: DetailVO = {}) => ( +
+
{`商家: ${dealer.settleDealerName || ''}`}
+ {(dealer.suppliers || []).map((supplier: SupplierVO = {}) => { const paList: any[] = flattenDeep((supplier.storages || []).map((st: any) => (st.parts || []))); return (
@@ -54,16 +55,17 @@ export default function Index({ match }: common.ConnectProps) {
); })} -
+
))} - setVisiblePart(false)} parts={parts} /> - history.back()} - /> -
-
+ setVisiblePart(false)} parts={parts} /> + history.back()} + /> + + +
); } diff --git a/src/pages/pms/partPlan/PlanPool/components/AreaTable.tsx b/src/pages/pms/partPlan/PlanPool/components/AreaTable.tsx index af6b97c..222f332 100644 --- a/src/pages/pms/partPlan/PlanPool/components/AreaTable.tsx +++ b/src/pages/pms/partPlan/PlanPool/components/AreaTable.tsx @@ -33,9 +33,9 @@ export default function Index(props: Props = {}) {
`${v.id}`} scroll={{y: 500, x: 2500}} dataSource={parts || []} pagination={false} loading={loading}> + (t || 0).toFixed(2)} /> (t || 0).toFixed(2)} /> - diff --git a/src/pages/pms/partPlan/PlanPool/components/Filter.tsx b/src/pages/pms/partPlan/PlanPool/components/Filter.tsx index 4b4c0f5..c2384ae 100644 --- a/src/pages/pms/partPlan/PlanPool/components/Filter.tsx +++ b/src/pages/pms/partPlan/PlanPool/components/Filter.tsx @@ -67,9 +67,9 @@ export default function Filter() { handleChangeKeywords(v)} - onChange={e => handleChangeKeywords(e.target.value)} /> ); diff --git a/src/pages/pms/partPlan/PlanPool/components/PartTable.tsx b/src/pages/pms/partPlan/PlanPool/components/PartTable.tsx index ddd714c..2df6c66 100644 --- a/src/pages/pms/partPlan/PlanPool/components/PartTable.tsx +++ b/src/pages/pms/partPlan/PlanPool/components/PartTable.tsx @@ -16,7 +16,7 @@ interface Props { id?: number, // 上一个列表ID } export default function Index(props: Props = {}) { - const { dfParams, key, partTypeData } = useStore(); + const { dfParams, key } = useStore(); const {showAnalyse=true} = props; const { data: parts, setParams, loading } = useInitial(getList, [], {...dfParams, ...props}); const [visible, setVisible] = useState(false); @@ -34,12 +34,14 @@ export default function Index(props: Props = {}) {
`${v.id}`} scroll={{y: 500, x: 3000}} dataSource={parts || []} pagination={false} loading={loading}> - + + - partTypeData.find(i => i.value == t)?.label} /> + + (t || 0).toFixed(2)} /> (t || 0).toFixed(2)} /> - + diff --git a/src/pages/pms/partPlan/PlanPool/components/SeriesTable.tsx b/src/pages/pms/partPlan/PlanPool/components/SeriesTable.tsx index 0a5608d..22f42b5 100644 --- a/src/pages/pms/partPlan/PlanPool/components/SeriesTable.tsx +++ b/src/pages/pms/partPlan/PlanPool/components/SeriesTable.tsx @@ -33,9 +33,10 @@ export default function Index(props: Props = {}) {
`${v.id}`} scroll={{y: 500, x: 2500}} dataSource={parts || []} pagination={false} loading={loading}> + (t || 0).toFixed(2)} /> (t || 0).toFixed(2)} /> - + diff --git a/src/pages/pms/partPlan/PlanPool/components/StoragePartTable.tsx b/src/pages/pms/partPlan/PlanPool/components/StoragePartTable.tsx index 8db4fa2..15d6027 100644 --- a/src/pages/pms/partPlan/PlanPool/components/StoragePartTable.tsx +++ b/src/pages/pms/partPlan/PlanPool/components/StoragePartTable.tsx @@ -12,7 +12,7 @@ interface Props { type?: number, // 类型1区域库2库房3车系4车型5配件 } export default function Index(props: Props = {}) { - const { dfParams, key, partTypeData } = useStore(); + const { dfParams, key } = useStore(); const [form] = Form.useForm(); const { data: parts, setParams, loading } = useInitial(getList, [], dfParams); const [visible, setVisible] = useState(false); @@ -36,23 +36,11 @@ export default function Index(props: Props = {}) {
`${v.poolId}`} scroll={{y: 500, x: 3000}} dataSource={parts || []} pagination={false} loading={loading}> - - - - - partTypeData.find(i => i.value == t)?.label} /> - (t || 0).toFixed(2)} /> - (t || 0).toFixed(2)} /> - - - - - - - - + + ( <> { setVisible(true); setItem(r); }}>编辑 @@ -60,7 +48,7 @@ export default function Index(props: Props = {}) { { - deleteApi({poolId: r.poolId}).then(res => { + deleteApi({ poolId: r.poolId }).then(res => { message.success("操作成功"); setParams({}, true); }).catch(e => message.error(e.message)); @@ -71,6 +59,22 @@ export default function Index(props: Props = {}) { )} /> + + + + + + (t || 0).toFixed(2)} /> + (t || 0).toFixed(2)} /> + + + + + + + + +
`${v.id}`} scroll={{y: 500, x: 2500}} dataSource={parts || []} pagination={false} loading={loading}> + (t || 0).toFixed(2)} /> (t || 0).toFixed(2)} /> - + diff --git a/src/pages/pms/partPlan/PlanShipping/components/UploadExcel.tsx b/src/pages/pms/partPlan/PlanShipping/components/UploadExcel.tsx index 68ec640..7836558 100644 --- a/src/pages/pms/partPlan/PlanShipping/components/UploadExcel.tsx +++ b/src/pages/pms/partPlan/PlanShipping/components/UploadExcel.tsx @@ -6,8 +6,8 @@ import usePagination from '@/hooks/usePagination'; import { getStoragePage } from '@/pages/pms/storage/StorageManage/api'; import { getPageListApi, Item } from '@/pages/pms/partPlan/PlanSupplier/api'; import SelectRow from '@/pages/pms/comonents/SelectRow'; -import {getDealerApi} from '@/common/api'; import useInitail from "@/hooks/useInitail"; +import { getShopApi } from '@/pages/pms/storage/partShop/api'; const Dragger = Upload.Dragger; @@ -22,9 +22,9 @@ export default function UploadExcel({ getList, importVisible, setImportVisible, const [delay, setDelay] = useState(true); const [fileList, setFileList] = useState([]); const { list: storages } = usePagination(getStoragePage, {pageSize: 1000}); - const {list: suppliers, setParams, innerParams} = usePagination(getPageListApi, {pageSize: 500}, {delay}); - const { data: dealers } = useInitail(getDealerApi, [], {}); - const [param, setParam] = useState({brandId: null, storageId: null, supplierId: null, settleDealerId: null}); + const { list: suppliers, setParams, innerParams } = usePagination(getPageListApi, { pageSize: 500, supplierType: 10 }, {delay}); + const { data: shops } = useInitail(getShopApi, [], {}); + const [param, setParam] = useState({ brandId: null, storageId: null, supplierId: null, settleShopId: null}); const [visibleDetail, setVisibleDetail] = useState(false); const [uploadResult, setUploadResult] = useState(); @@ -107,12 +107,12 @@ export default function UploadExcel({ getList, importVisible, setImportVisible, onChange={storageId => setParam({ ...param, storageId })} /> setParam({ ...param, settleDealerId })} + onChange={settleShopId => setParam({ ...param, settleShopId })} /> {!uploadResult ? !!param.brandId && !!param.storageId && !!param.supplierId && ( diff --git a/src/pages/pms/partPlan/PlanShipping/index.tsx b/src/pages/pms/partPlan/PlanShipping/index.tsx index 0c6a342..3f40953 100644 --- a/src/pages/pms/partPlan/PlanShipping/index.tsx +++ b/src/pages/pms/partPlan/PlanShipping/index.tsx @@ -30,9 +30,9 @@ export default function PartPriceCoefficient() {
setParams({...innerParams, month: v && v.valueOf(), current: 1}, true)} /> diff --git a/src/pages/pms/purchase/PurchasePool/index.tsx b/src/pages/pms/purchase/PurchasePool/index.tsx index f9abc04..fe055ba 100644 --- a/src/pages/pms/purchase/PurchasePool/index.tsx +++ b/src/pages/pms/purchase/PurchasePool/index.tsx @@ -31,9 +31,10 @@ export default function Index() {
setParams({keywords: e.target.value}, true)} - style={{ maxWidth: 280 }} + onSearch={e => setParams({keywords: e}, true)} + style={{ maxWidth: 300 }} />
i.id == itemData.storageId)?.dealerId}).then(res => { if (res.success) { @@ -88,7 +89,7 @@ export default function PartStorageModal({ onCancel, visible, itemData, setItemD useEffect(() => { if (storageid) { setDelay(false); - setParams({storageId: storageid}, true); + setParams({}, true); casSetParams({storageId: storageid}, true); } }, [storageid]); @@ -98,8 +99,6 @@ export default function PartStorageModal({ onCancel, visible, itemData, setItemD form.validateFields().then(fields => { const supplier = suppliers.find(it => it.supplierId == fields.supplierId) || {}; const storage = storages.find(it => it.id == fields.storageId) || {}; - - setBtnloading(true); const params = { storageId: storage.id, storageName: storage.storageName, @@ -111,8 +110,10 @@ export default function PartStorageModal({ onCancel, visible, itemData, setItemD parts: [...selectedParts.map(i => ({partId: i.partId, partCnt: i.partCnt, price: i.price, type: 1})), ...planePart.map(i => ({poolId: i.poolId, partId: i.partId, partCnt: i.cnt, price: i.price, type: 2})), ...(casPart?.map(i => (i.details?.map(it => ({partId: it.partId, partCnt: it.partCnt, poolId: it.poolId, expectInTime: it.expectInTime, price: it.price, type: 3})))).flat() || []) - ] + ], + isOutSide: !!fields.isOutSide }; + setBtnloading(true); purchaseApply(params).then(res => { message.success("提交成功"); setBtnloading(false); @@ -189,8 +190,6 @@ export default function PartStorageModal({ onCancel, visible, itemData, setItemD if (res.data?.length) { form.setFieldsValue({ proportion: res.data[0].billAmountRatio, accountCheckPeriod: res.data && res.data[0].accountCheckPeriod}); setListRelation(res.data && res.data[0].settleMethodList); - } else { - message.error(`请财务先配置${suppliers.find(i => i.supplierId == form.getFieldValue('supplierId'))?.supplierName}的结算方式`); } }).catch(e => message.error(e.message)); }} @@ -230,6 +229,15 @@ export default function PartStorageModal({ onCancel, visible, itemData, setItemD + + + @@ -262,9 +270,10 @@ export default function PartStorageModal({ onCancel, visible, itemData, setItemD
setParams({keywords: e.target.value}, true)} - style={{ width: 210 }} + onSearch={e => setParams({keywords: e}, true)} + style={{ width: 220 }} /> ({value: i.value, label: i.label}))} /> + setParams({storageId: v}, true)} + placeholder="请选择库房" + options={storages.map(i => ({value: i.id, label: i.storageName}))} + />
- partTypeData.find(i => i.value == t)?.label} /> + + _.ceil((r.cnt * r.price), 2)} />
@@ -310,9 +327,10 @@ export default function PartStorageModal({ onCancel, visible, itemData, setItemD
casSetParams({keywords: e.target.value}, true)} - style={{ width: 200 }} + onSearch={e => casSetParams({keywords: e}, true)} + style={{ width: 220 }} />
handleChange(e.target.value)} onSearch={handleChange} style={{ maxWidth: 240, marginRight: 10 }} /> diff --git a/src/pages/pms/purchase/PurchaseRecord/index.tsx b/src/pages/pms/purchase/PurchaseRecord/index.tsx index 6f15451..0f8ee0b 100644 --- a/src/pages/pms/purchase/PurchaseRecord/index.tsx +++ b/src/pages/pms/purchase/PurchaseRecord/index.tsx @@ -106,7 +106,13 @@ export default function Index() {
- setParams({keywords: e.target.value}, true)} /> + setParams({keywords: e}, true)} + /> `${r.purchaseId}`} > + diff --git a/src/pages/pms/storage/partFlow/index.tsx b/src/pages/pms/storage/partFlow/index.tsx index 3f5bd50..af28ca0 100644 --- a/src/pages/pms/storage/partFlow/index.tsx +++ b/src/pages/pms/storage/partFlow/index.tsx @@ -24,7 +24,8 @@ export default function Index() { setParams({keywords: v.target.value}, true)} + enterButton + onSearch={v => setParams({keywords: v}, true)} style={{width: 250, marginRight: 20}} /> handleChangeKeywords(v)} - onChange={e => handleChangeKeywords(e.target.value)} /> {`发运单号: ${obj.shippingNo}`}
} {!!obj.importUserName &&
{`导入人员: ${obj.importUserName}`}
} {!!obj.inStorageUserName &&
{`入库人员: ${obj.inStorageUserName}`}
} - {!!obj.importTime &&
{`入库时间: ${moment(obj.importTime).format('YYYY-MM-DD HH:mm')}`}
} + {!!obj.importTime &&
{`导入时间: ${moment(obj.importTime).format('YYYY-MM-DD HH:mm')}`}
} {!!obj.inStorageName &&
{`调入库房: ${obj.inStorageName}`}
} {!!obj.inShopName &&
{`调入门店: ${obj.inShopName}`}
} diff --git a/src/pages/pms/storage/partShop/components/LockDetailModal.tsx b/src/pages/pms/storage/partShop/components/LockDetailModal.tsx index 53bfe36..27a0f52 100644 --- a/src/pages/pms/storage/partShop/components/LockDetailModal.tsx +++ b/src/pages/pms/storage/partShop/components/LockDetailModal.tsx @@ -46,7 +46,7 @@ export default function Index({ item = {}, visible, onCancel }: Props) { ]} >
`${v.orderNo}`} scroll={{ y: 500 }} dataSource={data || []} pagination={false}> - (r.orderNo.slice(0, 1) == "D" ? "装潢订单锁定" : r.type)} /> + ((!!r.orderNo && r.orderNo.slice(0, 1) == "D") ? "装潢订单锁定" : r.type)} /> { + setImportVisible(false); + setUploadResult(null); + }; + return ( { setImportVisible(false); setUploadResult(null); }} + onCancel={cancel} footer={[ , - - - + uploadResult ? + + : ( + + + + ) ]} > {!uploadResult ? ( diff --git a/src/pages/pms/storage/partShop/components/UploadMoreModal.tsx b/src/pages/pms/storage/partShop/components/UploadMoreModal.tsx index d452743..7db1b39 100644 --- a/src/pages/pms/storage/partShop/components/UploadMoreModal.tsx +++ b/src/pages/pms/storage/partShop/components/UploadMoreModal.tsx @@ -1,61 +1,63 @@ import React, {useEffect, useState} from 'react'; import {Modal, Button, InputNumber, Select} from 'antd'; -import {getList} from './api'; +import { getList } from './api'; import useInitial from "@/hooks/useInitail"; import { useStore } from '../index'; interface Props { + islock?:boolean, + setIslock: Function, visible: boolean, onCancel: () => any, } const Option = Select.Option; export default function Upload(props: Props) { - // getLocationCnt const { storages: storageList } = useStore(); - const { visible, onCancel} = props; + const { visible, onCancel, islock, setIslock } = props; const [storageid, setStorageid] = useState(); const [storageName, setStorageName] = useState(); const [delay, setDelay] = useState(true); const { data: total, setParams } = useInitial(getList, 0, storageid, delay); const [pagesize, setPagesize] = useState(1000); const [list, setList] = useState([]); + async function f(s:number, a: Array) { for (let i = 0; i < s; i++) { a.push(i+1); } return a; } + useEffect(() => { if (total && pagesize) { const sum = Math.ceil(Number(total) / pagesize); const arr:Array= []; - // for (let i = 0; i < sum; i++) { - // arr.push(i+1); - // } f(sum, arr).then(a => setList(a)); - // setList(arr); } else { setList([]); } - }, [total, pagesize]); + }, [total, pagesize, storageid]); + useEffect(() => { if (!visible) { setStorageid(undefined); setList([]); + setIslock(false); } }, [visible]); + const handOnChange = (value: number) => { const storagename = storageList.find(it => it.id==value); setStorageid(value); - setParams(value, true); setStorageName(storagename?.storageName); setDelay(false); + setParams(value, true); }; return (
- {list.map((it, index) => ( + {islock ? list.map((it, index) => ( + {`${storageName}锁定库存${it}.xlsx`} + )) : + list.map((it, index) => ( {`${storageName}库存${it}.xlsx`} ))} +
); diff --git a/src/pages/pms/storage/partShop/index.tsx b/src/pages/pms/storage/partShop/index.tsx index a82b063..58b61ab 100644 --- a/src/pages/pms/storage/partShop/index.tsx +++ b/src/pages/pms/storage/partShop/index.tsx @@ -15,11 +15,12 @@ function PartShop() { const { setImportVisible, fw, setVisible, setIsadd } = useStore(); const [more, setMore] = useState(false); const [stock, setStock] = useState(false); + const [islock, setIslock] = useState(false); return ( -
+
{fw && ( @@ -41,13 +42,23 @@ function PartShop() { )} + {/* {!fw && ( */} + + {/* )} */}
- {/*

- 4:现金启票奖励 -

*/} {data.cashTicket?.rebateAmount || 0} @@ -307,11 +301,34 @@ function Index(props: Props) { }); }} > - {/* {`确认清单 >`} */} {`${readOnly ? "查看" : "确认"}清单 >`}
+ + + + {[1, 2].map((i) => { return ; diff --git a/src/pages/stock/AllowanceConfirm/EditComfirm/store.ts b/src/pages/stock/AllowanceConfirm/EditComfirm/store.ts index 67736fa..77d9b74 100644 --- a/src/pages/stock/AllowanceConfirm/EditComfirm/store.ts +++ b/src/pages/stock/AllowanceConfirm/EditComfirm/store.ts @@ -146,30 +146,15 @@ export default function useStore() { // 6: API.getDirectOrderListApi, }; - const commonOrderDetail = { - 1: API.getOrderDetail, - 2: API.getInwardOrderDetail, - 3: API.getCashOrderDetail, - 4: API.getPromotionOrderDetail, - // 6: API.getDirectOrderDetail, - }; - const commonSaveDiffApi = { 1: API.saveDiffApi, 2: API.saveInwardDiffApi, 3: API.savePromotionDiffApi, 4: API.saveCashDiffApi, + 7: API.saveOptionalDiffApi // 6: API.saveDirectDiffApi, }; - const commonComfirmApi = { - 1: API.subsidyComfirmApi, - 2: API.inwardComfirmApi, - 3: API.cashComfirmApi, - 4: API.promotionComfirmApi, - // 6: API.directComfirmApi - }; - /** * 未确认清单 * 1、厂家补贴 2、厂家代收款 3、厂家促销 4、现金启票 @@ -179,6 +164,7 @@ export default function useStore() { 2: API.getInwardWaitCheckListApi, 3: API.getPromotionWaitCheckListApi, 4: API.getCashWaitCheckListApi, + 7: API.getOptionalWaitCheckListApi // 6: API.getDirectOrderListApi, }; @@ -191,7 +177,7 @@ export default function useStore() { 2: API.getInwardCheckListApi, 3: API.getPromotionCheckListApi, 4: API.getCashCheckListApi, - // 6: API.getDirectOrderListApi, + 7: API.getOptionalCheckListApi, }; /** @@ -202,7 +188,7 @@ export default function useStore() { 2: API.rebateInwardCheck, 3: API.rebatePromotionCheck, 4: API.rebateCashCheck, - // 6: API.getDirectOrderListApi, + 7: API.rebateAddOptionalCheck, }; /** @@ -221,7 +207,7 @@ export default function useStore() { 2: API.rebateInwardRemove, 3: API.rebatePromotionRemove, 4: API.rebateCashRemove, - // 6: API.getDirectOrderListApi, + 7: API.rebateOptionalRemove, }; return { @@ -284,9 +270,8 @@ export default function useStore() { orderId, setOrderId, commonOrderList, - commonOrderDetail, + // commonOrderDetail, commonSaveDiffApi, - commonComfirmApi, setParams, params, carOrderTabkey, diff --git a/src/pages/stock/AllowanceConfirm/interface.d.ts b/src/pages/stock/AllowanceConfirm/interface.d.ts index 47dbc8f..3fd14f0 100644 --- a/src/pages/stock/AllowanceConfirm/interface.d.ts +++ b/src/pages/stock/AllowanceConfirm/interface.d.ts @@ -70,7 +70,8 @@ declare namespace FvmAllowance { cashTicket: CashTicket, /** 厂家代收款 */ inwardCollection: CashTicket, - + /**厂家选装返利 */ + optional: CashTicket } interface CashTicket { diff --git a/src/pages/stock/Components/OptionalDetails.tsx b/src/pages/stock/Components/OptionalDetails.tsx new file mode 100644 index 0000000..49711f9 --- /dev/null +++ b/src/pages/stock/Components/OptionalDetails.tsx @@ -0,0 +1,32 @@ +import React from 'react'; +import { Modal, Descriptions, Row, List } from 'antd'; + +interface Props { + visible: boolean, + onCancel: () => any, + listItem?: SpecialOfferCar.OptionalVo[], +} +export default function DetailModal({ visible, onCancel, listItem = [] }: Props) { + return ( + + ( + + +
{key + 1}.{item.optionalName}
+
{item.dealerPrice || 0}元
+
+
+ )} + /> +
+ ); +} \ No newline at end of file diff --git a/src/pages/stock/DirectVehicles/EditComfirm/Manufacturer/index.tsx b/src/pages/stock/DirectVehicles/EditComfirm/Manufacturer/index.tsx index eec0175..57a475d 100644 --- a/src/pages/stock/DirectVehicles/EditComfirm/Manufacturer/index.tsx +++ b/src/pages/stock/DirectVehicles/EditComfirm/Manufacturer/index.tsx @@ -36,7 +36,6 @@ export default function CreateModal(props: Props) { orderId, detailVisible, setDetailVisible, - // commonComfirmApi, setSelectedRowkeys, setSubmitSelectedRowkeys, selectedRowKeys, diff --git a/src/pages/stock/DirectVehicles/EditComfirm/components/BehalfMoney.tsx b/src/pages/stock/DirectVehicles/EditComfirm/components/BehalfMoney.tsx index bff470a..954b28d 100644 --- a/src/pages/stock/DirectVehicles/EditComfirm/components/BehalfMoney.tsx +++ b/src/pages/stock/DirectVehicles/EditComfirm/components/BehalfMoney.tsx @@ -36,7 +36,6 @@ export default function CreateModal(props: Props) { // differenceItem, const { reasonList, - commonOrderDetail, currentItem, commonSaveDiffApi, differenceItem, diff --git a/src/pages/stock/DirectVehicles/EditComfirm/components/CreatelModal.tsx b/src/pages/stock/DirectVehicles/EditComfirm/components/CreatelModal.tsx index 60bdd3c..4c1bc45 100644 --- a/src/pages/stock/DirectVehicles/EditComfirm/components/CreatelModal.tsx +++ b/src/pages/stock/DirectVehicles/EditComfirm/components/CreatelModal.tsx @@ -35,7 +35,6 @@ export default function CreateModal(props: Props) { const { visible, onCancel, fetchList, orderId } = props; const { reasonList, - commonOrderDetail, currentItem, commonSaveDiffApi, differenceItem, diff --git a/src/pages/stock/RepertoryFw/comps/QueryForm.tsx b/src/pages/stock/RepertoryFw/comps/QueryForm.tsx index a29e8d4..d566c77 100644 --- a/src/pages/stock/RepertoryFw/comps/QueryForm.tsx +++ b/src/pages/stock/RepertoryFw/comps/QueryForm.tsx @@ -220,11 +220,14 @@ export default function QueryForm({ onChange, delearData, setSearchParams, inner - onChange({ optionalTag: value })} style={{ width: 180 }}> + + + + -
+
( {text} @@ -80,6 +87,7 @@ export default function Repertory() { {record.decoratedCar === 1 && 前装车} {record.specialPriceCar === 1 && 特价车} {record.bindingTag && 绑定订单} + {record.optionalTag && 加装车} )} /> @@ -106,10 +114,18 @@ export default function Repertory() { getColumnStyle(text)} width="6%" /> getColumnStyle(text)} width="6%" /> getColumnStyle(text)} width="6%" /> - getColumnStyle(text)} width="6%" /> + getColumnStyle(text)} width="5%" /> + (text ? "是" : "否")} width="5%" /> + + (t && record.optionalTag ? () : "--")} + /> text || "--"} sorter={(a: Repertory.RepertoryItem, b: Repertory.RepertoryItem) => (a.lockedDuration || 0) - (b.lockedDuration || 0)} width="6%" /> (a.transportedNum || 0) - (b.transportedNum || 0)} render={(text) => text || "--"} width="6%" /> - + (a.dealerRetailPrice || 0) - (b.dealerRetailPrice || 0)} width="6%" /> (a.dealerRetailPrice || 0) - (b.dealerRetailPrice || 0)} width="6%" /> FinanceType[text] || ""} width="6%" /> @@ -140,6 +156,11 @@ export default function Repertory() { }} listItem={listRecord} /> + setOptionals({ visible: false, listItem: undefined })} + /> + {/* { setRecordVisible(false); }} diff --git a/src/pages/stock/RepertoryFw/interface.d.ts b/src/pages/stock/RepertoryFw/interface.d.ts index 7fb4b42..5c57f9b 100644 --- a/src/pages/stock/RepertoryFw/interface.d.ts +++ b/src/pages/stock/RepertoryFw/interface.d.ts @@ -1,4 +1,3 @@ - declare namespace Repertory { /** @@ -38,6 +37,7 @@ declare namespace Repertory { tempLocked?: number; //临时锁车标识 sold?: number; //库存状态 storageId?: number; //库房取值 + optionalTag?: boolean; // 加装车标识 } /** @@ -94,6 +94,9 @@ declare namespace Repertory { bindingTag?: number; intervalDay?: number; //启票导入间隔时长 shippingDay?: number; //发运天数 + optionalTag?: boolean; //加装车 + optionalPrice?: number; + optionalItemList?: any[] //选装项目 } /**库存列表详情 */ @@ -109,7 +112,7 @@ declare namespace Repertory { ticketPrice?: number, // 启票单价 ticketOrderNo?: string, // 启票订单号 ticketDate?: number, // 启票日期 - billEndDate?: number, //启票结束日期 + billEndDate?: number, //启票结束日期 brandName?: string, // 品牌名称 seriesName?: string, // 车系名称 specName?: string, // 车型名称 @@ -118,7 +121,7 @@ declare namespace Repertory { vin?: string, // 车架号 salesPrice?: number, // 销售价 storageName?: string, // 库位名称 - saleStatus?: number //销售状态,1可售,2不可售 + saleStatus?: number //销售状态,1可售,2不可售 materialCode?: string //物料代码 ticketDealerName?: string //启票商家 fakeRetail?: boolean // 特殊零售 diff --git a/src/pages/stock/SpecialOfferCar/SubPages/SaveData/index.tsx b/src/pages/stock/SpecialOfferCar/SubPages/SaveData/index.tsx index 315fa04..ba03a0f 100644 --- a/src/pages/stock/SpecialOfferCar/SubPages/SaveData/index.tsx +++ b/src/pages/stock/SpecialOfferCar/SubPages/SaveData/index.tsx @@ -121,6 +121,7 @@ export default function Index() { }; }) }; + setLoading(true); saveApi(param).then(e => { message.success('保存成功'); setLoading(false); diff --git a/src/pages/stock/SpecialOfferCar/index.tsx b/src/pages/stock/SpecialOfferCar/index.tsx index b1a4919..07738b1 100644 --- a/src/pages/stock/SpecialOfferCar/index.tsx +++ b/src/pages/stock/SpecialOfferCar/index.tsx @@ -9,6 +9,12 @@ import React, { useEffect, useState } from 'react'; import st from './style.less'; import moment from 'moment'; import { history } from "umi"; +import OptionalDetails from '@/pages/stock/Components/OptionalDetails'; + +interface Optionals { + visible: boolean, + listItem?: SpecialOfferCar.OptionalVo[], +} const Column = Table.Column; const Option = Select.Option; @@ -20,6 +26,7 @@ export default function Index() { const [timer, setTimer] = useState(); const [visible, setVisible] = useState(false); const [currentItem, setCurrentItem] = useState(); + const [Optionals, setOptionals] = useState({ visible: false }); /** * 条件查询 */ @@ -119,16 +126,25 @@ export default function Index() { }} className={st.table} > - - - - - - - + + + + + + + + + + + + (t && record.optionalTag ? () : "--")} + /> (

{record.startTime && moment(record.startTime).format('YYYY-MM-DD HH:mm:ss')}

@@ -183,6 +199,10 @@ export default function Index() { onCancel={() => setVisible(false)} currentItem={currentItem} /> + setOptionals({ visible: false, listItem: undefined })} + /> ); } \ No newline at end of file diff --git a/src/pages/stock/SpecialOfferCar/interface.d.ts b/src/pages/stock/SpecialOfferCar/interface.d.ts index 8afc7d7..29e5b75 100644 --- a/src/pages/stock/SpecialOfferCar/interface.d.ts +++ b/src/pages/stock/SpecialOfferCar/interface.d.ts @@ -30,7 +30,20 @@ declare namespace SpecialOfferCar { cancelTime: number, //取消时间 approveTime: number, //审批时间 image: string, - video: string + video: string, + optionalTag: boolean, //是否选装车 + dealerOptionalPrice: number, //商家加装价 + optionalItemList: OptionalVo[] //加装项目 + retailPrice: number, //商家零售价 + } + + interface OptionalVo { + vin: string, + optionalId: number, + optionalName: string, + dealerPrice: number, + factoryPrice: number, + rebatePrice: number } interface UploaderItem { diff --git a/src/pages/stock/TicketImport/api.ts b/src/pages/stock/TicketImport/api.ts index 9b7b668..ace259e 100644 --- a/src/pages/stock/TicketImport/api.ts +++ b/src/pages/stock/TicketImport/api.ts @@ -53,7 +53,7 @@ export function getTicketBrand(): http.PromiseRespA { //启票模板校验 export function getTemplateCheck(params: { brandId: number, fid: string }): http.PromiseResp { - return request.get(`${FVM_HOST}/erp/ticket/template/valid`, {params}); + return request.get(`${FVM_HOST}/erp/ticket/template/valid`, { params }); } /** @@ -74,6 +74,12 @@ export function saveCollateralApi(params: TicketImport.CollateralItem[]): http.P /** * 物料等待数据列表(选择指定客户列表) */ -export function queryPersonApi(params: { keyword?: string, current?: number, pageSize?: number }): http.PromisePageResp { +export function queryPersonApi(params: { keyword?: string, current?: number, pageSize?: number, seriesId?: number }): http.PromisePageResp { return request.get(`${FVM_HOST}/erp/ticket/waiting/material/query`, { params }); } +/** + * 查询物料选装项(加装车) + */ +export function queryOptionalListApi(params: { materialCode: string, keyword?: string }): http.PromiseResp { + return request.get(`${FVM_HOST}/erp/ticket/material/optional/item`, { params }); +} diff --git a/src/pages/stock/TicketImport/components/ComfirmOrder.tsx b/src/pages/stock/TicketImport/components/ComfirmOrder.tsx index 92388ac..0416b90 100644 --- a/src/pages/stock/TicketImport/components/ComfirmOrder.tsx +++ b/src/pages/stock/TicketImport/components/ComfirmOrder.tsx @@ -1,15 +1,37 @@ -import React, { useState } from 'react'; +import React, { useEffect, useState } from 'react'; import { Table, Card, Row, Button, message, Modal, Radio, Input, Select, Popconfirm } from 'antd'; import moment from 'moment'; import useInitial from '@/hooks/useInitail'; import { useStore } from '../index'; -import { getComfirmListApi, saveTicketApi, queryPersonApi } from '../api'; +import { getComfirmListApi, saveTicketApi, queryPersonApi, queryOptionalListApi } from '../api'; import { orderType, vehicleType, financeType } from '../entity'; import _ from 'lodash'; import usePagination from '@/hooks/usePagination'; +import { ColumnsType } from 'antd/lib/table'; +import { IMGURL } from '@/utils'; const Column = Table.Column; - +const columns: ColumnsType = [ + { + title: '加装项目', + dataIndex: 'name', + }, + { + title: '厂家加装价格(元)', + dataIndex: 'factoryPrice', + }, + { + title: "图片", + dataIndex: "image", + render: (image) => ( + <> +
+ {image && } +
+ + ) + } +]; export default function ComfirmModal() { const { ticketBatchId, setBreadcrumbs, setVisibleUpload, type, setCommonVisible, setuploadModalValue } = useStore(); const { data, loading, setData } = useInitial(getComfirmListApi, [], { ticketBatchId }, !ticketBatchId); @@ -17,12 +39,24 @@ export default function ComfirmModal() { const [visible, setVisible] = useState(false); const [editType, setEditType] = useState(); const [currentItem, setCurrentItem] = useState({}); + const [optionalList, setOptionalList] = useState([]); + const [optionalLoading, setOptionalLoading] = useState(false); /**定制人员列表 */ - const { list, errMsg, setParams } = usePagination(queryPersonApi, { pageSize: 20 }); + const { list, errMsg, innerParams, setParams } = usePagination(queryPersonApi, { pageSize: 20, optionalTag: currentItem.optionalTag }); + + useEffect(() => { + if (visible) { + setParams({ ...innerParams, optionalTag: currentItem.optionalTag, seriesId: currentItem.seriesId }, true); + } + }, [currentItem.optionalTag]); function submit() { setSaveLoading(true); - saveTicketApi(data).then(res => { + const params = data.map(d => ({ + ...d, + optionalList: d.optionalList ? d.optionalList.map((item: any) => ({ ...item, optionalId: item.id || item.optionalId, optionalName: item.name || item.optionalName })) : undefined + })); + saveTicketApi(params).then(res => { setSaveLoading(false); message.success('保存成功'); setBreadcrumbs([{ name: '列表', key: 'list' }]); @@ -39,13 +73,23 @@ export default function ComfirmModal() { setCurrentItem({ ...currentItem, ...pa }); }; + function getOptionals(materialCode: string, keyword?: string) { + setOptionalLoading(true); + materialCode && queryOptionalListApi({ materialCode, keyword }).then((res) => { + setOptionalList(res.data || []); + setOptionalLoading(false); + }).catch((err) => { + message.error(err.message); + setOptionalLoading(false); + }); + } function onSaveModal() { - if (currentItem.directSellingTag && !currentItem.memberIdCard) { - message.info("请选择指定客户后保存"); - return; - } - if (currentItem.bindingTag && !currentItem.memberIdCard) { - message.info("绑定订单需指定客户,请选择指定客户后保存", 5); + // if (currentItem.directSellingTag && !currentItem.memberIdCard) { + // message.info("请选择指定客户后保存"); + // return; + // } + if (currentItem.customTag && !currentItem.memberIdCard) { + message.info("定制车需指定客户,请选择指定客户后保存", 5); return; } const index = data.findIndex(i => i.id == currentItem.id); @@ -59,6 +103,13 @@ export default function ComfirmModal() { setParams({ keyword: val, current: 1 }, true); }, 500); + /**选择加装项目 */ + const rowSelection = { + onChange: (selectedRowKeys: React.Key[], selectedRows: TicketImport.OptionalList[]) => { + onChange({ optionalList: selectedRows }); + }, + }; + return (
- {text ? "是" : "否"}} /> - {text ? "是" : "否"}} /> - {text || '—'}} /> - {text || '—'}} /> - } /> + {text ? "是" : "否"}} /> + {text ? "是" : "否"}} /> + {text ? "是" : "否"}} /> + {text ? "是" : "否"}} /> + {text || '—'}} /> + {text || '—'}} /> + ( + + )} + />
@@ -135,51 +204,93 @@ export default function ComfirmModal() { ) : ( <> +
加装车:{currentItem.optionalTag ? "是" : "否"}
+
+
厂家直营车:
- (e.target.value ? onChange({ directSellingTag: e.target.value, bindingTag: 1 }) : onChange({ directSellingTag: e.target.value }))} value={Number(currentItem.directSellingTag)}> + (e.target.value ? onChange({ directSellingTag: e.target.value, customTag: 1 }) : onChange({ directSellingTag: e.target.value }))} value={Number(currentItem.directSellingTag)}>
-
是否绑定订单:
- onChange({ bindingTag: e.target.value })} value={Number(currentItem.bindingTag)}> +
是否定制车:
+ onChange({ customTag: e.target.value })} value={Number(currentItem.customTag)}>
- -
指定客户:
- -
+ {!!currentItem.customTag && ( + +
指定客户:
+ +
+ )} {currentItem.memberIdCard && (
身份证号:
)} + {currentItem.optionalTag && currentItem.memberIdCard ? ( + + + +
+ ) : currentItem.optionalTag && !currentItem.customTag ? ( + <> + +
选择加装车项目:
+ getOptionals(currentItem.materialCode!, v)} + /> +
+ item.id), + ...rowSelection, + }} + loading={optionalLoading} + rowKey="id" + size="small" + scroll={{ y: 500 }} + columns={columns} + dataSource={optionalList} + /> + + ) : null} )} diff --git a/src/pages/stock/TicketImport/components/TicketDetail.tsx b/src/pages/stock/TicketImport/components/TicketDetail.tsx index c85eead..6c31550 100644 --- a/src/pages/stock/TicketImport/components/TicketDetail.tsx +++ b/src/pages/stock/TicketImport/components/TicketDetail.tsx @@ -24,22 +24,29 @@ export default function TicketDetail() { pagination={paginationConfig} rowKey={(item) => `${item.id}`} dataSource={list} + scroll={{ x: 2000 }} onChange={(_pagination) => setParams({ ..._pagination }, true)} > + {orderType[text]}} /> {vehicleType[text]}} /> {financeType[text]}} /> - + {text && moment(text).format('YYYY-MM-DD') || '-'}} /> - {text && text.toFixed(2) || ' 0'}} /> + {text ? "是" : "否"}} /> + {text ? "是" : "否"}} /> + {text ? "是" : "否"}} /> + {text ? "是" : "否"}} /> + {text || '—'}} /> + {text || '—'}} />
); diff --git a/src/pages/stock/TicketImport/interface.d.ts b/src/pages/stock/TicketImport/interface.d.ts index bdf8ada..5e38cef 100644 --- a/src/pages/stock/TicketImport/interface.d.ts +++ b/src/pages/stock/TicketImport/interface.d.ts @@ -257,9 +257,20 @@ declare namespace TicketImport { bindingTag?: number, memberName?: string//指定客户 directSellingTag: boolean, // 厂家直营车标记 true 是 false 否 - memberIdCard?: string + memberIdCard?: string, + optionalTag?: boolean, + customTag?: boolean, //定制车 + optionalList?: OptionalList[], //加装项目 } + interface OptionalList { + optionalId: number; + optionalName: string; + dealerPrice: number; + factoryPrice: number; + rebatePrice: number; + image: string; + } /** * 选项 */ @@ -314,6 +325,7 @@ declare namespace TicketImport { brandName: string, seriesName: string, specName: string, - materialCode: string + materialCode: string, + optionalList?: OptionalList[], //加装项目 } } \ No newline at end of file diff --git a/src/pages/stock/TicketImport/store.ts b/src/pages/stock/TicketImport/store.ts index 1bcc306..c6911e1 100644 --- a/src/pages/stock/TicketImport/store.ts +++ b/src/pages/stock/TicketImport/store.ts @@ -45,8 +45,8 @@ export default function useStore() { useEffect(() => { if (brandId) { - setFactoryParams({ types: 10, compCategory: 1, brandId}, true); - setFinanceParams({ types: 50, compCategory: 1, brandId}, true); + setFactoryParams({ types: 10, compCategory: 1, brandId: typeof brandId === "object" ? brandId.value: brandId }, true); + setFinanceParams({ types: 50, compCategory: 1, brandId: typeof brandId === "object" ? brandId.value : brandId }, true); setDelay(false); } }, [brandId]); diff --git a/src/pages/stock/VehicleAdditional/SelelctCarTreeAuth/SelectSpec.tsx b/src/pages/stock/VehicleAdditional/SelelctCarTreeAuth/SelectSpec.tsx new file mode 100644 index 0000000..dce839d --- /dev/null +++ b/src/pages/stock/VehicleAdditional/SelelctCarTreeAuth/SelectSpec.tsx @@ -0,0 +1,63 @@ +import React, { useEffect, useState } from "react"; +import { + Table, + Select, +} from "antd"; +import { + CarOptionVo, +} from "@/pages/stock/Components/api"; +import { ColumnsType } from 'antd/lib/table'; + +interface Props { + onChange?: (pa: any) => void; + value?: any[]; + disabled?: boolean; + level?: number; //1品牌,2车系,3车型 + specList?: CarOptionVo[] +} + +interface Item { + label: string; + value: number; + key?: number; +} +const { Column } = Table; +const { Option } = Select; + +const columns: ColumnsType = [ + { + title: '车型', + dataIndex: 'name', + }, + { + title: '配置代码', + dataIndex: 'specConfigCodeList', + render: (t) => t.map((i: string, key: number) => (
{key + 1}.{i}
)) + }, +]; +export default function index({ onChange: onSelected, value, disabled, specList = [] }: Props) { + const rowSelection = { + onChange: (selectedRowKeys: React.Key[], selectedRows: CarOptionVo[]) => { + onSelected && onSelected(selectedRows); + }, + }; + + return ( + <> + item.id), + ...rowSelection, + }} + pagination={false} + // loading={} + rowKey="id" + size="small" + scroll={{ y: 500 }} + columns={columns} + dataSource={specList} + /> + + ); +} diff --git a/src/pages/stock/VehicleAdditional/SelelctCarTreeAuth/index.tsx b/src/pages/stock/VehicleAdditional/SelelctCarTreeAuth/index.tsx new file mode 100644 index 0000000..ceecda0 --- /dev/null +++ b/src/pages/stock/VehicleAdditional/SelelctCarTreeAuth/index.tsx @@ -0,0 +1,359 @@ +import React, { useEffect, useState } from "react"; +import { + Button, + Card, + Table, + Modal, + Form, + Select, + Space, + Spin, + message, +} from "antd"; +import { + CarOptionVo, + getOnsaleSeriesApi, + getOnsaleSpecApi, +} from "@/pages/stock/Components/api"; +import { PlusOutlined } from '@ant-design/icons'; +import { ColumnsType } from 'antd/lib/table'; +import SelectSpec from './SelectSpec'; + +interface Props { + onChange?: (pa: any) => void; + value?: any[]; + disabled?: boolean; + level?: number; //1品牌,2车系,3车型 + brandList?: CommonApi.OptionVO[] +} + +interface Item { + label: string; + value: number; + key?: number; +} +const { Column } = Table; +const { Option } = Select; + +const columns: ColumnsType = [ + { + title: '车型', + dataIndex: 'name', + }, + { + title: '配置代码', + dataIndex: 'specConfigCodeList', + render: (t) => t.map((i: string, key: number) => (
{key + 1}.{i}
)) + }, +]; +export default function index({ onChange, value, disabled, brandList = [] }: Props) { + const [form] = Form.useForm(); + // 控制Modal是否可见 + const [visible, setVisible] = useState(false); + // 控制是否可见车型下拉框 + const [level, setLevel] = useState(1); + //存储表格当前车系 + const [currentItem, setCurrentItem] = useState(); + //存储Modal中可选的车系 + const [series, setSeries] = useState([]); + //存储接口返回的车型 + const [specList, setSpecList] = useState([]); + //存储Modal选择的品牌和车系作为表格的数据源 + const [savaData, setSavadata] = useState([]); + // 存储已经选中的车系 + const [selectedSeries, setSelectedSeries] = useState([]); + const [fetchLoading, setFetchLoading] = useState(false); + + useEffect(() => { + if (value && value.length) { + setSelectedSeries([...value]); + setSavadata([...value]); + } + }, [value]); + + const _onOk = () => { + form + .validateFields() + .then((fileds) => { + if (level === 2) { + const { series } = fileds; + const _series = series.map((item: Item) => ({ + seriesId: item.value, + seriesName: item.label, + authType: 1, + })); + + const currentSeries = (savaData.filter((i: any) => i.brandId === currentItem.brandId)[0] || {}).children || []; + /**判断已有数据保留 */ + if (currentSeries.length) { + const selectedIds = currentSeries.map(i => i.seriesId); + let newAuthSeries: any[] = []; + _series.forEach((item: any) => { + if (selectedIds.includes(item.seriesId)) { + newAuthSeries = newAuthSeries.concat(currentSeries.filter((list: any) => list.seriesId === item.seriesId)); + } else { + newAuthSeries.push(item); + } + }); + currentItem.children = newAuthSeries; + } else { + currentItem.children = _series; + } + + const tempData = savaData.map((item: any) => (item.brandId === currentItem.brandId ? { ...currentItem, authType: series.length ? 2 : 1 } : { ...item, authType: 1 })); + setSavadata([...tempData]); + onChange && onChange(tempData); + setVisible(false); + return; + } + if (level === 3) { + const { spec } = fileds; + const _spec = spec.map((item: any) => ({ + specId: item.id, + specName: item.name, + })); + currentItem.children = _spec; + currentItem.authType = 2; + const tempData = savaData.map((item: any) => { + if (item.children) { + const newChildren = item.children.map((i: any) => (i.seriesId === currentItem.seriesId ? { ...currentItem, authType: spec.length ? 2 : 1 } : i)); + item.children = newChildren; + } + return { ...item, authType: 1 }; + }); + setSavadata([...tempData]); + onChange && onChange(tempData); + setVisible(false); + return; + } + const { brand } = fileds; + const tempArray = brand.map((item: any) => ({ + brandName: item.label, + brandId: item.value, + authType: 1, //1全部2部分 + })); + const selectedBrands: number[] = savaData.map((i: any) => i.brandId); + let newAuthCar: any[] = []; + tempArray.forEach((item: any) => { + if (selectedBrands.includes(item.brandId)) { + newAuthCar = newAuthCar.concat(savaData.filter(list => list.brandId === item.brandId)); + } else { + newAuthCar.push(item); + } + }); + setSavadata(newAuthCar); + onChange && onChange(newAuthCar); + setVisible(false); + }) + .catch((err) => console.log(err.message)); + }; + + // 选择部分车辆表格==》删除车系 + const onDelete = (record: any) => { + const _savaData = savaData.filter( + (item: any) => item.seriesId != record.seriesId + ); + const _selectedSeries = selectedSeries.filter( + (item) => item.seriesId != record.seriesId + ); + setSavadata([..._savaData]); + onChange && onChange(_savaData); + setSelectedSeries([..._selectedSeries]); + }; + + // 选择部分车辆表格==》编辑选择部分车系、车型 + const onSelectSpec = async (record: any) => { + setCurrentItem(record); + setVisible(true); + if (record.brandId) { + setLevel(2); + setFetchLoading(true); + try { + const { data } = await getOnsaleSeriesApi(record.brandId); + const selectedSeries = savaData.filter((brand: any) => brand.brandId === record.brandId)[0].children; + selectedSeries && form.setFieldValue("series", selectedSeries.map(i => ({ value: i.seriesId, label: i.seriesName }))); + setSeries(data); + setFetchLoading(false); + } catch (err: any) { + message.error(err.message); + setFetchLoading(false); + } + } + if (record.seriesId) { + setLevel(3); + setFetchLoading(true); + try { + const { data } = await getOnsaleSpecApi(record.seriesId); + record.children && form.setFieldValue("spec", record.children.map(i => ({ id: i.specId, name: i.specName }))); + setSpecList(data); + setFetchLoading(false); + } catch (err: any) { + message.error(err.message); + setFetchLoading(false); + } + } + }; + + return ( + <> + + {!disabled && ( +
+ +
+ )} + +
String(record.brandId || record.seriesId || record.specId)} + > + + { + return (text || record.specName || (record.children && record.children.length !== 0) ? ( + + {text} + + ) : ( + 全部车系 + )); + }} + /> + { + return (text || (record.children && record.children.length !== 0) ? ( + + {text} + + ) : ( + 全部车型 + )); + }} + /> + {!disabled && ( + { + return ( + + + {/* onDelete(record)} + > + + */} + + ); + }} + /> + )} +
+ + + {/* 选择品牌和车系 */} + form.submit()} + onCancel={() => { + setVisible(false); + }} + maskClosable={false} + afterClose={() => { + form.resetFields(); + setCurrentItem({}); + }} + > + +
+ {level === 1 ? ( + + + + ) : null} + + {/* 车系 */} + {level === 2 && ( + + + + )} + {level === 3 ? ( + + {/* */} + + + ) : null} +
+
+
+ + ); +} diff --git a/src/pages/stock/VehicleAdditional/api.ts b/src/pages/stock/VehicleAdditional/api.ts new file mode 100644 index 0000000..40f9914 --- /dev/null +++ b/src/pages/stock/VehicleAdditional/api.ts @@ -0,0 +1,28 @@ +import { http } from '@/typing/http'; +import request from '@/utils/request'; +import { FVM_HOST } from '@/utils/host'; + +/** + * 查询列表 + */ +export function getPageListApi(params?: AdditionalCarSpace.QueryParams): http.PromisePageResp { + return request.get(`${FVM_HOST}/erp/vehicle/optional/list`, { params }); +} + +/** + * 保存 + */ +export function saveApi(params: AdditionalCarSpace.Item): http.PromiseResp { + return request.post(`${FVM_HOST}/erp/vehicle/optional/save`, params); +} +/** 启用禁用 */ +export function changeStatusApi(params: { id: number, status: number }): http.PromiseResp { + return request.get(`${FVM_HOST}/erp/vehicle/optional/enable`, { params }); +} + +/** + * 查询库房列表 + */ +export function getDeatilListApi(params: AdditionalCarSpace.StorageParams): http.PromiseResp { + return request.get(`${FVM_HOST}/erp/vehicle/optional/Detail`, { params }); +} \ No newline at end of file diff --git a/src/pages/stock/VehicleAdditional/components/EditModal.tsx b/src/pages/stock/VehicleAdditional/components/EditModal.tsx new file mode 100644 index 0000000..5758215 --- /dev/null +++ b/src/pages/stock/VehicleAdditional/components/EditModal.tsx @@ -0,0 +1,141 @@ +import React, { useState, useEffect } from 'react'; +import '@ant-design/compatible/assets/index.css'; +import { message, Modal, Select, Form, Input, InputNumber, Radio, Button } from 'antd'; +import { saveApi } from '../api'; +import { UploadOutlined, PlusSquareOutlined } from '@ant-design/icons'; +import _ from 'lodash'; +import FeeweeUploadAttachment from '@/components/FeeweeUploadAttachment'; +import CarSelect from '../SelelctCarTreeAuth'; + +const Item = Form.Item; +const Option = Select.Option; +interface Props { + visible: boolean, + onCancel: Function, + item?: AdditionalCarSpace.Item, + brands: CommonApi.OptionVO[], + fetchList: () => any, +} + +function EditModal(props: Props) { + const { item, onCancel, fetchList, brands, visible } = props; + const [loading, setLoading] = useState(false); + const [form] = Form.useForm(); + + useEffect(() => { + if (visible && item != null) { + const a = item.optionalAuth.map((brand: any) => { + if (brand.authSeries) { + const newItem = brand.authSeries.map((child: any) => (child.authSpec ? { + ...child, brandId: undefined, children: child.authSpec.map((i: any) => ({ ...i, seriesId: undefined })), authSpec: undefined + } : child)); + return { ...brand, children: newItem, authSeries: undefined }; + } + return brand; + }); + form.setFieldsValue({ + ...item, + optionalAuth: a, + image: item.image ? [item.image] : [] + }); + } else { + form.resetFields(); + } + }, [visible]); + + function submit() { + form.validateFields().then(values => { + const params = { + id: item && item.id, + ...values, + image: values.image.join(','), + optionalAuth: values.optionalAuth.map((item: any) => { + if (item.children) { + item.authSeries = item.children.map((child: any) => (child.children ? { ...child, authSpec: child.children } : child)); + } + return item; + }) + }; + setLoading(true); + saveApi(params).then(() => { + message.success('保存成功'); + fetchList(); + onCancel(); + setLoading(false); + }).catch(e => { + setLoading(false); + message.error(e.message); + }); + }); + } + + return ( + onCancel()} + onOk={item && item.disabled ? () => onCancel() : form.submit} + confirmLoading={loading} + width="60%" + > +
+ {!item || !item.disabled ? ( + <> + + + + + + + + + + + + + + + + + + + + 无提成 + 有提成 + + + prevValues.rewardType !== curValues.rewardType} + > + {({ getFieldValue }) => { + const type = getFieldValue('rewardType'); + return type == 2 ? ( + <> + + + + + ) : null; + }} + + + ) : null} + + *点击图标展开授权详情} + > + !!i.optional)} /> + +
+
+ ); +} + +export default EditModal; \ No newline at end of file diff --git a/src/pages/stock/VehicleAdditional/index.tsx b/src/pages/stock/VehicleAdditional/index.tsx new file mode 100644 index 0000000..9130586 --- /dev/null +++ b/src/pages/stock/VehicleAdditional/index.tsx @@ -0,0 +1,126 @@ +import React, { useState } from "react"; +import { Button, Card, message, Popconfirm, Table, Select, Switch, Input } from "antd"; +import { PageHeaderWrapper } from "@ant-design/pro-layout"; +import usePagination from "@/hooks/usePagination"; +import SaveModal from "./components/EditModal"; +import { changeStatusApi, getPageListApi } from "./api"; +import useInitial from "@/hooks/useInitail"; +import { getBrandFilterApi } from "@/common/api"; +import { IMGURL } from '@/utils'; +import { debounce } from 'lodash'; + +const Column = Table.Column; + +export default function StorageList() { + const { list, paginationConfig, loading, setParams, setLoading, innerParams } = usePagination(getPageListApi, { status: 1 }); + const { data: brandList } = useInitial(getBrandFilterApi, [], {}); + const [visible, setVisible] = useState(false); + const [item, setItem] = useState(); + + /**启用禁用 */ + function handleChangeStatus(item: AdditionalCarSpace.Item) { + const pa = { + id: item.id, + status: item.status === 0 ? 1 : 0, + }; + changeStatusApi(pa) + .then((res) => { + setLoading(true); + message.success("操作成功"); + }) + .catch((e) => { + message.error(e.message); + }); + } + const _filter = debounce((value: string) => { + setParams({ keyword: value, current: 1 }, true); + }, 600); + + return ( + + +
+
+ {/* */} + _filter(e.target.value)} + /> + +
+ +
+ String(item.id)} dataSource={list} onChange={(_pagination) => setParams({ ..._pagination }, true)}> + + ( + <> +
+ +
+ + )} + /> + + + + (t == 1 ? "--" : r.rewardAmount)} /> + {/* */} + } + /> + ( + <> + handleChangeStatus(_item)}> + + + + )} + /> + ( + <> + {/* handleChangeStatus(_item)}> + + */} + + + )} + /> +
+ setParams({ ...innerParams, current: 1 }, true)} onCancel={() => setVisible(false)} /> +
+
+ ); +} diff --git a/src/pages/stock/VehicleAdditional/interface.d.ts b/src/pages/stock/VehicleAdditional/interface.d.ts new file mode 100644 index 0000000..f880245 --- /dev/null +++ b/src/pages/stock/VehicleAdditional/interface.d.ts @@ -0,0 +1,93 @@ +declare namespace AdditionalCarSpace { + + /** + * 查询参数 + */ + interface QueryParams { + current?: number, + pageSize?: number, + } + + /** + * 列表项 + */ + interface Item { + id: number; + groupId: number; + name: string; + dealerPrice: number; + factoryPrice: number; + /**返利价格 */ + rebatePrice: number; + /**内部提成方式 1无提成 2单独提成 */ + rewardType: number; + /**单独提成金额 */ + rewardAmount: number; + image: string; + status: number; + createTime: number; + optionalAuth: AuthCarItem[] + disabled?: boolean; + } + + interface AuthCarItem { + optionalId: number; + authType: number; + brandId: number; + brandName: string; + authSeries: [ + { + optionalId: number; + brandId: number; + authType: number; + seriesId: number; + seriesName: string; + authSpec: [ + { + optionalId: number; + seriesId: number; + specId: number; + specName: string + } + ] + } + ] + } + /** + * 保存参数 + */ + interface SaveParam { + id?: number, // 库位ID + name?: string, // 名称 + regionName?: string, // 地区名称 + regionBh?: string, // 地区编号 + lng?: number, // 经度 + lat?: number, // 纬度 + acreage?: number, // 面积 + parkCount?: number, // 车位数 + maxParkCount?: number, //最大车位数 + type?: number, // 库位类型1区域库3展厅库 + } + + /** + * 整车库集合 + */ + interface Storage { + storageId: number, //库房id + storageName: string, //库房名称 + type: number //1-普通库,2-门店库 + } + + interface StorageParams { + brandId?: number, // 品牌id + areaId?: number, //区域库id, + } + /** + * 选项 + */ + interface StorageVo { + id: number, + name: string, + type: number + } +} \ No newline at end of file diff --git a/src/pages/vms/VehicleMaintenance/components/EditForm.tsx b/src/pages/vms/VehicleMaintenance/components/EditForm.tsx index ef30d1d..e56b7e0 100644 --- a/src/pages/vms/VehicleMaintenance/components/EditForm.tsx +++ b/src/pages/vms/VehicleMaintenance/components/EditForm.tsx @@ -52,7 +52,7 @@ export default function GpsDeviceEditFrom() { function handleOk() { form.validateFields().then(values => { - if (!values.maintainTime) { + if (!currentListItem.vin && !values.maintainTime) { message.error("保养信息不能为空,请编辑后提交"); return; }