aldehyde 0.2.456 → 0.2.458

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (81) hide show
  1. package/lib/icon/aliIcon.d.ts +1 -1
  2. package/lib/icon/aliIcon.d.ts.map +1 -1
  3. package/lib/icon/aliIcon.js +4 -3
  4. package/lib/icon/aliIcon.js.map +1 -1
  5. package/lib/icon/local-aliIcon/iconfont.d.ts +1 -0
  6. package/lib/icon/local-aliIcon/iconfont.d.ts.map +1 -0
  7. package/lib/icon/local-aliIcon/iconfont.js +20 -0
  8. package/lib/icon/local-aliIcon/iconfont.js.map +1 -0
  9. package/lib/layout2/components/system-messages.d.ts +8 -0
  10. package/lib/layout2/components/system-messages.d.ts.map +1 -0
  11. package/lib/layout2/components/system-messages.js +70 -0
  12. package/lib/layout2/components/system-messages.js.map +1 -0
  13. package/lib/layout2/components/user-button.d.ts.map +1 -1
  14. package/lib/layout2/components/user-button.js +3 -7
  15. package/lib/layout2/components/user-button.js.map +1 -1
  16. package/lib/layout2/components/user-notification.d.ts +8 -0
  17. package/lib/layout2/components/user-notification.d.ts.map +1 -0
  18. package/lib/layout2/components/user-notification.js +69 -0
  19. package/lib/layout2/components/user-notification.js.map +1 -0
  20. package/lib/layout2/header.d.ts.map +1 -1
  21. package/lib/layout2/header.js +5 -0
  22. package/lib/layout2/header.js.map +1 -1
  23. package/lib/layout3/header.d.ts.map +1 -1
  24. package/lib/layout3/header.js +5 -0
  25. package/lib/layout3/header.js.map +1 -1
  26. package/lib/layout4/header.d.ts.map +1 -1
  27. package/lib/layout4/header.js +5 -0
  28. package/lib/layout4/header.js.map +1 -1
  29. package/lib/layout5/header.d.ts.map +1 -1
  30. package/lib/layout5/header.js +5 -0
  31. package/lib/layout5/header.js.map +1 -1
  32. package/lib/routable/ltmpl-route.js +1 -1
  33. package/lib/routable/ltmpl-route.js.map +1 -1
  34. package/lib/sso-Login/index.d.ts.map +1 -1
  35. package/lib/sso-Login/index.js +29 -5
  36. package/lib/sso-Login/index.js.map +1 -1
  37. package/lib/sso-Login/service/index.d.ts +2 -0
  38. package/lib/sso-Login/service/index.d.ts.map +1 -0
  39. package/lib/sso-Login/service/index.js +24 -0
  40. package/lib/sso-Login/service/index.js.map +1 -0
  41. package/lib/sso-Login/service/login.d.ts +2 -0
  42. package/lib/sso-Login/service/login.d.ts.map +1 -0
  43. package/lib/sso-Login/service/login.js +87 -0
  44. package/lib/sso-Login/service/login.js.map +1 -0
  45. package/lib/table/modal-select-table.d.ts +8 -1
  46. package/lib/table/modal-select-table.d.ts.map +1 -1
  47. package/lib/table/modal-select-table.js +25 -1
  48. package/lib/table/modal-select-table.js.map +1 -1
  49. package/lib/table/relation-table.d.ts +3 -0
  50. package/lib/table/relation-table.d.ts.map +1 -1
  51. package/lib/table/relation-table.js +1 -1
  52. package/lib/table/relation-table.js.map +1 -1
  53. package/lib/tmpl/hcservice-v3.d.ts +1 -0
  54. package/lib/tmpl/hcservice-v3.d.ts.map +1 -1
  55. package/lib/tmpl/hcservice-v3.js +15 -0
  56. package/lib/tmpl/hcservice-v3.js.map +1 -1
  57. package/lib/tmpl/interface.d.ts +4 -0
  58. package/lib/tmpl/interface.d.ts.map +1 -1
  59. package/lib/tmpl/interface.js.map +1 -1
  60. package/lib/tmpl/tmpl-config-analysis.d.ts.map +1 -1
  61. package/lib/tmpl/tmpl-config-analysis.js +14 -5
  62. package/lib/tmpl/tmpl-config-analysis.js.map +1 -1
  63. package/package.json +1 -1
  64. package/src/aldehyde/icon/aliIcon.tsx +5 -3
  65. package/src/aldehyde/icon/local-aliIcon/iconfont.js +1 -0
  66. package/src/aldehyde/layout2/components/system-messages.tsx +75 -0
  67. package/src/aldehyde/layout2/components/user-button.tsx +3 -7
  68. package/src/aldehyde/layout2/components/user-notification.tsx +74 -0
  69. package/src/aldehyde/layout2/header.tsx +4 -0
  70. package/src/aldehyde/layout3/header.tsx +4 -0
  71. package/src/aldehyde/layout4/header.tsx +4 -0
  72. package/src/aldehyde/layout5/header.tsx +4 -0
  73. package/src/aldehyde/routable/ltmpl-route.tsx +1 -1
  74. package/src/aldehyde/sso-Login/index.tsx +28 -5
  75. package/src/aldehyde/sso-Login/service/index.js +16 -0
  76. package/src/aldehyde/sso-Login/service/login.js +75 -0
  77. package/src/aldehyde/table/modal-select-table.tsx +33 -5
  78. package/src/aldehyde/table/relation-table.tsx +3 -1
  79. package/src/aldehyde/tmpl/hcservice-v3.tsx +13 -0
  80. package/src/aldehyde/tmpl/interface.tsx +4 -0
  81. package/src/aldehyde/tmpl/tmpl-config-analysis.tsx +14 -5
@@ -0,0 +1,74 @@
1
+ import React, { useEffect, useRef } from "react";
2
+ import { notification, Modal, Button } from "antd";
3
+ import { useNavigate } from "react-router-dom";
4
+ import { MenuType } from "../type/layout-type";
5
+ import WebSocket from "../../tmpl/web-socket";
6
+ import Units from "../../units";
7
+ import { useLocale } from "../../locale/useLocale";
8
+
9
+ interface UserNotification {
10
+ title?: string; // 标题
11
+ description?: string; // 内容
12
+ duration?: number; // 延迟时间
13
+ type?: "success" | "error" | "info" | "warning"; // 类型
14
+ closable?: boolean; // 是否可以关闭
15
+ sysDisabled?: boolean; // 是否显示遮罩层
16
+ sourceId?: string; // 用户消息推送,菜单sourceId
17
+ }
18
+
19
+ interface Props {
20
+ menuList: MenuType[];
21
+ }
22
+
23
+ // 用户消息
24
+ const Index = (props: Props) => {
25
+ const { menuList } = props;
26
+ const [api, contextHolder] = notification.useNotification();
27
+ const { translate } = useLocale();
28
+ const navigate = useNavigate();
29
+ const wsRef = useRef(undefined); // 实时数据websocket连接
30
+ const subscribeRef = useRef(undefined); // 实时数据订阅
31
+
32
+ // 订阅消息数据
33
+ const getWebSocketUserNotification = async () => {
34
+ if (subscribeRef.current) { subscribeRef.current.unsubscribe(); }
35
+ wsRef.current = WebSocket.getInstance("v3/kk-ws");
36
+ subscribeRef.current = await wsRef.current.subscribe("/user/queue/notification", {}, (data) => {
37
+ openNotification(data);
38
+ });
39
+ }
40
+
41
+ useEffect(() => {
42
+ getWebSocketUserNotification();
43
+ return () => {
44
+ if (subscribeRef.current) { subscribeRef.current.unsubscribe(); }
45
+ }
46
+ }, []);
47
+
48
+ const routerTo = (sourceId: string) => {
49
+ const menu = Units.findItemByIdIterative(menuList, sourceId);
50
+ if (menu) {
51
+ navigate(`/${menu.url}`);
52
+ }
53
+ }
54
+
55
+ const openNotification = (message: UserNotification) => {
56
+ if (!message) {
57
+ return;
58
+ }
59
+ const { title, description, duration, type, closable, sysDisabled, sourceId } = message;
60
+ const btn = sourceId ? <div style={{ textAlign: "end" }}><Button style={{ padding: 0 }} type="link" onClick={() => routerTo(sourceId)}>{translate("${查看}")}</Button></div> : false;
61
+ const nContent = { style: { padding: "12px" }, message: title, description, duration, closeIcon: closable, btn };
62
+ const mContent = { styles: { content: { padding: "20px 20px 12px" } }, title, content: description, closable, footer: btn };
63
+ if (sysDisabled) { // 带遮罩层
64
+ const modal = Modal[type || "confirm"](mContent);
65
+ if (duration) setTimeout(() => modal.destroy(), duration * 1000);
66
+ } else { // 不带遮罩层
67
+ api[type || "open"](nContent);
68
+ }
69
+ };
70
+
71
+ return contextHolder;
72
+ };
73
+
74
+ export default Index;
@@ -25,6 +25,8 @@ import { useLayoutContext } from "./layout-context";
25
25
  import IconFont from "./components/icon-font";
26
26
  import SearchMenu from "./components/search-menu";
27
27
  import ScreenfullButton from "./components/screenfull-button";
28
+ import SystemMessages from "./components/system-messages";
29
+ import UserNotification from "./components/user-notification";
28
30
  import { ThemeConfig } from "../tmpl/interface";
29
31
 
30
32
  const toolbarStyle: CSSProperties = {
@@ -247,6 +249,8 @@ const Header: React.FC<HeaderPropsType> = ({ systemName, menuList, style, logoIm
247
249
  flexDirection: "row",
248
250
  }}
249
251
  >
252
+ {themeConfig?.wsTypes?.includes("sys-messages") ? <SystemMessages menuList={menuList} /> : ""}
253
+ {themeConfig?.wsTypes?.includes("user-notification") ? <UserNotification menuList={menuList} /> : ""}
250
254
  <Space size="large">
251
255
  <ScreenfullButton style={toolbarStyle} />
252
256
  <SearchMenu menuList={menuList} />
@@ -13,6 +13,8 @@ import { useLayoutContext } from "../layout2/layout-context";
13
13
  import UserButton from "../layout2/components/user-button";
14
14
  import SearchMenu from "../layout2/components/search-menu";
15
15
  import ScreenfullButton from "../layout2/components/screenfull-button";
16
+ import SystemMessages from "../layout2/components/system-messages";
17
+ import UserNotification from "../layout2/components/user-notification";
16
18
  import headerBgImg from "./imgs/header-bg.png";
17
19
  import homeBgImg from "./imgs/home-bg.png";
18
20
  import Time from "./components/time";
@@ -141,6 +143,8 @@ const Header: React.FC<HeaderPropsType> = ({ systemName, menuList, themeConfig,
141
143
  <div className="header-time"><Time /></div>
142
144
  <div className="header-title">{translate("${" + systemName + "}")}</div>
143
145
  <div className="header-right" >
146
+ {themeConfig?.wsTypes?.includes("sys-messages") ? <SystemMessages menuList={menuList} /> : ""}
147
+ {themeConfig?.wsTypes?.includes("user-notification") ? <UserNotification menuList={menuList} /> : ""}
144
148
  <Space size="large" >
145
149
  <ScreenfullButton style={toolbarStyle} />
146
150
  <SearchMenu menuList={menuList} style={toolbarStyle} />
@@ -12,6 +12,8 @@ import { useLayoutContext } from "../layout2/layout-context";
12
12
  import UserButton from "../layout2/components/user-button";
13
13
  import SearchMenu from "../layout2/components/search-menu";
14
14
  import ScreenfullButton from "../layout2/components/screenfull-button";
15
+ import SystemMessages from "../layout2/components/system-messages";
16
+ import UserNotification from "../layout2/components/user-notification";
15
17
  import headerBgImg from "./imgs/header-bg.png";
16
18
  import menuItemBgImg from "./imgs/menu-item-bg.png";
17
19
  import userImg from "./imgs/user.png";
@@ -156,6 +158,8 @@ const Header: React.FC<HeaderPropsType> = ({ systemName, menuList, logoImg, them
156
158
  />
157
159
  </div>
158
160
  <div className="header-right" >
161
+ {themeConfig?.wsTypes?.includes("sys-messages") ? <SystemMessages menuList={menuList} /> : ""}
162
+ {themeConfig?.wsTypes?.includes("user-notification") ? <UserNotification menuList={menuList} /> : ""}
159
163
  <Space size="large">
160
164
  <ScreenfullButton style={toolbarStyle} />
161
165
  <SearchMenu menuList={menuList} style={toolbarStyle} />
@@ -9,6 +9,8 @@ import L2MenuMessageBar from "../layout/menu/l2menu-message-bar";
9
9
  import UserButton from "../layout2/components/user-button";
10
10
  import SearchMenu from "../layout2/components/search-menu";
11
11
  import ScreenfullButton from "../layout2/components/screenfull-button";
12
+ import SystemMessages from "../layout2/components/system-messages";
13
+ import UserNotification from "../layout2/components/user-notification";
12
14
  import { MenuType } from "../layout2/type/layout-type";
13
15
  import { useLocale } from "../locale/useLocale";
14
16
  import { getLeftMostRouteInfo, handlePropsMenuToAntdMenu } from "../layout2/util/menu-util";
@@ -164,6 +166,8 @@ const Header: React.FC<HeaderPropsType> = ({ menuList, themeConfig }) => {
164
166
  <Breadcrumb items={breadcrumbItems} />
165
167
  </ConfigProvider>
166
168
  <Space size="large" style={{ height: "100%" }}>
169
+ {themeConfig?.wsTypes?.includes("sys-messages") ? <SystemMessages menuList={menuList} /> : ""}
170
+ {themeConfig?.wsTypes?.includes("user-notification") ? <UserNotification menuList={menuList} /> : ""}
167
171
  <ScreenfullButton style={toolbarStyle} />
168
172
  <SearchMenu menuList={menuList} style={toolbarStyle} />
169
173
  {menu?.length > 1 &&
@@ -351,7 +351,7 @@ class LtmplRoute extends React.PureComponent<LtmplRouteProps, LtmplRouteState> {
351
351
 
352
352
  onChangePage = (pageNo: number, pageSize: number, pageSizeOptions?: number[]) => {
353
353
  const { location } = this.props;
354
- const temPageSizeOptions = pageSizeOptions ? pageSizeOptions : this.state.pageSizeOptions;
354
+ const temPageSizeOptions = pageSizeOptions?.length ? pageSizeOptions : this.state.pageSizeOptions;
355
355
  let search = location.search;
356
356
  let params = Units.transQueryStrToParams(search, null);
357
357
  params["pageNo"] = pageNo;
@@ -4,6 +4,7 @@ import { Spin } from "antd";
4
4
  import HCserviceV3 from "../tmpl/hcservice-v3";
5
5
  import HCDataSource from "../tmpl/hc-data-source";
6
6
  import ProgramConfig from "../units";
7
+ import { getMenuConfig } from "../layout2/page";
7
8
 
8
9
  interface Props {
9
10
  serverKey?: string;
@@ -19,18 +20,26 @@ const Index = (props: Props) => {
19
20
  const username = temParams.get("username");
20
21
  const ssoToken = temParams.get("ssoToken");
21
22
  const programCode = temParams.get("programCode");
22
- return { username, ssoToken, programCode };
23
+ const token = temParams.get("token");
24
+ const sourceId = temParams.get("sourceId");
25
+ return { username, ssoToken, programCode, token, sourceId };
23
26
  }, [search]);
24
27
 
25
- const login = async () => {
28
+ const ssoTokenLogin = async () => {
26
29
  setLoading(true);
27
- const { username, ssoToken, programCode } = params;
30
+ const { username, ssoToken, programCode, sourceId } = params;
28
31
  const res = await HCserviceV3.ssoTokenLogin({ username, ssoToken }, programCode, serverKey);
29
32
  const { defaultStyleTheme } = await ProgramConfig.getThemeConfig() || {};
30
33
  if (res.status === "success") {
31
34
  HCDataSource.clear();
32
- window.location.hash = `/${defaultStyleTheme || "v2"}/home`;
33
35
  ProgramConfig.setHydrocarbonToken(res.token);
36
+ if (sourceId) {
37
+ const temData = await getMenuConfig(defaultStyleTheme || "v2");
38
+ const menu = ProgramConfig.findItemByIdIterative(temData.menu, sourceId);
39
+ window.location.hash = menu?.url || `/${defaultStyleTheme || "v2"}/home`;
40
+ } else {
41
+ window.location.hash = `/${defaultStyleTheme || "v2"}/home`;
42
+ }
34
43
  } else if (res.status === "error") {
35
44
  const allThemes = ProgramConfig.getAllThemes();
36
45
  window.location.hash = `/${allThemes[defaultStyleTheme || "v2"].loginPath}`;
@@ -38,9 +47,23 @@ const Index = (props: Props) => {
38
47
  setLoading(false);
39
48
  };
40
49
 
50
+ const tokenLogin = async () => {
51
+ const { token, sourceId } = params;
52
+ const { defaultStyleTheme } = await ProgramConfig.getThemeConfig() || {};
53
+ HCDataSource.clear();
54
+ ProgramConfig.setHydrocarbonToken(token);
55
+ if (sourceId) {
56
+ const temData = await getMenuConfig(defaultStyleTheme || "v2");
57
+ const menu = ProgramConfig.findItemByIdIterative(temData.menu, sourceId);
58
+ window.location.hash = menu?.url || `/${defaultStyleTheme || "v2"}/home`;
59
+ } else {
60
+ window.location.hash = `/${defaultStyleTheme || "v2"}/home`;
61
+ }
62
+ }
63
+
41
64
  useEffect(() => {
42
65
  if (params) {
43
- login();
66
+ params.token ? tokenLogin() : ssoTokenLogin();
44
67
  }
45
68
  }, [params])
46
69
 
@@ -0,0 +1,16 @@
1
+ import { handleLogin } from "./login";
2
+
3
+ const Username = "";
4
+ const Password = "";
5
+ const SourceId = ""; // 菜单SourceId
6
+ const Path = "";
7
+ const ProgramCode = "";
8
+
9
+ export const getUrl = async () => {
10
+ const token = await handleLogin({ path: Path, username: Username, password: Password, programCode: ProgramCode });
11
+ if (!token) {
12
+ return null;
13
+ }
14
+ const url = `${Path}/#/sso-token?token=${token}&sourceId=${SourceId}`;
15
+ return url;
16
+ }
@@ -0,0 +1,75 @@
1
+ import dayjs from "dayjs";
2
+ import JSEncrypt from 'jsencrypt';
3
+ import superagent from "superagent";
4
+
5
+ export const handleLogin = async (params) => {
6
+ const { username, password, programCode, path } = params || {};
7
+ if (!username || !password || !programCode || !path) {
8
+ return null;
9
+ }
10
+ const pubkey = await getPubkey(params);
11
+ if (!pubkey) {
12
+ return null;
13
+ }
14
+ const res = await login({ loginData: { username, password }, pubkey, programCode, path });
15
+ if (res.status === "success") {
16
+ return res.token;
17
+ } else {
18
+ console.log("error:", res.message);
19
+ return null;
20
+ }
21
+ }
22
+
23
+ const getPubkey = async (params) => {
24
+ const { programCode, path } = params || {};
25
+ if (!programCode) {
26
+ return null;
27
+ }
28
+ const res = await request({ url: "/v3/auth/ras-pubkey", programCode, method: "GET", path });
29
+ return res?.status === "success" ? res.rasPubkey : null;
30
+ };
31
+
32
+ const rsaEncrypt = (word, keyStr) => {
33
+ const encrypt = new JSEncrypt();
34
+ encrypt.setPublicKey(keyStr);
35
+ return encrypt.encrypt(word);
36
+ }
37
+
38
+ const login = async (params) => {
39
+ const { loginData, pubkey, programCode, serverKey, path } = params;
40
+ let datetime = dayjs(new Date()).tz("Europe/London").format("YYYY-MM-DD HH:mm:ss");
41
+ let userInfo = rsaEncrypt(JSON.stringify({ ...loginData, datetime }), pubkey);
42
+ let res = await request({ url: "/v3/auth/hctoken", serverKey, programCode, query: { userInfo }, method: "GET", path });
43
+ return { status: res.status, token: res.token };
44
+ }
45
+
46
+ const request = (params) => {
47
+ const { programCode, method, path, query, data, url } = params;
48
+ return new Promise((resolve, reject) => {
49
+ superagent(method || "POST", path + url)
50
+ .type("form")
51
+ .set("hydrocarbon-program-token", programCode)
52
+ .query(query || "")
53
+ .send(data)
54
+ .end((req, res) => {
55
+ if (!res) {
56
+ resolve({ message: "服务器连接失败" });
57
+ } else {
58
+ if (res.status === 200) {
59
+ let result = res.body;
60
+ resolve(result);
61
+ } else if ([201, 403].includes(res.status)) {
62
+ resolve(res);
63
+ } else if (res.status === 405 || res.status === 406) {
64
+ resolve({ ...res, message: "权限不足" });
65
+ } else if (res.status === 404 || res.status === 504) {
66
+ resolve({ ...res, message: "没找到服务" });
67
+ } else if (res.status === 500) {
68
+ resolve(undefined);
69
+ } else {
70
+ reject(res.body);
71
+ }
72
+ }
73
+ });
74
+ });
75
+ }
@@ -1,6 +1,7 @@
1
- import React from 'react'
2
- import "./index.css"
3
- import { DtmplData, QueryKey, SelectConfig, SelectedRow } from "../tmpl/interface";
1
+ import React from 'react';
2
+ import { FormInstance } from "antd";
3
+ import "./index.css";
4
+ import { DtmplData, QueryKey, SelectConfig, SelectedRow, FieldConfig } from "../tmpl/interface";
4
5
  import TableUnits from "./table-util";
5
6
  import SupportInputTypes from '../tmpl/control-type-supportor';
6
7
  import HCDataSource from '../tmpl/hc-data-source';
@@ -23,6 +24,8 @@ interface ModelSelectTableProps {
23
24
  onCancel: () => void,
24
25
  defaultCriteriaValue?: object,
25
26
  onOK: (selectedRows: SelectedRow[]) => void,
27
+ parentFormInstance?: FormInstance,
28
+ selectRelValueField?: FieldConfig,
26
29
  };
27
30
 
28
31
  interface ModelSelectTableStat {
@@ -54,8 +57,33 @@ class ModelSelectTable extends React.PureComponent<ModelSelectTableProps, ModelS
54
57
  selectedRows: [],
55
58
  }
56
59
 
57
- loadData = async (selectConfig: SelectConfig, criteriaData: object) => {
60
+ // 表单关系字段组查询取值start
61
+ getSubDtmplData = async (valueField, code) => {
62
+ const { serverKey } = this.props;
63
+ const dtmplData = await HcserviceV3.requestDtmplData(serverKey, valueField.id, code.split("@R@")[0], null);
64
+ const subField = valueField.subRelValueField;
65
+ const subData = dtmplData.fieldMap[subField.id];
66
+ if (subField.subRelValueField && subData) { // 存在下级关联项
67
+ return this.getSubDtmplData(subField, subData);
68
+ }
69
+ return subData;
70
+ }
71
+
72
+ getSecondCriteria = async () => {
73
+ const { parentFormInstance, selectRelValueField } = this.props;
74
+ let secondCriteria;
75
+ if (selectRelValueField && parentFormInstance) {
76
+ secondCriteria = parentFormInstance.getFieldValue(selectRelValueField.id);
77
+ if (selectRelValueField.subRelValueField && secondCriteria) {
78
+ secondCriteria = await this.getSubDtmplData(selectRelValueField, secondCriteria);
79
+ }
80
+ }
81
+ return { secondCriteria };
82
+ }
83
+ // 表单关系字段组查询点选取值end
58
84
 
85
+ loadData = async (selectConfig: SelectConfig, criteriaData: object) => {
86
+ const secondCriteria = await this.getSecondCriteria();
59
87
  this.setState({
60
88
  loading: true,
61
89
  })
@@ -70,7 +98,7 @@ class ModelSelectTable extends React.PureComponent<ModelSelectTableProps, ModelS
70
98
  const { sourceId, exceptCodes, serverKey, mainCode, existRelation } = this.props;
71
99
  /** 构建 dataSource **/
72
100
  //构建过滤条件
73
- let queryKey: QueryKey = await HcserviceV3.requestLtmplQueryKey(serverKey, sourceId, { exceptCodes, ...criteriaData, ...pageInfo, mainCode, existRelation });
101
+ let queryKey: QueryKey = await HcserviceV3.requestLtmplQueryKey(serverKey, sourceId, { exceptCodes, ...criteriaData, ...pageInfo, ...secondCriteria, mainCode, existRelation });
74
102
  this.setState({
75
103
  queryKey,
76
104
  criteriaData,
@@ -1081,7 +1081,9 @@ class RelationTable extends React.PureComponent<
1081
1081
  exceptCodes={exceptCodes}
1082
1082
  mainCode={mainCode1}
1083
1083
  sourceId={fieldGroupConfig.id}
1084
- ></ModelSelectTable>
1084
+ selectRelValueField={fieldGroupConfig.selectRelValueField}
1085
+ parentFormInstance={parentFormInstance}
1086
+ />
1085
1087
  ) : ""}
1086
1088
  </>
1087
1089
  );
@@ -1523,4 +1523,17 @@ export default class HcserviceV3 {
1523
1523
  message.error(translate("${发送失败}"), 3);
1524
1524
  }
1525
1525
  }
1526
+
1527
+ static async wsPushTopic(hydrocarbonToken, data) {
1528
+ const res = await Super.super({
1529
+ url: `/v3/ws-push-topic/${hydrocarbonToken}`,
1530
+ data,
1531
+ method: "POST",
1532
+ });
1533
+ if (res.code === 200) {
1534
+ message.success(translate("${已发送}"));
1535
+ } else {
1536
+ message.error(translate("${发送失败}"), 3);
1537
+ }
1538
+ }
1526
1539
  }
@@ -373,6 +373,7 @@ export interface FieldGroupConfig extends OrderableTmplBase {
373
373
  batchAddFileField?: FieldConfig;
374
374
  addRowPosition?: "begin" | "end";
375
375
  submitType?: "separate" | "follow";
376
+ selectRelValueField?: FieldConfig; // 关联关系组点选查询取值字段
376
377
  }
377
378
 
378
379
  export type SaveJumpType = "list" | "add" | "edit";
@@ -446,6 +447,7 @@ export interface FieldConfig extends FieldBase {
446
447
  requiredRuleCriterias?: FieldConfig[];
447
448
  usableRuleCriterias?: FieldConfig[];
448
449
  relValueField?: FieldConfig;
450
+ subRelValueField?: FieldConfig;
449
451
  hidden?: boolean;
450
452
  serverKey?: string;
451
453
  sourceId?: string;
@@ -471,6 +473,7 @@ export interface FieldConfig extends FieldBase {
471
473
  defShowIcon?: boolean; // 图片组件,是否默认显示缩略图,默认显示
472
474
  showUploadList?: boolean; // 上传组件是否显示文件列表
473
475
  uploadText?: string; // 上传组件文本配置
476
+ fieldSwitchRequiredClearType?: "doNotClear" | "toOptionalClear" | "toRequiredClear" | "switchClear"; // 必填条件-是否清除关联项
474
477
  }
475
478
 
476
479
  export interface ActionRenderProps {
@@ -891,4 +894,5 @@ export interface ThemeConfig {
891
894
  homeSourceId?: string; // 首页菜单
892
895
  supportedLanguages?: string[]; // 支持语言
893
896
  defaultLanguage?: string; // 默认语言
897
+ wsTypes?: ("sys-messages" | "user-notification")[];
894
898
  }
@@ -402,7 +402,7 @@ TmplConfigAnalysis.buildInDtmplConfig = (
402
402
  if (!changedValues) {
403
403
  continue;
404
404
  }
405
- const requireValue = field.requiredRuleCriterias?.some(r => {
405
+ const requireValue = field.requiredRuleCriterias?.find(r => {
406
406
  const id = TmplConfigAnalysis.getFieldId(dtmplConfig, r.mstrucId);
407
407
  return changedValues.hasOwnProperty(id);
408
408
  });
@@ -419,11 +419,20 @@ TmplConfigAnalysis.buildInDtmplConfig = (
419
419
  // "secondCriteria": changedValues[field.relValueField.id]
420
420
  };
421
421
  field.configChanged = true;
422
- if (formInstance.getFieldValue(field.id)) {
423
- formInstance.setFieldValue(field.id, null);
422
+ // 必填条件配置是否清除/可用条件默认清除
423
+ let isClear = false;
424
+ if (requireValue) {
425
+ const clearType = requireValue?.fieldSwitchRequiredClearType;
426
+ const isRequired = field?.required;
427
+ isClear = (clearType === "switchClear" || (clearType === "toRequiredClear" && isRequired) || (clearType === "toOptionalClear" && !isRequired)) ? true : false;
424
428
  }
425
- if (formInstance.getFieldValue("c_" + field.id)) {
426
- formInstance.setFieldValue("c_" + field.id, null);
429
+ if (isClear || usableValue) { // 清除关联项值
430
+ if (formInstance.getFieldValue(field.id)) {
431
+ formInstance.setFieldValue(field.id, null);
432
+ }
433
+ if (formInstance.getFieldValue("c_" + field.id)) {
434
+ formInstance.setFieldValue("c_" + field.id, null);
435
+ }
427
436
  }
428
437
  }
429
438
  }