ModelSettingsVisualEditor.js 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251
  1. // ModelSettingsVisualEditor.js
  2. import React, { useEffect, useState } from 'react';
  3. import { Table, Button, Input, Modal, Form, Space } from '@douyinfe/semi-ui';
  4. import { IconDelete, IconPlus, IconSearch } from '@douyinfe/semi-icons';
  5. import { showError, showSuccess } from '../../../helpers';
  6. import { API } from '../../../helpers';
  7. export default function ModelSettingsVisualEditor(props) {
  8. const [models, setModels] = useState([]);
  9. const [visible, setVisible] = useState(false);
  10. const [currentModel, setCurrentModel] = useState(null);
  11. const [searchText, setSearchText] = useState('');
  12. const [currentPage, setCurrentPage] = useState(1);
  13. const pageSize = 10;
  14. useEffect(() => {
  15. try {
  16. const modelPrice = JSON.parse(props.options.ModelPrice || '{}');
  17. const modelRatio = JSON.parse(props.options.ModelRatio || '{}');
  18. const completionRatio = JSON.parse(props.options.CompletionRatio || '{}');
  19. // 合并所有模型名称
  20. const modelNames = new Set([
  21. ...Object.keys(modelPrice),
  22. ...Object.keys(modelRatio),
  23. ...Object.keys(completionRatio)
  24. ]);
  25. const modelData = Array.from(modelNames).map(name => ({
  26. name,
  27. price: modelPrice[name] === undefined ? '' : modelPrice[name],
  28. ratio: modelRatio[name] === undefined ? '' : modelRatio[name],
  29. completionRatio: completionRatio[name] === undefined ? '' : completionRatio[name]
  30. }));
  31. setModels(modelData);
  32. } catch (error) {
  33. console.error('JSON解析错误:', error);
  34. }
  35. }, [props.options]);
  36. // 首先声明分页相关的工具函数
  37. const getPagedData = (data, currentPage, pageSize) => {
  38. const start = (currentPage - 1) * pageSize;
  39. const end = start + pageSize;
  40. return data.slice(start, end);
  41. };
  42. // 在 return 语句之前,先处理过滤和分页逻辑
  43. const filteredModels = models.filter(model =>
  44. searchText ? model.name.toLowerCase().includes(searchText.toLowerCase()) : true
  45. );
  46. // 然后基于过滤后的数据计算分页数据
  47. const pagedData = getPagedData(filteredModels, currentPage, pageSize);
  48. // 转换回JSON格式
  49. const generateJSONOutput = async () => {
  50. const output = {
  51. ModelPrice: {},
  52. ModelRatio: {},
  53. CompletionRatio: {}
  54. };
  55. let currentConvertModelName = '';
  56. try {
  57. models.forEach(model => {
  58. currentConvertModelName = model.name;
  59. if (model.price !== '') output.ModelPrice[model.name] = parseFloat(model.price);
  60. if (model.ratio !== '') output.ModelRatio[model.name] = parseFloat(model.ratio);
  61. if (model.completionRatio != '') output.CompletionRatio[model.name] = parseFloat(model.completionRatio);
  62. });
  63. } catch (error) {
  64. console.error('JSON转换错误:', error);
  65. showError('JSON转换错误, 请检查输入+模型名称: ' + currentConvertModelName);
  66. return;
  67. }
  68. const finalOutput = {
  69. ModelPrice: JSON.stringify(output.ModelPrice, null, 2),
  70. ModelRatio: JSON.stringify(output.ModelRatio, null, 2),
  71. CompletionRatio: JSON.stringify(output.CompletionRatio, null, 2)
  72. }
  73. forEach(finalOutput, (value, key) => {
  74. API.put('/api/option/', {
  75. key: key,
  76. value
  77. }).then(res => {
  78. if (res.data.success) {
  79. showSuccess('保存成功');
  80. } else {
  81. showError(res.data.message);
  82. }
  83. })
  84. })
  85. showSuccess('转换成功');
  86. props.refresh();
  87. };
  88. const columns = [
  89. {
  90. title: '模型名称',
  91. dataIndex: 'name',
  92. key: 'name',
  93. },
  94. {
  95. title: '固定价格',
  96. dataIndex: 'price',
  97. key: 'price',
  98. render: (text, record) => (
  99. <Input
  100. value={text}
  101. placeholder="无"
  102. onChange={value => updateModel(record.name, 'price', value)}
  103. />
  104. )
  105. },
  106. {
  107. title: '模型倍率',
  108. dataIndex: 'ratio',
  109. key: 'ratio',
  110. render: (text, record) => (
  111. <Input
  112. value={text}
  113. placeholder="默认倍率"
  114. onChange={value => updateModel(record.name, 'ratio', value)}
  115. />
  116. )
  117. },
  118. {
  119. title: '补全倍率',
  120. dataIndex: 'completionRatio',
  121. key: 'completionRatio',
  122. render: (text, record) => (
  123. <Input
  124. value={text}
  125. placeholder="默认补全值"
  126. onChange={value => updateModel(record.name, 'completionRatio', value)}
  127. />
  128. )
  129. },
  130. {
  131. title: '操作',
  132. key: 'action',
  133. render: (_, record) => (
  134. <Button
  135. icon={<IconDelete />}
  136. type="danger"
  137. onClick={() => deleteModel(record.name)}
  138. />
  139. )
  140. }
  141. ];
  142. const updateModel = (name, field, value) => {
  143. setModels(prev =>
  144. prev.map(model =>
  145. model.name === name
  146. ? { ...model, [field]: value }
  147. : model
  148. )
  149. );
  150. };
  151. const deleteModel = (name) => {
  152. setModels(prev => prev.filter(model => model.name !== name));
  153. };
  154. const addModel = (values) => {
  155. setModels(prev => [...prev, {
  156. name: values.name,
  157. price: values.price || '',
  158. ratio: values.ratio || '',
  159. completionRatio: values.completionRatio || ''
  160. }]);
  161. setVisible(false);
  162. };
  163. return (
  164. <>
  165. <Space vertical align="start" style={{ width: '100%' }}>
  166. <Space>
  167. <Button icon={<IconPlus />} onClick={() => setVisible(true)}>
  168. 添加模型
  169. </Button>
  170. <Button type="primary" onClick={generateJSONOutput}>
  171. 保存更改
  172. </Button>
  173. <Input
  174. prefix={<IconSearch />}
  175. placeholder="搜索模型名称"
  176. value={searchText}
  177. onChange={value => {
  178. setSearchText(value)
  179. // 搜索时重置页码
  180. setCurrentPage(1);
  181. }}
  182. style={{ width: 200 }}
  183. />
  184. </Space>
  185. <Table
  186. columns={columns}
  187. dataSource={pagedData} // 使用分页后的数据
  188. pagination={{
  189. currentPage: currentPage,
  190. pageSize: pageSize,
  191. total: filteredModels.length,
  192. onPageChange: page => setCurrentPage(page),
  193. showTotal: true,
  194. showSizeChanger: false
  195. }}
  196. />
  197. </Space>
  198. <Modal
  199. title="添加模型"
  200. visible={visible}
  201. onCancel={() => setVisible(false)}
  202. onOk={() => {
  203. currentModel && addModel(currentModel);
  204. }}
  205. >
  206. <Form>
  207. <Form.Input
  208. field="name"
  209. label="模型名称"
  210. required
  211. onChange={value => setCurrentModel(prev => ({ ...prev, name: value }))}
  212. />
  213. <Form.Input
  214. field="price"
  215. label="固定价格"
  216. onChange={value => setCurrentModel(prev => ({ ...prev, price: value }))}
  217. />
  218. <Form.Input
  219. field="ratio"
  220. label="模型倍率"
  221. onChange={value => setCurrentModel(prev => ({ ...prev, ratio: value }))}
  222. />
  223. <Form.Input
  224. field="completionRatio"
  225. label="补全倍率"
  226. onChange={value => setCurrentModel(prev => ({ ...prev, completionRatio: value }))}
  227. />
  228. </Form>
  229. </Modal>
  230. </>
  231. );
  232. }