AutoAccessTaskDetail.js 12 KB

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