index.tsx 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  1. import { apiInterceptors, deletePrompt, getPromptList } from '@/client/api';
  2. import useUser from '@/hooks/use-user';
  3. import ConstructLayout from '@/new-components/layout/Construct';
  4. import { IPrompt, PromptListResponse } from '@/types/prompt';
  5. import { PlusOutlined } from '@ant-design/icons';
  6. import { useRequest } from 'ahooks';
  7. import type { SegmentedProps } from 'antd';
  8. import { App, Button, Popconfirm, Segmented, Space, Table, Typography } from 'antd';
  9. import type { ColumnsType } from 'antd/es/table';
  10. import { TFunction } from 'i18next';
  11. import { useRouter } from 'next/router';
  12. import React, { useEffect, useState } from 'react';
  13. import { useTranslation } from 'react-i18next';
  14. import styles from './styles.module.css';
  15. const LangMap = { zh: '中文', en: 'English' };
  16. const DeleteBtn: React.FC<{ record: IPrompt; refresh: () => void }> = ({ record, refresh }) => {
  17. const userInfo = useUser();
  18. const { t } = useTranslation();
  19. const { message } = App.useApp();
  20. // 删除prompt
  21. const { run: deletePromptRun, loading: deleteLoading } = useRequest(
  22. async record => {
  23. await deletePrompt({
  24. ...record,
  25. });
  26. },
  27. {
  28. manual: true,
  29. onSuccess: async () => {
  30. message.success('删除成功');
  31. await refresh();
  32. },
  33. },
  34. );
  35. if (userInfo?.user_id !== record?.user_id) {
  36. return null;
  37. }
  38. return (
  39. <Popconfirm title='确认删除吗?' onConfirm={async () => await deletePromptRun(record)}>
  40. <Button loading={deleteLoading}>{t('Delete')}</Button>
  41. </Popconfirm>
  42. );
  43. };
  44. const Prompt = () => {
  45. const router = useRouter();
  46. const { t } = useTranslation();
  47. const [promptType, setPromptType] = useState<string>('common');
  48. const [promptList, setPromptList] = useState<PromptListResponse>();
  49. const {
  50. run: getPrompts,
  51. loading,
  52. refresh,
  53. } = useRequest(
  54. async (page = 1, page_size = 6) => {
  55. const [_, data] = await apiInterceptors(
  56. getPromptList({
  57. page,
  58. page_size,
  59. }),
  60. );
  61. return data;
  62. },
  63. {
  64. manual: true,
  65. onSuccess: data => {
  66. setPromptList(data!);
  67. },
  68. },
  69. );
  70. const handleEditBtn = (prompt: IPrompt) => {
  71. localStorage.setItem('edit_prompt_data', JSON.stringify(prompt));
  72. router.push('/construct/prompt/edit');
  73. };
  74. const handleAddBtn = () => {
  75. router.push('/construct/prompt/add');
  76. };
  77. const getColumns = (t: TFunction, handleEdit: (prompt: IPrompt) => void): ColumnsType<IPrompt> => [
  78. {
  79. title: t('Prompt_Info_Name'),
  80. dataIndex: 'prompt_name',
  81. key: 'prompt_name',
  82. width: '10%',
  83. },
  84. {
  85. title: t('Prompt_Info_Scene'),
  86. dataIndex: 'chat_scene',
  87. key: 'chat_scene',
  88. width: '10%',
  89. },
  90. {
  91. title: t('language'),
  92. dataIndex: 'prompt_language',
  93. key: 'prompt_language',
  94. render: lang => (lang ? LangMap[lang as keyof typeof LangMap] : '-'),
  95. width: '10%',
  96. },
  97. {
  98. title: t('Prompt_Info_Content'),
  99. dataIndex: 'content',
  100. key: 'content',
  101. render: content => <Typography.Paragraph ellipsis={{ rows: 2, tooltip: true }}>{content}</Typography.Paragraph>,
  102. },
  103. {
  104. title: t('Operation'),
  105. dataIndex: 'operate',
  106. key: 'operate',
  107. render: (_, record) => (
  108. <Space align='center'>
  109. <Button
  110. onClick={() => {
  111. handleEdit(record);
  112. }}
  113. type='primary'
  114. >
  115. {t('Edit')}
  116. </Button>
  117. <DeleteBtn record={record} refresh={refresh} />
  118. </Space>
  119. ),
  120. },
  121. ];
  122. useEffect(() => {
  123. getPrompts();
  124. }, [promptType]);
  125. const items: SegmentedProps['options'] = [
  126. {
  127. value: 'common',
  128. label: t('Public') + ' Prompts',
  129. },
  130. // {
  131. // value: 'private',
  132. // label: t('Private') + ' Prompts',
  133. // },
  134. ];
  135. return (
  136. <ConstructLayout>
  137. <div className={`px-6 py-2 ${styles['prompt-container']} md:p-6 h-[90vh] overflow-y-auto`}>
  138. <div className='flex justify-between items-center mb-6'>
  139. <div className='flex items-center gap-4'>
  140. <Segmented
  141. className='backdrop-filter backdrop-blur-lg bg-white bg-opacity-30 border-2 border-white rounded-lg shadow p-1 dark:border-[#6f7f95] dark:bg-[#6f7f95] dark:bg-opacity-60'
  142. options={items}
  143. onChange={type => {
  144. setPromptType(type as string);
  145. }}
  146. value={promptType}
  147. />
  148. {/* <Input
  149. variant="filled"
  150. prefix={<SearchOutlined />}
  151. placeholder={t('please_enter_the_keywords')}
  152. allowClear
  153. className="w-[230px] h-[40px] border-1 border-white backdrop-filter backdrop-blur-lg bg-white bg-opacity-30 dark:border-[#6f7f95] dark:bg-[#6f7f95] dark:bg-opacity-60"
  154. /> */}
  155. </div>
  156. <div className='flex items-center gap-4 h-10'>
  157. {/* {promptType === 'common' && (
  158. <Button className="border-none h-full" icon={<PlusOutlined />} disabled>
  159. {t('Add')} Prompts {t('template')}
  160. </Button>
  161. )} */}
  162. <Button
  163. className='border-none text-white bg-button-gradient h-full'
  164. onClick={handleAddBtn}
  165. icon={<PlusOutlined />}
  166. >
  167. {t('Add')} Prompts
  168. </Button>
  169. </div>
  170. </div>
  171. <Table
  172. columns={getColumns(t, handleEditBtn)}
  173. dataSource={promptList?.items || []}
  174. loading={loading}
  175. rowKey={record => record.prompt_name}
  176. pagination={{
  177. pageSize: 6,
  178. total: promptList?.total_count,
  179. onChange: async (page, page_size) => {
  180. await getPrompts(page, page_size);
  181. },
  182. }}
  183. />
  184. </div>
  185. </ConstructLayout>
  186. );
  187. };
  188. export default Prompt;