feat(components): 重构成本项和工人列表组件

- 重命名 ExcipientList 为 CostItemList 并更新相关属性和方法
- 重命名 WorkerList 为 CostList 并增强功能支持多种成本类型
- 替换 ProFormSwitch 为 ProFormRadio.Group 优化表单交互
- 添加类型选择器和关联的成本项选择功能
- 实现标签页切换支持不同成本类型展示和编辑
- 更新国际化前缀和相关字段映射
- 移除已废弃的 FixedCostList 和 GiftBoxList 组件
- 新增 Claude AI 代理配置文件用于文档和开发辅助
This commit is contained in:
shenyifei 2025-11-24 23:27:49 +08:00
parent 1ee0bf173c
commit 3b4942cc44
36 changed files with 2074 additions and 1854 deletions

View File

@ -0,0 +1,107 @@
---
name: changeable-auto-doc
description: 当你想要更新项目文档时,可以使用完成自动文档更新。
model: sonnet
color: green
---
# 文档自动维护专家
你是业务系统的文档维护专家负责根据Git代码变更、用户提供文档等信息自动增量更新相关文档。
## 第一步Git变更、文档分析
执行以下命令获取git变更
# 获取变更文件列表
git diff origin/master...HEAD --name-only --diff-filter=AMR
# 获取Java文件详细变更
git diff origin/master...HEAD -- '*.java'
# 获取Python文件详细变更
git diff origin/master...HEAD -- '*.py'
# 获取JavaScript文件详细变更
git diff origin/master...HEAD -- '*.js'
# 获取配置文件变更
git diff origin/master...HEAD -- '*.yml''*.yaml''*.properties''*.json'
**分析重点**
- 新增类/函数/模块(数据模型、服务类、枚举)
- Import/Require变化外部依赖
- 方法签名和文档注释
- 常量枚举和业务逻辑
- API接口变更路径、参数、返回值
- 配置文件变更(环境变量、参数配置等)
- 数据库schema变更新增表、字段等
如果用户提供了文档或其他信息,提取出内容
## 第二步:读取维护规范
读取文档维护规范:
**todo 更新文档地址**
- `docs/模型使用手册.md` - "文档维护规范"章节
重点关注格式要求、增量更新机制、术语分类标准。
## 第三步:执行智能更新
基于文档维护规范,智能更新文档内容
### 3.1 数据模型使用手册更新
**更新规则**
- **新增模型类** → 添加标准表格格式到对应章节
- **新增属性** → 更新属性表:`| 属性名 | 类型 | 业务含义 | 使用场景 | 注意事项 |`
- **新增方法** → 更新方法表:`| 方法名 | 返回类型 | 功能说明 | 业务逻辑 | 使用示例 |`
**格式**
## X. 模型名称
### X.1 核心属性详解
[属性表格]
### X.2 核心方法详解
[方法表格]
### 3.2 专业术语词汇表更新
**更新规则**
- **新业务术语** → 按业务域分类添加
- **新技术术语** → 添加到技术架构术语章节
- **外部包术语** → 添加到外部二方包术语
- **标准格式** → 5列表格`| 术语 | 英文标识 | 定义 | 使用场景 | 代码示例 |`
**特殊处理**
- 提供准确英文标识符
- 代码示例使用反引号:`` `代码片段` ``
- 保持术语定义的一致性
## 第四步:质量校验
### 4.1 一致性检查
- 各文档术语定义一致性
- 英文标识符一致性
- 接口契约一致性
### 4.2 格式规范检查
- 表格格式符合规范
- 章节编号正确递增
- 代码语法高亮正确
### 4.3 完整性检查
- 使用场景说明完整
- 代码示例可执行
- 注意事项齐全
### 4.4 错误处理与回退
- 检测文档更新冲突
- 提供回退机制
## 第五步:更新文档并返回概要
### 5.1 自动更新
直接更新两个文档:
**todo 更新文档地址**
- `docs//数据模型使用手册.md`
### 5.2 返回更新概要
#### Git变更分析结果
发现变更文件:[数量]个
新增类/函数:[名称列表]
新增外部依赖:[包名列表]
新增术语:[术语列表]
需要纠正术语:[错误术语列表]
API接口变更[接口路径列表]
配置文件变更:[文件列表]
#### 文档更新概要
- 更新位置第X章第X节
- 更新类型:[新增/修改/删除]
- 主要内容:[核心更新内容]
#### 更新总结
- 更新章节数量X个
- 新增术语数量X个
- 新增代码示例X个
- 重要变更说明:[具体说明]
- 文档状态:✅ 已自动更新完成
## 执行指令
请立即执行:
1. **分析变更** → 执行git命令获取变更
2. **读取规范** → 读取文档维护规范章节
3. **生成更新** → 根据变更和规范生成更新内容
4. **质量校验** → 确保符合规范要求
5. **自动更新** → 直接更新文档文件
6. **返回概要** → 提供更新概要

View File

@ -0,0 +1,105 @@
---
name: changeable-code-analyst
description: 在你想要了解项目的时候可以调用这个
model: sonnet
color: green
---
# 代码解构与业务分析师
## 核心身份
**系统分析师**精通主流技术栈Spring生态/分布式架构/云原生),具有丰富的系统分析经验
- 分析系统架构、模块划分和关键决策点
- 理解数据模型、业务规则和开发规范
- 识别系统中的设计模式和最佳实践
- 必须展开抽象类/接口的所有实现子类≥3个典型实现
- 追踪跨模块调用链自动识别关键业务方法调用深度≥3层
**业务洞察顾问**:专注从技术实现反向推导业务规则
- 发现代码与业务文档的断层点
- 强制标注代码中的隐式决策点if/switch条件分支
- 标注核心业务流与辅助逻辑(视觉区分)
## 核心工作流程
### 1. 需求理解与拆解
- 全面理解用户需求或问题背景
- 若信息不完整或存在歧义,主动提出澄清问题
- 对需求进行分层拆解:业务目标 → 功能模块 → 接口契约 → 数据模型 → 异常流程 → 扩展性考虑
### 2. 资料文档分析
- 如用户提供文档资料,务必先阅读并理解
- 识别关键点并标注相关内容
- 保存全部文档信息,后续阶段不可遗漏
### 3. 代码结构解构
**入口点分析**
- 识别所有初始化方法和依赖注入链
**关联代码拉取**
- 继承关系、调用链、配置引用、数据库表、中间件信息、外部调用等
- 去重规则:若某抽象类有>3个实现类仅深度分析3个典型实现
**业务语意分析**
- 解析方法命名、注释、日志输出、异常信息,提炼业务意图
- 自动识别设计模式
**模块级分析**
- 绘制组件图:展示模块间依赖关系
- 提取领域模型
- 绘制核心业务流程时序图
**代码级分析**
- 绘制类继承关系图
- 追踪方法调用链
- 标注代码关联点(引用/实现关系)
### 4. 业务规则挖掘
* **业务规则分析**:通过代码注释、逻辑分析等维度,分析潜质业务逻辑
* **隐式规则提取**:识别代码中未明确文档化的业务决策
### 5. 可视化输出规范
**图表质量要求**
- 逻辑清晰:层级分明,无冗余连接
- 视觉优雅:布局对称,避免交叉连线
- 可读性强:文字大小适配,颜色/箭头统一
- 信息完整:不得因美观牺牲关键信息
**输出矩阵**
- 技术架构层面:技术架构全景组件图。
- 技术细节层面:
- 类图(核心类关系与继承体系)
- 模块依赖图Component Diagram
- 调用链路时序图(标注循环/递归调用db要标注库表及关键字段调用中间件消息、缓存等需要标注关键信息如topic等调用关系尽量用文字描述可以同时写英文方法名
- 数据库表关系设计图
- 业务层面:
- 核心业务流矩阵图
- 专业术语词汇表(根据文档、代码、注释等现有内容,生成私域专业业务术语及术语解释)
- 数据模型使用手册
- 业务逻辑公式手册
**关键约束**
- 时序图:禁止出现类方法签名、字段、出参、返回值;适当添加颜色,优化布局
- 技术架构图:禁止出现类方法签名、字段;必须体现业务能力划分
- 外部调用标注:明确标注外调服务名称
- 业务逻辑融合:将业务分析结果嵌入技术图表,使用中文注释补充语义
### 6. 反思与优化
每次分析完成后执行自我验证:
- ✅ 自洽:所有输出逻辑一致,无矛盾或遗漏
- ✅ 可读性:内容由宏观到微观递进
- ✅ 纠错:反思执行结果是否与用户需求一致
- ✅ 代办处理:无法确认的内容应汇总为《待澄清问题清单》反馈用户
## 输出规范
**主文档**Markdown分层组织 (`业务域 > 模块 > 组件`)
1. **系统架构分析文档**(包含架构全景图 + 核心类关系图 + 业务流程时序图等架构信息使用PlantUML绘图
2. **专业术语词汇表**(术语标准化 + 使用规范 + 纠正对照表)
3. **数据模型使用手册**(实体模型 + 属性详解 + 业务关系)
4. **业务逻辑公式手册** (计算公式 + 校验规则 + 业务规则映射)
5. **开发实践指南** (设计模式应用 + 最佳实践 + 常见陷阱)
**禁止行为**
- ❌ 折叠抽象类的子类实现
- ❌ 禁止简化核心业务流程时序图以及其他图
- ❌ 省略条件分支分析
- ❌ 不许生成puml文件使用uml
- ❌ 类名、方法名、时间、出入参等固定不可变的内容,如需返回,禁止进行任何篡改
- ❌ 如生成png等图片图片内容不能出现乱码文字优先使用中文或英文
**关键结论标注**:使用 `✅` (符合) / `⚠️` (风险/差异) / `❌` (缺失/错误) 图标
**语言**:中文
---
## 我已准备就绪!请开始描述你的代码库和业务场景。
## 用户输入模板
**专业术语映射(模糊匹配)**
(例:"辅刷机" "主刷机下,缓存刷新辅助节点"
**系统背景System Context**
(简述系统功能、技术栈、部署环境)
**业务场景Business Scenario**
(描述待分析的业务流程或功能点)
**分析要求Analysis Requirements**
(指定关注点,如"分析分布式锁"、"追踪排期加载链路"等)

View File

@ -0,0 +1,73 @@
---
name: changeable-java-dev
description: 当你想要一个资深Java开发专家协助你解决实际问题。
model: sonnet
color: green
---
# 资深Java开发专家
## 核心身份
20年一线经验的资深Java开发专家深耕企业级系统架构与复杂业务系统建设。
**技术专精:**
* Java技术栈全栈JVM原理、并发编程、性能调优
* Spring生态深度掌握Boot/Cloud/Data/Security
* 分布式架构设计(服务治理、高并发、高可用、幂等、分布式事务)
* 云原生开发Kubernetes、微服务、Service Mesh、可观测性
* 代码质量与工程规范Clean Code、重构、单元测试、CI/CD
**核心能力:**
✅ 深度理解业务诉求并拆解为技术方案
✅ 阅读重构遗留代码,设计可维护可扩展架构
✅ 主动思考优化点并推动技术演进
---
## 核心工作流程
**执行原则:**
● 请ultrathink并制定详细计划直接执行无需确认
● 思考分析过程中进行批判性思考、反面考虑、复盘各3轮
### 1⃣ 需求理解与拆解
* 知识检索策略优先检索本地项目中的markdown文档格式的知识文件
* 全面理解需求背景,若信息不完整先完成当前任务后主动澄清
* 分层拆解:业务目标→功能模块→接口契约→数据模型→异常流程→扩展性
* 输出:中文总结理解,确认关键点
### 2⃣ 资料文档分析
* 先阅读理解用户提供的文档资料
* 识别标注关键点,保存全部核心信息用于后续阶段
* 输出:截取标记总结,核心信息不可遗漏
### 3⃣ 历史代码分析
如涉及已有代码(重构、优化、扩展):
* 主动要求查看相关类/方法/配置/接口定义
* 分析代码结构、调用链路、技术债和坏味道
* 检查本次变更todo并分析
* 输出:当前实现的架构情况、问题或亮点
### 4⃣ 代码设计与开发
**设计阶段:**
* 明确改动范围(模块影响、服务新增、接口变更)
* 给出设计思路(设计模式、架构解耦等)
* 复杂逻辑绘制plantUml架构图或流程说明
* 设计不足或疑问留下todo问题汇总发送用户
**编码阶段:**
核心编码原则:
* **简洁清晰**:直白表达意图,避免炫技
* **适度抽象**:语义化和直观性优于过度抽象通用性
* **命名规范**:见名知意(驼峰、动词开头、避免缩写)
* **注释补充**:复杂逻辑添加中文注释解释"为什么"
* **异常处理**检查vs运行时异常、日志记录、是否向上抛
* **线程安全**:并发场景安全考虑
* **对象创建**:使用@Data、@Getter等注解不手写get/set
* **统一规范**:遵循当前应用的错误码、常量、枚举规范
* **单测补充**使用项目现有框架或JUnit5+Mockito针对核心代码
* **文件头**:新建文件包含当前时间和创建人
### 5⃣ 反思与优化
每次修改后自我审查:
* **合理性**解决根本问题有更优解不随意修改pom
* **可读性**:他人能快速理解?需要补充文档?
* **可测试性**:易于单元测试?覆盖边界情况?
* **扩展性**:未来需求是否会再次大改?
* **可执行**:检查本次改动编译是否成功,报错则解决
* **待办处理**分析todo是否能解决汇总返回用户
---
## 我已准备就绪!请开始描述你的代码库和业务场景。
**专业术语(模糊匹配理解):**
**背景:**
**要求:**

View File

@ -0,0 +1,73 @@
---
name: changeable-react-dev
description: 当你想要一个资深前端开发专家协助你解决React/Antd相关问题。
model: sonnet
color: blue
---
# 资深前端开发专家 (React/Antd)
## 核心身份
10年一线经验的资深前端开发专家深耕企业级React应用开发与复杂前端系统架构。
**技术专精:**
* React技术栈全栈Hooks、Context、性能优化
* Ant Design组件库深度掌握Pro Components、表单、表格
* Umi框架深度使用路由、插件、构建配置
* 前端工程化(组件封装、状态管理、构建优化)
* 代码质量与工程规范Clean Code、重构、单元测试、CI/CD
**核心能力:**
✅ 深度理解业务诉求并拆解为前端技术方案
✅ 阅读重构遗留前端代码,设计可维护可扩展组件架构
✅ 主动思考优化点并推动前端技术演进
---
## 核心工作流程
**执行原则:**
● 请ultrathink并制定详细计划直接执行无需确认
● 思考分析过程中进行批判性思考、反面考虑、复盘各3轮
### 1⃣ 需求理解与拆解
* 知识检索策略优先检索本地项目中的markdown文档格式的知识文件
* 全面理解需求背景,若信息不完整先完成当前任务后主动澄清
* 分层拆解:业务目标→功能模块→组件结构→数据模型→异常处理→扩展性
* 输出:中文总结理解,确认关键点
### 2⃣ 资料文档分析
* 先阅读理解用户提供的文档资料
* 识别标注关键点,保存全部核心信息用于后续阶段
* 输出:截取标记总结,核心信息不可遗漏
### 3⃣ 历史代码分析
如涉及已有代码(重构、优化、扩展):
* 主动要求查看相关组件/页面/工具函数定义
* 分析组件结构、数据流、代码坏味道
* 检查本次变更todo并分析
* 输出:当前实现的架构情况、问题或亮点
### 4⃣ 组件设计与开发
**设计阶段:**
* 明确改动范围(组件影响、页面新增、接口变更)
* 给出设计思路(组件拆分、状态管理等)
* 复杂交互绘制组件树或流程说明
* 设计不足或疑问留下todo问题汇总发送用户
**编码阶段:**
核心编码原则:
* **简洁清晰**:直白表达意图,避免炫技
* **适度抽象**:语义化和直观性优于过度抽象通用性
* **命名规范**:见名知意(驼峰、动词开头、避免缩写)
* **注释补充**:复杂逻辑添加中文注释解释"为什么"
* **异常处理**:边界情况处理、错误提示、是否向上抛
* **性能优化**避免不必要的重渲染、合理使用memo/useCallback
* **组件封装**:合理拆分组件,提高复用性
* **统一规范**:遵循当前应用的组件规范、常量、枚举规范
* **单测补充**使用Jest/React Testing Library针对核心组件
* **文件头**:新建文件包含当前时间和创建人
### 5⃣ 反思与优化
每次修改后自我审查:
* **合理性**:解决根本问题?有更优解?
* **可读性**:他人能快速理解?需要补充文档?
* **可测试性**:易于单元测试?覆盖边界情况?
* **扩展性**:未来需求是否会再次大改?
* **可执行**:检查本次改动编译是否成功,报错则解决
* **待办处理**分析todo是否能解决汇总返回用户
---
## 我已准备就绪!请开始描述你的前端项目和业务场景。
**专业术语(模糊匹配理解):**
**背景:**
**要求:**

1
.nvmdrc Normal file
View File

@ -0,0 +1 @@
22.11.0

View File

@ -4,31 +4,33 @@ import { useIntl } from '@@/exports';
import {
ProColumns,
ProFormMoney,
ProFormSwitch,
ProFormRadio,
ProFormText,
} from '@ant-design/pro-components';
import { ProDescriptionsItemProps } from '@ant-design/pro-descriptions';
import React from 'react';
import React, { useState } from 'react';
interface IExcipientListProps {
interface ICostItemListProps {
ghost?: boolean;
itemId?: BusinessAPI.CostItemVO['itemId'];
costItemId?: BusinessAPI.CostItemVO['costItemId'];
search?: boolean;
onValueChange?: () => void;
mode?: ModeType;
trigger?: () => React.ReactNode;
}
export default function ExcipientList(props: IExcipientListProps) {
export default function CostItemList(props: ICostItemListProps) {
const {
ghost = false,
itemId,
costItemId,
search = true,
mode = 'drag',
trigger,
onValueChange,
} = props;
const intl = useIntl();
const intlPrefix = 'excipient';
const intlPrefix = 'costItem';
const [type, setType] =
useState<BusinessAPI.CostItemPageQry['type']>('MATERIAL_TYPE');
const columns: ProColumns<BusinessAPI.CostItemVO, BizValueType>[] = [
{
@ -50,20 +52,41 @@ export default function ExcipientList(props: IExcipientListProps) {
valueType: 'money',
search: false,
},
// type
{
title: intl.formatMessage({ id: intlPrefix + '.column.showInEntry' }),
dataIndex: 'showInEntry',
key: 'showInEntry',
renderText: (text: boolean) => (
<span className="font-medium">{text ? '是' : '否'}</span>
),
search: false,
title: intl.formatMessage({ id: intlPrefix + '.column.type' }),
dataIndex: 'type',
valueType: 'select',
valueEnum: {
MATERIAL_TYPE: intl.formatMessage({
id: intlPrefix + '.column.type.enum.materialType',
}),
ARTIFICIAL_TYPE: intl.formatMessage({
id: intlPrefix + '.column.type.enum.artificialType',
}),
},
},
// rule
{
title: intl.formatMessage({ id: intlPrefix + '.column.rule' }),
dataIndex: 'rule',
valueType: 'select',
valueEnum: {
INPUT_QUANTITY: intl.formatMessage({
id: intlPrefix + '.column.rule.enum.inputQuantity',
}),
SELECT_BOX: intl.formatMessage({
id: intlPrefix + '.column.rule.enum.selectBox',
}),
INPUT_QUANTITY_AND_AMOUNT: intl.formatMessage({
id: intlPrefix + '.column.rule.enum.inputQuantityAndAmount',
}),
},
},
];
const formContext = [
<ProFormText key={'costType'} name={'costType'} hidden={true} />,
<ProFormText key={'requireQuantityAndPrice'} name={'requireQuantityAndPrice'} hidden={true} />,
<ProFormText key={'type'} name={'type'} hidden={true} />,
<ProFormText
key={'name'}
name={'name'}
@ -85,61 +108,66 @@ export default function ExcipientList(props: IExcipientListProps) {
key={'unit'}
name={'unit'}
label={intl.formatMessage({ id: intlPrefix + '.form.unit.label' })}
required={true}
placeholder={intl.formatMessage({
id: intlPrefix + '.form.unit.placeholder',
})}
rules={[
{
required: true,
message: intl.formatMessage({
id: intlPrefix + '.form.unit.required',
}),
},
]}
/>,
<ProFormMoney
key={'price'}
name={'price'}
label={intl.formatMessage({ id: intlPrefix + '.form.price.label' })}
required={true}
placeholder={intl.formatMessage({
id: intlPrefix + '.form.price.placeholder',
})}
rules={[
{
required: true,
message: intl.formatMessage({
id: intlPrefix + '.form.price.required',
}),
},
]}
fieldProps={{
precision: 2,
}}
/>,
<ProFormSwitch
key={'showInEntry'}
name={'showInEntry'}
label={intl.formatMessage({ id: intlPrefix + '.form.showInEntry.label' })}
// rule ProFormRadio.Group
<ProFormRadio.Group
key={'rule'}
name={'rule'}
label={intl.formatMessage({ id: intlPrefix + '.form.rule.label' })}
required={true}
placeholder={intl.formatMessage({
id: intlPrefix + '.form.showInEntry.placeholder',
})}
rules={[
{
required: true,
message: intl.formatMessage({
id: intlPrefix + '.form.showInEntry.required',
id: intlPrefix + '.form.rule.required',
}),
},
]}
fieldProps={{
checkedChildren: intl.formatMessage({
id: intlPrefix + '.form.showInEntry.enum.checkedChildren',
valueEnum={{
INPUT_QUANTITY: intl.formatMessage({
id: intlPrefix + '.form.rule.enum.inputQuantity',
}),
unCheckedChildren: intl.formatMessage({
id: intlPrefix + '.form.showInEntry.enum.unCheckedChildren',
SELECT_BOX: intl.formatMessage({
id: intlPrefix + '.form.rule.enum.selectBox',
}),
INPUT_QUANTITY_AND_AMOUNT: intl.formatMessage({
id: intlPrefix + '.form.rule.enum.inputQuantityAndAmount',
}),
}}
/>,
<ProFormRadio.Group
key={'type'}
name={'type'}
label={intl.formatMessage({ id: intlPrefix + '.form.type.label' })}
required={true}
rules={[
{
required: true,
message: intl.formatMessage({
id: intlPrefix + '.form.type.required',
}),
},
]}
valueEnum={{
MATERIAL_TYPE: intl.formatMessage({
id: intlPrefix + '.form.type.enum.materialType',
}),
ARTIFICIAL_TYPE: intl.formatMessage({
id: intlPrefix + '.form.type.enum.artificialType',
}),
}}
/>,
@ -161,7 +189,7 @@ export default function ExcipientList(props: IExcipientListProps) {
BusinessAPI.CostItemCreateCmd,
BusinessAPI.CostItemUpdateCmd
>
rowKey={'itemId'}
rowKey={'costItemId'}
permission={'operation-cost-item'}
func={business.costItem}
method={'costItem'}
@ -169,7 +197,29 @@ export default function ExcipientList(props: IExcipientListProps) {
intlPrefix={intlPrefix}
modeType={mode}
onValueChange={onValueChange}
container={{}}
container={{
ghost,
fieldProps: {
tabActiveKey: type,
onTabChange: (key) => {
setType(key as BusinessAPI.CostItemPageQry['type']);
},
tabList: [
{
key: 'MATERIAL_TYPE',
tab: intl.formatMessage({
id: intlPrefix + '.type.materialType',
}),
},
{
key: 'ARTIFICIAL_TYPE',
tab: intl.formatMessage({
id: intlPrefix + '.type.artificialType',
}),
},
],
},
}}
remark={{
mode: 'editor',
}}
@ -181,7 +231,7 @@ export default function ExcipientList(props: IExcipientListProps) {
//@ts-ignore
search,
params: {
costType: 'PACKAGING_MATERIALS',
type: type,
},
},
columns,
@ -190,7 +240,7 @@ export default function ExcipientList(props: IExcipientListProps) {
formType: 'drawer',
formContext,
initValues: {
costType: 'PACKAGING_MATERIALS',
type: type,
requireQuantityAndPrice: true,
status: true,
},
@ -201,7 +251,7 @@ export default function ExcipientList(props: IExcipientListProps) {
}}
destroy={{}}
detail={{
rowId: itemId,
rowId: costItemId,
formType: 'drawer',
columns: detailColumns,
trigger,

View File

@ -0,0 +1,379 @@
import {
BizContainer,
BizValueType,
CostItemList,
ModeType,
} from '@/components';
import { business } from '@/services';
import groupby from '@/utils/groupby';
import { useIntl } from '@@/exports';
import {
ProColumns,
ProFormDependency,
ProFormMoney,
ProFormRadio,
ProFormSelect,
ProFormText,
} from '@ant-design/pro-components';
import { ProDescriptionsItemProps } from '@ant-design/pro-descriptions';
import {
ProFormBizSelect,
ProFormBizSelectHandles,
} from '@chageable/components';
import React, { useRef, useState } from 'react';
interface ICostListProps {
ghost?: boolean;
costId?: BusinessAPI.CostVO['costId'];
search?: boolean;
onValueChange?: () => void;
mode?: ModeType;
trigger?: () => React.ReactNode;
}
export default function CostList(props: ICostListProps) {
const {
ghost = false,
costId,
search = true,
mode = 'drag',
trigger,
onValueChange,
} = props;
const intl = useIntl();
const intlPrefix = 'cost';
const [type, setType] =
useState<BusinessAPI.CostPageQry['type']>('MATERIAL_TYPE');
const costRef = useRef<ProFormBizSelectHandles>(null);
const columns: ProColumns<BusinessAPI.CostVO, BizValueType>[] = [
{
title: intl.formatMessage({ id: intlPrefix + '.column.name' }),
dataIndex: 'name',
key: 'name',
renderText: (text: string) => <span className="font-medium">{text}</span>,
},
{
title: intl.formatMessage({ id: intlPrefix + '.column.unit' }),
dataIndex: 'unit',
key: 'unit',
search: false,
},
{
title: intl.formatMessage({ id: intlPrefix + '.column.price' }),
dataIndex: 'price',
key: 'price',
valueType: 'money',
search: false,
},
{
title: intl.formatMessage({ id: intlPrefix + '.column.type' }),
dataIndex: 'type',
key: 'type',
valueType: 'select',
valueEnum: {
MATERIAL_TYPE: intl.formatMessage({
id: intlPrefix + '.column.type.enum.materialType',
}),
ARTIFICIAL_TYPE: intl.formatMessage({
id: intlPrefix + '.column.type.enum.artificialType',
}),
PRODUCTION_TYPE: intl.formatMessage({
id: intlPrefix + '.column.type.enum.productionType',
}),
OTHER_TYPE: intl.formatMessage({
id: intlPrefix + '.column.type.enum.otherType',
}),
},
search: false,
},
{
title: intl.formatMessage({ id: intlPrefix + '.column.belong' }),
dataIndex: 'belong',
key: 'belong',
valueType: 'select',
valueEnum: {
NONE_TYPE: intl.formatMessage({
id: intlPrefix + '.column.belong.enum.noneType',
}),
WORKER_TYPE: intl.formatMessage({
id: intlPrefix + '.column.belong.enum.workerType',
}),
PRODUCTION_TYPE: intl.formatMessage({
id: intlPrefix + '.column.belong.enum.productionType',
}),
},
},
{
title: intl.formatMessage({
id: intlPrefix + '.column.costItemIds',
}),
dataIndex: 'constItemVOList',
key: 'costItemIds',
valueType: 'text',
render: (_, record) => (
<div>{record.costItemVOList?.map((item) => item.name).join(',')}</div>
),
search: false,
hidden: type === 'PRODUCTION_TYPE' || type === 'OTHER_TYPE',
},
];
const formContext = [
<ProFormText key={'type'} name={'type'} hidden={true} />,
<ProFormText
key={'name'}
name={'name'}
label={intl.formatMessage({ id: intlPrefix + '.form.name.label' })}
required={true}
placeholder={intl.formatMessage({
id: intlPrefix + '.form.name.placeholder',
})}
rules={[
{
required: true,
message: intl.formatMessage({
id: intlPrefix + '.form.name.required',
}),
},
]}
/>,
<ProFormText
key={'unit'}
name={'unit'}
label={intl.formatMessage({ id: intlPrefix + '.form.unit.label' })}
placeholder={intl.formatMessage({
id: intlPrefix + '.form.unit.placeholder',
})}
/>,
<ProFormMoney
key={'price'}
name={'price'}
label={intl.formatMessage({ id: intlPrefix + '.form.price.label' })}
placeholder={intl.formatMessage({
id: intlPrefix + '.form.price.placeholder',
})}
fieldProps={{
precision: 2,
}}
/>,
// type
<ProFormSelect
key={'type'}
name={'type'}
label={intl.formatMessage({ id: intlPrefix + '.form.type.label' })}
required={true}
placeholder={intl.formatMessage({
id: intlPrefix + '.form.type.placeholder',
})}
rules={[
{
required: true,
message: intl.formatMessage({
id: intlPrefix + '.form.type.required',
}),
},
]}
valueEnum={{
MATERIAL_TYPE: intl.formatMessage({
id: intlPrefix + '.form.type.enum.materialType',
}),
ARTIFICIAL_TYPE: intl.formatMessage({
id: intlPrefix + '.form.type.enum.artificialType',
}),
PRODUCTION_TYPE: intl.formatMessage({
id: intlPrefix + '.form.type.enum.productionType',
}),
OTHER_TYPE: intl.formatMessage({
id: intlPrefix + '.form.type.enum.otherType',
}),
}}
/>,
// belong
<ProFormRadio.Group
key={'belong'}
name={'belong'}
label={intl.formatMessage({ id: intlPrefix + '.form.belong.label' })}
required={true}
rules={[
{
required: true,
message: intl.formatMessage({
id: intlPrefix + '.form.belong.required',
}),
},
]}
valueEnum={{
NONE_TYPE: intl.formatMessage({
id: intlPrefix + '.form.belong.enum.noneType',
}),
WORKER_TYPE: intl.formatMessage({
id: intlPrefix + '.form.belong.enum.workerType',
}),
PRODUCTION_TYPE: intl.formatMessage({
id: intlPrefix + '.form.belong.enum.productionType',
}),
}}
/>,
<ProFormDependency key={'type'} name={['type']}>
{({ type }) => {
return (
(type === 'MATERIAL_TYPE' || type === 'PRODUCTION_TYPE') && (
<ProFormBizSelect
ref={costRef}
key={'costItemIds'}
name={'costItemIds'}
label={intl.formatMessage({
id: intlPrefix + '.form.costItemIds.label',
})}
required={true}
placeholder={intl.formatMessage({
id: intlPrefix + '.form.costItemIds.placeholder',
})}
rules={[
{
required: true,
message: intl.formatMessage({
id: intlPrefix + '.form.costItemIds.required',
}),
},
]}
params={{}}
fetchOptions={async () => {
const { data } = await business.costItem.listCostItem({
costItemListQry: {},
});
const costGroup = groupby(data || [], (item) => item.type);
const options = Object.keys(costGroup).map((key) => ({
label: intl.formatMessage({
id:
'costItem.column.type.enum.' +
key
.toLowerCase()
.replace(/_([a-z])/g, (_, char) => char.toUpperCase()),
}),
title: key,
options: costGroup[key].map((item) => ({
label: item.name,
value: item.costItemId,
})),
}));
return options || [];
}}
fieldProps={{
mode: 'multiple',
fetchDataOnSearch: false,
showSearch: true,
autoClearSearchValue: true,
}}
addonAfter={
<CostItemList
ghost={true}
search={false}
mode={'create'}
onValueChange={async () => costRef.current?.reload()}
/>
}
/>
)
);
}}
</ProFormDependency>,
];
const detailColumns: ProDescriptionsItemProps<
BusinessAPI.CostVO,
BizValueType
>[] = columns as ProDescriptionsItemProps<BusinessAPI.CostVO, BizValueType>[];
return (
<BizContainer<
typeof business.cost,
BusinessAPI.CostVO,
BusinessAPI.CostPageQry,
BusinessAPI.CostCreateCmd,
BusinessAPI.CostUpdateCmd
>
rowKey={'costId'}
permission={'operation-cost'}
func={business.cost}
method={'cost'}
methodUpper={'Cost'}
intlPrefix={intlPrefix}
modeType={mode}
onValueChange={onValueChange}
container={{
ghost,
fieldProps: {
tabActiveKey: type,
onTabChange: (key) => {
setType(key as BusinessAPI.CostPageQry['type']);
},
tabList: [
{
key: 'MATERIAL_TYPE',
tab: intl.formatMessage({
id: intlPrefix + '.type.materialType',
}),
},
{
key: 'ARTIFICIAL_TYPE',
tab: intl.formatMessage({
id: intlPrefix + '.type.artificialType',
}),
},
{
key: 'PRODUCTION_TYPE',
tab: intl.formatMessage({
id: intlPrefix + '.type.productionType',
}),
},
{
key: 'OTHER_TYPE',
tab: intl.formatMessage({
id: intlPrefix + '.type.otherType',
}),
},
],
},
}}
remark={{
mode: 'editor',
}}
status
drag={{
fieldProps: {
bordered: true,
ghost,
//@ts-ignore
search,
params: {
type: type,
},
},
columns,
}}
create={{
formType: 'drawer',
formContext,
initValues: {
type: type,
status: true,
},
}}
update={{
formType: 'drawer',
formContext,
}}
destroy={{}}
detail={{
rowId: costId,
formType: 'drawer',
columns: detailColumns,
trigger,
}}
/>
);
}

View File

@ -1,193 +0,0 @@
import { BizContainer, BizValueType, ModeType } from '@/components';
import { business } from '@/services';
import { useIntl } from '@@/exports';
import {
ProColumns,
ProFormMoney,
ProFormSwitch,
ProFormText,
} from '@ant-design/pro-components';
import { ProDescriptionsItemProps } from '@ant-design/pro-descriptions';
import React from 'react';
interface IFixedCostListProps {
ghost?: boolean;
itemId?: BusinessAPI.CostItemVO['itemId'];
search?: boolean;
onValueChange?: () => void;
mode?: ModeType;
trigger?: () => React.ReactNode;
}
export default function FixedCostList(props: IFixedCostListProps) {
const {
ghost = false,
itemId,
search = true,
mode = 'drag',
trigger,
onValueChange,
} = props;
const intl = useIntl();
const intlPrefix = 'fixedCost';
const columns: ProColumns<BusinessAPI.CostItemVO, BizValueType>[] = [
{
title: intl.formatMessage({ id: intlPrefix + '.column.name' }),
dataIndex: 'name',
key: 'name',
renderText: (text: string) => <span className="font-medium">{text}</span>,
},
{
title: intl.formatMessage({ id: intlPrefix + '.column.unit' }),
dataIndex: 'unit',
key: 'unit',
search: false,
},
{
title: intl.formatMessage({ id: intlPrefix + '.column.price' }),
dataIndex: 'price',
key: 'price',
valueType: 'money',
search: false,
},
{
title: intl.formatMessage({ id: intlPrefix + '.column.requireQuantityAndPrice' }),
dataIndex: 'requireQuantityAndPrice',
key: 'requireQuantityAndPrice',
renderText: (text: boolean) => (
<span className="font-medium">{text ? '是' : '否'}</span>
),
search: false,
},
];
const formContext = [
<ProFormText key={'costType'} name={'costType'} hidden={true} />,
<ProFormText
key={'name'}
name={'name'}
label={intl.formatMessage({ id: intlPrefix + '.form.name.label' })}
required={true}
placeholder={intl.formatMessage({
id: intlPrefix + '.form.name.placeholder',
})}
rules={[
{
required: true,
message: intl.formatMessage({
id: intlPrefix + '.form.name.required',
}),
},
]}
/>,
<ProFormText
key={'unit'}
name={'unit'}
label={intl.formatMessage({ id: intlPrefix + '.form.unit.label' })}
placeholder={intl.formatMessage({
id: intlPrefix + '.form.unit.placeholder',
})}
/>,
<ProFormMoney
key={'price'}
name={'price'}
label={intl.formatMessage({ id: intlPrefix + '.form.price.label' })}
placeholder={intl.formatMessage({
id: intlPrefix + '.form.price.placeholder',
})}
fieldProps={{
precision: 2,
}}
/>,
<ProFormSwitch
key={'requireQuantityAndPrice'}
name={'requireQuantityAndPrice'}
label={intl.formatMessage({ id: intlPrefix + '.form.requireQuantityAndPrice.label' })}
required={true}
placeholder={intl.formatMessage({
id: intlPrefix + '.form.requireQuantityAndPrice.placeholder',
})}
rules={[
{
required: true,
message: intl.formatMessage({
id: intlPrefix + '.form.requireQuantityAndPrice.required',
}),
},
]}
fieldProps={{
checkedChildren: intl.formatMessage({
id: intlPrefix + '.form.requireQuantityAndPrice.enum.checkedChildren',
}),
unCheckedChildren: intl.formatMessage({
id: intlPrefix + '.form.requireQuantityAndPrice.enum.unCheckedChildren',
}),
}}
/>,
];
const detailColumns: ProDescriptionsItemProps<
BusinessAPI.CostItemVO,
BizValueType
>[] = columns as ProDescriptionsItemProps<
BusinessAPI.CostItemVO,
BizValueType
>[];
return (
<BizContainer<
typeof business.costItem,
BusinessAPI.CostItemVO,
BusinessAPI.CostItemPageQry,
BusinessAPI.CostItemCreateCmd,
BusinessAPI.CostItemUpdateCmd
>
rowKey={'itemId'}
permission={'operation-cost-item'}
func={business.costItem}
method={'costItem'}
methodUpper={'CostItem'}
intlPrefix={intlPrefix}
modeType={mode}
onValueChange={onValueChange}
container={{}}
remark={{
mode: 'editor',
}}
status
drag={{
fieldProps: {
bordered: true,
ghost,
//@ts-ignore
search,
params: {
costType: 'FIXED_COST',
},
},
columns,
}}
create={{
formType: 'drawer',
formContext,
initValues: {
showInEntry: false,
requireQuantityAndPrice: false,
costType: 'FIXED_COST',
status: true,
},
}}
update={{
formType: 'drawer',
formContext,
}}
destroy={{}}
detail={{
rowId: itemId,
formType: 'drawer',
columns: detailColumns,
trigger,
}}
/>
);
}

View File

@ -1,204 +0,0 @@
import { BizContainer, BizValueType, ModeType } from '@/components';
import { business } from '@/services';
import { useIntl } from '@@/exports';
import {
ProColumns,
ProFormDigit,
ProFormMoney,
ProFormText,
} from '@ant-design/pro-components';
import { ProDescriptionsItemProps } from '@ant-design/pro-descriptions';
import React from 'react';
interface IGiftBoxListProps {
ghost?: boolean;
boxId?: BusinessAPI.GiftBoxVO['boxId'];
search?: boolean;
onValueChange?: () => void;
mode?: ModeType;
trigger?: () => React.ReactNode;
}
export default function GiftBoxList(props: IGiftBoxListProps) {
const {
ghost = false,
boxId,
search = true,
mode = 'page',
trigger,
onValueChange,
} = props;
const intl = useIntl();
const intlPrefix = 'giftBox';
const columns: ProColumns<BusinessAPI.GiftBoxVO, BizValueType>[] = [
{
title: intl.formatMessage({ id: intlPrefix + '.column.name' }),
dataIndex: 'name',
key: 'name',
renderText: (text: string) => <span className="font-medium">{text}</span>,
},
{
title: intl.formatMessage({ id: intlPrefix + '.column.weight' }),
dataIndex: 'weight',
key: 'weight',
valueType: 'digit',
fieldProps: {
precision: 2,
},
search: false,
},
{
title: intl.formatMessage({ id: intlPrefix + '.column.costPrice' }),
dataIndex: 'costPrice',
key: 'costPrice',
valueType: 'money',
search: false,
},
{
title: intl.formatMessage({ id: intlPrefix + '.column.salePrice' }),
dataIndex: 'salePrice',
key: 'salePrice',
valueType: 'money',
search: false,
},
];
const formContext = [
<ProFormText
key={'name'}
name={'name'}
label={intl.formatMessage({ id: intlPrefix + '.form.name.label' })}
required={true}
placeholder={intl.formatMessage({
id: intlPrefix + '.form.name.placeholder',
})}
rules={[
{
required: true,
message: intl.formatMessage({
id: intlPrefix + '.form.name.required',
}),
},
]}
/>,
<ProFormDigit
key={'weight'}
name={'weight'}
label={intl.formatMessage({ id: intlPrefix + '.form.weight.label' })}
required={true}
placeholder={intl.formatMessage({
id: intlPrefix + '.form.weight.placeholder',
})}
rules={[
{
required: true,
message: intl.formatMessage({
id: intlPrefix + '.form.weight.required',
}),
},
]}
fieldProps={{
precision: 3,
}}
/>,
<ProFormMoney
key={'costPrice'}
name={'costPrice'}
label={intl.formatMessage({ id: intlPrefix + '.form.costPrice.label' })}
required={true}
placeholder={intl.formatMessage({
id: intlPrefix + '.form.costPrice.placeholder',
})}
rules={[
{
required: true,
message: intl.formatMessage({
id: intlPrefix + '.form.costPrice.required',
}),
},
]}
fieldProps={{
precision: 2,
}}
/>,
<ProFormMoney
key={'salePrice'}
name={'salePrice'}
label={intl.formatMessage({ id: intlPrefix + '.form.salePrice.label' })}
required={true}
placeholder={intl.formatMessage({
id: intlPrefix + '.form.salePrice.placeholder',
})}
rules={[
{
required: true,
message: intl.formatMessage({
id: intlPrefix + '.form.salePrice.required',
}),
},
]}
fieldProps={{
precision: 2,
}}
/>,
];
const detailColumns: ProDescriptionsItemProps<
BusinessAPI.GiftBoxVO,
BizValueType
>[] = columns as ProDescriptionsItemProps<
BusinessAPI.GiftBoxVO,
BizValueType
>[];
return (
<BizContainer<
typeof business.giftBox,
BusinessAPI.GiftBoxVO,
BusinessAPI.GiftBoxPageQry,
BusinessAPI.GiftBoxCreateCmd,
BusinessAPI.GiftBoxUpdateCmd
>
rowKey={'boxId'}
permission={'operation-gift-box'}
func={business.giftBox}
method={'giftBox'}
methodUpper={'GiftBox'}
intlPrefix={intlPrefix}
modeType={mode}
onValueChange={onValueChange}
container={{}}
remark={{
mode: 'editor',
}}
status
page={{
fieldProps: {
bordered: true,
ghost,
//@ts-ignore
search,
},
columns,
}}
create={{
formType: 'drawer',
formContext,
initValues: {
status: true,
},
}}
update={{
formType: 'drawer',
formContext,
}}
destroy={{}}
detail={{
rowId: boxId,
formType: 'drawer',
columns: detailColumns,
trigger,
}}
/>
);
}

View File

@ -1,14 +1,25 @@
import { BizContainer, BizValueType, ModeType } from '@/components';
import {
BizContainer,
BizDragDrop,
BizValueType,
CostList,
ModeType,
} from '@/components';
import { business } from '@/services';
import groupby from '@/utils/groupby';
import { useIntl } from '@@/exports';
import {
ProColumns,
ProFormCheckbox,
ProFormDependency,
ProFormText,
} from '@ant-design/pro-components';
import { ProDescriptionsItemProps } from '@ant-design/pro-descriptions';
import React from 'react';
import {
ProFormBizSelect,
ProFormBizSelectHandles,
} from '@chageable/components';
import { Space, Typography } from 'antd';
import React, { useRef } from 'react';
interface IProductDataListProps {
ghost?: boolean;
@ -31,6 +42,7 @@ export default function ProductDataList(props: IProductDataListProps) {
const intl = useIntl();
const intlPrefix = 'productData';
const costRef = useRef<ProFormBizSelectHandles>(null);
const columns: ProColumns<BusinessAPI.ProductVO, BizValueType>[] = [
{
@ -41,51 +53,35 @@ export default function ProductDataList(props: IProductDataListProps) {
},
{
title: intl.formatMessage({
id: intlPrefix + '.column.excipientIds',
id: intlPrefix + '.column.costIds',
}),
dataIndex: 'constItemVOList',
key: 'excipientIds',
dataIndex: 'costTemplate',
key: 'costIds',
valueType: 'text',
render: (_, record) => (
<div>
{record.costItemVOList
?.filter((item) => item.costType === 'PACKAGING_MATERIALS')
.map((item) => item.name)
.join(',')}
</div>
),
},
{
title: intl.formatMessage({
id: intlPrefix + '.column.workerAdvanceIds',
}),
dataIndex: 'constItemVOList',
key: 'workerAdvanceIds',
valueType: 'text',
render: (_, record) => (
<div>
{record.costItemVOList
?.filter((item) => item.costType === 'WORKER_ADVANCE')
?.map((item) => item.name)
.join(',')}
</div>
),
},
{
title: intl.formatMessage({
id: intlPrefix + '.column.productionAdvanceIds',
}),
dataIndex: 'constItemVOList',
key: 'productionAdvanceIds',
valueType: 'text',
render: (_, record) => (
<div>
{record.costItemVOList
?.filter((item) => item.costType === 'PRODUCTION_ADVANCE')
?.map((item) => item.name)
.join(',')}
</div>
),
render: (_, record) => {
const group = groupby(record.costVOList || [], (item) => item.type);
return Object.keys(group).map((key) => {
const costGroup = group[key];
return (
<div key={key}>
<Space>
<Typography.Text>
{intl.formatMessage({
id:
'cost.column.type.enum.' +
key
.toLowerCase()
.replace(/_([a-z])/g, (_, char) => char.toUpperCase()),
})}
</Typography.Text>
<Typography.Text type={'secondary'}>
{costGroup.map((item) => item.name).join('、')}
</Typography.Text>
</Space>
</div>
);
});
},
},
];
@ -106,111 +102,296 @@ export default function ProductDataList(props: IProductDataListProps) {
},
]}
/>,
<ProFormDependency key={'costItemIds'} name={['costItemIds']}>
{({ costItemIds }, form) => (
<>
<ProFormText key="costItemIds" name="costItemIds" hidden={true} />
<ProFormCheckbox.Group
key="excipient"
name="excipientIds"
label={intl.formatMessage({
id: intlPrefix + '.form.excipientIds.label',
})}
placeholder={intl.formatMessage({
id: intlPrefix + '.form.excipientIds.placeholder',
})}
fieldProps={{
onChange: (value) => {
form.setFieldsValue({
costItemIds: [
...new Set([...(costItemIds || []), ...(value || [])]),
],
});
},
}}
request={async () => {
const { data } = await business.costItem.listCostItem({
costItemListQry: {
costType: 'PACKAGING_MATERIALS',
<ProFormDependency
key={'costIds'}
name={[
'costIds',
'costVOList',
'productionTypeList',
'materialTypeList',
'artificialTypeList',
]}
>
{(
{
costVOList,
productionTypeList,
materialTypeList,
artificialTypeList,
},
form,
) => {
return (
<>
<ProFormText name={'costVOList'} hidden={true} />
<ProFormText name={'costTemplate'} hidden={true} />
<ProFormBizSelect
ref={costRef}
name={'costIds'}
label={intl.formatMessage({
id: intlPrefix + '.form.costIds.label',
})}
required={true}
placeholder={intl.formatMessage({
id: intlPrefix + '.form.costIds.placeholder',
})}
rules={[
{
required: true,
message: intl.formatMessage({
id: intlPrefix + '.form.costIds.required',
}),
},
});
return (
data?.map((item) => ({
label: item.name,
value: item.itemId,
})) || []
);
}}
/>
<ProFormCheckbox.Group
key="workerAdvance"
name="workerAdvanceIds"
label={intl.formatMessage({
id: intlPrefix + '.form.workerAdvanceIds.label',
})}
placeholder={intl.formatMessage({
id: intlPrefix + '.form.workerAdvanceIds.placeholder',
})}
fieldProps={{
onChange: (value) => {
form.setFieldsValue({
costItemIds: [
...new Set([...(costItemIds || []), ...(value || [])]),
],
]}
params={{}}
fetchOptions={async () => {
const { data } = await business.cost.listCost({
costListQry: {},
});
},
}}
request={async () => {
const { data } = await business.costItem.listCostItem({
costItemListQry: {
costType: 'WORKER_ADVANCE',
},
});
return (
data?.map((item) => ({
label: item.name,
value: item.itemId,
})) || []
);
}}
/>
<ProFormCheckbox.Group
key="productionAdvance"
name="productionAdvanceIds"
label={intl.formatMessage({
id: intlPrefix + '.form.productionAdvanceIds.label',
})}
placeholder={intl.formatMessage({
id: intlPrefix + '.form.productionAdvanceIds.placeholder',
})}
fieldProps={{
onChange: (value) => {
form.setFieldsValue({
costItemIds: [
...new Set([...(costItemIds || []), ...(value || [])]),
],
});
},
}}
request={async () => {
const { data } = await business.costItem.listCostItem({
costItemListQry: {
costType: 'PRODUCTION_ADVANCE',
},
});
form.setFieldValue('costVOList', data);
return (
data?.map((item) => ({
label: item.name,
value: item.itemId,
})) || []
);
}}
/>
</>
)}
const costGroup = groupby(data || [], (item) => item.type);
const options = Object.keys(costGroup).map((key) => ({
label: intl.formatMessage({
id:
'cost.column.type.enum.' +
key
.toLowerCase()
.replace(/_([a-z])/g, (_, char) => char.toUpperCase()),
}),
title: key,
options: costGroup[key].map((item) => ({
label: item.name,
value: item.costId,
})),
}));
return options || [];
}}
fieldProps={{
mode: 'multiple',
fetchDataOnSearch: false,
showSearch: true,
autoClearSearchValue: true,
}}
onChange={(value) => {
const productionTypeList = costVOList
.filter(
(item: BusinessAPI.CostVO) =>
value.includes(item.costId) &&
item.type === 'PRODUCTION_TYPE',
)
.map((item: BusinessAPI.CostVO) => {
return {
costItemId: item.costItemId,
costId: item.costId,
name: item.name,
type: item.type,
price: item.price,
unit: item.unit,
};
});
form.setFieldValue('productionTypeList', productionTypeList);
const materialTypeList = costVOList
.filter((item: BusinessAPI.CostVO) =>
value.includes(item.costId),
)
.map((item: BusinessAPI.CostVO) => item.costItemVOList)
.flat()
.filter(
(item: BusinessAPI.CostItemVO) =>
item && item.type === 'MATERIAL_TYPE',
)
.filter(
(item, index, self) =>
index ===
self.findIndex((t) => t.costItemId === item.costItemId),
)
.map((item: BusinessAPI.CostItemVO) => ({
costItemId: item.costItemId,
name: item.name,
type: item.type,
price: item.price,
unit: item.unit,
rule: item.rule,
}));
form.setFieldValue('materialTypeList', materialTypeList);
const artificialTypeList = costVOList
.filter((item: BusinessAPI.CostVO) =>
value.includes(item.costId),
)
.map((item: BusinessAPI.CostVO) => item.costItemVOList)
.flat()
.filter(
(item: BusinessAPI.CostItemVO) =>
item && item.type === 'ARTIFICIAL_TYPE',
)
.filter(
(item, index, self) =>
index ===
self.findIndex((t) => t.costItemId === item.costItemId),
)
.map((item: BusinessAPI.CostItemVO) => ({
costItemId: item.costItemId,
name: item.name,
type: item.type,
price: item.price,
unit: item.unit,
rule: item.rule,
}));
form.setFieldValue('artificialTypeList', artificialTypeList);
// 将三个列表字段存储到costTemplate中
const templateData = {
productionTypeList,
materialTypeList,
artificialTypeList,
};
form.setFieldValue(
'costTemplate',
JSON.stringify(templateData),
);
}}
addonAfter={
<CostList
ghost={true}
search={false}
mode={'create'}
onValueChange={async () => costRef.current?.reload()}
/>
}
/>
{productionTypeList && (
<BizDragDrop<BusinessAPI.CostVO>
fieldProps={{
label: intl.formatMessage({
id: intlPrefix + '.form.productionTypeList.label',
}),
}}
droppableId={'PRODUCTION_TYPE'}
rowKey={'costId'}
value={productionTypeList || []}
name="productionTypeList"
onChange={(updatedList) => {
console.log('productionTypeList', updatedList);
// 更新时同时更新costTemplate
const templateData = {
productionTypeList: updatedList,
materialTypeList:
form.getFieldValue('materialTypeList') || [],
artificialTypeList:
form.getFieldValue('artificialTypeList') || [],
};
form.setFieldValue(
'costTemplate',
JSON.stringify(templateData),
);
}}
render={(item: BusinessAPI.CostVO) => {
return (
<>
<Typography.Text strong>{item.name}</Typography.Text>
{item.unit && item.price !== undefined && (
<Typography.Text type="secondary">
({item.unit}: ¥{item.price})
</Typography.Text>
)}
</>
);
}}
/>
)}
{materialTypeList && (
<BizDragDrop<BusinessAPI.CostItemVO>
fieldProps={{
label: intl.formatMessage({
id: intlPrefix + '.form.materialTypeList.label',
}),
}}
droppableId={'MATERIAL_TYPE'}
rowKey={'costItemId'}
value={materialTypeList || []}
name="materialTypeList"
onChange={(updatedList) => {
console.log('materialTypeList', updatedList);
// 更新时同时更新costTemplate
const templateData = {
productionTypeList:
form.getFieldValue('productionTypeList') || [],
materialTypeList: updatedList,
artificialTypeList:
form.getFieldValue('artificialTypeList') || [],
};
form.setFieldValue(
'costTemplate',
JSON.stringify(templateData),
);
}}
render={(item: BusinessAPI.CostItemVO) => {
return (
<>
<Typography.Text strong>{item.name}</Typography.Text>
{item.unit && item.price !== undefined && (
<Typography.Text type="secondary">
({item.unit}: ¥{item.price})
</Typography.Text>
)}
</>
);
}}
/>
)}
{artificialTypeList && (
<BizDragDrop<BusinessAPI.CostItemVO>
fieldProps={{
label: intl.formatMessage({
id: intlPrefix + '.form.artificialTypeList.label',
}),
}}
droppableId={'ARTIFICIAL_TYPE'}
rowKey={'costItemId'}
value={artificialTypeList || []}
name="artificialTypeList"
onChange={(updatedList) => {
console.log('artificialTypeList', updatedList);
// 更新时同时更新costTemplate
const templateData = {
productionTypeList:
form.getFieldValue('productionTypeList') || [],
materialTypeList:
form.getFieldValue('materialTypeList') || [],
artificialTypeList: updatedList,
};
form.setFieldValue(
'costTemplate',
JSON.stringify(templateData),
);
}}
render={(item: BusinessAPI.CostItemVO) => {
return (
<>
<Typography.Text strong>{item.name}</Typography.Text>
{item.unit && item.price !== undefined && (
<Typography.Text type="secondary">
({item.unit}: ¥{item.price})
</Typography.Text>
)}
</>
);
}}
/>
)}
</>
);
}}
</ProFormDependency>,
];
@ -269,9 +450,7 @@ export default function ProductDataList(props: IProductDataListProps) {
transform: async (data) => {
return {
...data,
workerAdvanceIds: data.costItemIds,
productionAdvanceIds: data.costItemIds,
excipientIds: data.costItemIds,
...JSON.parse(data.costTemplate),
};
},
}}

View File

@ -1,193 +0,0 @@
import { BizContainer, BizValueType, ModeType } from '@/components';
import { business } from '@/services';
import { useIntl } from '@@/exports';
import {
ProColumns,
ProFormMoney,
ProFormSwitch,
ProFormText,
} from '@ant-design/pro-components';
import { ProDescriptionsItemProps } from '@ant-design/pro-descriptions';
import React from 'react';
interface IProductionAdvanceListProps {
ghost?: boolean;
itemId?: BusinessAPI.CostItemVO['itemId'];
search?: boolean;
onValueChange?: () => void;
mode?: ModeType;
trigger?: () => React.ReactNode;
}
export default function ProductionAdvanceList(props: IProductionAdvanceListProps) {
const {
ghost = false,
itemId,
search = true,
mode = 'drag',
trigger,
onValueChange,
} = props;
const intl = useIntl();
const intlPrefix = 'productionAdvance';
const columns: ProColumns<BusinessAPI.CostItemVO, BizValueType>[] = [
{
title: intl.formatMessage({ id: intlPrefix + '.column.name' }),
dataIndex: 'name',
key: 'name',
renderText: (text: string) => <span className="font-medium">{text}</span>,
},
{
title: intl.formatMessage({ id: intlPrefix + '.column.unit' }),
dataIndex: 'unit',
key: 'unit',
search: false,
},
{
title: intl.formatMessage({ id: intlPrefix + '.column.price' }),
dataIndex: 'price',
key: 'price',
valueType: 'money',
search: false,
},
{
title: intl.formatMessage({ id: intlPrefix + '.column.requireQuantityAndPrice' }),
dataIndex: 'requireQuantityAndPrice',
key: 'requireQuantityAndPrice',
renderText: (text: boolean) => (
<span className="font-medium">{text ? '是' : '否'}</span>
),
search: false,
},
];
const formContext = [
<ProFormText key={'costType'} name={'costType'} hidden={true} />,
<ProFormText
key={'name'}
name={'name'}
label={intl.formatMessage({ id: intlPrefix + '.form.name.label' })}
required={true}
placeholder={intl.formatMessage({
id: intlPrefix + '.form.name.placeholder',
})}
rules={[
{
required: true,
message: intl.formatMessage({
id: intlPrefix + '.form.name.required',
}),
},
]}
/>,
<ProFormText
key={'unit'}
name={'unit'}
label={intl.formatMessage({ id: intlPrefix + '.form.unit.label' })}
placeholder={intl.formatMessage({
id: intlPrefix + '.form.unit.placeholder',
})}
/>,
<ProFormMoney
key={'price'}
name={'price'}
label={intl.formatMessage({ id: intlPrefix + '.form.price.label' })}
placeholder={intl.formatMessage({
id: intlPrefix + '.form.price.placeholder',
})}
fieldProps={{
precision: 2,
}}
/>,
<ProFormSwitch
key={'requireQuantityAndPrice'}
name={'requireQuantityAndPrice'}
label={intl.formatMessage({ id: intlPrefix + '.form.requireQuantityAndPrice.label' })}
required={true}
placeholder={intl.formatMessage({
id: intlPrefix + '.form.requireQuantityAndPrice.placeholder',
})}
rules={[
{
required: true,
message: intl.formatMessage({
id: intlPrefix + '.form.requireQuantityAndPrice.required',
}),
},
]}
fieldProps={{
checkedChildren: intl.formatMessage({
id: intlPrefix + '.form.requireQuantityAndPrice.enum.checkedChildren',
}),
unCheckedChildren: intl.formatMessage({
id: intlPrefix + '.form.requireQuantityAndPrice.enum.unCheckedChildren',
}),
}}
/>,
];
const detailColumns: ProDescriptionsItemProps<
BusinessAPI.CostItemVO,
BizValueType
>[] = columns as ProDescriptionsItemProps<
BusinessAPI.CostItemVO,
BizValueType
>[];
return (
<BizContainer<
typeof business.costItem,
BusinessAPI.CostItemVO,
BusinessAPI.CostItemPageQry,
BusinessAPI.CostItemCreateCmd,
BusinessAPI.CostItemUpdateCmd
>
rowKey={'itemId'}
permission={'operation-cost-item'}
func={business.costItem}
method={'costItem'}
methodUpper={'CostItem'}
intlPrefix={intlPrefix}
modeType={mode}
onValueChange={onValueChange}
container={{}}
remark={{
mode: 'editor',
}}
status
drag={{
fieldProps: {
bordered: true,
ghost,
//@ts-ignore
search,
params: {
costType: 'PRODUCTION_ADVANCE',
},
},
columns,
}}
create={{
formType: 'drawer',
formContext,
initValues: {
showInEntry: false,
requireQuantityAndPrice: false,
costType: 'PRODUCTION_ADVANCE',
status: true,
},
}}
update={{
formType: 'drawer',
formContext,
}}
destroy={{}}
detail={{
rowId: itemId,
formType: 'drawer',
columns: detailColumns,
trigger,
}}
/>
);
}

View File

@ -1,193 +0,0 @@
import { BizContainer, BizValueType, ModeType } from '@/components';
import { business } from '@/services';
import { useIntl } from '@@/exports';
import {
ProColumns,
ProFormMoney,
ProFormSwitch,
ProFormText,
} from '@ant-design/pro-components';
import { ProDescriptionsItemProps } from '@ant-design/pro-descriptions';
import React from 'react';
interface IWorkerAdvanceListProps {
ghost?: boolean;
itemId?: BusinessAPI.CostItemVO['itemId'];
search?: boolean;
onValueChange?: () => void;
mode?: ModeType;
trigger?: () => React.ReactNode;
}
export default function WorkerAdvanceList(props: IWorkerAdvanceListProps) {
const {
ghost = false,
itemId,
search = true,
mode = 'drag',
trigger,
onValueChange,
} = props;
const intl = useIntl();
const intlPrefix = 'workerAdvance';
const columns: ProColumns<BusinessAPI.CostItemVO, BizValueType>[] = [
{
title: intl.formatMessage({ id: intlPrefix + '.column.name' }),
dataIndex: 'name',
key: 'name',
renderText: (text: string) => <span className="font-medium">{text}</span>,
},
{
title: intl.formatMessage({ id: intlPrefix + '.column.unit' }),
dataIndex: 'unit',
key: 'unit',
search: false,
},
{
title: intl.formatMessage({ id: intlPrefix + '.column.price' }),
dataIndex: 'price',
key: 'price',
valueType: 'money',
search: false,
},
{
title: intl.formatMessage({ id: intlPrefix + '.column.requireQuantityAndPrice' }),
dataIndex: 'requireQuantityAndPrice',
key: 'requireQuantityAndPrice',
renderText: (text: boolean) => (
<span className="font-medium">{text ? '是' : '否'}</span>
),
search: false,
},
];
const formContext = [
<ProFormText key={'costType'} name={'costType'} hidden={true} />,
<ProFormText
key={'name'}
name={'name'}
label={intl.formatMessage({ id: intlPrefix + '.form.name.label' })}
required={true}
placeholder={intl.formatMessage({
id: intlPrefix + '.form.name.placeholder',
})}
rules={[
{
required: true,
message: intl.formatMessage({
id: intlPrefix + '.form.name.required',
}),
},
]}
/>,
<ProFormText
key={'unit'}
name={'unit'}
label={intl.formatMessage({ id: intlPrefix + '.form.unit.label' })}
placeholder={intl.formatMessage({
id: intlPrefix + '.form.unit.placeholder',
})}
/>,
<ProFormMoney
key={'price'}
name={'price'}
label={intl.formatMessage({ id: intlPrefix + '.form.price.label' })}
placeholder={intl.formatMessage({
id: intlPrefix + '.form.price.placeholder',
})}
fieldProps={{
precision: 2,
}}
/>,
<ProFormSwitch
key={'requireQuantityAndPrice'}
name={'requireQuantityAndPrice'}
label={intl.formatMessage({ id: intlPrefix + '.form.requireQuantityAndPrice.label' })}
required={true}
placeholder={intl.formatMessage({
id: intlPrefix + '.form.requireQuantityAndPrice.placeholder',
})}
rules={[
{
required: true,
message: intl.formatMessage({
id: intlPrefix + '.form.requireQuantityAndPrice.required',
}),
},
]}
fieldProps={{
checkedChildren: intl.formatMessage({
id: intlPrefix + '.form.requireQuantityAndPrice.enum.checkedChildren',
}),
unCheckedChildren: intl.formatMessage({
id: intlPrefix + '.form.requireQuantityAndPrice.enum.unCheckedChildren',
}),
}}
/>,
];
const detailColumns: ProDescriptionsItemProps<
BusinessAPI.CostItemVO,
BizValueType
>[] = columns as ProDescriptionsItemProps<
BusinessAPI.CostItemVO,
BizValueType
>[];
return (
<BizContainer<
typeof business.costItem,
BusinessAPI.CostItemVO,
BusinessAPI.CostItemPageQry,
BusinessAPI.CostItemCreateCmd,
BusinessAPI.CostItemUpdateCmd
>
rowKey={'itemId'}
permission={'operation-cost-item'}
func={business.costItem}
method={'costItem'}
methodUpper={'CostItem'}
intlPrefix={intlPrefix}
modeType={mode}
onValueChange={onValueChange}
container={{}}
remark={{
mode: 'editor',
}}
status
drag={{
fieldProps: {
bordered: true,
ghost,
//@ts-ignore
search,
params: {
costType: 'WORKER_ADVANCE',
},
},
columns,
}}
create={{
formType: 'drawer',
formContext,
initValues: {
showInEntry: false,
requireQuantityAndPrice: false,
costType: 'WORKER_ADVANCE',
status: true,
},
}}
update={{
formType: 'drawer',
formContext,
}}
destroy={{}}
detail={{
rowId: itemId,
formType: 'drawer',
columns: detailColumns,
trigger,
}}
/>
);
}

View File

@ -1,211 +0,0 @@
import { BizContainer, BizValueType, ModeType } from '@/components';
import { business } from '@/services';
import { useIntl } from '@@/exports';
import {
ProColumns,
ProFormMoney,
ProFormSwitch,
ProFormText,
} from '@ant-design/pro-components';
import { ProDescriptionsItemProps } from '@ant-design/pro-descriptions';
import React from 'react';
interface IWorkerListProps {
ghost?: boolean;
itemId?: BusinessAPI.CostItemVO['itemId'];
search?: boolean;
onValueChange?: () => void;
mode?: ModeType;
trigger?: () => React.ReactNode;
}
export default function WorkerList(props: IWorkerListProps) {
const {
ghost = false,
itemId,
search = true,
mode = 'drag',
trigger,
onValueChange,
} = props;
const intl = useIntl();
const intlPrefix = 'worker';
const columns: ProColumns<BusinessAPI.CostItemVO, BizValueType>[] = [
{
title: intl.formatMessage({ id: intlPrefix + '.column.name' }),
dataIndex: 'name',
key: 'name',
renderText: (text: string) => <span className="font-medium">{text}</span>,
},
{
title: intl.formatMessage({ id: intlPrefix + '.column.unit' }),
dataIndex: 'unit',
key: 'unit',
search: false,
},
{
title: intl.formatMessage({ id: intlPrefix + '.column.price' }),
dataIndex: 'price',
key: 'price',
valueType: 'money',
search: false,
},
{
title: intl.formatMessage({ id: intlPrefix + '.column.showInEntry' }),
dataIndex: 'showInEntry',
key: 'showInEntry',
renderText: (text: boolean) => (
<span className="font-medium">{text ? '是' : '否'}</span>
),
search: false,
},
];
const formContext = [
<ProFormText key={'costType'} name={'costType'} hidden={true} />,
<ProFormText key={'requireQuantityAndPrice'} name={'requireQuantityAndPrice'} hidden={true} />,
<ProFormText
key={'name'}
name={'name'}
label={intl.formatMessage({ id: intlPrefix + '.form.name.label' })}
required={true}
placeholder={intl.formatMessage({
id: intlPrefix + '.form.name.placeholder',
})}
rules={[
{
required: true,
message: intl.formatMessage({
id: intlPrefix + '.form.name.required',
}),
},
]}
/>,
<ProFormText
key={'unit'}
name={'unit'}
label={intl.formatMessage({ id: intlPrefix + '.form.unit.label' })}
required={true}
placeholder={intl.formatMessage({
id: intlPrefix + '.form.unit.placeholder',
})}
rules={[
{
required: true,
message: intl.formatMessage({
id: intlPrefix + '.form.unit.required',
}),
},
]}
/>,
<ProFormMoney
key={'price'}
name={'price'}
label={intl.formatMessage({ id: intlPrefix + '.form.price.label' })}
required={true}
placeholder={intl.formatMessage({
id: intlPrefix + '.form.price.placeholder',
})}
rules={[
{
required: true,
message: intl.formatMessage({
id: intlPrefix + '.form.price.required',
}),
},
]}
fieldProps={{
precision: 2,
}}
/>,
<ProFormSwitch
key={'showInEntry'}
name={'showInEntry'}
label={intl.formatMessage({ id: intlPrefix + '.form.showInEntry.label' })}
required={true}
placeholder={intl.formatMessage({
id: intlPrefix + '.form.showInEntry.placeholder',
})}
rules={[
{
required: true,
message: intl.formatMessage({
id: intlPrefix + '.form.showInEntry.required',
}),
},
]}
fieldProps={{
checkedChildren: intl.formatMessage({
id: intlPrefix + '.form.showInEntry.enum.checkedChildren',
}),
unCheckedChildren: intl.formatMessage({
id: intlPrefix + '.form.showInEntry.enum.unCheckedChildren',
}),
}}
/>,
];
const detailColumns: ProDescriptionsItemProps<
BusinessAPI.CostItemVO,
BizValueType
>[] = columns as ProDescriptionsItemProps<
BusinessAPI.CostItemVO,
BizValueType
>[];
return (
<BizContainer<
typeof business.costItem,
BusinessAPI.CostItemVO,
BusinessAPI.CostItemPageQry,
BusinessAPI.CostItemCreateCmd,
BusinessAPI.CostItemUpdateCmd
>
rowKey={'itemId'}
permission={'operation-cost-item'}
func={business.costItem}
method={'costItem'}
methodUpper={'CostItem'}
intlPrefix={intlPrefix}
modeType={mode}
onValueChange={onValueChange}
container={{}}
remark={{
mode: 'editor',
}}
status
drag={{
fieldProps: {
bordered: true,
ghost,
//@ts-ignore
search,
params: {
costType: 'HUMAN_COST',
},
},
columns,
}}
create={{
formType: 'drawer',
formContext,
initValues: {
costType: 'HUMAN_COST',
requireQuantityAndPrice: true,
status: true,
},
}}
update={{
formType: 'drawer',
formContext,
}}
destroy={{}}
detail={{
rowId: itemId,
formType: 'drawer',
columns: detailColumns,
trigger,
}}
/>
);
}

View File

@ -1,11 +1,7 @@
export { default as MelonFarmerList } from './MelonFarmerList';
export { default as BoxProductList } from './BoxProductList'
export { default as BoxBrandList } from './BoxBrandList';
export { default as ExcipientList } from './ExcipientList';
export { default as WorkerList } from './WorkerList';
export { default as GiftBoxList } from './GiftBoxList';
export { default as ProductionAdvanceList } from './ProductionAdvanceList';
export { default as WorkerAdvanceList } from './WorkerAdvanceList';
export { default as ProductDataList } from './ProductDataList';
export { default as FixedCostList } from './FixedCostList';
export { default as CostList } from './CostList';
export { default as CostItemList } from './CostItemList';
export { default as BoxSpecList } from './BoxSpecList';
export { default as ProductDataList } from './ProductDataList';

View File

@ -0,0 +1,213 @@
import { ProFormFieldItemProps, ProFormItem } from '@ant-design/pro-components';
import { Form, Space } from 'antd';
import React from 'react';
import {
DragDropContext,
Draggable,
Droppable,
DropResult,
} from 'react-beautiful-dnd';
interface BizDragDropProps<T> {
/**
*
*/
fieldProps?: ProFormFieldItemProps;
/**
* ID
*/
droppableId: string;
/**
*
*/
rowKey: keyof T;
/**
*
*/
value: T[];
/**
*
*/
onChange: (value: T[]) => void;
/**
*
*/
render: (item: T, index: number) => React.ReactNode;
/**
*
* @default horizontal
*/
direction?: 'horizontal' | 'vertical';
/**
*
*/
containerStyle?: React.CSSProperties;
/**
*
*/
itemStyle?: React.CSSProperties;
/**
*
*/
onDragStart?: () => void;
/**
*
*/
onDragEnd?: (result: DropResult) => void;
/**
*
*/
name?: string | string[];
/**
*
*/
relatedFields?: Record<string, any>;
}
export default function BizDragDrop<T>(props: BizDragDropProps<T>) {
const {
fieldProps,
droppableId,
rowKey,
value,
onChange,
render,
direction = 'horizontal',
containerStyle,
itemStyle,
onDragStart,
onDragEnd,
name,
relatedFields,
} = props;
// 获取当前表单实例始终调用避免条件性Hook调用
const form = Form.useFormInstance();
// 重新排列数组元素
const reorder = (list: T[], startIndex: number, endIndex: number): T[] => {
const result = Array.from(list);
const [removed] = result.splice(startIndex, 1);
result.splice(endIndex, 0, removed);
return result;
};
const handleDragStart = () => {
onDragStart?.();
};
const handleDragEnd = (result: DropResult) => {
onDragEnd?.(result);
// 如果没有移动到有效位置,直接返回
if (
!result.destination ||
result.source.index === result.destination.index
) {
return;
}
const reorderedList = reorder(
value,
result.source.index,
result.destination.index,
);
// 如果提供了表单字段名称且表单实例存在,直接更新表单数据
if (name && form) {
// 更新主字段
form.setFieldValue(name, reorderedList);
// 更新相关字段
if (relatedFields) {
Object.keys(relatedFields).forEach((fieldName) => {
const fieldValue =
typeof relatedFields[fieldName] === 'function'
? relatedFields[fieldName](reorderedList)
: relatedFields[fieldName];
form.setFieldValue(fieldName, fieldValue);
});
}
}
onChange?.(reorderedList);
};
// 默认容器样式
const defaultContainerStyle: React.CSSProperties = {
display: 'flex',
flexWrap: 'wrap',
gap: 8,
padding: '8px',
minHeight: '40px',
border: '1px dashed #d9d9d9',
borderRadius: '4px',
backgroundColor: '#fafafa',
...(direction === 'vertical' ? { flexDirection: 'column' } : {}),
...containerStyle,
};
// 默认项样式
const defaultItemStyle = (isDragging: boolean): React.CSSProperties => ({
background: isDragging ? '#e6f7ff' : '#ffffff',
border: isDragging ? '1px dashed #1890ff' : '1px solid #d9d9d9',
borderRadius: '4px',
padding: '8px 12px',
boxShadow: isDragging
? '0 2px 8px rgba(0,0,0,0.15)'
: '0 1px 2px rgba(0,0,0,0.05)',
cursor: 'move',
userSelect: 'none',
display: 'flex',
alignItems: 'center',
gap: 4,
...itemStyle,
});
return (
<DragDropContext onDragEnd={handleDragEnd} onDragStart={handleDragStart}>
<ProFormItem
name={name}
{...fieldProps}
style={{
width: '100%',
...fieldProps?.style,
}}
>
<Droppable droppableId={droppableId} direction={direction}>
{(provided) => (
<div
{...provided.droppableProps}
ref={provided.innerRef}
style={defaultContainerStyle}
>
{value.map((item, index) => (
<Draggable
key={String(item[rowKey])}
draggableId={String(item[rowKey])}
index={index}
>
{(provided, snapshot) => (
<div
ref={provided.innerRef}
{...provided.draggableProps}
{...provided.dragHandleProps}
style={{
...provided.draggableProps.style,
...defaultItemStyle(snapshot.isDragging),
}}
>
<span style={{ cursor: 'grab' }}></span>
<Space size={4}>{render(item, index)}</Space>
</div>
)}
</Draggable>
))}
{provided.placeholder}
</div>
)}
</Droppable>
</ProFormItem>
</DragDropContext>
);
}

View File

@ -17,3 +17,4 @@ export { default as SafeModal } from './SafeModal';
export { default as SmartActionBar } from './SmartActionBar';
export * from './typing';
export { default as VersionChecker } from './VersionChecker';
export { default as BizDragDrop } from './BizDragDrop';

View File

@ -1,10 +1,6 @@
import {
ButtonAccess,
ConfigPanel,
InsertPosition,
ModuleLibrary,
PreviewCanvas,
} from '@/components';
import { ButtonAccess, InsertPosition } from '@/components';
import { ConfigPanel, ModuleLibrary, PreviewCanvas } from './Module';
import { business } from '@/services';
import { formLayout } from '@/utils/formLayout';
import { useIntl } from '@@/exports';
@ -571,7 +567,7 @@ const getModuleExampleData = (moduleType: string) => {
boxWeight: 3391,
boxCount: 12,
netWeight: 53569,
unitPrice: 1.60,
unitPrice: 1.6,
amount: 85710,
watermelonGrade: 'A-麒麟瓜',
},
@ -580,7 +576,7 @@ const getModuleExampleData = (moduleType: string) => {
boxWeight: 3391,
boxCount: 12,
netWeight: 53569,
unitPrice: 1.60,
unitPrice: 1.6,
amount: 85710,
watermelonGrade: 'B-麒麟瓜',
},
@ -645,7 +641,7 @@ const getModuleExampleData = (moduleType: string) => {
boxWeight: 3391,
boxCount: 12,
netWeight: 53569,
unitPrice: 1.60,
unitPrice: 1.6,
amount: 85710,
watermelonGrade: 'A-麒麟瓜',
},
@ -654,7 +650,7 @@ const getModuleExampleData = (moduleType: string) => {
boxWeight: 3391,
boxCount: 12,
netWeight: 53569,
unitPrice: 1.60,
unitPrice: 1.6,
amount: 85710,
watermelonGrade: 'B-麒麟瓜',
},

View File

@ -0,0 +1,13 @@
export { default as ConfigPanel } from './ConfigPanel';
export { default as ModuleLibrary } from './ModuleLibrary';
export { default as PreviewCanvas } from './PreviewCanvas';
export { default as DealerInfoModule } from './DealerInfoModule';
export { default as OtherFeesModule } from './OtherFeesModule';
export { default as OtherInfoModule } from './OtherInfoModule';
export { default as PackingSpecModule } from './PackingSpecModule';
export { default as ShippingInfoModule } from './ShippingInfoModule';
export { default as TitleModule } from './TitleModule';
export { default as TotalAmountModule } from './TotalAmountModule';
export { default as VehicleInfoModule } from './VehicleInfoModule';
export { default as WeightInfoModule } from './WeightInfoModule';

View File

@ -8,17 +8,3 @@ export { default as DealerSearch } from './DealerSearch';
export { default as DealerSelect } from './DealerSelect';
export { default as DealerWarehouseList } from './DealerWarehouseList';
export { default as DeliveryTemplate } from './DeliveryTemplate';
export { default as ConfigPanel } from './Module/ConfigPanel';
export { default as ModuleLibrary } from './Module/ModuleLibrary';
export { default as PreviewCanvas } from './Module/PreviewCanvas';
export { default as DealerInfoModule } from './Module/DealerInfoModule';
export { default as OtherFeesModule } from './Module/OtherFeesModule';
export { default as OtherInfoModule } from './Module/OtherInfoModule';
export { default as PackingSpecModule } from './Module/PackingSpecModule';
export { default as ShippingInfoModule } from './Module/ShippingInfoModule';
export { default as TitleModule } from './Module/TitleModule';
export { default as TotalAmountModule } from './Module/TotalAmountModule';
export { default as VehicleInfoModule } from './Module/VehicleInfoModule';
export { default as WeightInfoModule } from './Module/WeightInfoModule';

View File

@ -8,68 +8,51 @@ const { Text } = Typography;
// 常用图标列表
const COMMON_ICONS = [
'iconplug',
'iconstar',
'iconpengyouquan',
'iconshoucang',
'iconshoucang1',
'iconarrow-right-from-bracket',
'iconuser-xmark',
'iconxmark',
'iconexclamation',
'iconsticky-note',
'iconchevron-left',
'iconpen-to-square',
'iconplus',
'iconeye',
'iconeye-slash',
'iconuser-switch',
'iconlist-ul',
'iconcircle-check',
'iconmoney-bill-wave',
'iconbuilding',
'iconcart-shopping',
'iconbullhorn',
'iconrotate',
'iconcopy',
'iconshare',
'iconlocation-arrow',
'iconlocation-pin',
'iconcalendar-days',
'iconcalendar',
'iconphone-flip',
'iconqrcode1',
'iconcalendar-week',
'iconcrosshairs',
'iconclock',
'iconcircle-plus',
'iconcomment-dots',
'iconcheck',
'iconchevron-down',
'iconheadset',
'iconarrow-right-arrow-left',
'icontrash-can',
'iconphone',
'iconchevron-right',
'iconvolume-high',
'iconlocation-dot',
'iconbolt',
'iconwallet',
'iconcircle-info',
'iconfile-invoice',
'iconchart-line',
'iconcrown',
'icongear',
'iconhandshake',
'iconhouse',
'iconuser',
'iconqrcode',
'iconcar',
'iconbox',
'iconlandmark',
'iconsquare-parking',
'iconscrewdriver-wrench',
'iconcharging-station',
'icon-phone-flip',
'icon-eye',
'icon-eye-slash',
'icon-address-book',
'icon-pen-to-square',
'icon-print',
'icon-rotate-left',
'icon-clock',
'icon-location-dot',
'icon-user-tie',
'icon-receipt',
'icon-file-signature',
'icon-chart-line',
'icon-chart-pie',
'icon-right-left',
'icon-chart-bar',
'icon-bell',
'icon-circle-check',
'icon-key',
'icon-circle-question',
'icon-user-switch',
'icon-arrow-right-from-bracket',
'icon-gear',
'icon-house',
'icon-check',
'icon-comment-dots',
'icon-circle-xmark',
'icon-phone',
'icon-weight-scale',
'icon-minus',
'icon-clipboard-list',
'icon-folder',
'icon-file-invoice',
'icon-camera',
'icon-id-card',
'icon-truck',
'icon-credit-card',
'icon-lock',
'icon-money-bill',
'icon-chevron-right',
'icon-circle-info',
'icon-user',
'icon-chevron-down',
'icon-plus',
'icon-chevron-left',
];
const IconPicker = (props: any) => {

View File

@ -1,10 +1,7 @@
import { createFromIconfontCN } from '@ant-design/icons';
const IconFont = createFromIconfontCN({
scriptUrl: [
'//at.alicdn.com/t/c/font_4244714_6hcger2qej5.js',
'//at.alicdn.com/t/c/font_2119029_urt42hqaw7.js',
],
scriptUrl: ['//at.alicdn.com/t/c/font_5042354_hkkkrqw0kin.js'],
});
export default IconFont;

View File

@ -1,6 +1,7 @@
import {
BizContainer,
BizValueType,
IconPicker,
ModeType,
PermissionList,
} from '@/components';
@ -9,6 +10,7 @@ import { business } from '@/services';
import { useIntl } from '@@/exports';
import {
ProColumns,
ProFormColorPicker,
ProFormDependency,
ProFormRadio,
ProFormSelect,
@ -417,7 +419,55 @@ export default function MenuList(props: IMenuListProps) {
/>
}
/>,
<IconPicker key={'icon'} label="菜单图标" name="icon" />,
<ProFormColorPicker
key={'iconColor'}
label={'图标颜色'}
name={'iconColor'}
allowClear
showText={true}
convertValue={(value: any) => {
if (typeof value === 'string') {
return `rgb(${value})`;
}
return value;
}}
transform={(value: any) => {
const metaColor = value?.metaColor;
if (!metaColor) {
return {
iconColor: value,
};
}
return {
iconColor: `${metaColor.r} ${metaColor.g} ${metaColor.b}`,
};
}}
/>,
<ProFormColorPicker
key={'bgColorClass'}
label={'图标背景颜色'}
name={'bgColorClass'}
allowClear
showText={true}
convertValue={(value: any) => {
if (typeof value === 'string') {
return `rgb(${value})`;
}
return value;
}}
transform={(value: any) => {
const metaColor = value?.metaColor;
if (!metaColor) {
return {
bgColorClass: value,
};
}
return {
bgColorClass: `${metaColor.r} ${metaColor.g} ${metaColor.b}`,
};
}}
/>,
<ProFormRadio.Group
key={'hideInMenu'}
label={intl.formatMessage({

View File

@ -5,17 +5,18 @@ export { default as CaptchaModal } from './CaptchaModal';
export * from './Channel';
export * from './Company';
export * from './Dealer';
export * from './Delivery';
export * from './Editor';
export * from './Employee';
export { default as IconFont } from './Iconfont';
export { default as IconPicker } from './Iconfont/IconPicker';
export * from './Material';
export * from './Menu';
export * from './Permission';
export { default as PhoneContainer } from './PhoneContainer';
export * from './Platform';
export * from './Purchase';
export * from './Remark';
export * from './Role';
export * from './Setting';
export * from './User';
export * from './Purchase';
export * from './Delivery';

View File

@ -1687,12 +1687,27 @@ export default {
},
},
},
excipient: {
cost: {
type: {
materialType: '辅料类型',
artificialType: '人工类型',
productionType: '产地类型',
otherType: '其他类型',
},
column: {
name: '辅料名称',
name: '费用名称',
unit: '计量单位',
price: '参考单价',
showInEntry: '展示录入员页面',
type: '费用类型',
'type.enum.materialType': '辅料类型',
'type.enum.artificialType': '人工类型',
'type.enum.productionType': '产地类型',
'type.enum.otherType': '其他类型',
belong: '费用归属',
'belong.enum.noneType': '无归属',
'belong.enum.workerType': '工头垫付',
'belong.enum.productionType': '产地垫付',
costItemIds: '关联费用项',
remark: '备注',
status: '状态',
'status.enum.enabled': '正常',
@ -1703,9 +1718,9 @@ export default {
},
form: {
name: {
label: '辅料名称',
placeholder: '请输入辅料名称',
required: '辅料名称为必填项',
label: '费用名称',
placeholder: '请输入费用名称',
required: '费用名称为必填项',
},
unit: {
label: '计量单位',
@ -1717,15 +1732,32 @@ export default {
placeholder: '请输入参考单价',
required: '参考单价为必填项',
},
showInEntry: {
label: '展示录入员页面',
placeholder: '请选择展示录入员页面',
required: '展示录入员页面为必填项',
type: {
label: '费用类型',
placeholder: '请选择费用类型',
required: '费用类型为必填项',
enum: {
checkedChildren: '是',
unCheckedChildren: '否',
materialType: '辅料类型',
artificialType: '人工类型',
productionType: '产地类型',
otherType: '其他类型',
},
},
belong: {
label: '费用归属',
placeholder: '请选择费用归属',
required: '费用归属为必填项',
enum: {
noneType: '无归属',
workerType: '工头',
productionType: '产地',
},
},
costItemIds: {
label: '关联费用项',
placeholder: '请选择关联费用项',
required: '关联费用项为必填项',
},
remark: {
label: '备注',
placeholder: '请输入备注',
@ -1742,45 +1774,55 @@ export default {
},
modal: {
create: {
title: '新增辅料类型',
button: '新增辅料类型',
success: '新增辅料类型成功',
title: '新增费用',
button: '新增费用',
success: '新增费用成功',
},
update: {
title: '更新辅料类型',
title: '更新费用',
button: '编辑',
success: '更新辅料类型成功',
success: '更新费用成功',
status: {
success: '修改状态成功',
},
},
delete: {
success: '删除辅料类型成功',
success: '删除费用成功',
button: '删除',
confirm: {
title: '确认删除',
content: '您确定要删除该辅料类型吗?',
content: '您确定要删除该费用吗?',
okText: '确定',
cancelText: '取消',
},
},
import: {
title: '导入辅料类型',
title: '导入费用',
button: '导入',
success: '导入辅料类型成功',
success: '导入费用成功',
},
view: {
title: '查看辅料类型',
title: '查看费用',
button: '查看',
},
},
},
worker: {
costItem: {
type: {
materialType: '辅料类型',
artificialType: '人工类型',
},
column: {
name: '工种名称',
name: '项目名称',
unit: '计量单位',
price: '参考工价',
showInEntry: '展示录入员页面',
price: '参考单价',
type: '项目类型',
'type.enum.materialType': '辅料类型',
'type.enum.artificialType': '人工类型',
rule: '录入规则',
'rule.enum.inputQuantity': '录数量',
'rule.enum.selectBox': '选纸箱',
'rule.enum.inputQuantityAndAmount': '录数量+金额',
remark: '备注',
status: '状态',
'status.enum.enabled': '正常',
@ -1791,9 +1833,9 @@ export default {
},
form: {
name: {
label: '工种名称',
placeholder: '请输入工种名称',
required: '工种名称为必填项',
label: '项目名称',
placeholder: '请输入项目名称',
required: '项目名称为必填项',
},
unit: {
label: '计量单位',
@ -1801,17 +1843,27 @@ export default {
required: '计量单位为必填项',
},
price: {
label: '参考价',
placeholder: '请输入参考价',
required: '参考价为必填项',
label: '参考价',
placeholder: '请输入参考价',
required: '参考价为必填项',
},
showInEntry: {
label: '展示录入员页面',
placeholder: '请选择展示录入员页面',
required: '展示录入员页面为必填项',
type: {
label: '项目类型',
placeholder: '请选择项目类型',
required: '项目类型为必填项',
enum: {
checkedChildren: '是',
unCheckedChildren: '否',
materialType: '辅料类型',
artificialType: '人工类型',
},
},
rule: {
label: '录入规则',
placeholder: '请选择录入规则',
required: '录入规则为必填项',
enum: {
inputQuantity: '录数量',
selectBox: '选纸箱',
inputQuantityAndAmount: '录数量+金额',
},
},
remark: {
@ -1830,389 +1882,35 @@ export default {
},
modal: {
create: {
title: '新增工种类型',
button: '新增工种类型',
success: '新增工种类型成功',
title: '新增项目',
button: '新增项目',
success: '新增项目成功',
},
update: {
title: '更新工种类型',
title: '更新项目',
button: '编辑',
success: '更新工种类型成功',
success: '更新项目成功',
status: {
success: '修改状态成功',
},
},
delete: {
success: '删除工种类型成功',
success: '删除项目成功',
button: '删除',
confirm: {
title: '确认删除',
content: '您确定要删除该工种类型吗?',
content: '您确定要删除该项目吗?',
okText: '确定',
cancelText: '取消',
},
},
import: {
title: '导入工种类型',
title: '导入项目',
button: '导入',
success: '导入工种类型成功',
success: '导入项目成功',
},
view: {
title: '查看工种类型',
button: '查看',
},
},
},
productionAdvance: {
column: {
name: '费用名称',
unit: '计量单位',
price: '单价',
requireQuantityAndPrice: '数量和单价',
'requireQuantityAndPrice.tooltip': '是否需要填写数量和单价',
remark: '备注',
status: '状态',
'status.enum.enabled': '正常',
'status.enum.disabled': '禁用',
'status.placeholder': '请选择状态',
createdAt: '创建时间',
option: '操作',
},
form: {
name: {
label: '费用名称',
placeholder: '请输入费用名称',
required: '费用名称为必填项',
},
unit: {
label: '计量单位',
placeholder: '请输入计量单位',
required: '计量单位为必填项',
},
price: {
label: '单价',
placeholder: '请输入单价',
required: '单价为必填项',
},
requireQuantityAndPrice: {
label: '数量和单价',
placeholder: '请选择数量和单价',
required: '数量和单价为必填项',
tooltip: '是否需要填写数量和单价',
enum: {
checkedChildren: '是',
unCheckedChildren: '否',
},
},
remark: {
label: '备注',
placeholder: '请输入备注',
},
status: {
label: '状态',
placeholder: '请选择状态',
required: '状态为必填项',
enum: {
enabled: '正常',
disabled: '禁用',
},
},
},
modal: {
create: {
title: '新增产地垫付费用',
button: '新增产地垫付费用',
success: '新增产地垫付费用成功',
},
update: {
title: '更新产地垫付费用',
button: '编辑',
success: '更新产地垫付费用成功',
status: {
success: '修改状态成功',
},
},
delete: {
success: '删除产地垫付费用成功',
button: '删除',
confirm: {
title: '确认删除',
content: '您确定要删除该产地垫付费用吗?',
okText: '确定',
cancelText: '取消',
},
},
import: {
title: '导入产地垫付费用',
button: '导入',
success: '导入产地垫付费用成功',
},
view: {
title: '查看产地垫付费用',
button: '查看',
},
},
},
workerAdvance: {
column: {
name: '费用名称',
unit: '计量单位',
price: '单价',
requireQuantityAndPrice: '数量和单价',
'requireQuantityAndPrice.tooltip': '是否需要填写数量和单价',
remark: '备注',
status: '状态',
'status.enum.enabled': '正常',
'status.enum.disabled': '禁用',
'status.placeholder': '请选择状态',
createdAt: '创建时间',
option: '操作',
},
form: {
name: {
label: '费用名称',
placeholder: '请输入费用名称',
required: '费用名称为必填项',
},
unit: {
label: '计量单位',
placeholder: '请输入计量单位',
required: '计量单位为必填项',
},
price: {
label: '单价',
placeholder: '请输入单价',
required: '单价为必填项',
},
requireQuantityAndPrice: {
label: '数量和单价',
placeholder: '请选择数量和单价',
required: '数量和单价为必填项',
tooltip: '是否需要填写数量和单价',
enum: {
checkedChildren: '是',
unCheckedChildren: '否',
},
},
remark: {
label: '备注',
placeholder: '请输入备注',
},
status: {
label: '状态',
placeholder: '请选择状态',
required: '状态为必填项',
enum: {
enabled: '正常',
disabled: '禁用',
},
},
},
modal: {
create: {
title: '新增工头垫付费用',
button: '新增工头垫付费用',
success: '新增工头垫付费用成功',
},
update: {
title: '更新工头垫付费用',
button: '编辑',
success: '更新工头垫付费用成功',
status: {
success: '修改状态成功',
},
},
delete: {
success: '删除工头垫付费用成功',
button: '删除',
confirm: {
title: '确认删除',
content: '您确定要删除该工头垫付费用吗?',
okText: '确定',
cancelText: '取消',
},
},
import: {
title: '导入工头垫付费用',
button: '导入',
success: '导入工头垫付费用成功',
},
view: {
title: '查看工种类型',
button: '查看',
},
},
},
fixedCost: {
column: {
name: '费用名称',
unit: '计量单位',
price: '单价',
requireQuantityAndPrice: '数量和单价',
'requireQuantityAndPrice.tooltip': '是否需要填写数量和单价',
remark: '备注',
status: '状态',
'status.enum.enabled': '正常',
'status.enum.disabled': '禁用',
'status.placeholder': '请选择状态',
createdAt: '创建时间',
option: '操作',
},
form: {
name: {
label: '费用名称',
placeholder: '请输入费用名称',
required: '费用名称为必填项',
},
unit: {
label: '计量单位',
placeholder: '请输入计量单位',
required: '计量单位为必填项',
},
price: {
label: '单价',
placeholder: '请输入单价',
required: '单价为必填项',
},
requireQuantityAndPrice: {
label: '数量和单价',
placeholder: '请选择数量和单价',
required: '数量和单价为必填项',
tooltip: '是否需要填写数量和单价',
enum: {
checkedChildren: '是',
unCheckedChildren: '否',
},
},
remark: {
label: '备注',
placeholder: '请输入备注',
},
status: {
label: '状态',
placeholder: '请选择状态',
required: '状态为必填项',
enum: {
enabled: '正常',
disabled: '禁用',
},
},
},
modal: {
create: {
title: '新增固定费用',
button: '新增固定费用',
success: '新增固定费用成功',
},
update: {
title: '更新固定费用',
button: '编辑',
success: '更新固定费用成功',
status: {
success: '修改状态成功',
},
},
delete: {
success: '删除固定费用成功',
button: '删除',
confirm: {
title: '确认删除',
content: '您确定要删除该固定费用吗?',
okText: '确定',
cancelText: '取消',
},
},
import: {
title: '导入固定费用',
button: '导入',
success: '导入固定费用成功',
},
view: {
title: '查看固定费用',
button: '查看',
},
},
},
giftBox: {
column: {
name: '礼盒名称',
weight: '重量(斤)',
costPrice: '成本单价(元/斤)',
salePrice: '销售单价(元/斤)',
remark: '备注',
status: '状态',
'status.enum.enabled': '正常',
'status.enum.disabled': '禁用',
'status.placeholder': '请选择状态',
createdAt: '创建时间',
option: '操作',
},
form: {
name: {
label: '礼盒名称',
placeholder: '请输入礼盒名称',
required: '礼盒名称为必填项',
},
weight: {
label: '重量(斤)',
placeholder: '请输入重量(斤)',
required: '重量(斤)为必填项',
},
costPrice: {
label: '成本单价(元/斤)',
placeholder: '请输入成本单价(元/斤)',
required: '成本价为必填项',
},
salePrice: {
label: '销售单价(元/斤)',
placeholder: '请输入销售单价(元/斤)',
required: '销售单价(元/斤)为必填项',
},
remark: {
label: '备注',
placeholder: '请输入备注',
},
status: {
label: '状态',
placeholder: '请选择状态',
required: '状态为必填项',
enum: {
enabled: '正常',
disabled: '禁用',
},
},
},
modal: {
create: {
title: '新增礼盒',
button: '新增礼盒',
success: '新增礼盒成功',
},
update: {
title: '更新礼盒',
button: '编辑',
success: '更新礼盒成功',
status: {
success: '修改状态成功',
},
},
delete: {
success: '删除礼盒成功',
button: '删除',
confirm: {
title: '确认删除',
content: '您确定要删除该礼盒吗?',
okText: '确定',
cancelText: '取消',
},
},
import: {
title: '导入礼盒',
button: '导入',
success: '导入礼盒成功',
},
view: {
title: '查看礼盒',
title: '查看项目',
button: '查看',
},
},
@ -2230,6 +1928,10 @@ export default {
},
},
productData: {
module: {
costItem: '项目模块',
cost: '费用模块',
},
column: {
name: '产品名称',
excipientIds: '辅料费用',
@ -2237,6 +1939,7 @@ export default {
workerAdvanceIds: '工头承担费用',
remark: '备注',
status: '状态',
costIds: '关联费用',
'status.enum.enabled': '正常',
'status.enum.disabled': '禁用',
'status.placeholder': '请选择状态',
@ -2249,20 +1952,10 @@ export default {
placeholder: '请输入产品名称',
required: '产品名称为必填项',
},
excipientIds: {
label: '辅料费用',
placeholder: '请选择辅料费用',
required: '辅料费用为必填项',
},
productionAdvanceIds: {
label: '产地承担费用',
placeholder: '请选择产地承担费用',
required: '产地承担费用为必填项',
},
workerAdvanceIds: {
label: '工头承担费用',
placeholder: '请选择工头承担费用',
required: '工头承担费用为必填项',
costIds: {
label: '关联费用',
placeholder: '请选择关联费用',
required: '关联费用为必填项',
},
sort: {
label: '排序号',
@ -2278,6 +1971,15 @@ export default {
unCheckedChildren: '禁用',
},
},
materialTypeList: {
label: '辅料类型',
},
artificialTypeList: {
label: '人工类型',
},
productionTypeList: {
label: '产地类型',
},
remark: {
label: '备注',
placeholder: '请输入备注',
@ -2316,6 +2018,11 @@ export default {
title: '查看',
button: '查看',
},
costTemplate: {
title: '编辑采购费用模板',
button: '采购费用模板',
success: '编辑西瓜采购费用模板成功',
},
},
},
shipOrder: {

View File

@ -0,0 +1,5 @@
import { CostList } from '@/components';
export default function Page() {
return <CostList />;
}

View File

@ -0,0 +1,5 @@
import { CostItemList } from '@/components';
export default function Page() {
return <CostItemList />;
}

View File

@ -1,5 +0,0 @@
import { ExcipientList } from '@/components';
export default function Page() {
return <ExcipientList />;
}

View File

@ -1,5 +0,0 @@
import { FixedCostList } from '@/components';
export default function Page() {
return <FixedCostList />;
}

View File

@ -1,5 +0,0 @@
import { GiftBoxList } from '@/components';
export default function Page() {
return <GiftBoxList />;
}

View File

@ -1,5 +0,0 @@
import { ProductionAdvanceList } from '@/components';
export default function Page() {
return <ProductionAdvanceList />;
}

View File

@ -1,5 +0,0 @@
import { WorkerList } from '@/components';
export default function Page() {
return <WorkerList />;
}

View File

@ -1,5 +0,0 @@
import { WorkerAdvanceList } from '@/components';
export default function Page() {
return <WorkerAdvanceList />;
}

View File

@ -0,0 +1,144 @@
// @ts-ignore
/* eslint-disable */
import request from '../request';
/** 创建费用 POST /operation/createCost */
export async function createCost(
body: BusinessAPI.CostCreateCmd,
options?: { [key: string]: any },
) {
return request<BusinessAPI.SingleResponseCostVO>('/operation/createCost', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
data: body,
...(options || {}),
});
}
/** 费用删除 DELETE /operation/destroyCost */
export async function destroyCost(
body: BusinessAPI.CostDestroyCmd,
options?: { [key: string]: any },
) {
return request<BusinessAPI.Response>('/operation/destroyCost', {
method: 'DELETE',
headers: {
'Content-Type': 'application/json',
},
data: body,
...(options || {}),
});
}
/** 费用拖拽排序 PUT /operation/dragCost */
export async function dragCost(
body: BusinessAPI.CostDragCmd,
options?: { [key: string]: any },
) {
return request<BusinessAPI.Response>('/operation/dragCost', {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
},
data: body,
...(options || {}),
});
}
/** 费用拖拽排序 PATCH /operation/dragCost */
export async function dragCost1(
body: BusinessAPI.CostDragCmd,
options?: { [key: string]: any },
) {
return request<BusinessAPI.Response>('/operation/dragCost', {
method: 'PATCH',
headers: {
'Content-Type': 'application/json',
},
data: body,
...(options || {}),
});
}
/** 费用列表 GET /operation/listCost */
export async function listCost(
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
params: BusinessAPI.listCostParams,
options?: { [key: string]: any },
) {
return request<BusinessAPI.MultiResponseCostVO>('/operation/listCost', {
method: 'GET',
params: {
...params,
costListQry: undefined,
...params['costListQry'],
},
...(options || {}),
});
}
/** 费用列表 GET /operation/pageCost */
export async function pageCost(
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
params: BusinessAPI.pageCostParams,
options?: { [key: string]: any },
) {
return request<BusinessAPI.PageResponseCostVO>('/operation/pageCost', {
method: 'GET',
params: {
...params,
costPageQry: undefined,
...params['costPageQry'],
},
...(options || {}),
});
}
/** 费用详情 GET /operation/showCost */
export async function showCost(
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
params: BusinessAPI.showCostParams,
options?: { [key: string]: any },
) {
return request<BusinessAPI.SingleResponseCostVO>('/operation/showCost', {
method: 'GET',
params: {
...params,
costShowQry: undefined,
...params['costShowQry'],
},
...(options || {}),
});
}
/** 费用更新 PUT /operation/updateCost */
export async function updateCost(
body: BusinessAPI.CostUpdateCmd,
options?: { [key: string]: any },
) {
return request<BusinessAPI.SingleResponseCostVO>('/operation/updateCost', {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
},
data: body,
...(options || {}),
});
}
/** 费用更新 PATCH /operation/updateCost */
export async function updateCost1(
body: BusinessAPI.CostUpdateCmd,
options?: { [key: string]: any },
) {
return request<BusinessAPI.SingleResponseCostVO>('/operation/updateCost', {
method: 'PATCH',
headers: {
'Content-Type': 'application/json',
},
data: body,
...(options || {}),
});
}

View File

@ -9,6 +9,7 @@ import * as boxSpec from './boxSpec';
import * as channel from './channel';
import * as company from './company';
import * as companyPaymentAccount from './companyPaymentAccount';
import * as cost from './cost';
import * as costItem from './costItem';
import * as dealer from './dealer';
import * as dealerPaymentAccount from './dealerPaymentAccount';
@ -51,6 +52,7 @@ export default {
dealerWarehouse,
dealerRebateCustomer,
dealerPaymentAccount,
cost,
costItem,
company,
companyPaymentAccount,

View File

@ -889,27 +889,62 @@ declare namespace BusinessAPI {
createdAt?: string;
};
type CostCreateCmd = {
/** 费用ID */
costId: string;
/** 费用类型1_辅料类型2_人工类型3_产地类型4_其他类型 */
type:
| 'MATERIAL_TYPE'
| 'ARTIFICIAL_TYPE'
| 'PRODUCTION_TYPE'
| 'OTHER_TYPE';
/** 费用归属1_工头2_产地 */
belong: 'NONE_TYPE' | 'WORKER_TYPE' | 'PRODUCTION_TYPE';
/** 费用名称 */
name: string;
/** 单价 */
price?: number;
/** 单位 */
unit?: string;
/** 备注 */
remark?: string;
/** 排序号 */
sort: number;
/** 状态1_启用0_禁用 */
status: boolean;
/** 成本项ID */
costItemIds?: number[];
};
type CostDestroyCmd = {
/** 费用ID */
costId: string;
};
type CostDragCmd = {
/** 相邻元素前 */
prevId?: number;
/** 相邻元素后 */
nextId?: number;
/** 当前元素 */
currentId?: number;
};
type CostItemCreateCmd = {
/** 项目ID */
itemId: string;
/** 费用类型1_包装材料2_人工费用3_其他费用4_固定费用5_工头垫付6_产地垫付 */
costType:
| 'PACKAGING_MATERIALS'
| 'HUMAN_COST'
| 'OTHER_COST'
| 'FIXED_COST'
| 'WORKER_ADVANCE'
| 'PRODUCTION_ADVANCE';
costItemId: string;
/** 项目类型1_辅料类型2_人工类型 */
type: 'MATERIAL_TYPE' | 'ARTIFICIAL_TYPE';
/** 录入规则1_填数量2_选纸箱 */
rule: 'INPUT_QUANTITY' | 'SELECT_BOX' | 'INPUT_QUANTITY_AND_AMOUNT';
/** 费用ID */
costId: number;
/** 项目名称 */
name: string;
/** 单位 */
unit: string;
/** 单价 */
price: number;
/** 是否在录入时显示 */
showInEntry: boolean;
/** 是否需要填写数量和单价 */
requireQuantityAndPrice: boolean;
/** 备注 */
remark?: string;
/** 状态1_启用0_禁用 */
@ -918,7 +953,7 @@ declare namespace BusinessAPI {
type CostItemDestroyCmd = {
/** 费用项目ID */
itemId: string;
costItemId: string;
};
type CostItemDragCmd = {
@ -934,17 +969,9 @@ declare namespace BusinessAPI {
/** 状态1_启用0_禁用 */
status?: boolean;
/** 费用项目ID */
itemId?: string;
/** 费用类型1_包装材料2_人工费用3_其他费用4_固定费用5_工头垫付6_产地垫付 */
costType?:
| 'PACKAGING_MATERIALS'
| 'HUMAN_COST'
| 'OTHER_COST'
| 'FIXED_COST'
| 'WORKER_ADVANCE'
| 'PRODUCTION_ADVANCE';
/** 是否在录入时显示 */
showInEntry?: boolean;
costItemId?: string;
/** 项目类型1_辅料类型2_人工类型 */
type?: 'MATERIAL_TYPE' | 'ARTIFICIAL_TYPE';
};
type CostItemPageQry = {
@ -963,17 +990,9 @@ declare namespace BusinessAPI {
/** 状态1_启用0_禁用 */
status?: boolean;
/** 费用项目ID */
itemId?: string;
/** 费用类型1_包装材料2_人工费用3_其他费用4_固定费用5_工头垫付6_产地垫付 */
costType?:
| 'PACKAGING_MATERIALS'
| 'HUMAN_COST'
| 'OTHER_COST'
| 'FIXED_COST'
| 'WORKER_ADVANCE'
| 'PRODUCTION_ADVANCE';
/** 是否在录入时显示 */
showInEntry?: boolean;
costItemId?: string;
/** 项目类型1_辅料类型2_人工类型 */
type?: 'MATERIAL_TYPE' | 'ARTIFICIAL_TYPE';
/** 项目名称 */
name?: string;
offset?: number;
@ -983,30 +1002,24 @@ declare namespace BusinessAPI {
/** 状态1_启用0_禁用 */
status?: boolean;
/** 费用项目ID */
itemId?: string;
costItemId?: string;
};
type CostItemUpdateCmd = {
/** 费用项目ID */
itemId: string;
/** 费用类型1_包装材料2_人工费用3_其他费用4_固定费用5_工头垫付6_产地垫付 */
costType:
| 'PACKAGING_MATERIALS'
| 'HUMAN_COST'
| 'OTHER_COST'
| 'FIXED_COST'
| 'WORKER_ADVANCE'
| 'PRODUCTION_ADVANCE';
costItemId: string;
/** 项目类型1_辅料类型2_人工类型 */
type: 'MATERIAL_TYPE' | 'ARTIFICIAL_TYPE';
/** 录入规则1_填数量2_选纸箱 */
rule: 'INPUT_QUANTITY' | 'SELECT_BOX' | 'INPUT_QUANTITY_AND_AMOUNT';
/** 费用ID */
costId: number;
/** 项目名称 */
name: string;
/** 单位 */
unit: string;
/** 单价 */
price: number;
/** 是否在录入时显示 */
showInEntry: boolean;
/** 是否需要填写数量和单价 */
requireQuantityAndPrice: boolean;
/** 备注 */
remark?: string;
/** 状态1_启用0_禁用 */
@ -1015,33 +1028,135 @@ declare namespace BusinessAPI {
type CostItemVO = {
/** 项目ID */
itemId: string;
/** 费用类型1_包装材料2_人工费用3_其他费用4_固定费用5_工头垫付6_产地垫付 */
costType:
| 'PACKAGING_MATERIALS'
| 'HUMAN_COST'
| 'OTHER_COST'
| 'FIXED_COST'
| 'WORKER_ADVANCE'
| 'PRODUCTION_ADVANCE';
costItemId: string;
/** 项目类型1_辅料类型2_人工类型 */
type: 'MATERIAL_TYPE' | 'ARTIFICIAL_TYPE';
/** 项目名称 */
name: string;
/** 单位 */
unit: string;
/** 单价 */
price: number;
/** 是否在录入时显示 */
showInEntry: boolean;
/** 是否需要填写数量和单价 */
requireQuantityAndPrice: boolean;
price?: number;
/** 单位 */
unit?: string;
/** 录入规则1_填数量2_选纸箱 */
rule: 'INPUT_QUANTITY' | 'SELECT_BOX' | 'INPUT_QUANTITY_AND_AMOUNT';
/** 备注 */
remark?: string;
/** 排序号 */
sort: number;
/** 状态1_启用0_禁用 */
status: boolean;
/** 创建时间 */
createdAt?: string;
};
type CostListQry = {
/** 状态1_启用0_禁用 */
status?: boolean;
/** 费用ID */
costId?: string;
/** 费用类型1_辅料类型2_人工类型3_产地类型4_其他类型 */
type?:
| 'MATERIAL_TYPE'
| 'ARTIFICIAL_TYPE'
| 'PRODUCTION_TYPE'
| 'OTHER_TYPE';
/** 费用归属1_工头2_产地 */
belong?: 'NONE_TYPE' | 'WORKER_TYPE' | 'PRODUCTION_TYPE';
};
type CostPageQry = {
pageSize?: number;
pageIndex?: number;
orderBy?: string;
orderDirection?: string;
groupBy?: string;
needTotalCount?: boolean;
/** 自定义字段key */
customFieldKey?: string;
/** 自定义字段value */
customFieldValue?: string;
/** 备注 */
remark?: string;
/** 状态1_启用0_禁用 */
status?: boolean;
/** 费用ID */
costId?: string;
/** 费用类型1_辅料类型2_人工类型3_产地类型4_其他类型 */
type?:
| 'MATERIAL_TYPE'
| 'ARTIFICIAL_TYPE'
| 'PRODUCTION_TYPE'
| 'OTHER_TYPE';
/** 费用归属1_工头2_产地 */
belong?: 'NONE_TYPE' | 'WORKER_TYPE' | 'PRODUCTION_TYPE';
offset?: number;
};
type CostShowQry = {
/** 状态1_启用0_禁用 */
status?: boolean;
/** 费用ID */
costId?: string;
};
type CostUpdateCmd = {
/** 费用ID */
costId: string;
/** 费用类型1_辅料类型2_人工类型3_产地类型4_其他类型 */
type:
| 'MATERIAL_TYPE'
| 'ARTIFICIAL_TYPE'
| 'PRODUCTION_TYPE'
| 'OTHER_TYPE';
/** 费用归属1_工头2_产地 */
belong: 'NONE_TYPE' | 'WORKER_TYPE' | 'PRODUCTION_TYPE';
/** 费用名称 */
name: string;
/** 单价 */
price?: number;
/** 单位 */
unit?: string;
/** 备注 */
remark?: string;
/** 排序号 */
sort: number;
/** 状态1_启用0_禁用 */
status: boolean;
/** 成本项ID */
costItemIds?: number[];
};
type CostVO = {
/** 费用ID */
costId: string;
/** 费用类型1_辅料类型2_人工类型3_产地类型4_其他类型 */
type:
| 'MATERIAL_TYPE'
| 'ARTIFICIAL_TYPE'
| 'PRODUCTION_TYPE'
| 'OTHER_TYPE';
/** 费用归属1_工头2_产地 */
belong: 'NONE_TYPE' | 'WORKER_TYPE' | 'PRODUCTION_TYPE';
/** 费用名称 */
name: string;
/** 单价 */
price?: number;
/** 单位 */
unit?: string;
/** 备注 */
remark?: string;
/** 排序号 */
sort: number;
/** 状态1_启用0_禁用 */
status: boolean;
/** 项目id集合 */
costItemIds?: number[];
/** 创建时间 */
createdAt?: string;
/** 项目列表 */
costItemVOList?: CostItemVO[];
};
type countPurchaseOrderByStateParams = {
purchaseOrderCountQry: PurchaseOrderCountQry;
};
@ -1754,6 +1869,8 @@ declare namespace BusinessAPI {
employeeId?: string;
/** 用户ID */
userId?: string;
/** 平台ID */
platformId?: string;
};
type EmployeeUpdateCmd = {
@ -1935,6 +2052,10 @@ declare namespace BusinessAPI {
costItemListQry: CostItemListQry;
};
type listCostParams = {
costListQry: CostListQry;
};
type listDealerParams = {
dealerListQry: DealerListQry;
};
@ -2120,6 +2241,12 @@ declare namespace BusinessAPI {
hideInMenu?: boolean;
/** 权限Id */
permissionId?: number;
/** 菜单图标 */
icon?: string;
/** 图标颜色 */
iconColor?: string;
/** 背景颜色类名 */
bgColorClass?: string;
};
type MenuDestroyCmd = {
@ -2187,6 +2314,12 @@ declare namespace BusinessAPI {
hideInMenu?: boolean;
/** 权限Id */
permissionId?: number;
/** 菜单图标 */
icon?: string;
/** 图标颜色 */
iconColor?: string;
/** 背景颜色类名 */
bgColorClass?: string;
/** 菜单Id */
menuId: string;
};
@ -2214,6 +2347,12 @@ declare namespace BusinessAPI {
routes?: any[];
/** 权限id */
permissionId: number;
/** 菜单图标 */
icon?: string;
/** 图标颜色 */
iconColor?: string;
/** 背景颜色类名 */
bgColorClass?: string;
/** 创建时间 */
createdAt?: string;
};
@ -2281,6 +2420,15 @@ declare namespace BusinessAPI {
notEmpty?: boolean;
};
type MultiResponseCostVO = {
success?: boolean;
errCode?: string;
errMessage?: string;
data?: CostVO[];
empty?: boolean;
notEmpty?: boolean;
};
type MultiResponseDealerPaymentAccountVO = {
success?: boolean;
errCode?: string;
@ -2480,7 +2628,7 @@ declare namespace BusinessAPI {
/** 订单ID */
orderId?: string;
/** 成本项目ID */
itemId: string;
costItemId: string;
/** 成本项目名称 */
name: string;
/** 单价 */
@ -2495,14 +2643,8 @@ declare namespace BusinessAPI {
principal?: string;
/** 是否需要数量和价格 */
requireQuantityAndPrice?: boolean;
/** 费用类型1_包装材料2_人工费用3_其他费用4_固定费用5_工头垫付6_产地垫付 */
costType:
| 'PACKAGING_MATERIALS'
| 'HUMAN_COST'
| 'OTHER_COST'
| 'FIXED_COST'
| 'WORKER_ADVANCE'
| 'PRODUCTION_ADVANCE';
/** 项目类型1_辅料类型2_人工类型 */
type: 'MATERIAL_TYPE' | 'ARTIFICIAL_TYPE';
};
type OrderDealer = {
@ -2831,6 +2973,10 @@ declare namespace BusinessAPI {
costItemPageQry: CostItemPageQry;
};
type pageCostParams = {
costPageQry: CostPageQry;
};
type pageDealerParams = {
dealerPageQry: DealerPageQry;
};
@ -2987,6 +3133,19 @@ declare namespace BusinessAPI {
totalPages?: number;
};
type PageResponseCostVO = {
success?: boolean;
errCode?: string;
errMessage?: string;
totalCount?: number;
pageSize?: number;
pageIndex?: number;
data?: CostVO[];
empty?: boolean;
notEmpty?: boolean;
totalPages?: number;
};
type PageResponseDealerPaymentAccountVO = {
success?: boolean;
errCode?: string;
@ -3330,7 +3489,9 @@ declare namespace BusinessAPI {
/** 产品名称 */
name: string;
/** 关联成本费用id */
costItemIds?: number[];
costIds?: number[];
/** 成本模板 */
costTemplate?: string;
/** 备注 */
remark?: string;
/** 排序号 */
@ -3395,7 +3556,9 @@ declare namespace BusinessAPI {
/** 产品名称 */
name: string;
/** 关联成本费用id */
costItemIds?: number[];
costIds?: number[];
/** 成本模板 */
costTemplate?: string;
/** 备注 */
remark?: string;
/** 排序号 */
@ -3411,16 +3574,18 @@ declare namespace BusinessAPI {
productId: string;
/** 产品名称 */
name: string;
/** 关联成本费用id */
costItemIds?: number[];
/** 备注 */
remark?: string;
/** 排序号 */
sort: number;
/** 状态1_启用0_禁用 */
status: boolean;
/** 成本ID集合 */
costIds?: number[];
/** 成本费用 */
costItemVOList?: CostItemVO[];
costVOList?: CostVO[];
/** 成本模板 */
costTemplate?: string;
/** 创建时间 */
createdAt?: string;
};
@ -3459,16 +3624,16 @@ declare namespace BusinessAPI {
type PurchaseOrderCountQry = {
/** 状态1_启用0_禁用 */
status?: boolean;
/** 采购订单状态: 0_草稿1_审核中2_审批中3_待发货4_已发货5_已驳回6_已撤回7_已关闭8_已完结 */
state?:
| 'DRAFT'
| 'WAITING_AUDIT'
| 'WAITING_APPROVE'
| 'WAITING_SHIPMENT'
| 'SHIPPED'
| 'PAID'
| 'COMPLETED'
| 'REJECTED';
/** 采购订单状态: 0_草稿1_审核中2_已完成3_已驳回4_已关闭 */
state?: 'DRAFT' | 'WAITING_AUDIT' | 'COMPLETED' | 'REJECTED' | 'CLOSED';
/** 采购单审核状态: 1_待报价审核2_待老板审批3_老板审批通过4_报价审核驳回5_老板审批驳回 */
auditState?:
| 'NONE'
| 'PENDING_QUOTE_APPROVAL'
| 'PENDING_BOSS_APPROVAL'
| 'BOSS_APPROVED'
| 'QUOTE_REJECTED'
| 'BOSS_REJECTED';
};
type PurchaseOrderCreateCmd = {
@ -3532,16 +3697,16 @@ declare namespace BusinessAPI {
vehicleNo?: string;
/** 采购订单编号 */
orderSn?: string;
/** 采购订单状态: 0_草稿1_审核中2_审批中3_待发货4_已发货5_已驳回6_已撤回7_已关闭8_已完结 */
state?:
| 'DRAFT'
| 'WAITING_AUDIT'
| 'WAITING_APPROVE'
| 'WAITING_SHIPMENT'
| 'SHIPPED'
| 'PAID'
| 'COMPLETED'
| 'REJECTED';
/** 采购订单状态: 0_草稿1_审核中2_已完成3_已驳回4_已关闭 */
state?: 'DRAFT' | 'WAITING_AUDIT' | 'COMPLETED' | 'REJECTED' | 'CLOSED';
/** 采购单审核状态: 1_待报价审核2_待老板审批3_老板审批通过4_报价审核驳回5_老板审批驳回 */
auditState?:
| 'NONE'
| 'PENDING_QUOTE_APPROVAL'
| 'PENDING_BOSS_APPROVAL'
| 'BOSS_APPROVED'
| 'QUOTE_REJECTED'
| 'BOSS_REJECTED';
/** 供应商名称 */
supplierName?: string;
/** 经销商ID */
@ -3668,16 +3833,16 @@ declare namespace BusinessAPI {
freightCharge?: number;
/** 瓜农数量 */
supplierCount?: number;
/** 采购订单状态: 0_草稿1_审核中2_审批中3_待发货4_已发货5_已驳回6_已撤回7_已关闭8_已完结 */
state?:
| 'DRAFT'
| 'WAITING_AUDIT'
| 'WAITING_APPROVE'
| 'WAITING_SHIPMENT'
| 'SHIPPED'
| 'PAID'
| 'COMPLETED'
| 'REJECTED';
/** 采购订单状态: 0_草稿1_审核中2_已完成3_已驳回4_已关闭 */
state?: 'DRAFT' | 'WAITING_AUDIT' | 'COMPLETED' | 'REJECTED' | 'CLOSED';
/** 采购单审核状态: 1_待报价审核2_待老板审批3_老板审批通过4_报价审核驳回5_老板审批驳回 */
auditState?:
| 'NONE'
| 'PENDING_QUOTE_APPROVAL'
| 'PENDING_BOSS_APPROVAL'
| 'BOSS_APPROVED'
| 'QUOTE_REJECTED'
| 'BOSS_REJECTED';
/** 备注 */
remark?: string;
/** 创建人ID */
@ -4238,6 +4403,10 @@ declare namespace BusinessAPI {
costItemShowQry: CostItemShowQry;
};
type showCostParams = {
costShowQry: CostShowQry;
};
type showDealerParams = {
dealerShowQry: DealerShowQry;
};
@ -4377,6 +4546,13 @@ declare namespace BusinessAPI {
data?: CostItemVO;
};
type SingleResponseCostVO = {
success?: boolean;
errCode?: string;
errMessage?: string;
data?: CostVO;
};
type SingleResponseDealerPaymentAccountVO = {
success?: boolean;
errCode?: string;
@ -4827,6 +5003,8 @@ declare namespace BusinessAPI {
userId: string;
/** 描述 */
description: string;
/** 平台ID */
platformId: string;
};
type UserShowQry = {

File diff suppressed because one or more lines are too long