km-card-layout-component-miniprogram 0.1.19 → 0.1.20

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 (46) hide show
  1. package/example/app.js +11 -1
  2. package/example/pages/home/index.js +324 -101
  3. package/example/pages/home/index.wxml +2 -1
  4. package/miniprogram_dist/components/card-layout/elements/custom-element/index.js +12 -6
  5. package/miniprogram_dist/components/card-layout/elements/custom-element/index.wxml +4 -6
  6. package/miniprogram_dist/components/card-layout/elements/custom-element/index.wxss +1 -1
  7. package/miniprogram_dist/components/card-layout/elements/icon-element/index.js +32 -15
  8. package/miniprogram_dist/components/card-layout/elements/icon-element/index.wxml +3 -7
  9. package/miniprogram_dist/components/card-layout/elements/icon-element/index.wxss +3 -17
  10. package/miniprogram_dist/components/card-layout/elements/icon-font.wxss +438 -0
  11. package/miniprogram_dist/components/card-layout/elements/image-element/index.js +18 -9
  12. package/miniprogram_dist/components/card-layout/elements/image-element/index.wxml +8 -10
  13. package/miniprogram_dist/components/card-layout/elements/image-element/index.wxss +1 -1
  14. package/miniprogram_dist/components/card-layout/elements/layout-panel-element/index.js +37 -0
  15. package/miniprogram_dist/components/card-layout/elements/layout-panel-element/index.json +3 -0
  16. package/miniprogram_dist/components/card-layout/elements/layout-panel-element/index.wxml +5 -0
  17. package/miniprogram_dist/components/card-layout/elements/layout-panel-element/index.wxss +10 -0
  18. package/miniprogram_dist/components/card-layout/elements/text-element/index.js +41 -17
  19. package/miniprogram_dist/components/card-layout/elements/text-element/index.wxml +8 -34
  20. package/miniprogram_dist/components/card-layout/elements/text-element/index.wxss +5 -18
  21. package/miniprogram_dist/components/card-layout/index.js +31 -108
  22. package/miniprogram_dist/components/card-layout/index.json +9 -1
  23. package/miniprogram_dist/components/card-layout/index.wxml +25 -46
  24. package/miniprogram_dist/components/card-layout/index.wxss +1 -538
  25. package/package.json +1 -1
  26. package/src/components/card-layout/elements/custom-element/index.ts +13 -7
  27. package/src/components/card-layout/elements/custom-element/index.wxml +4 -6
  28. package/src/components/card-layout/elements/custom-element/index.wxss +1 -1
  29. package/src/components/card-layout/elements/icon-element/index.ts +34 -16
  30. package/src/components/card-layout/elements/icon-element/index.wxml +3 -7
  31. package/src/components/card-layout/elements/icon-element/index.wxss +3 -17
  32. package/src/components/card-layout/elements/icon-font.wxss +438 -0
  33. package/src/components/card-layout/elements/image-element/index.ts +21 -11
  34. package/src/components/card-layout/elements/image-element/index.wxml +8 -10
  35. package/src/components/card-layout/elements/image-element/index.wxss +1 -1
  36. package/src/components/card-layout/elements/layout-panel-element/index.json +3 -0
  37. package/src/components/card-layout/elements/layout-panel-element/index.ts +40 -0
  38. package/src/components/card-layout/elements/layout-panel-element/index.wxml +5 -0
  39. package/src/components/card-layout/elements/layout-panel-element/index.wxss +10 -0
  40. package/src/components/card-layout/elements/text-element/index.ts +48 -19
  41. package/src/components/card-layout/elements/text-element/index.wxml +8 -34
  42. package/src/components/card-layout/elements/text-element/index.wxss +5 -18
  43. package/src/components/card-layout/index.json +9 -1
  44. package/src/components/card-layout/index.ts +36 -156
  45. package/src/components/card-layout/index.wxml +25 -46
  46. package/src/components/card-layout/index.wxss +1 -538
@@ -0,0 +1,40 @@
1
+ import {
2
+ buildPanelContentStyle,
3
+ buildWrapperStyle,
4
+ styleObjectToString,
5
+ type LayoutPanelElement,
6
+ } from "../../../../vendor/km-card-layout-core/index";
7
+
8
+ Component({
9
+ options: {
10
+ styleIsolation: "apply-shared",
11
+ },
12
+ properties: {
13
+ element: {
14
+ type: Object,
15
+ value: {},
16
+ },
17
+ rootData: {
18
+ type: Object,
19
+ value: {},
20
+ },
21
+ },
22
+ data: {
23
+ wrapperStyle: "",
24
+ contentStyle: "",
25
+ },
26
+ observers: {
27
+ element() {
28
+ this.rebuild();
29
+ },
30
+ },
31
+ methods: {
32
+ rebuild() {
33
+ const el = this.data.element as LayoutPanelElement;
34
+ if (!el) return;
35
+ const wrapperStyle = styleObjectToString(buildWrapperStyle(el, "rpx"), "rpx");
36
+ const contentStyle = styleObjectToString(buildPanelContentStyle(el, "rpx"), "rpx");
37
+ this.setData({ wrapperStyle, contentStyle });
38
+ },
39
+ },
40
+ });
@@ -0,0 +1,5 @@
1
+ <view class="km-node itemClass" style="{{wrapperStyle}}">
2
+ <view class="km-node__panel itemClass" style="{{contentStyle}}">
3
+ <slot></slot>
4
+ </view>
5
+ </view>
@@ -0,0 +1,10 @@
1
+ .km-node {
2
+ box-sizing: border-box;
3
+ color: inherit;
4
+ }
5
+
6
+ .km-node__panel {
7
+ width: 100%;
8
+ height: 100%;
9
+ box-sizing: border-box;
10
+ }
@@ -1,23 +1,34 @@
1
1
  import {
2
2
  buildTextContentStyle,
3
3
  buildTextIconMeta,
4
+ buildTextValueStyle,
4
5
  buildWrapperStyle,
5
6
  getTextValue,
6
7
  styleObjectToString,
7
8
  type TextElement,
8
- } from '../../../../vendor/km-card-layout-core/index';
9
- import { ICON_CODE_MAP } from '../../icon-map';
9
+ } from "../../../../vendor/km-card-layout-core/index";
10
+ import { ICON_CODE_MAP } from "../../icon-map";
10
11
 
11
- const mapIconGlyph = (name?: string, fallback?: string) => {
12
- if (!name) return fallback;
13
- const glyph = ICON_CODE_MAP[name];
14
- if (glyph) return String.fromCharCode(parseInt(glyph, 16));
15
- return fallback || name;
12
+ const normalizeIconName = (name?: string) => {
13
+ if (!name) return "";
14
+ return name.startsWith("icon-") ? name.slice(5) : name;
15
+ };
16
+
17
+ const buildIconClassName = (name?: string) => {
18
+ const normalized = normalizeIconName(name);
19
+ if (!normalized) return "";
20
+ return `icon-${normalized}`;
21
+ };
22
+
23
+ const buildIconCode = (name?: string) => {
24
+ const normalized = normalizeIconName(name);
25
+ if (!normalized) return "";
26
+ return ICON_CODE_MAP[normalized] || "";
16
27
  };
17
28
 
18
29
  Component({
19
30
  options: {
20
- styleIsolation: 'apply-shared',
31
+ styleIsolation: "apply-shared",
21
32
  },
22
33
  properties: {
23
34
  element: {
@@ -30,28 +41,46 @@ Component({
30
41
  },
31
42
  },
32
43
  data: {
33
- wrapperStyle: '',
34
- contentStyle: '',
35
- textValue: '',
44
+ wrapperStyle: "",
45
+ contentStyle: "",
46
+ textValue: "",
47
+ textStyle: "",
36
48
  iconMeta: null as any,
37
49
  },
38
50
  observers: {
39
- element(el: TextElement) {
51
+ element() {
52
+ this.rebuild();
53
+ },
54
+ rootData() {
55
+ this.rebuild();
56
+ },
57
+ },
58
+ methods: {
59
+ rebuild() {
60
+ const el = this.data.element as TextElement;
40
61
  if (!el) return;
41
- const data: Record<string, any> = this.data.rootData || {};
42
- const wrapperStyle = styleObjectToString(buildWrapperStyle(el, 'rpx'), 'rpx');
43
- const contentStyle = styleObjectToString(buildTextContentStyle(el, 'rpx'), 'rpx');
62
+ const data = this.data.rootData || {};
63
+ const wrapperStyle = styleObjectToString(buildWrapperStyle(el, "rpx"), "rpx");
64
+ const contentStyle = styleObjectToString(buildTextContentStyle(el, "rpx"), "rpx");
44
65
  const textValue = getTextValue(el, data);
45
- const iconRaw = buildTextIconMeta(el, 'rpx');
66
+ const textStyle = styleObjectToString(
67
+ {
68
+ ...buildTextContentStyle(el, "rpx"),
69
+ ...buildTextValueStyle(el, "rpx"),
70
+ },
71
+ "rpx"
72
+ );
73
+ const iconRaw = buildTextIconMeta(el, "rpx");
46
74
  const iconMeta =
47
75
  iconRaw && iconRaw.name
48
76
  ? {
49
77
  ...iconRaw,
50
- text: mapIconGlyph(iconRaw.name, iconRaw.name),
51
- wrapperStyle: styleObjectToString(iconRaw.wrapperStyle, 'rpx'),
78
+ className: buildIconClassName(iconRaw.name),
79
+ iconCode: buildIconCode(iconRaw.name),
80
+ wrapperStyle: styleObjectToString(iconRaw.wrapperStyle, "rpx"),
52
81
  }
53
82
  : iconRaw;
54
- this.setData({ wrapperStyle, contentStyle, textValue, iconMeta });
83
+ this.setData({ wrapperStyle, contentStyle, textValue, textStyle, iconMeta });
55
84
  },
56
85
  },
57
86
  });
@@ -1,44 +1,18 @@
1
- <template name="text-element">
2
- <view class="km-node km-node--text" style="{{wrapperStyle}}">
3
- <view class="km-node__text" style="{{contentStyle}}">
4
- <block wx:if="{{(iconMeta && (iconMeta.name || iconMeta.text)) && (element.icon && element.icon.style !== 'text')}}">
5
- <view class="km-node__text-content">
6
-
7
- <!-- icon 在右侧 -->
8
- <block wx:if="{{iconMeta && iconMeta.align === 'right'}}">
9
- <text class="km-node__text-value">{{(element.icon && element.icon.style === 'text' && element.icon.enable) ? (element.label + ':') : ''}}{{textValue || ''}}</text>
1
+ <view class="km-node km-node--text canvas-item" style="{{wrapperStyle}}">
2
+ <view class="km-node__text canvas-item" style="{{contentStyle}}">
3
+ <block wx:if="{{iconMeta && iconMeta.name && (element.icon && element.icon.style !== 'text')}}">
4
+ <view class="km-node__text-content canvas-item">
10
5
  <view
11
- class="km-node__text-icon--wrapper"
6
+ class="km-node__text-icon--wrapper canvas-item"
12
7
  style="{{iconMeta.wrapperStyle}}"
13
8
  >
14
- <text
15
- class="km-node__text-icon icon"
16
- style="font-size: {{iconMeta.size || '16px'}}; color: {{iconMeta.color || ''}}; margin-right: {{iconMeta.gap || ''}};"
17
- >{{iconMeta.text || iconMeta.name || ''}}</text>
9
+ <i class="km-node__text-icon icon {{iconMeta.className}} canvas-item" style="font-size: {{iconMeta.size || '16px'}}; color: {{iconMeta.color || ''}}; margin-right: {{iconMeta.gap || ''}};" data-icon="{{iconMeta.iconCode}}" ></i>
18
10
  </view>
19
- </block>
20
-
21
- <!-- icon 在左侧 -->
22
- <block wx:else>
23
- <view
24
- class="km-node__text-icon--wrapper"
25
- style="{{iconMeta.wrapperStyle}}"
26
- >
27
- <text
28
- class="km-node__text-icon icon"
29
- style="font-size: {{iconMeta.size || '16px'}}; color: {{iconMeta.color || ''}}; margin-right: {{iconMeta.gap || ''}};"
30
- >{{iconMeta.text || iconMeta.name || ''}}</text>
31
- </view>
32
- <text class="km-node__text-value">{{textValue || ''}}</text>
33
- </block>
34
-
11
+ <text class="km-node__text-value canvas-item" style="{{textStyle}}" data-text="{{textValue || ''}}">{{textValue || ''}}</text>
35
12
  </view>
36
13
  </block>
37
-
38
- <!-- 无 icon -->
39
14
  <block wx:else>
40
- <text class="km-node__text-value">{{(element.icon && element.icon.style === 'text' && element.icon.enable) ? (element.label + ':') : ''}}{{textValue || ''}}</text>
15
+ <text class="km-node__text-value canvas-item" style="{{textStyle}}" data-text="{{(element.icon && element.icon.style === 'text' && element.icon.enable) ? (element.label + ':') : ''}}{{textValue || ''}}">{{(element.icon && element.icon.style === 'text' && element.icon.enable) ? (element.label + ':') : ''}}{{textValue || ''}}</text>
41
16
  </block>
42
17
  </view>
43
18
  </view>
44
- </template>
@@ -1,3 +1,5 @@
1
+ @import "../icon-font.wxss";
2
+
1
3
  .km-node {
2
4
  box-sizing: border-box;
3
5
  color: inherit;
@@ -19,6 +21,7 @@
19
21
  display: inline-block;
20
22
  vertical-align: middle;
21
23
  height: 100%;
24
+ display: inline-flex;
22
25
  }
23
26
 
24
27
  .km-node__text-icon {
@@ -34,22 +37,6 @@
34
37
  vertical-align: middle;
35
38
  }
36
39
 
37
- @font-face {
38
- font-family: 'km-icon';
39
- src: url('data:font/woff;charset=utf-8;base64,d09GRgABAAAAAEl4AA0AAAAAcmgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABGRlRNAABJXAAAABoAAAAcrMtJV0dERUYAAEk8AAAAHgAAAB4AKQByT1MvMgAAAaQAAABGAAAAYDw3SVljbWFwAAAC7AAAAM8AAAIW8XL3K2dhc3AAAEk0AAAACAAAAAj//wADZ2x5ZgAABJgAAEBZAABkZPJymXJoZWFkAAABMAAAADEAAAA2MtZiFmhoZWEAAAFkAAAAIAAAACQNagmCaG10eAAAAewAAAD/AAABqqs3Ii9sb2NhAAADvAAAANoAAADaKv0P7G1heHAAAAGEAAAAHwAAACABmQHEbmFtZQAARPQAAAFGAAACgl6CAQJwb3N0AABGPAAAAvUAAATh1g15W3jaY2BkYGAA4lqffPd4fpuvDNwsDCDwVIyfA0b///i/gXMWcyeQy8HABBIFAAVdCfwAAAB42mNgZGBgbvjfwBDDOfP/x///OWcxAEVQQCYAuxgH/XjaY2BkYGDIYdzBoMwAAkxAzAWEDAz/wXwGACjlAl8AeNpjYGFRYJzAwMrAwNTJdIaBgaEfQjO+ZjBi5ACKMrAyM2AFAWmuKQwHnjE+y2Ju+N/AwMB8h6ERKMyIpESBgREAenQNCwAAeNo90cErBGEYx/Hf1LMH7MVxoigHtS600pzWnMjBlt2dFAeiNuWgXLgokgslbpyE/Aduyl38J3ty4aCs7/vOk6lPv+d5531n3nfGVF5JIZlUx9fAbawnEfIFq14/YhddFPjFmynZ9n4TbYzg2tcMW6Epr4NQT3jSJ2lcW9ec1fSEAheMnVume7KKBbQwiMye+5/kEpqYwQoOY59pn1xGw3Lt8NwHS7UY35frivqbet2fNYZp+4j76vj+GpUhjZJreLfxODecay/eTzVPzmIj9uX7VLnUmfdb/2fN4trcv0kYv8Oxe/V5Rzhg7inZ8wzjN5b0f6z8PV2d/AHivi0JAHja3dBFUoVRDITR88PD3d3d3d3d3d33zQqYwwVGbIGk8qV6kK7qIN7vlIsCRdlBRT865iPsWOig318/PwOjbwYd+7mKSZAoSbIUqdKky5ApS7YcufLkK1CoSLESpcqCZ4VKVarVqFWnXoNGTZq1aNWmXYdOXbr16NWn34BBQ4aNGDVm3IRJU6bNmDVn3oJFS5atWLVm3YZNW7bt2LVn34FDR46dOHXm3IVLV67duHXn3oNHT8Hv2YtXbyFaot9HfMeMC4jztyL/vr4AXx4eawAAAAAAAAAAAACwAPIDSgQ8BLIFUgWUBcIF/gY8BpIHCgdAB3wHoAgOCHAIxgk+CV4JzAnqCkQKrgtUC8QMEAxsDNQNFA1SDegONg6qDyQPgg/CEAIQxBEwEaQSHBLYE14T4hRcFPIVTBYMFkwWqBckGGAYxhmYGegaEBpeGuIbXhvwHPQd5B62Hygf6CBeILog9CFUIbgiBCJ0ItQjbCQSJGgkuCVsJcImKib0J44ocijOKSApUCo2KmQqtituK34sJixkLMgtdC3WLpgvPC+QMBww/DGCMagyMgAA') format('woff');
40
- font-weight: normal;
41
- font-style: normal;
42
- font-display: swap;
43
- }
44
-
45
- .icon {
46
- font-family: 'km-icon' !important;
47
- font-size: 16px;
48
- font-style: normal;
49
- -webkit-font-smoothing: antialiased;
50
- -moz-osx-font-smoothing: grayscale;
51
- }
52
-
53
- .km-node__text-icon--wrapper{
40
+ .km-node__text-icon--wrapper {
54
41
  display: inline-block;
55
- }
42
+ }
@@ -1,3 +1,11 @@
1
1
  {
2
- "component": true
2
+ "component": true,
3
+ "usingComponents": {
4
+ "text-element": "./elements/text-element/index",
5
+ "image-element": "./elements/image-element/index",
6
+ "icon-element": "./elements/icon-element/index",
7
+ "custom-element": "./elements/custom-element/index",
8
+ "layout-panel-element": "./elements/layout-panel-element/index",
9
+ "wxml2canvas": "../../vendor/wxml2canvas-2d/index"
10
+ }
3
11
  }
@@ -1,48 +1,23 @@
1
1
  import type {
2
2
  CardElement,
3
- CardLayoutInput,
4
3
  CardLayoutSchema,
5
- CustomElement,
6
- IconElement,
7
- ImageElement,
8
- LayoutPanelElement,
9
- TextElement,
10
- } from '../../vendor/km-card-layout-core/index';
4
+ } from "../../vendor/km-card-layout-core/index";
11
5
  import {
12
6
  buildBackgroundStyle,
13
- buildBaseContentStyle,
14
7
  buildCardStyle,
15
- buildImageContentStyle,
16
- buildPanelContentStyle,
17
- buildTextContentStyle,
18
- buildTextIconMeta,
19
- buildWrapperStyle,
20
- getIconName,
21
- getImageSrc,
22
- getTextValue,
23
8
  normalizeLayout,
24
9
  processCardLayout,
25
10
  styleObjectToString,
26
- } from '../../vendor/km-card-layout-core/index';
27
- import { ICON_CODE_MAP } from './icon-map';
11
+ } from "../../vendor/km-card-layout-core/index";
28
12
 
29
13
  type CompanyDuty = {
30
14
  company: string;
31
15
  duty: string;
32
16
  };
33
17
 
34
- const mapIconGlyph = (name?: string, fallback?: string) => {
35
- if (!name) return fallback;
36
- const glyph = ICON_CODE_MAP[name];
37
- if (glyph) return String.fromCharCode(parseInt(glyph, 16));
38
- return fallback || name;
39
- };
40
-
41
-
42
-
43
18
  const EMPTY_COMPANY_DUTY: CompanyDuty = {
44
- company: '',
45
- duty: '',
19
+ company: "",
20
+ duty: "",
46
21
  };
47
22
 
48
23
  /**
@@ -79,7 +54,6 @@ export function normalizeMoreCompany(data: AnyObject): AnyObject {
79
54
  };
80
55
  }
81
56
 
82
-
83
57
  const handleSpecialFields = (data: { user: Record<string, any> }) => {
84
58
  const user = data.user ?? {};
85
59
  return {
@@ -87,15 +61,13 @@ const handleSpecialFields = (data: { user: Record<string, any> }) => {
87
61
  user: {
88
62
  ...user,
89
63
  baseCompanyDuty:
90
- user.company && user.duty
91
- ? `${user.company} ${user.duty}`
92
- : user.baseCompanyDuty,
64
+ user.company && user.duty ? `${user.company} ${user.duty}` : user.baseCompanyDuty,
93
65
  moreCardInfo: user.moreCardInfo
94
66
  ? {
95
67
  ...user.moreCardInfo,
96
68
  company: Array.isArray(user.moreCardInfo.company)
97
69
  ? (user.moreCardInfo.company as CompanyDuty[]).map(
98
- item => `${item.company} ${item.duty}`
70
+ (item) => `${item.company} ${item.duty}`
99
71
  )
100
72
  : user.moreCardInfo.company,
101
73
  }
@@ -104,22 +76,7 @@ const handleSpecialFields = (data: { user: Record<string, any> }) => {
104
76
  };
105
77
  };
106
78
 
107
- type RenderElement = CardElement & {
108
- wrapperStyle?: string;
109
- contentStyle?: string;
110
- imageSrc?: string;
111
- mode?: string;
112
- iconText?: string;
113
- textValue?: string;
114
- iconMeta?: any;
115
- children?: RenderElement[];
116
- };
117
-
118
- type PanelElement = LayoutPanelElement & {
119
- wrapperStyle: string;
120
- contentStyle: string;
121
- children?: RenderElement[];
122
- };
79
+ type RenderElement = CardElement;
123
80
 
124
81
  type RenderCard = {
125
82
  id: string;
@@ -129,123 +86,33 @@ type RenderCard = {
129
86
  elements: RenderElement[];
130
87
  };
131
88
 
132
- const ensureArray = (input: CardLayoutInput | any): CardLayoutInput => {
133
- if (!input) return [];
134
- return Array.isArray(input) ? input : [input];
135
- };
136
-
137
89
  const pickCardId = (layout: any, idx: number) => {
138
90
  if (layout && (layout.name || layout.id)) return layout.name || layout.id;
139
91
  return `card-${idx}`;
140
92
  };
141
93
 
142
- const decorateElements = (
143
- children: CardElement[] = [],
144
- rootData: Record<string, any>
145
- ): RenderElement[] => {
146
- const data = rootData || {};
147
-
148
- return (children || []).map(el => {
149
- const wrapperStyle = styleObjectToString(buildWrapperStyle(el, 'rpx'), 'rpx');
150
-
151
- switch (el.type) {
152
- case 'layout-panel': {
153
- const panel = el as LayoutPanelElement;
154
- return {
155
- ...panel,
156
- wrapperStyle,
157
- contentStyle: styleObjectToString(buildPanelContentStyle(panel, 'rpx'), 'rpx'),
158
- children: decorateElements(panel.children || [], rootData),
159
- } as PanelElement;
160
- }
161
- case 'image': {
162
- const imageEl = el as ImageElement;
163
- const contentStyle = styleObjectToString(buildImageContentStyle(imageEl), 'rpx');
164
- const imageSrc = getImageSrc(imageEl, data);
165
- const mode = imageEl.fit === 'contain' ? 'aspectFit' : 'aspectFill';
166
- return {
167
- ...imageEl,
168
- wrapperStyle,
169
- contentStyle,
170
- imageSrc,
171
- mode,
172
- };
173
- }
174
- case 'icon': {
175
- const iconEl = el as IconElement;
176
- const contentStyle = styleObjectToString(buildBaseContentStyle(iconEl), 'rpx');
177
- const name = getIconName(iconEl);
178
- const iconText = mapIconGlyph(name, name || '');
179
- return {
180
- ...iconEl,
181
- wrapperStyle,
182
- contentStyle,
183
- iconText,
184
- };
185
- }
186
- case 'custom': {
187
- const customEl = el as CustomElement;
188
- const contentStyle = styleObjectToString(buildBaseContentStyle(customEl), 'rpx');
189
- return {
190
- ...customEl,
191
- wrapperStyle,
192
- contentStyle,
193
- };
194
- }
195
- default: {
196
- const textEl = el as TextElement;
197
- const contentStyle = styleObjectToString(buildTextContentStyle(textEl, 'rpx'), 'rpx');
198
- const textValue = getTextValue(textEl, data);
199
- const iconRaw = buildTextIconMeta(textEl, 'rpx');
200
- const iconMeta =
201
- iconRaw && iconRaw.name
202
- ? {
203
- ...iconRaw,
204
- text: mapIconGlyph(iconRaw.name, iconRaw.name),
205
- wrapperStyle: styleObjectToString(iconRaw.wrapperStyle, 'rpx'),
206
- }
207
- : iconRaw;
208
- return {
209
- ...textEl,
210
- wrapperStyle,
211
- contentStyle,
212
- textValue,
213
- iconMeta,
214
- };
215
- }
216
- }
217
- });
218
- };
219
-
220
- const buildCards = (layouts: CardLayoutSchema[], rootData: Record<string, any>) => {
94
+ const buildCards = (layouts: CardLayoutSchema[]) => {
221
95
  return layouts.map((layout, idx) => ({
222
96
  id: pickCardId(layouts[idx], idx),
223
- cardStyle: styleObjectToString(buildCardStyle(layout, 'rpx'), 'rpx'),
224
- backgroundImage: layout.backgroundImage || '',
225
- backgroundStyle: styleObjectToString(buildBackgroundStyle(layout, 'rpx'), 'rpx'),
226
- elements: decorateElements(layout.children || [], rootData),
97
+ cardStyle: styleObjectToString(buildCardStyle(layout, "rpx"), "rpx"),
98
+ backgroundImage: layout.backgroundImage || "",
99
+ backgroundStyle: styleObjectToString(buildBackgroundStyle(layout, "rpx"), "rpx"),
100
+ elements: layout.children || [],
227
101
  }));
228
102
  };
229
103
 
230
-
231
- export const hasCompanyDutyKey = (
232
- schemas: CardLayoutSchema[]
233
- ): boolean => {
234
- const TARGET_KEYS = new Set([
235
- 'company_duty_custom',
236
- 'company_duty_1',
237
- 'company_duty_2',
238
- ]);
104
+ export const hasCompanyDutyKey = (schemas: CardLayoutSchema[]): boolean => {
105
+ const TARGET_KEYS = new Set(["company_duty_custom", "company_duty_1", "company_duty_2"]);
239
106
 
240
107
  const traverse = (elements: CardElement[]): boolean => {
241
- return elements.some(el => {
108
+ return elements.some((el) => {
242
109
  // 命中 key
243
110
  if (el.key && TARGET_KEYS.has(el.key)) {
244
111
  return true;
245
112
  }
246
113
 
247
114
  // 递归 layout-panel
248
- if (el.type === 'layout-panel' && el.children?.length) {
115
+ if (el.type === "layout-panel" && el.children?.length) {
249
116
  return traverse(el.children);
250
117
  }
251
118
 
@@ -253,13 +120,12 @@ export const hasCompanyDutyKey = (
253
120
  });
254
121
  };
255
122
 
256
- return schemas.some(schema => traverse(schema.children));
123
+ return schemas.some((schema) => traverse(schema.children));
257
124
  };
258
125
 
259
-
260
126
  Component({
261
127
  options: {
262
- styleIsolation: 'apply-shared',
128
+ styleIsolation: "apply-shared",
263
129
  },
264
130
  properties: {
265
131
  layout: {
@@ -277,6 +143,7 @@ Component({
277
143
  data: {
278
144
  cards: [] as RenderCard[],
279
145
  rootData: {} as Record<string, any>,
146
+ firstCard: [] as RenderCard[],
280
147
  },
281
148
  observers: {
282
149
  layout() {
@@ -293,16 +160,29 @@ Component({
293
160
  },
294
161
  methods: {
295
162
  rebuild() {
296
- const data = normalizeMoreCompany(this.data.data)
297
- const layoutInput = hasCompanyDutyKey(this.data.layout)?processCardLayout(this.data.layout, data as any): this.data.layout;
163
+ const data = normalizeMoreCompany(this.data.data);
164
+ const layoutInput = hasCompanyDutyKey(this.data.layout)
165
+ ? processCardLayout(this.data.layout, data as any)
166
+ : this.data.layout;
298
167
  const rootData = handleSpecialFields(data as any);
299
168
  if (!layoutInput.length) {
300
169
  this.setData({ cards: [], rootData });
301
170
  return;
302
171
  }
303
172
  const normalizedLayouts = normalizeLayout(layoutInput);
304
- const cards = buildCards(normalizedLayouts, rootData);
305
- this.setData({ cards, rootData });
173
+ const cards = buildCards(normalizedLayouts);
174
+ this.setData({ cards, rootData, firstCard: [cards[0]] });
175
+ },
176
+
177
+ async handleDrawCanvas() {
178
+ try {
179
+ const canvas = this.selectComponent(`#layout-canvas`);
180
+ await canvas.draw(this);
181
+ const filePath = await canvas.toTempFilePath();
182
+ return filePath;
183
+ } catch {
184
+ wx.showToast({ title: "保存失败", icon: "error" });
185
+ }
306
186
  },
307
187
  },
308
188
  });
@@ -1,59 +1,38 @@
1
- <import src="./elements/custom-element/index.wxml" />
2
- <import src="./elements/icon-element/index.wxml" />
3
- <import src="./elements/image-element/index.wxml" />
4
- <import src="./elements/text-element/index.wxml" />
5
-
6
- <view class="km-card-layout">
7
- <block wx:for="{{cards}}" wx:key="id">
8
- <view class="km-card-layout__item">
9
- <view class="km-card" style="{{item.cardStyle}}">
10
- <image
11
- wx:if="{{item.backgroundImage}}"
12
- class="km-card__bg"
13
- style="{{item.backgroundStyle}}"
14
- src="{{item.backgroundImage}}"
15
- mode="aspectFill"
16
- />
17
- <block wx:for="{{item.elements}}" wx:key="id">
18
- <template wx:if="{{item.visible !== false}}" is="render-element" data="{{el:item, rootData: rootData}}" />
19
- </block>
1
+ <template name="layout-template">
2
+ <view class="km-card-layout layout-container">
3
+ <block wx:for="{{renderCards}}" wx:key="id">
4
+ <view class="km-card-layout__item canvas-item">
5
+ <view class="km-card canvas-item" style="{{item.cardStyle}}">
6
+ <image wx:if="{{item.backgroundImage}}" class="km-card__bg canvas-item" style="{{item.backgroundStyle}}" src="{{item.backgroundImage}}" mode="aspectFill" />
7
+ <block wx:for="{{item.elements}}" wx:key="id">
8
+ <template wx:if="{{item.visible !== false}}" is="render-element" data="{{el:item, rootData: rootData}}" />
9
+ </block>
10
+ </view>
20
11
  </view>
21
- </view>
22
- </block>
23
- </view>
24
-
12
+ </block>
13
+ </view>
14
+ </template>
15
+ <template is="layout-template" data="{{ renderCards: cards, rootData: rootData }}"></template>
16
+ <!-- 暂时只绘制第一张卡片 -->
17
+ <wxml2canvas id="layout-canvas" container-class="layout-container" item-class="canvas-item"></wxml2canvas>
25
18
  <template name="render-element">
26
19
  <block wx:if="{{el.type === 'image'}}">
27
- <template
28
- is="image-element"
29
- data="{{wrapperStyle: el.wrapperStyle, contentStyle: el.contentStyle, imageSrc: el.imageSrc, mode: el.mode}}"
30
- />
20
+ <image-element id="node-{{el.id}}" class="canvas-item" data-component="{{true}}" element="{{el}}" rootData="{{rootData}}" />
31
21
  </block>
32
22
  <block wx:elif="{{el.type === 'icon'}}">
33
- <template
34
- is="icon-element"
35
- data="{{wrapperStyle: el.wrapperStyle, contentStyle: el.contentStyle, iconText: el.iconText}}"
36
- />
23
+ <icon-element id="node-{{el.id}}" class="canvas-item" data-component="{{true}}" element="{{el}}" rootData="{{rootData}}" />
37
24
  </block>
38
25
  <block wx:elif="{{el.type === 'layout-panel'}}">
39
- <view class="km-node" style="{{el.wrapperStyle}}">
40
- <view class="km-node__panel" style="{{el.contentStyle}}">
41
- <block wx:for="{{el.children}}" wx:key="id">
42
- <template is="render-element" data="{{el:item, rootData: rootData}}" />
43
- </block>
44
- </view>
45
- </view>
26
+ <layout-panel-element id="node-{{el.id}}" class="canvas-item" data-component="{{true}}" element="{{el}}" rootData="{{rootData}}">
27
+ <block wx:for="{{el.children}}" wx:key="id">
28
+ <template is="render-element" data="{{el:item, rootData: rootData}}" />
29
+ </block>
30
+ </layout-panel-element>
46
31
  </block>
47
32
  <block wx:elif="{{el.type === 'custom'}}">
48
- <template
49
- is="custom-element"
50
- data="{{wrapperStyle: el.wrapperStyle, contentStyle: el.contentStyle, element: el}}"
51
- />
33
+ <custom-element id="node-{{el.id}}" class="canvas-item" data-component="{{true}}" element="{{el}}" rootData="{{rootData}}" />
52
34
  </block>
53
35
  <block wx:else>
54
- <template
55
- is="text-element"
56
- data="{{wrapperStyle: el.wrapperStyle, contentStyle: el.contentStyle, textValue: el.textValue, iconMeta: el.iconMeta, element: el}}"
57
- />
36
+ <text-element id="node-{{el.id}}" class="canvas-item" data-component="{{true}}" element="{{el}}" rootData="{{rootData}}" />
58
37
  </block>
59
38
  </template>