AutoAccessTaskDetail.js 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433
  1. import React, { useState, useEffect } from "react";
  2. import { Form, Input, Select, Button, Card, Descriptions, Tag, message, Spin, Row, Col, Tooltip } from "antd";
  3. import { useParams, useNavigate, useLocation } from "react-router-dom";
  4. import { ArrowLeftOutlined, CopyOutlined } from "@ant-design/icons";
  5. import { autoAccessTasksApi } from "../services/api";
  6. import moment from "moment";
  7. import { STATUS_MAP, STATUS_TAG_COLOR } from "./AutoAccessTaskList";
  8. import { ACCESS_PROVIDER_OPTIONS } from "./AutoAccessTaskAdd";
  9. const { TextArea } = Input;
  10. const { Option } = Select;
  11. // 状态枚举
  12. const STATUS_OPTIONS = [
  13. { value: 0, label: "待执行" },
  14. { value: 1, label: "执行中" },
  15. { value: 2, label: "已完成" },
  16. { value: 3, label: "失败" },
  17. { value: 4, label: "已注册" },
  18. { value: 5, label: "待审核" },
  19. { value: 6, label: "审核不通过" },
  20. ];
  21. // 状态映射(用于显示)
  22. const AutoAccessTaskDetail = () => {
  23. const [form] = Form.useForm();
  24. const [data, setData] = useState(null);
  25. const [loading, setLoading] = useState(true);
  26. const [saving, setSaving] = useState(false);
  27. const [accessType, setAccessType] = useState(undefined);
  28. const { id } = useParams();
  29. const navigate = useNavigate();
  30. const location = useLocation();
  31. const isEditMode = location.search.includes("mode=edit");
  32. const getStatusColor = (status) => {
  33. return STATUS_TAG_COLOR[status] || "default";
  34. };
  35. const getStatusText = (status) => {
  36. return STATUS_MAP[status] || "未知";
  37. };
  38. const getAccessTypeText = (type) => {
  39. const typeMap = {
  40. api_no_crack: "API无破解",
  41. api_crack: "API破解",
  42. browser_auto_operate: "浏览器自动操作",
  43. };
  44. return typeMap[type] || type;
  45. };
  46. const fetchData = async () => {
  47. try {
  48. const response = await autoAccessTasksApi.getDetail(id);
  49. setData(response.data);
  50. form.setFieldsValue(response.data);
  51. setAccessType(response.data.access_type);
  52. } catch (error) {
  53. message.error("获取详情失败");
  54. } finally {
  55. setLoading(false);
  56. }
  57. };
  58. const handleSave = async (values) => {
  59. setSaving(true);
  60. try {
  61. await autoAccessTasksApi.update(id, values);
  62. message.success("更新成功");
  63. navigate("/auto-access-tasks");
  64. } catch (error) {
  65. message.error("更新失败");
  66. } finally {
  67. setSaving(false);
  68. }
  69. };
  70. const handleCopyApiDoc = () => {
  71. const apiDoc = form.getFieldValue("api_doc");
  72. if (apiDoc) {
  73. navigator.clipboard
  74. .writeText(apiDoc)
  75. .then(() => {
  76. message.success("API文档已复制到剪贴板");
  77. })
  78. .catch(() => {
  79. message.error("复制失败,请手动复制");
  80. });
  81. } else {
  82. message.warning("API文档为空,无法复制");
  83. }
  84. };
  85. const handleAccessTypeChange = (value) => {
  86. setAccessType(value);
  87. // 当接入方式改变时,清空相关字段的值
  88. if (value === "browser_auto_operate") {
  89. form.setFieldsValue({
  90. api_provider: undefined,
  91. api_doc: undefined,
  92. });
  93. } else if (value === "api_no_crack" || value === "api_crack") {
  94. form.setFieldsValue({
  95. operate_path_data: undefined,
  96. });
  97. }
  98. };
  99. useEffect(() => {
  100. fetchData();
  101. }, [id]);
  102. if (loading) {
  103. return (
  104. <div style={{ textAlign: "center", padding: "50px" }}>
  105. <Spin size="large" />
  106. </div>
  107. );
  108. }
  109. if (!data) {
  110. return <div>数据不存在</div>;
  111. }
  112. return (
  113. <div className="detail-container">
  114. <Button
  115. icon={<ArrowLeftOutlined />}
  116. onClick={() => navigate("/auto-access-tasks")}
  117. style={{ marginBottom: 16 }}
  118. >
  119. 返回列表
  120. </Button>
  121. {isEditMode ? (
  122. <Card
  123. title="编辑自动接入任务"
  124. style={{ marginBottom: 24 }}
  125. >
  126. <Form
  127. form={form}
  128. layout="vertical"
  129. onFinish={handleSave}
  130. className="w-full"
  131. >
  132. <Row gutter={24}>
  133. {/* <Col span={12}>
  134. <Form.Item
  135. label="检索任务ID"
  136. name="search_task_id"
  137. >
  138. <Input />
  139. </Form.Item>
  140. </Col> */}
  141. <Col span={12}>
  142. <Form.Item
  143. label="工具名称"
  144. name="tools_name"
  145. rules={[{ required: true, message: "请输入工具名称" }]}
  146. >
  147. <Input />
  148. </Form.Item>
  149. </Col>
  150. <Col span={12}>
  151. <Form.Item
  152. label="工具功能名称"
  153. name="tools_function_name"
  154. rules={[{ required: false, message: "请输入工具功能名称" }]}
  155. >
  156. <Input />
  157. </Form.Item>
  158. </Col>
  159. </Row>
  160. <Row gutter={24}>
  161. <Col span={12}>
  162. <Form.Item
  163. label="接入方式"
  164. name="access_type"
  165. rules={[{ required: true, message: "请选择接入方式" }]}
  166. >
  167. <Select onChange={handleAccessTypeChange}>
  168. <Option value="api_no_crack">API无破解</Option>
  169. <Option value="api_crack">API破解</Option>
  170. <Option value="browser_auto_operate">浏览器自动操作</Option>
  171. </Select>
  172. </Form.Item>
  173. </Col>
  174. <Col span={12}>
  175. <Form.Item
  176. label="状态"
  177. name="status"
  178. rules={[{ required: false, message: "请选择状态" }]}
  179. >
  180. <Select>
  181. {STATUS_OPTIONS.map((option) => (
  182. <Option
  183. key={option.value}
  184. value={option.value}
  185. >
  186. {option.label}
  187. </Option>
  188. ))}
  189. </Select>
  190. </Form.Item>
  191. </Col>
  192. </Row>
  193. <Row gutter={24}>
  194. <Col span={12}>
  195. <Form.Item
  196. label="API类名"
  197. name="api_class_name"
  198. >
  199. <Input />
  200. </Form.Item>
  201. </Col>
  202. <Col span={12}>
  203. <Form.Item
  204. label="补充ApiKey"
  205. name="api_key"
  206. >
  207. <Input />
  208. </Form.Item>
  209. </Col>
  210. </Row>
  211. <Row gutter={24}>
  212. <Col span={12}>
  213. <Form.Item
  214. label="API提供方"
  215. name="api_provider"
  216. rules={[
  217. {
  218. required: accessType === "api_no_crack" || accessType === "api_crack",
  219. message: "请输入API提供方",
  220. },
  221. ]}
  222. >
  223. <Select placeholder="请选择API提供方">
  224. {ACCESS_PROVIDER_OPTIONS.map((option) => (
  225. <Option
  226. key={option.value}
  227. value={option.value}
  228. >
  229. {option.label}
  230. </Option>
  231. ))}
  232. </Select>
  233. </Form.Item>
  234. </Col>
  235. </Row>
  236. <Form.Item
  237. label={
  238. <div style={{ display: "flex", alignItems: "center", gap: "8px" }}>
  239. API文档
  240. <Tooltip title="点击复制API文档">
  241. <Button
  242. type="text"
  243. style={{ color: "blue" }}
  244. size="small"
  245. icon={<CopyOutlined />}
  246. onClick={handleCopyApiDoc}
  247. />
  248. </Tooltip>
  249. </div>
  250. }
  251. name="api_doc"
  252. rules={[
  253. {
  254. required: accessType === "api_no_crack" || accessType === "api_crack",
  255. message: "请输入API文档",
  256. },
  257. ]}
  258. >
  259. <TextArea rows={6} />
  260. </Form.Item>
  261. <Form.Item
  262. label="操作路径数据"
  263. name="operate_path_data"
  264. rules={[
  265. {
  266. required: accessType === "browser_auto_operate",
  267. message: "请输入操作路径数据",
  268. },
  269. ]}
  270. >
  271. <TextArea rows={4} />
  272. </Form.Item>
  273. <Form.Item
  274. label="源内容链接"
  275. name="origin_content_link"
  276. >
  277. <Input />
  278. </Form.Item>
  279. <Form.Item
  280. label="工具功能描述"
  281. name="tools_function_desc"
  282. >
  283. <TextArea rows={4} />
  284. </Form.Item>
  285. <Form.Item
  286. label="失败原因"
  287. name="fail_reason"
  288. >
  289. <TextArea rows={3} />
  290. </Form.Item>
  291. <div className="button-group">
  292. <Button onClick={() => navigate("/auto-access-tasks")}>取消</Button>
  293. <Button
  294. type="primary"
  295. htmlType="submit"
  296. loading={saving}
  297. >
  298. 保存
  299. </Button>
  300. </div>
  301. </Form>
  302. </Card>
  303. ) : (
  304. <Card title="自动接入任务详情">
  305. <Descriptions
  306. column={2}
  307. bordered
  308. labelStyle={{ width: "140px", minWidth: "120px" }}
  309. >
  310. <Descriptions.Item label="接入任务ID">{data.access_task_id}</Descriptions.Item>
  311. <Descriptions.Item label="检索任务ID">{data.search_task_id}</Descriptions.Item>
  312. <Descriptions.Item label="工具名称">{data.tools_name}</Descriptions.Item>
  313. <Descriptions.Item label="工具功能名称">{data.tools_function_name}</Descriptions.Item>
  314. <Descriptions.Item label="接入方式">
  315. <Tag color="blue">{getAccessTypeText(data.access_type)}</Tag>
  316. </Descriptions.Item>
  317. <Descriptions.Item label="状态">
  318. <Tag color={getStatusColor(data.status)}>{getStatusText(data.status)}</Tag>
  319. </Descriptions.Item>
  320. <Descriptions.Item label="API类名">{data.api_class_name}</Descriptions.Item>
  321. <Descriptions.Item label="API提供方">{data.api_provider}</Descriptions.Item>
  322. <Descriptions.Item
  323. label="补充ApiKey"
  324. span={2}
  325. >
  326. {data.api_key || "无"}
  327. </Descriptions.Item>
  328. <Descriptions.Item
  329. label="工具功能描述"
  330. span={2}
  331. >
  332. {data.tools_function_desc}
  333. </Descriptions.Item>
  334. <Descriptions.Item
  335. label={
  336. <div style={{ display: "flex", alignItems: "center", gap: "8px" }}>
  337. API文档
  338. <Tooltip title="点击复制API文档">
  339. <Button
  340. type="text"
  341. style={{ color: "blue" }}
  342. size="small"
  343. icon={<CopyOutlined />}
  344. onClick={() => {
  345. const apiDoc = data.api_doc;
  346. if (apiDoc) {
  347. navigator.clipboard
  348. .writeText(apiDoc)
  349. .then(() => {
  350. message.success("API文档已复制到剪贴板");
  351. })
  352. .catch(() => {
  353. message.error("复制失败,请手动复制");
  354. });
  355. } else {
  356. message.warning("API文档为空,无法复制");
  357. }
  358. }}
  359. />
  360. </Tooltip>
  361. </div>
  362. }
  363. span={2}
  364. >
  365. <div style={{ maxHeight: "200px", overflow: "auto" }}>
  366. <pre style={{ whiteSpace: "pre-wrap", wordBreak: "break-word" }}>{data.api_doc || "无"}</pre>
  367. </div>
  368. </Descriptions.Item>
  369. <Descriptions.Item label="源内容链接">
  370. {data.origin_content_link ? (
  371. <a
  372. href={data.origin_content_link}
  373. target="_blank"
  374. rel="noopener noreferrer"
  375. >
  376. {data.origin_content_link}
  377. </a>
  378. ) : (
  379. "无"
  380. )}
  381. </Descriptions.Item>
  382. <Descriptions.Item
  383. label="操作路径数据"
  384. span={2}
  385. >
  386. <div style={{ maxHeight: "200px", overflow: "auto" }}>
  387. <pre style={{ whiteSpace: "pre-wrap", wordBreak: "break-word" }}>{data.operate_path_data || "无"}</pre>
  388. </div>
  389. </Descriptions.Item>
  390. <Descriptions.Item
  391. label="失败原因"
  392. span={2}
  393. >
  394. {data.fail_reason || "无"}
  395. </Descriptions.Item>
  396. <Descriptions.Item label="创建时间">
  397. {moment(data.create_time).format("YYYY-MM-DD HH:mm:ss")}
  398. </Descriptions.Item>
  399. <Descriptions.Item label="更新时间">
  400. {moment(data.update_time).format("YYYY-MM-DD HH:mm:ss")}
  401. </Descriptions.Item>
  402. </Descriptions>
  403. </Card>
  404. )}
  405. </div>
  406. );
  407. };
  408. export default AutoAccessTaskDetail;