balibabu commited on
Commit
f30b544
·
1 Parent(s): ef0f1be

feat: display chunk token number when category of knowledge as general and unavailable llm models appear disabled and if the backend returns 401, it will jump to the login page and fixed the issue where the greeting would disappear when clicking on a new dialog (#117)

Browse files

* feat: Fixed the issue where the greeting would disappear when clicking on a new dialog

* feat: replace favicon with logo.svg

* feat: if the backend returns 401, it will jump to the login page.

* feat: unavailable llm models appear disabled

* feat: display chunk token number when category of knowledge as general

web/.umirc.ts CHANGED
@@ -11,6 +11,7 @@ export default defineConfig({
11
  esbuildMinifyIIFE: true,
12
  icons: {},
13
  hash: true,
 
14
  history: {
15
  type: 'browser',
16
  },
 
11
  esbuildMinifyIIFE: true,
12
  icons: {},
13
  hash: true,
14
+ favicons: ['/logo.svg'],
15
  history: {
16
  type: 'browser',
17
  },
web/public/logo.svg ADDED
web/src/hooks/llmHooks.ts CHANGED
@@ -30,6 +30,7 @@ export const useSelectLlmOptions = () => {
30
  options: value.map((x) => ({
31
  label: x.llm_name,
32
  value: x.llm_name,
 
33
  })),
34
  };
35
  });
 
30
  options: value.map((x) => ({
31
  label: x.llm_name,
32
  value: x.llm_name,
33
+ disabled: !x.available,
34
  })),
35
  };
36
  });
web/src/pages/add-knowledge/components/knowledge-setting/configuration.tsx CHANGED
@@ -10,10 +10,13 @@ import {
10
  import {
11
  Button,
12
  Divider,
 
13
  Form,
14
  Input,
 
15
  Radio,
16
  Select,
 
17
  Space,
18
  Typography,
19
  Upload,
@@ -80,6 +83,7 @@ const Configuration = () => {
80
  'permission',
81
  'embd_id',
82
  'parser_id',
 
83
  ]),
84
  avatar: fileList,
85
  });
@@ -144,6 +148,7 @@ const Configuration = () => {
144
  name="embd_id"
145
  label="Embedding Model"
146
  rules={[{ required: true }]}
 
147
  >
148
  <Select
149
  placeholder="Please select a country"
@@ -153,6 +158,7 @@ const Configuration = () => {
153
  <Form.Item
154
  name="parser_id"
155
  label="Knowledge base category"
 
156
  rules={[{ required: true }]}
157
  >
158
  <Select placeholder="Please select a country">
@@ -163,6 +169,48 @@ const Configuration = () => {
163
  ))}
164
  </Select>
165
  </Form.Item>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
166
  <Form.Item>
167
  <div className={styles.buttonWrapper}>
168
  <Space>
 
10
  import {
11
  Button,
12
  Divider,
13
+ Flex,
14
  Form,
15
  Input,
16
+ InputNumber,
17
  Radio,
18
  Select,
19
+ Slider,
20
  Space,
21
  Typography,
22
  Upload,
 
83
  'permission',
84
  'embd_id',
85
  'parser_id',
86
+ 'parser_config.chunk_token_num',
87
  ]),
88
  avatar: fileList,
89
  });
 
148
  name="embd_id"
149
  label="Embedding Model"
150
  rules={[{ required: true }]}
151
+ tooltip="xx"
152
  >
153
  <Select
154
  placeholder="Please select a country"
 
158
  <Form.Item
159
  name="parser_id"
160
  label="Knowledge base category"
161
+ tooltip="xx"
162
  rules={[{ required: true }]}
163
  >
164
  <Select placeholder="Please select a country">
 
169
  ))}
170
  </Select>
171
  </Form.Item>
172
+ <Form.Item noStyle dependencies={['parser_id']}>
173
+ {({ getFieldValue }) => {
174
+ const parserId = getFieldValue('parser_id');
175
+
176
+ if (parserId === 'general') {
177
+ return (
178
+ <Form.Item label="Chunk token number" tooltip="xxx">
179
+ <Flex gap={20} align="center">
180
+ <Flex flex={1}>
181
+ <Form.Item
182
+ name={['parser_config', 'chunk_token_num']}
183
+ noStyle
184
+ initialValue={128}
185
+ rules={[
186
+ { required: true, message: 'Province is required' },
187
+ ]}
188
+ >
189
+ <Slider className={styles.variableSlider} max={2048} />
190
+ </Form.Item>
191
+ </Flex>
192
+ <Form.Item
193
+ name={['parser_config', 'chunk_token_num']}
194
+ noStyle
195
+ initialValue={128}
196
+ rules={[
197
+ { required: true, message: 'Street is required' },
198
+ ]}
199
+ >
200
+ <InputNumber
201
+ className={styles.sliderInputNumber}
202
+ max={2048}
203
+ min={0}
204
+ />
205
+ </Form.Item>
206
+ </Flex>
207
+ </Form.Item>
208
+ );
209
+ }
210
+
211
+ return null;
212
+ }}
213
+ </Form.Item>
214
  <Form.Item>
215
  <div className={styles.buttonWrapper}>
216
  <Space>
web/src/pages/add-knowledge/components/knowledge-setting/index.less CHANGED
@@ -27,4 +27,7 @@
27
  .buttonWrapper {
28
  text-align: right;
29
  }
 
 
 
30
  }
 
27
  .buttonWrapper {
28
  text-align: right;
29
  }
30
+ .variableSlider {
31
+ width: 100%;
32
+ }
33
  }
web/src/pages/chat/chat-configuration-modal/index.tsx CHANGED
@@ -1,19 +1,18 @@
1
  import { ReactComponent as ChatConfigurationAtom } from '@/assets/svg/chat-configuration-atom.svg';
2
  import { IModalManagerChildrenProps } from '@/components/modal-manager';
 
3
  import { Divider, Flex, Form, Modal, Segmented, UploadFile } from 'antd';
4
  import { SegmentedValue } from 'antd/es/segmented';
5
  import omit from 'lodash/omit';
6
  import { useEffect, useRef, useState } from 'react';
7
- import AssistantSetting from './assistant-setting';
8
- import ModelSetting from './model-setting';
9
- import PromptEngine from './prompt-engine';
10
-
11
- import { useOneNamespaceEffectsLoading } from '@/hooks/storeHooks';
12
  import { variableEnabledFieldMap } from '../constants';
13
- import { useFetchDialog, useResetCurrentDialog, useSetDialog } from '../hooks';
14
  import { IPromptConfigParameters } from '../interface';
15
  import { excludeUnEnabledVariables } from '../utils';
 
16
  import { useFetchModelId } from './hooks';
 
 
 
17
  import styles from './index.less';
18
 
19
  enum ConfigurationSegmented {
@@ -45,22 +44,27 @@ const validateMessages = {
45
  };
46
 
47
  interface IProps extends IModalManagerChildrenProps {
48
- id: string;
 
 
 
49
  }
50
 
51
- const ChatConfigurationModal = ({ visible, hideModal, id }: IProps) => {
 
 
 
 
 
 
 
52
  const [form] = Form.useForm();
53
  const [value, setValue] = useState<ConfigurationSegmented>(
54
  ConfigurationSegmented.AssistantSetting,
55
  );
56
  const promptEngineRef = useRef<Array<IPromptConfigParameters>>([]);
57
- const loading = useOneNamespaceEffectsLoading('chatModel', ['setDialog']);
58
  const modelId = useFetchModelId(visible);
59
 
60
- const setDialog = useSetDialog();
61
- const currentDialog = useFetchDialog(id, visible);
62
- const { resetCurrentDialog } = useResetCurrentDialog();
63
-
64
  const handleOk = async () => {
65
  const values = await form.validateFields();
66
  const nextValues: any = omit(values, [
@@ -78,7 +82,7 @@ const ChatConfigurationModal = ({ visible, hideModal, id }: IProps) => {
78
  }
79
 
80
  const finalValues = {
81
- dialog_id: id,
82
  ...nextValues,
83
  prompt_config: {
84
  ...nextValues.prompt_config,
@@ -87,13 +91,7 @@ const ChatConfigurationModal = ({ visible, hideModal, id }: IProps) => {
87
  },
88
  icon,
89
  };
90
- console.info(promptEngineRef.current);
91
- console.info(nextValues);
92
- console.info(finalValues);
93
- const retcode: number = await setDialog(finalValues);
94
- if (retcode === 0) {
95
- hideModal();
96
- }
97
  };
98
 
99
  const handleCancel = () => {
@@ -105,7 +103,7 @@ const ChatConfigurationModal = ({ visible, hideModal, id }: IProps) => {
105
  };
106
 
107
  const handleModalAfterClose = () => {
108
- resetCurrentDialog();
109
  form.resetFields();
110
  };
111
 
@@ -124,19 +122,19 @@ const ChatConfigurationModal = ({ visible, hideModal, id }: IProps) => {
124
 
125
  useEffect(() => {
126
  if (visible) {
127
- const icon = currentDialog.icon;
128
  let fileList: UploadFile[] = [];
129
 
130
  if (icon) {
131
  fileList = [{ uid: '1', name: 'file', thumbUrl: icon, status: 'done' }];
132
  }
133
  form.setFieldsValue({
134
- ...currentDialog,
135
  icon: fileList,
136
- llm_id: currentDialog.llm_id ?? modelId,
137
  });
138
  }
139
- }, [currentDialog, form, visible, modelId]);
140
 
141
  return (
142
  <Modal
 
1
  import { ReactComponent as ChatConfigurationAtom } from '@/assets/svg/chat-configuration-atom.svg';
2
  import { IModalManagerChildrenProps } from '@/components/modal-manager';
3
+ import { IDialog } from '@/interfaces/database/chat';
4
  import { Divider, Flex, Form, Modal, Segmented, UploadFile } from 'antd';
5
  import { SegmentedValue } from 'antd/es/segmented';
6
  import omit from 'lodash/omit';
7
  import { useEffect, useRef, useState } from 'react';
 
 
 
 
 
8
  import { variableEnabledFieldMap } from '../constants';
 
9
  import { IPromptConfigParameters } from '../interface';
10
  import { excludeUnEnabledVariables } from '../utils';
11
+ import AssistantSetting from './assistant-setting';
12
  import { useFetchModelId } from './hooks';
13
+ import ModelSetting from './model-setting';
14
+ import PromptEngine from './prompt-engine';
15
+
16
  import styles from './index.less';
17
 
18
  enum ConfigurationSegmented {
 
44
  };
45
 
46
  interface IProps extends IModalManagerChildrenProps {
47
+ initialDialog: IDialog;
48
+ loading: boolean;
49
+ onOk: (dialog: IDialog) => void;
50
+ clearDialog: () => void;
51
  }
52
 
53
+ const ChatConfigurationModal = ({
54
+ visible,
55
+ hideModal,
56
+ initialDialog,
57
+ loading,
58
+ onOk,
59
+ clearDialog,
60
+ }: IProps) => {
61
  const [form] = Form.useForm();
62
  const [value, setValue] = useState<ConfigurationSegmented>(
63
  ConfigurationSegmented.AssistantSetting,
64
  );
65
  const promptEngineRef = useRef<Array<IPromptConfigParameters>>([]);
 
66
  const modelId = useFetchModelId(visible);
67
 
 
 
 
 
68
  const handleOk = async () => {
69
  const values = await form.validateFields();
70
  const nextValues: any = omit(values, [
 
82
  }
83
 
84
  const finalValues = {
85
+ dialog_id: initialDialog.id,
86
  ...nextValues,
87
  prompt_config: {
88
  ...nextValues.prompt_config,
 
91
  },
92
  icon,
93
  };
94
+ onOk(finalValues);
 
 
 
 
 
 
95
  };
96
 
97
  const handleCancel = () => {
 
103
  };
104
 
105
  const handleModalAfterClose = () => {
106
+ clearDialog();
107
  form.resetFields();
108
  };
109
 
 
122
 
123
  useEffect(() => {
124
  if (visible) {
125
+ const icon = initialDialog.icon;
126
  let fileList: UploadFile[] = [];
127
 
128
  if (icon) {
129
  fileList = [{ uid: '1', name: 'file', thumbUrl: icon, status: 'done' }];
130
  }
131
  form.setFieldsValue({
132
+ ...initialDialog,
133
  icon: fileList,
134
+ llm_id: initialDialog.llm_id ?? modelId,
135
  });
136
  }
137
+ }, [initialDialog, form, visible, modelId]);
138
 
139
  return (
140
  <Modal
web/src/pages/chat/chat-configuration-modal/model-setting.tsx CHANGED
@@ -54,7 +54,7 @@ const ModelSetting = ({ show, form }: ISegmentedContentProps) => {
54
  name="llm_id"
55
  rules={[{ required: true, message: 'Please select!' }]}
56
  >
57
- <Select options={modelOptions} />
58
  </Form.Item>
59
  <Divider></Divider>
60
  <Form.Item
 
54
  name="llm_id"
55
  rules={[{ required: true, message: 'Please select!' }]}
56
  >
57
+ <Select options={modelOptions} showSearch />
58
  </Form.Item>
59
  <Divider></Divider>
60
  <Form.Item
web/src/pages/chat/hooks.ts CHANGED
@@ -45,24 +45,42 @@ export const useSetDialog = () => {
45
  return setDialog;
46
  };
47
 
48
- export const useFetchDialog = (dialogId: string, visible: boolean): IDialog => {
49
- const dispatch = useDispatch();
50
  const currentDialog: IDialog = useSelector(
51
  (state: any) => state.chatModel.currentDialog,
52
  );
53
 
54
- const fetchDialog = useCallback(() => {
55
- if (dialogId) {
56
- dispatch({
57
- type: 'chatModel/getDialog',
58
- payload: { dialog_id: dialogId },
59
- });
60
- }
61
- }, [dispatch, dialogId]);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
62
 
63
  useEffect(() => {
64
  if (dialogId && visible) {
65
- fetchDialog();
66
  }
67
  }, [dialogId, fetchDialog, visible]);
68
 
@@ -123,14 +141,6 @@ export const useSelectPromptConfigParameters = (): VariableTableDataType[] => {
123
  return finalParameters;
124
  };
125
 
126
- export const useSelectCurrentDialog = () => {
127
- const currentDialog: IDialog = useSelector(
128
- (state: any) => state.chatModel.currentDialog,
129
- );
130
-
131
- return currentDialog;
132
- };
133
-
134
  export const useRemoveDialog = () => {
135
  const dispatch = useDispatch();
136
 
@@ -231,6 +241,57 @@ export const useHandleItemHover = () => {
231
  };
232
  };
233
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
234
  //#region conversation
235
 
236
  export const useFetchConversationList = () => {
 
45
  return setDialog;
46
  };
47
 
48
+ export const useSelectCurrentDialog = () => {
 
49
  const currentDialog: IDialog = useSelector(
50
  (state: any) => state.chatModel.currentDialog,
51
  );
52
 
53
+ return currentDialog;
54
+ };
55
+
56
+ export const useFetchDialog = () => {
57
+ const dispatch = useDispatch();
58
+
59
+ const fetchDialog = useCallback(
60
+ (dialogId: string, needToBeSaved = true) => {
61
+ if (dialogId) {
62
+ return dispatch<any>({
63
+ type: 'chatModel/getDialog',
64
+ payload: { dialog_id: dialogId, needToBeSaved },
65
+ });
66
+ }
67
+ },
68
+ [dispatch],
69
+ );
70
+
71
+ return fetchDialog;
72
+ };
73
+
74
+ export const useFetchDialogOnMount = (
75
+ dialogId: string,
76
+ visible: boolean,
77
+ ): IDialog => {
78
+ const currentDialog: IDialog = useSelectCurrentDialog();
79
+ const fetchDialog = useFetchDialog();
80
 
81
  useEffect(() => {
82
  if (dialogId && visible) {
83
+ fetchDialog(dialogId);
84
  }
85
  }, [dialogId, fetchDialog, visible]);
86
 
 
141
  return finalParameters;
142
  };
143
 
 
 
 
 
 
 
 
 
144
  export const useRemoveDialog = () => {
145
  const dispatch = useDispatch();
146
 
 
241
  };
242
  };
243
 
244
+ export const useEditDialog = () => {
245
+ const [dialog, setDialog] = useState<IDialog>({} as IDialog);
246
+ const fetchDialog = useFetchDialog();
247
+ const submitDialog = useSetDialog();
248
+ const loading = useOneNamespaceEffectsLoading('chatModel', ['setDialog']);
249
+
250
+ const {
251
+ visible: dialogEditVisible,
252
+ hideModal: hideDialogEditModal,
253
+ showModal: showDialogEditModal,
254
+ } = useSetModalState();
255
+
256
+ const onDialogEditOk = useCallback(
257
+ async (dialog: IDialog) => {
258
+ const ret = await submitDialog(dialog);
259
+
260
+ if (ret === 0) {
261
+ hideDialogEditModal();
262
+ }
263
+ },
264
+ [submitDialog, hideDialogEditModal],
265
+ );
266
+
267
+ const handleShowDialogEditModal = useCallback(
268
+ async (dialogId?: string) => {
269
+ if (dialogId) {
270
+ const ret = await fetchDialog(dialogId, false);
271
+ if (ret.retcode === 0) {
272
+ setDialog(ret.data);
273
+ }
274
+ }
275
+ showDialogEditModal();
276
+ },
277
+ [showDialogEditModal, fetchDialog],
278
+ );
279
+
280
+ const clearDialog = useCallback(() => {
281
+ setDialog({} as IDialog);
282
+ }, []);
283
+
284
+ return {
285
+ dialogSettingLoading: loading,
286
+ initialDialog: dialog,
287
+ onDialogEditOk,
288
+ dialogEditVisible,
289
+ hideDialogEditModal,
290
+ showDialogEditModal: handleShowDialogEditModal,
291
+ clearDialog,
292
+ };
293
+ };
294
+
295
  //#region conversation
296
 
297
  export const useFetchConversationList = () => {
web/src/pages/chat/index.tsx CHANGED
@@ -20,8 +20,9 @@ import ChatContainer from './chat-container';
20
  import {
21
  useClickConversationCard,
22
  useClickDialogCard,
 
23
  useFetchConversationList,
24
- useFetchDialog,
25
  useGetChatSearchParams,
26
  useHandleItemHover,
27
  useRemoveConversation,
@@ -60,8 +61,17 @@ const Chat = () => {
60
  hideConversationRenameModal,
61
  showConversationRenameModal,
62
  } = useRenameConversation();
 
 
 
 
 
 
 
 
 
63
 
64
- useFetchDialog(dialogId, true);
65
 
66
  const handleAppCardEnter = (id: string) => () => {
67
  handleItemEnter(id);
@@ -76,10 +86,7 @@ const Chat = () => {
76
  (info: any) => {
77
  info?.domEvent?.preventDefault();
78
  info?.domEvent?.stopPropagation();
79
- // if (dialogId) {
80
- setCurrentDialog(dialogId ?? '');
81
- // }
82
- showModal();
83
  };
84
 
85
  const handleRemoveDialog =
@@ -276,10 +283,13 @@ const Chat = () => {
276
  <Divider type={'vertical'} className={styles.divider}></Divider>
277
  <ChatContainer></ChatContainer>
278
  <ChatConfigurationModal
279
- visible={visible}
280
- showModal={showModal}
281
- hideModal={hideModal}
282
- id={currentDialog.id}
 
 
 
283
  ></ChatConfigurationModal>
284
  <RenameModal
285
  visible={conversationRenameVisible}
 
20
  import {
21
  useClickConversationCard,
22
  useClickDialogCard,
23
+ useEditDialog,
24
  useFetchConversationList,
25
+ useFetchDialogOnMount,
26
  useGetChatSearchParams,
27
  useHandleItemHover,
28
  useRemoveConversation,
 
61
  hideConversationRenameModal,
62
  showConversationRenameModal,
63
  } = useRenameConversation();
64
+ const {
65
+ dialogSettingLoading,
66
+ initialDialog,
67
+ onDialogEditOk,
68
+ dialogEditVisible,
69
+ clearDialog,
70
+ hideDialogEditModal,
71
+ showDialogEditModal,
72
+ } = useEditDialog();
73
 
74
+ useFetchDialogOnMount(dialogId, true);
75
 
76
  const handleAppCardEnter = (id: string) => () => {
77
  handleItemEnter(id);
 
86
  (info: any) => {
87
  info?.domEvent?.preventDefault();
88
  info?.domEvent?.stopPropagation();
89
+ showDialogEditModal(dialogId);
 
 
 
90
  };
91
 
92
  const handleRemoveDialog =
 
283
  <Divider type={'vertical'} className={styles.divider}></Divider>
284
  <ChatContainer></ChatContainer>
285
  <ChatConfigurationModal
286
+ visible={dialogEditVisible}
287
+ initialDialog={initialDialog}
288
+ showModal={showDialogEditModal}
289
+ hideModal={hideDialogEditModal}
290
+ loading={dialogSettingLoading}
291
+ onOk={onDialogEditOk}
292
+ clearDialog={clearDialog}
293
  ></ChatConfigurationModal>
294
  <RenameModal
295
  visible={conversationRenameVisible}
web/src/pages/chat/model.ts CHANGED
@@ -63,16 +63,21 @@ const model: DvaModel<ChatModelState> = {
63
 
64
  effects: {
65
  *getDialog({ payload }, { call, put }) {
66
- const { data } = yield call(chatService.getDialog, payload);
67
- if (data.retcode === 0) {
 
 
 
 
68
  yield put({ type: 'setCurrentDialog', payload: data.data });
69
  }
 
70
  },
71
  *setDialog({ payload }, { call, put }) {
72
  const { data } = yield call(chatService.setDialog, payload);
73
  if (data.retcode === 0) {
74
  yield put({ type: 'listDialog' });
75
- message.success('Created successfully !');
76
  }
77
  return data.retcode;
78
  },
 
63
 
64
  effects: {
65
  *getDialog({ payload }, { call, put }) {
66
+ const needToBeSaved =
67
+ payload.needToBeSaved === undefined ? true : payload.needToBeSaved;
68
+ const { data } = yield call(chatService.getDialog, {
69
+ dialog_id: payload.dialog_id,
70
+ });
71
+ if (data.retcode === 0 && needToBeSaved) {
72
  yield put({ type: 'setCurrentDialog', payload: data.data });
73
  }
74
+ return data;
75
  },
76
  *setDialog({ payload }, { call, put }) {
77
  const { data } = yield call(chatService.setDialog, payload);
78
  if (data.retcode === 0) {
79
  yield put({ type: 'listDialog' });
80
+ message.success(payload.dialog_id ? 'Modified!' : 'Created!');
81
  }
82
  return data.retcode;
83
  },
web/src/utils/history.ts DELETED
@@ -1,3 +0,0 @@
1
- import { createBrowserHistory } from 'history';
2
-
3
- export const history = createBrowserHistory();
 
 
 
 
web/src/utils/request.ts CHANGED
@@ -1,11 +1,8 @@
1
- import { message, notification } from 'antd';
2
- import { RequestMethod, extend } from 'umi-request';
3
-
4
  import { Authorization } from '@/constants/authorization';
5
- import api from '@/utils/api';
6
  import authorizationUtil from '@/utils/authorizationUtil';
7
-
8
- const { login } = api;
 
9
 
10
  const ABORT_REQUEST_ERR_MESSAGE = 'The user aborted a request.'; // 手动中断请求。errorHandler 抛出的error message
11
 
@@ -120,7 +117,7 @@ request.interceptors.response.use(async (response: any, options) => {
120
  duration: 3,
121
  });
122
  authorizationUtil.removeAll();
123
- // history.push('/login'); // Will not jump to the login page
124
  } else if (data.retcode !== 0) {
125
  if (data.retcode === 100) {
126
  message.error(data.retmsg);
 
 
 
 
1
  import { Authorization } from '@/constants/authorization';
 
2
  import authorizationUtil from '@/utils/authorizationUtil';
3
+ import { message, notification } from 'antd';
4
+ import { history } from 'umi';
5
+ import { RequestMethod, extend } from 'umi-request';
6
 
7
  const ABORT_REQUEST_ERR_MESSAGE = 'The user aborted a request.'; // 手动中断请求。errorHandler 抛出的error message
8
 
 
117
  duration: 3,
118
  });
119
  authorizationUtil.removeAll();
120
+ history.push('/login'); // Will not jump to the login page
121
  } else if (data.retcode !== 0) {
122
  if (data.retcode === 100) {
123
  message.error(data.retmsg);