npmapps 1.1.5 → 1.2.0

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 (115) hide show
  1. package/app/wujie-wk/t.html +90 -0
  2. package/app/{wujie-vue2-child → wujie-wk/wujie-vue2-child}/src/components/EventCalendar/README.md +122 -5
  3. package/app/{wujie-vue2-child → wujie-wk/wujie-vue2-child}/src/components/EventCalendar/example.vue +203 -7
  4. package/app/{wujie-vue2-child → wujie-wk/wujie-vue2-child}/src/components/EventCalendar/index.vue +1124 -50
  5. package/app/{wujie-vue2-child → wujie-wk/wujie-vue2-child}/src/components/EventCalendar/mockData.js +126 -0
  6. package/app/wujie-wk/wujie-vue2-child/src/components/EventCalendar/recruitmentAdapter.js +51 -0
  7. package/app/{wujie-vue2-child → wujie-wk/wujie-vue2-child}/src/components/EventCalendar/utils.js +1 -0
  8. package/package.json +1 -1
  9. /package/app/{wujie-vue2-child → wujie-wk/wujie-vue2-child}/.eslintrc.js +0 -0
  10. /package/app/{wujie-vue2-child → wujie-wk/wujie-vue2-child}/README.md +0 -0
  11. /package/app/{wujie-vue2-child → wujie-wk/wujie-vue2-child}/babel.config.js +0 -0
  12. /package/app/{wujie-vue2-child → wujie-wk/wujie-vue2-child}/docs/superpowers/plans/2026-05-29-quill-editor.md +0 -0
  13. /package/app/{wujie-vue2-child → wujie-wk/wujie-vue2-child}/docs/superpowers/specs/2026-05-29-quill-editor-design.md +0 -0
  14. /package/app/{wujie-vue2-child → wujie-wk/wujie-vue2-child}/jsconfig.json +0 -0
  15. /package/app/{wujie-vue2-child → wujie-wk/wujie-vue2-child}/package-lock.json +0 -0
  16. /package/app/{wujie-vue2-child → wujie-wk/wujie-vue2-child}/package.json +0 -0
  17. /package/app/{wujie-vue2-child → wujie-wk/wujie-vue2-child}/postcss.config.js +0 -0
  18. /package/app/{wujie-vue2-child → wujie-wk/wujie-vue2-child}/public/favicon.ico +0 -0
  19. /package/app/{wujie-vue2-child → wujie-wk/wujie-vue2-child}/public/index.html +0 -0
  20. /package/app/{wujie-vue2-child → wujie-wk/wujie-vue2-child}/public/rili.jpg +0 -0
  21. /package/app/{wujie-vue2-child → wujie-wk/wujie-vue2-child}/public//344/270/200/351/224/256/351/273/221/346/232/227.html" +0 -0
  22. /package/app/{wujie-vue2-child → wujie-wk/wujie-vue2-child}/src/App.vue +0 -0
  23. /package/app/{wujie-vue2-child → wujie-wk/wujie-vue2-child}/src/assets/bpmn-camunda.jpg +0 -0
  24. /package/app/{wujie-vue2-child → wujie-wk/wujie-vue2-child}/src/assets/css/diagram.less +0 -0
  25. /package/app/{wujie-vue2-child → wujie-wk/wujie-vue2-child}/src/assets/icon/Icon.less +0 -0
  26. /package/app/{wujie-vue2-child → wujie-wk/wujie-vue2-child}/src/assets/icon/font/app-codes.css +0 -0
  27. /package/app/{wujie-vue2-child → wujie-wk/wujie-vue2-child}/src/assets/icon/font/app.eot +0 -0
  28. /package/app/{wujie-vue2-child → wujie-wk/wujie-vue2-child}/src/assets/icon/font/app.svg +0 -0
  29. /package/app/{wujie-vue2-child → wujie-wk/wujie-vue2-child}/src/assets/icon/font/app.ttf +0 -0
  30. /package/app/{wujie-vue2-child → wujie-wk/wujie-vue2-child}/src/assets/icon/font/app.woff +0 -0
  31. /package/app/{wujie-vue2-child → wujie-wk/wujie-vue2-child}/src/assets/icon/font/app.woff2 +0 -0
  32. /package/app/{wujie-vue2-child → wujie-wk/wujie-vue2-child}/src/assets/icon/font/config.json +0 -0
  33. /package/app/{wujie-vue2-child → wujie-wk/wujie-vue2-child}/src/assets/icon/font/source/raw/align-bottom-tool.svg +0 -0
  34. /package/app/{wujie-vue2-child → wujie-wk/wujie-vue2-child}/src/assets/icon/font/source/raw/align-horizontal-center-tool.svg +0 -0
  35. /package/app/{wujie-vue2-child → wujie-wk/wujie-vue2-child}/src/assets/icon/font/source/raw/align-left-tool.svg +0 -0
  36. /package/app/{wujie-vue2-child → wujie-wk/wujie-vue2-child}/src/assets/icon/font/source/raw/align-right-tool.svg +0 -0
  37. /package/app/{wujie-vue2-child → wujie-wk/wujie-vue2-child}/src/assets/icon/font/source/raw/align-top-tool.svg +0 -0
  38. /package/app/{wujie-vue2-child → wujie-wk/wujie-vue2-child}/src/assets/icon/font/source/raw/align-vertical-center-tool.svg +0 -0
  39. /package/app/{wujie-vue2-child → wujie-wk/wujie-vue2-child}/src/assets/icon/font/source/raw/distribute-horizontally-tool.svg +0 -0
  40. /package/app/{wujie-vue2-child → wujie-wk/wujie-vue2-child}/src/assets/icon/font/source/raw/distribute-vertically-tool.svg +0 -0
  41. /package/app/{wujie-vue2-child → wujie-wk/wujie-vue2-child}/src/assets/icon/font/source/raw/set-color-tool.svg +0 -0
  42. /package/app/{wujie-vue2-child → wujie-wk/wujie-vue2-child}/src/assets/icon/font/source/symbols/align-bottom-tool.svg +0 -0
  43. /package/app/{wujie-vue2-child → wujie-wk/wujie-vue2-child}/src/assets/icon/font/source/symbols/align-horizontal-center-tool.svg +0 -0
  44. /package/app/{wujie-vue2-child → wujie-wk/wujie-vue2-child}/src/assets/icon/font/source/symbols/align-left-tool.svg +0 -0
  45. /package/app/{wujie-vue2-child → wujie-wk/wujie-vue2-child}/src/assets/icon/font/source/symbols/align-right-tool.svg +0 -0
  46. /package/app/{wujie-vue2-child → wujie-wk/wujie-vue2-child}/src/assets/icon/font/source/symbols/align-top-tool.svg +0 -0
  47. /package/app/{wujie-vue2-child → wujie-wk/wujie-vue2-child}/src/assets/icon/font/source/symbols/align-vertical-center-tool.svg +0 -0
  48. /package/app/{wujie-vue2-child → wujie-wk/wujie-vue2-child}/src/assets/icon/font/source/symbols/distribute-horizontally-tool.svg +0 -0
  49. /package/app/{wujie-vue2-child → wujie-wk/wujie-vue2-child}/src/assets/icon/font/source/symbols/distribute-vertically-tool.svg +0 -0
  50. /package/app/{wujie-vue2-child → wujie-wk/wujie-vue2-child}/src/assets/icon/font/source/symbols/set-color-tool.svg +0 -0
  51. /package/app/{wujie-vue2-child → wujie-wk/wujie-vue2-child}/src/assets/logo.png +0 -0
  52. /package/app/{wujie-vue2-child → wujie-wk/wujie-vue2-child}/src/components/EllTable/README.md +0 -0
  53. /package/app/{wujie-vue2-child → wujie-wk/wujie-vue2-child}/src/components/EllTable/article.md +0 -0
  54. /package/app/{wujie-vue2-child → wujie-wk/wujie-vue2-child}/src/components/EllTable/index.js +0 -0
  55. /package/app/{wujie-vue2-child → wujie-wk/wujie-vue2-child}/src/components/EventCalendar/CalendarSkeleton.vue +0 -0
  56. /package/app/{wujie-vue2-child → wujie-wk/wujie-vue2-child}/src/components/EventCalendar/CodeBlock.vue +0 -0
  57. /package/app/{wujie-vue2-child → wujie-wk/wujie-vue2-child}/src/components/EventCalendar/MonthSelect.vue +0 -0
  58. /package/app/{wujie-vue2-child → wujie-wk/wujie-vue2-child}/src/components/FormulaEditor/FunctionSelector.vue +0 -0
  59. /package/app/{wujie-vue2-child → wujie-wk/wujie-vue2-child}/src/components/FormulaEditor/OperatorSelector.vue +0 -0
  60. /package/app/{wujie-vue2-child → wujie-wk/wujie-vue2-child}/src/components/FormulaEditor/ParameterSelector.vue +0 -0
  61. /package/app/{wujie-vue2-child → wujie-wk/wujie-vue2-child}/src/components/FormulaEditor/api.js +0 -0
  62. /package/app/{wujie-vue2-child → wujie-wk/wujie-vue2-child}/src/components/FormulaEditor/index.vue +0 -0
  63. /package/app/{wujie-vue2-child → wujie-wk/wujie-vue2-child}/src/components/HelloWorld.vue +0 -0
  64. /package/app/{wujie-vue2-child → wujie-wk/wujie-vue2-child}/src/components/PageHeader/index.vue +0 -0
  65. /package/app/{wujie-vue2-child → wujie-wk/wujie-vue2-child}/src/components/Splitter/README.md +0 -0
  66. /package/app/{wujie-vue2-child → wujie-wk/wujie-vue2-child}/src/components/Splitter/example.vue +0 -0
  67. /package/app/{wujie-vue2-child → wujie-wk/wujie-vue2-child}/src/components/Splitter/index.vue +0 -0
  68. /package/app/{wujie-vue2-child → wujie-wk/wujie-vue2-child}/src/components/diagram/ToolBar.vue +0 -0
  69. /package/app/{wujie-vue2-child → wujie-wk/wujie-vue2-child}/src/components/diagram/customTranslate/customTranslate.js +0 -0
  70. /package/app/{wujie-vue2-child → wujie-wk/wujie-vue2-child}/src/components/diagram/customTranslate/translationsGerman.js +0 -0
  71. /package/app/{wujie-vue2-child → wujie-wk/wujie-vue2-child}/src/components/diagram/index.vue +0 -0
  72. /package/app/{wujie-vue2-child → wujie-wk/wujie-vue2-child}/src/components/diagram/xmlData.js +0 -0
  73. /package/app/{wujie-vue2-child → wujie-wk/wujie-vue2-child}/src/directives/filldown.js +0 -0
  74. /package/app/{wujie-vue2-child → wujie-wk/wujie-vue2-child}/src/directives/filldownTable.js +0 -0
  75. /package/app/{wujie-vue2-child → wujie-wk/wujie-vue2-child}/src/main.js +0 -0
  76. /package/app/{wujie-vue2-child → wujie-wk/wujie-vue2-child}/src/router/index.js +0 -0
  77. /package/app/{wujie-vue2-child → wujie-wk/wujie-vue2-child}/src/store/index.js +0 -0
  78. /package/app/{wujie-vue2-child → wujie-wk/wujie-vue2-child}/src/utils/winBox.js +0 -0
  79. /package/app/{wujie-vue2-child → wujie-wk/wujie-vue2-child}/src/views/Extend/A.vue +0 -0
  80. /package/app/{wujie-vue2-child → wujie-wk/wujie-vue2-child}/src/views/Extend/B.vue +0 -0
  81. /package/app/{wujie-vue2-child → wujie-wk/wujie-vue2-child}/src/views/Extend/MagicalComponentsForELFormItem.vue +0 -0
  82. /package/app/{wujie-vue2-child → wujie-wk/wujie-vue2-child}/src/views/Extend/index.vue +0 -0
  83. /package/app/{wujie-vue2-child → wujie-wk/wujie-vue2-child}/src/views/Extend/tableMouseHorizontalWheel.vue +0 -0
  84. /package/app/{wujie-vue2-child → wujie-wk/wujie-vue2-child}/src/views/Home.vue +0 -0
  85. /package/app/{wujie-vue2-child → wujie-wk/wujie-vue2-child}/src/views/RouterJump.vue +0 -0
  86. /package/app/{wujie-vue2-child → wujie-wk/wujie-vue2-child}/src/views/calendar/index.vue +0 -0
  87. /package/app/{wujie-vue2-child → wujie-wk/wujie-vue2-child}/src/views/css.vue +0 -0
  88. /package/app/{wujie-vue2-child → wujie-wk/wujie-vue2-child}/src/views/cssComponents/EllipsisText.vue +0 -0
  89. /package/app/{wujie-vue2-child → wujie-wk/wujie-vue2-child}/src/views/cssComponents/HoverCard.vue +0 -0
  90. /package/app/{wujie-vue2-child → wujie-wk/wujie-vue2-child}/src/views/cssComponents/TableHover.vue +0 -0
  91. /package/app/{wujie-vue2-child → wujie-wk/wujie-vue2-child}/src/views/cssComponents/inputSlo.vue +0 -0
  92. /package/app/{wujie-vue2-child → wujie-wk/wujie-vue2-child}/src/views/cssComponents/tableFixed.vue +0 -0
  93. /package/app/{wujie-vue2-child → wujie-wk/wujie-vue2-child}/src/views/echarts/echart-dome.vue +0 -0
  94. /package/app/{wujie-vue2-child → wujie-wk/wujie-vue2-child}/src/views/echarts/index.vue +0 -0
  95. /package/app/{wujie-vue2-child → wujie-wk/wujie-vue2-child}/src/views/echarts/pei3d.vue +0 -0
  96. /package/app/{wujie-vue2-child → wujie-wk/wujie-vue2-child}/src/views/element/bpmn/index.vue +0 -0
  97. /package/app/{wujie-vue2-child → wujie-wk/wujie-vue2-child}/src/views/element/components/attendanceCycle/index.vue +0 -0
  98. /package/app/{wujie-vue2-child → wujie-wk/wujie-vue2-child}/src/views/element/components/attendanceGroup/index.vue +0 -0
  99. /package/app/{wujie-vue2-child → wujie-wk/wujie-vue2-child}/src/views/element/components/attendancePersonnel/index.vue +0 -0
  100. /package/app/{wujie-vue2-child → wujie-wk/wujie-vue2-child}/src/views/element/components/companyCalendar/index.vue +0 -0
  101. /package/app/{wujie-vue2-child → wujie-wk/wujie-vue2-child}/src/views/element/components/shift/index.vue +0 -0
  102. /package/app/{wujie-vue2-child → wujie-wk/wujie-vue2-child}/src/views/element/components/shiftRotationSystem/index.vue +0 -0
  103. /package/app/{wujie-vue2-child → wujie-wk/wujie-vue2-child}/src/views/element/elTableJsx/columnManagement.vue +0 -0
  104. /package/app/{wujie-vue2-child → wujie-wk/wujie-vue2-child}/src/views/element/elTableJsx/dialogInput.vue +0 -0
  105. /package/app/{wujie-vue2-child → wujie-wk/wujie-vue2-child}/src/views/element/elTableJsx/elTableJsx.vue +0 -0
  106. /package/app/{wujie-vue2-child → wujie-wk/wujie-vue2-child}/src/views/element/elTableJsx/formTable.vue +0 -0
  107. /package/app/{wujie-vue2-child → wujie-wk/wujie-vue2-child}/src/views/element/elTableJsx/index.vue +0 -0
  108. /package/app/{wujie-vue2-child → wujie-wk/wujie-vue2-child}/src/views/element/elTableJsx/simpleTable.vue +0 -0
  109. /package/app/{wujie-vue2-child → wujie-wk/wujie-vue2-child}/src/views/element/elTableJsx.zip +0 -0
  110. /package/app/{wujie-vue2-child → wujie-wk/wujie-vue2-child}/src/views/element/index.vue +0 -0
  111. /package/app/{wujie-vue2-child → wujie-wk/wujie-vue2-child}/src/views/element/quillEditor/README.md +0 -0
  112. /package/app/{wujie-vue2-child → wujie-wk/wujie-vue2-child}/src/views/element/quillEditor/example.vue +0 -0
  113. /package/app/{wujie-vue2-child → wujie-wk/wujie-vue2-child}/src/views/element/quillEditor/index.vue +0 -0
  114. /package/app/{wujie-vue2-child → wujie-wk/wujie-vue2-child}/src/views/element/quillEditor/toolbar.js +0 -0
  115. /package/app/{wujie-vue2-child → wujie-wk/wujie-vue2-child}/vue.config.js +0 -0
@@ -0,0 +1,90 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <meta charset="utf-8" />
5
+ <title>vue.draggable vue3例子</title>
6
+ <meta name="viewport"
7
+ content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no, minimal-ui">
8
+ <script src="https://www.itxst.com/package/vue3/vue.global.js"></script>
9
+ <script src="https://www.itxst.com/package/sortable/Sortable.min.js"></script>
10
+ <script src="https://www.itxst.com/package/vuedraggablenext/vuedraggable.umd.min.js"></script>
11
+ </head>
12
+ <body style="padding:10px;">
13
+ <div id="app" class="demo">
14
+ <draggable :list="list" ghost-class="ghost" :force-fallback="true" chosen-class="chosenClass" animation="300"
15
+ @start="onStart" @end="onEnd">
16
+ <template #item="{ element }">
17
+ <div class="item">
18
+ {{ element.name }}
19
+ </div>
20
+ </template>
21
+ </draggable>
22
+ </div>
23
+ <script>
24
+ const app = {
25
+ data() {
26
+ return {
27
+ //需要拖拽的数据
28
+ list: [
29
+ { name: "www.itxst.com", id: 0 },
30
+ { name: "www.baidu.com", id: 1 },
31
+ { name: "www.google.com", id: 2 },
32
+ ]
33
+ }
34
+ },
35
+ //注册draggable组件
36
+ components: {
37
+ 'draggable': window.vuedraggable
38
+ },
39
+ methods: {
40
+ //开始拖拽事件
41
+ onStart() {
42
+
43
+ },
44
+ //结束拖拽事件
45
+ onEnd() {
46
+
47
+ }
48
+ }
49
+ }
50
+ Vue.createApp(app).mount('#app')
51
+ </script>
52
+ <style>
53
+ .itxst {
54
+ width: 600px;
55
+ display: flex;
56
+ }
57
+ .itxst>div:nth-of-type(1) {
58
+ flex: 1;
59
+ }
60
+ .itxst>div:nth-of-type(2) {
61
+ width: 270px;
62
+ padding-left: 20px;
63
+ }
64
+ .item {
65
+ border: solid 1px #eee;
66
+ padding: 6px 10px;
67
+ text-align: left;
68
+ }
69
+ .item:hover {
70
+ cursor: move;
71
+ }
72
+
73
+ .item+.item {
74
+ margin-top: 10px;
75
+ }
76
+ .ghost {
77
+ border: solid 1px rgb(19, 41, 239) !important;
78
+ }
79
+
80
+ .chosenClass {
81
+ background-color: #eee;
82
+ opacity: 1;
83
+ border: solid 1px red;
84
+ }
85
+ .fallbackClass {
86
+ background-color: aquamarine;
87
+ }
88
+ </style>
89
+ </body>
90
+ </html>
@@ -15,13 +15,15 @@ EventCalendar/
15
15
  ├── CalendarSkeleton.vue # 骨架屏
16
16
  ├── CodeBlock.vue # 示例页用的代码块(业务中可删)
17
17
  ├── utils.js # 日期计算与字段映射工具
18
+ ├── recruitmentAdapter.js # NodeQ mock 响应 -> EventCalendar 数据
18
19
  ├── mockData.js # 模拟数据(setTimeout 模拟异步接口)
19
- ├── example.vue # 完整示例集合(12 个 demo + API 文档)
20
+ ├── example.vue # 完整示例集合(14 个 demo + API 文档)
20
21
  └── README.md
21
22
  ```
22
23
 
23
- 真正接入业务时,**必需**的只有 `index.vue`、`MonthSelect.vue`、`CalendarSkeleton.vue`、`utils.js`。
24
- `mockData.js` / `example.vue` / `CodeBlock.vue` 是演示用的,可以删掉。
24
+ 真正接入普通日历时,**必需**的只有 `index.vue`、`MonthSelect.vue`、`CalendarSkeleton.vue`、`utils.js`。
25
+ 接 NodeQ 招聘接口时再加入 `recruitmentAdapter.js`。`mockData.js` / `example.vue` / `CodeBlock.vue`
26
+ 是演示用的,可以删掉。
25
27
 
26
28
  ## 快速开始
27
29
 
@@ -78,6 +80,7 @@ export default {
78
80
  {
79
81
  id: 'a1',
80
82
  label: '香港中文大学(深圳)', // 主文案
83
+ address: '深圳市南山区校区报告厅', // 地址,为空时不显示地址行
81
84
  badge: '宣讲', // 右上角角标
82
85
  type: 'talk' // 类型,决定配色
83
86
  }
@@ -99,6 +102,88 @@ export default {
99
102
  ]
100
103
  ```
101
104
 
105
+ ## NodeQ mock 数据转换
106
+
107
+ 转换方法只负责把当前 mock 响应中的 `data.nbcbRecAnnJourneyMaps` 映射为组件默认结构,
108
+ 不包含字段猜测或展示配置:
109
+
110
+ ```js
111
+ import EventCalendar from '@/components/EventCalendar/index.vue'
112
+ import { transformNodeqCalendarResponse } from '@/components/EventCalendar/recruitmentAdapter'
113
+
114
+ const data = transformNodeqCalendarResponse(response)
115
+ ```
116
+
117
+ ```vue
118
+ <EventCalendar
119
+ :data="data"
120
+ item-align="center"
121
+ :item-horizontal-padding="0"
122
+ :item-height="40"
123
+ />
124
+ ```
125
+
126
+ 转换后条目固定包含 `id`、`label`、`address`、`badge`、`type`、`disabled`。
127
+ mock 中没有的值使用空字符串或 `false`。`address` 为空时,日历组件不会渲染地址行。
128
+
129
+ 大学名称不超过 7 个字符时为 14px,超过 7 个字符时为 12px;地址统一为 12px。
130
+ `item-align` 控制靠左或居中,`item-horizontal-padding="0"` 可去掉条目左右内边距。
131
+
132
+ ## 原生布局配置工具栏
133
+
134
+ 外边距、内边距、条目、溢出与行高、角标缩放等均为组件原生 Props。开启工具栏后,
135
+ 改完点「复制配置」,把 JSON 粘回 `layoutConfig` 再 `v-bind` 即可:
136
+
137
+ ```vue
138
+ <EventCalendar
139
+ :data="data"
140
+ v-bind="layoutConfig"
141
+ :show-config-toolbar="isDevelopment"
142
+ />
143
+ ```
144
+
145
+ ```js
146
+ export default {
147
+ data() {
148
+ return {
149
+ isDevelopment: process.env.NODE_ENV !== 'production',
150
+ // 结构与工具栏「复制配置」得到的 JSON 一致,可直接赋值应用
151
+ layoutConfig: {
152
+ itemAlign: 'center',
153
+ calendarMargin: 0,
154
+ calendarPadding: 0,
155
+ headerPadding: '4px 4px 16px',
156
+ cellPadding: '12px 10px',
157
+ mobileCellPadding: '8px 6px',
158
+ itemHorizontalPadding: 0,
159
+ itemVerticalPadding: 4,
160
+ itemGap: 6,
161
+ itemLineGap: 2,
162
+ itemBgGradient: false,
163
+ itemBgGradientDir: 'to-bottom',
164
+ itemBgHover: true,
165
+ overflowMode: 'scroll',
166
+ maxVisibleItems: 4,
167
+ itemHeight: 28,
168
+ minRowHeight: 118,
169
+ badgeScale: 0.75,
170
+ // 条目色留空表示沿用 type/主题配色
171
+ itemTextColor: '',
172
+ itemBgColor: ''
173
+ }
174
+ }
175
+ }
176
+ }
177
+ ```
178
+
179
+ `show-config-toolbar` 默认是 `false`。开启后组件顶部会出现配置工具栏(P1~P14):
180
+ 条目对齐、日期格/窄屏日期格内边距(各拆「上下 / 左右」两块)、条目左右/上下内边距与间距、
181
+ 名称与地址间距、单格最多显示、条目高度、条目背景效果(纯色/渐变,方向可上下或左右)、
182
+ 悬浮加深(可关闭)与条目文字色/背景色;每张卡片右上角都有「还原」可回到初始值。
183
+ 选定条目背景色后,鼠标悬浮会自动把背景调淡一档,不喜欢可在「悬浮加深」里关闭。
184
+ 底部实时显示当前配置 JSON,右上角「复制配置」一键复制。用户把复制出的 JSON 发回后,
185
+ 研发直接把它赋给 `layoutConfig` 通过 `v-bind` 应用即可。
186
+
102
187
  ## 字段映射(后端字段不一致时)
103
188
 
104
189
  **不需要改数据**,传 `field-names` 即可。字段路径支持 `'a.b.c'` 形式。
@@ -112,6 +197,7 @@ const fieldNames = {
112
197
  items: 'activityList',
113
198
  itemKey: 'activityId',
114
199
  itemLabel: 'schoolName',
200
+ itemAddress: 'rawAddress',
115
201
  itemBadge: 'activityTypeName',
116
202
  itemType: 'activityType',
117
203
  itemDisabled: 'expired'
@@ -152,6 +238,9 @@ const fieldNames = {
152
238
  | `scroll`(默认) | 格内出现细滚动条,滚动区高度 = `n × item-height + (n-1) × item-gap` |
153
239
  | `collapse` | 只显示前 n-1 条,末尾出现「还有 N 项」,可监听 `more-click` |
154
240
 
241
+ 大学名称不超过 7 个字符时使用 14px,超过 7 个字符时使用 12px;地址行统一使用 12px,
242
+ 地址为空时不渲染。
243
+
155
244
  `min-row-height` 保证没有条目的行不会塌陷。
156
245
 
157
246
  ### 3. 轮播与暂停
@@ -213,6 +302,22 @@ const fieldNames = {
213
302
  | overflow-mode | 溢出处理:`scroll` / `collapse` | String | `'scroll'` |
214
303
  | item-height | 单条条目高度(px) | Number | `28` |
215
304
  | item-gap | 条目间距(px) | Number | `6` |
305
+ | item-align | 条目内容对齐方式:`left` / `center` | String | `'left'` |
306
+ | calendar-margin | 日历根节点外边距;Number 按 px 处理,String 支持 CSS 简写 | Number / String | `0` |
307
+ | calendar-padding | 日历根节点内边距;Number 按 px 处理,String 支持 CSS 简写 | Number / String | `0` |
308
+ | header-padding | 顶部区域内边距,支持 CSS 简写 | Number / String | `'4px 4px 16px'` |
309
+ | cell-padding | 日期格内边距,支持 CSS 简写 | Number / String | `'12px 10px'` |
310
+ | mobile-cell-padding | 768px 及以下日期格内边距 | Number / String | `'8px 6px'` |
311
+ | item-horizontal-padding | 条目左右内边距(px),传 0 可去除 | Number | `8` |
312
+ | item-vertical-padding | 条目上下内边距(px) | Number | `4` |
313
+ | item-line-gap | 条目内名称与地址的行间距(px) | Number | `2` |
314
+ | item-bg-gradient | 条目背景是否启用渐变(在底色上叠柔和渐变) | Boolean | `false` |
315
+ | item-bg-gradient-dir | 渐变方向:to-bottom 上到下 | to-right 左到右 | String | `'to-bottom'` |
316
+ | item-bg-hover | 悬浮时是否自动把条目背景调淡一档 | Boolean | `true` |
317
+ | badge-scale | 右上角角标整体缩放倍率(越小越紧凑) | Number | `0.75` |
318
+ | show-config-toolbar | 显示原生布局配置工具栏 | Boolean | `false` |
319
+ | item-bg-color | 条目(.ec__item)背景色覆盖;空串按 type/主题配色(工具栏可取色) | String | `''` |
320
+ | item-text-color | 条目(.ec__item)文字色覆盖;空串按 type/主题配色(工具栏可取色) | String | `''` |
216
321
  | min-row-height | 单元格最小高度(px) | Number | `118` |
217
322
  | show-adjacent-items | 补位日期是否也渲染条目 | Boolean | `true` |
218
323
  | highlight-today | 高亮今天 | Boolean | `true` |
@@ -237,6 +342,7 @@ const fieldNames = {
237
342
  | autoplay-toggle | 点击播放/暂停按钮 | `(playing: Boolean)` |
238
343
  | autoplay-end | `loop=false` 时播到最后一个月 | — |
239
344
  | transition-end | 月份切换动画结束 | `(month)` |
345
+ | config-change | 工具栏配置变化(编辑每一项都会触发) | `(config)` |
240
346
 
241
347
  `month-change` 的 `source` 表明触发来源:`select` / `arrow` / `autoplay` / `prop` / `api`。
242
348
 
@@ -292,6 +398,7 @@ const fieldNames = {
292
398
  | `goTo(index)` | 切到第 index 个月(从 0 开始) |
293
399
  | `setMonth(month)` | 切到指定月份,如 `setMonth('2026-10')` |
294
400
  | `restartAutoplay()` | 重置轮播计时 |
401
+ | `getLayoutConfig()` | 获取可直接通过 `v-bind` 应用的当前布局配置 |
295
402
 
296
403
  ## 主题定制
297
404
 
@@ -339,9 +446,13 @@ import {
339
446
  fetchCalendarDataV2, // 字段名完全不同,配合 ALT_FIELD_NAMES 演示映射
340
447
  fetchCrossYearData, // 2025-12 / 2026-01 / 2026-02,验证跨年补全
341
448
  fetchEmptyData, // 空数据
449
+ fetchNodeqCalendarData, // NodeQ mock 响应(三个月、每天 3~5 条)
450
+ NODEQ_MOCK_RESPONSE, // 同一份响应的同步版本
451
+ createNodeqMockResponse,
342
452
  SIMPLE_DATA, // 一份写死的小数据
343
453
  ALT_FIELD_NAMES
344
454
  } from './mockData'
455
+ import { transformNodeqCalendarResponse } from './recruitmentAdapter'
345
456
 
346
457
  const data = await fetchCalendarData({
347
458
  months: ['2026-09', '2026-10'],
@@ -349,15 +460,21 @@ const data = await fetchCalendarData({
349
460
  maxItems: 6,
350
461
  density: 0.62
351
462
  })
463
+
464
+ const nodeqResponse = await fetchNodeqCalendarData()
465
+ const nodeqData = transformNodeqCalendarResponse(nodeqResponse)
352
466
  ```
353
467
 
354
468
  数据用固定种子的伪随机生成,**每次刷新结果一致**,方便调样式和截图对比。
469
+ `createNodeqMockResponse()` 默认生成 2026 年 9~11 月,每个月 14 个有安排的日期,
470
+ 每天 3~5 条 NodeQ mock 记录。转换方法只按这份 mock 的固定字段做映射。
355
471
 
356
472
  ## 示例页
357
473
 
358
- `example.vue` 是按 UI 组件库文档形式组织的完整示例集合,包含 12 个可交互 demo
474
+ `example.vue` 是按 UI 组件库文档形式组织的完整示例集合,包含 14 个可交互 demo
359
475
  (基础用法、异步骨架屏、多月切换、自动轮播、切换动效、跨年补全、字段映射、
360
- 溢出与行高、插槽定制、事件、主题、空状态)与完整 API 表格。
476
+ 溢出与行高、插槽定制、事件、主题、空状态、NodeQ 后端适配、布局配置与 JSON 导出)
477
+ 与完整 API 表格。
361
478
 
362
479
  本项目中已挂到路由 `/calendar`。
363
480
 
@@ -237,7 +237,7 @@
237
237
  <p class="demo__desc">
238
238
  后端字段名和组件默认约定不一致时,<strong>不需要改数据</strong>,
239
239
  传一个 <code>field-names</code> 即可。下面这份数据用的是
240
- <code>ym / dateList / dayStr / activityList / schoolName / activityTypeName</code>,
240
+ <code>ym / dateList / dayStr / activityList / schoolName / rawAddress</code>,
241
241
  字段路径还支持 <code>'a.b.c'</code> 形式。
242
242
  </p>
243
243
  <div class="demo__cols">
@@ -337,7 +337,7 @@
337
337
  </div>
338
338
  <div class="custom-item__row custom-item__row--sub">
339
339
  <span class="custom-item__addr">{{ item.address || '地点待定' }}</span>
340
- <span class="custom-item__tag">{{ badge }}</span>
340
+ <span v-if="badge" class="custom-item__tag">{{ badge }}</span>
341
341
  </div>
342
342
  </div>
343
343
  </template>
@@ -454,6 +454,86 @@
454
454
  </div>
455
455
  </section>
456
456
 
457
+ <!-- ------------------------------------------------------------ -->
458
+ <!-- 13. NodeQ 后端数据适配 -->
459
+ <!-- ------------------------------------------------------------ -->
460
+ <section id="nodeq" class="demo">
461
+ <h2 class="demo__title">13. NodeQ 后端数据适配</h2>
462
+ <p class="demo__desc">
463
+ mock 响应先通过简单转换方法得到标准日历数据,再直接传给
464
+ <code>EventCalendar</code>。地址、居中和左右内边距均由组件原生支持。
465
+ </p>
466
+ <div class="demo__toolbar">
467
+ <span class="doc__hint">条目对齐:</span>
468
+ <button
469
+ v-for="opt in nodeqAlignmentOptions"
470
+ :key="opt.value"
471
+ class="doc__seg"
472
+ :class="{ 'is-active': nodeqAlignment === opt.value }"
473
+ @click="nodeqAlignment = opt.value"
474
+ >{{ opt.label }}</button>
475
+
476
+ <label class="doc__check">
477
+ <input v-model="nodeqNoHorizontalPadding" type="checkbox" />
478
+ <span>去除条目左右内边距</span>
479
+ </label>
480
+ </div>
481
+ <div class="demo__stage">
482
+ <EventCalendar
483
+ :data="nodeqData"
484
+ :active-month.sync="nodeqActiveMonth"
485
+ :item-align="nodeqAlignment"
486
+ :item-horizontal-padding="nodeqNoHorizontalPadding ? 0 : 8"
487
+ :item-height="40"
488
+ :max-visible-items="5"
489
+ :min-row-height="142"
490
+ show-arrows
491
+ title="宣讲日历(NodeQ)"
492
+ subtitle="三个月模拟数据 · 每个有安排的日期 3~5 条"
493
+ />
494
+ </div>
495
+ <CodeBlock :code="code.nodeq" />
496
+ </section>
497
+
498
+ <!-- ------------------------------------------------------------ -->
499
+ <!-- 14. 原生布局配置与 JSON 导出 -->
500
+ <!-- ------------------------------------------------------------ -->
501
+ <section id="layout-config" class="demo">
502
+ <h2 class="demo__title">14. 原生布局配置与一键复制</h2>
503
+ <p class="demo__desc">
504
+ 配置工具栏属于 <code>EventCalendar</code> 自身能力,按 P1~P14 排列常用项:
505
+ 条目对齐、日期格/窄屏日期格内边距(各拆「上下 / 左右」两块)、条目边距与间距、
506
+ 名称与地址间距、单格最多显示、条目高度、条目背景效果(纯色/渐变,方向可上下或左右)、
507
+ 悬浮加深(可关闭)与条目背景/文字色;选定背景色后悬浮会自动调淡一档。
508
+ 每张卡片右上角的「还原」可回到初始值,调整后点「复制配置」,JSON 直接进剪贴板,发给研发即可。
509
+ 生产环境保持默认隐藏,开发配置时再传入 <code>show-config-toolbar</code>。
510
+ </p>
511
+ <div class="demo__toolbar">
512
+ <label class="doc__check">
513
+ <input v-model="layoutToolbarVisible" type="checkbox" />
514
+ <span>显示组件内配置工具栏</span>
515
+ </label>
516
+ <span class="doc__hint">
517
+ 当前参数:<code>show-config-toolbar="{{ layoutToolbarVisible }}"</code>
518
+ </span>
519
+ </div>
520
+ <div class="demo__stage">
521
+ <EventCalendar
522
+ :data="nodeqData"
523
+ :active-month.sync="layoutActiveMonth"
524
+ v-bind="savedLayoutConfig"
525
+ :show-config-toolbar="layoutToolbarVisible"
526
+ :item-height="40"
527
+ :max-visible-items="5"
528
+ :min-row-height="142"
529
+ show-arrows
530
+ title="可配置宣讲日历"
531
+ subtitle="配置结果点「复制配置」,粘贴发给研发即可"
532
+ />
533
+ </div>
534
+ <CodeBlock :code="code.layoutConfig" />
535
+ </section>
536
+
457
537
  <!-- ------------------------------------------------------------ -->
458
538
  <!-- API -->
459
539
  <!-- ------------------------------------------------------------ -->
@@ -543,8 +623,10 @@ import {
543
623
  ALT_FIELD_NAMES,
544
624
  fetchCalendarData,
545
625
  fetchCalendarDataV2,
546
- fetchCrossYearData
626
+ fetchCrossYearData,
627
+ NODEQ_MOCK_RESPONSE
547
628
  } from './mockData'
629
+ import { transformNodeqCalendarResponse } from './recruitmentAdapter'
548
630
 
549
631
  export default {
550
632
  name: 'EventCalendarExample',
@@ -553,7 +635,7 @@ export default {
553
635
 
554
636
  data() {
555
637
  return {
556
- heroTags: ['零依赖', '自动补月', '轮播动效', '字段可配', '插槽定制', '骨架屏'],
638
+ heroTags: ['零依赖', '自动补月', '轮播动效', '字段可配', '布局配置', 'NodeQ 适配', '插槽定制', '骨架屏'],
557
639
 
558
640
  sections: [
559
641
  { id: 'basic', title: '1. 基础用法' },
@@ -568,6 +650,8 @@ export default {
568
650
  { id: 'events', title: '10. 事件' },
569
651
  { id: 'theme', title: '11. 主题定制' },
570
652
  { id: 'empty', title: '12. 空状态' },
653
+ { id: 'nodeq', title: '13. NodeQ 后端适配' },
654
+ { id: 'layout-config', title: '14. 布局配置与导出' },
571
655
  { id: 'api', title: 'API' }
572
656
  ],
573
657
  activeSection: 'basic',
@@ -631,6 +715,37 @@ export default {
631
715
  /* -------- 10. 事件 -------- */
632
716
  logs: [],
633
717
 
718
+ /* -------- 13. NodeQ 后端形状 -------- */
719
+ nodeqData: transformNodeqCalendarResponse(NODEQ_MOCK_RESPONSE),
720
+ nodeqAlignment: 'left',
721
+ nodeqNoHorizontalPadding: false,
722
+ nodeqActiveMonth: '2026-09',
723
+ nodeqAlignmentOptions: [
724
+ { label: '靠左', value: 'left' },
725
+ { label: '居中', value: 'center' }
726
+ ],
727
+
728
+ /* -------- 14. 原生布局配置 -------- */
729
+ layoutToolbarVisible: true,
730
+ layoutActiveMonth: '2026-09',
731
+ savedLayoutConfig: {
732
+ itemAlign: 'left',
733
+ calendarMargin: 0,
734
+ calendarPadding: 0,
735
+ headerPadding: '4px 4px 16px',
736
+ cellPadding: '12px 10px',
737
+ mobileCellPadding: '8px 6px',
738
+ itemHorizontalPadding: 8,
739
+ itemVerticalPadding: 4,
740
+ itemGap: 6,
741
+ itemLineGap: 2,
742
+ itemBgGradient: false,
743
+ itemBgGradientDir: 'to-bottom',
744
+ itemBgHover: true,
745
+ itemTextColor: '',
746
+ itemBgColor: ''
747
+ },
748
+
634
749
  /* -------- 11. 主题 -------- */
635
750
  themeName: 'default',
636
751
  colorful: true,
@@ -761,6 +876,7 @@ onMonthChange(month, info) {
761
876
  activityList: [{
762
877
  activityId: 1,
763
878
  schoolName: '南方科技大学',
879
+ rawAddress: '深圳市南山区校区报告厅',
764
880
  activityTypeName: '宣讲',
765
881
  activityType: 'talk',
766
882
  expired: false
@@ -776,6 +892,7 @@ onMonthChange(month, info) {
776
892
  items: 'activityList',
777
893
  itemKey: 'activityId',
778
894
  itemLabel: 'schoolName',
895
+ itemAddress: 'rawAddress',
779
896
  itemBadge: 'activityTypeName',
780
897
  itemType: 'activityType',
781
898
  itemDisabled: 'expired'
@@ -822,13 +939,69 @@ onDayClick(scope, event) {
822
939
  // scope = { day, date, dateKey, items, raw, isCurrentMonth, isToday, ... }
823
940
  }
824
941
  onItemClick(scope, event) {
825
- // scope = { item, label, badge, type, index, day, dateKey }
942
+ // scope = { item, label, address, badge, type, index, day, dateKey }
826
943
  // item 是后端返回的原始对象,字段齐全
827
944
  }
828
945
  onTagClick(scope, event) {
829
946
  // 点角标;未监听时会自动退化成 item-click
830
947
  }`,
831
948
 
949
+ nodeq: `import EventCalendar from '@/components/EventCalendar/index.vue'
950
+ import { fetchNodeqCalendarData } from '@/components/EventCalendar/mockData'
951
+ import { transformNodeqCalendarResponse } from '@/components/EventCalendar/recruitmentAdapter'
952
+
953
+ // 后端原始响应:response.data.nbcbRecAnnJourneyMaps
954
+ const response = await fetchNodeqCalendarData()
955
+ const data = transformNodeqCalendarResponse(response)
956
+
957
+ <EventCalendar
958
+ :data="data"
959
+ item-align="center"
960
+ :item-horizontal-padding="0"
961
+ :item-height="40"
962
+ />
963
+ // address 为空时,组件不会渲染地址行。`,
964
+
965
+ layoutConfig: `<!-- 默认不显示工具栏;建议只在开发环境开启 -->
966
+ <EventCalendar
967
+ :data="data"
968
+ v-bind="layoutConfig"
969
+ :show-config-toolbar="isDevelopment"
970
+ />
971
+ <!-- 工具栏里改完点「复制配置」,把 JSON 粘回来赋给 layoutConfig 即可 -->
972
+
973
+ export default {
974
+ data() {
975
+ return {
976
+ isDevelopment: process.env.NODE_ENV !== 'production',
977
+ // 结构同工具栏「复制配置」得到的 JSON,可直接 v-bind 应用
978
+ layoutConfig: {
979
+ itemAlign: 'center',
980
+ calendarMargin: 0,
981
+ calendarPadding: 0,
982
+ headerPadding: '4px 4px 16px',
983
+ cellPadding: '12px 10px',
984
+ mobileCellPadding: '8px 6px',
985
+ itemHorizontalPadding: 0,
986
+ itemVerticalPadding: 4,
987
+ itemGap: 6,
988
+ itemLineGap: 2,
989
+ itemBgGradient: false,
990
+ itemBgGradientDir: 'to-bottom',
991
+ itemBgHover: true,
992
+ overflowMode: 'scroll',
993
+ maxVisibleItems: 4,
994
+ itemHeight: 28,
995
+ minRowHeight: 118,
996
+ badgeScale: 0.75,
997
+ // 条目色留空表示沿用 type/主题配色
998
+ itemTextColor: '',
999
+ itemBgColor: ''
1000
+ }
1001
+ }
1002
+ }
1003
+ }`,
1004
+
832
1005
  theme: `<EventCalendar
833
1006
  :data="data"
834
1007
  :theme="{
@@ -868,6 +1041,22 @@ onTagClick(scope, event) {
868
1041
  ['overflow-mode', '溢出处理:scroll / collapse', 'String', "'scroll'"],
869
1042
  ['item-height', '单条条目高度(px)', 'Number', '28'],
870
1043
  ['item-gap', '条目间距(px)', 'Number', '6'],
1044
+ ['item-align', '条目内容对齐方式:left / center', 'String', "'left'"],
1045
+ ['calendar-margin', '日历根节点外边距,Number 按 px 处理,String 支持 CSS 简写', 'Number / String', '0'],
1046
+ ['calendar-padding', '日历根节点内边距,Number 按 px 处理,String 支持 CSS 简写', 'Number / String', '0'],
1047
+ ['header-padding', '顶部区域内边距,支持 CSS 简写', 'Number / String', "'4px 4px 16px'"],
1048
+ ['cell-padding', '日期格内边距,支持 CSS 简写', 'Number / String', "'12px 10px'"],
1049
+ ['mobile-cell-padding', '768px 及以下的日期格内边距', 'Number / String', "'8px 6px'"],
1050
+ ['item-horizontal-padding', '条目左右内边距(px),传 0 可去除', 'Number', '8'],
1051
+ ['item-vertical-padding', '条目上下内边距(px)', 'Number', '4'],
1052
+ ['item-line-gap', '条目内名称与地址的行间距(px)', 'Number', '2'],
1053
+ ['item-bg-gradient', '条目背景是否启用渐变(在底色上叠柔和渐变)', 'Boolean', 'false'],
1054
+ ['item-bg-gradient-dir', '渐变方向:to-bottom 上到下 | to-right 左到右', 'String', "'to-bottom'"],
1055
+ ['item-bg-hover', '悬浮时是否自动把条目背景调淡一档', 'Boolean', 'true'],
1056
+ ['badge-scale', '右上角角标整体缩放倍率(越小越紧凑)', 'Number', '0.75'],
1057
+ ['show-config-toolbar', '显示原生布局配置工具栏,生产环境默认隐藏', 'Boolean', 'false'],
1058
+ ['item-bg-color', '条目(.ec__item)背景色覆盖,空串按 type/主题配色(工具栏可取色)', 'String', "''"],
1059
+ ['item-text-color', '条目(.ec__item)文字色覆盖,空串按 type/主题配色(工具栏可取色)', 'String', "''"],
871
1060
  ['min-row-height', '单元格最小高度(px)', 'Number', '118'],
872
1061
  ['show-adjacent-items', '补位日期是否也渲染条目', 'Boolean', 'true'],
873
1062
  ['highlight-today', '高亮今天', 'Boolean', 'true'],
@@ -888,7 +1077,8 @@ onTagClick(scope, event) {
888
1077
  ['update:activeMonth', '配合 v-model / .sync', '(month)'],
889
1078
  ['autoplay-toggle', '点击播放/暂停按钮', '(playing: Boolean)'],
890
1079
  ['autoplay-end', 'loop=false 时播到最后一个月', '—'],
891
- ['transition-end', '月份切换动画结束', '(month)']
1080
+ ['transition-end', '月份切换动画结束', '(month)'],
1081
+ ['config-change', '工具栏配置变化', '(config)']
892
1082
  ],
893
1083
  apiSlots: [
894
1084
  ['header-left', '顶部左侧(设计稿的标题区)', '{ month, monthLabel, monthIndex, monthCount, prev, next, goTo }'],
@@ -907,7 +1097,8 @@ onTagClick(scope, event) {
907
1097
  ['next()', '切到下一个月'],
908
1098
  ['goTo(index)', '切到第 index 个月(从 0 开始)'],
909
1099
  ['setMonth(month)', '切到指定月份,如 setMonth("2026-10")'],
910
- ['restartAutoplay()', '重置轮播计时']
1100
+ ['restartAutoplay()', '重置轮播计时'],
1101
+ ['getLayoutConfig()', '获取可直接通过 v-bind 应用的当前布局配置']
911
1102
  ]
912
1103
  }
913
1104
  },
@@ -1310,6 +1501,7 @@ onTagClick(scope, event) {
1310
1501
  color: #3d6cf0 !important;
1311
1502
  }
1312
1503
 
1504
+
1313
1505
  /* ------------------------------ 事件日志 ------------------------------ */
1314
1506
  .event-log {
1315
1507
  flex: none;
@@ -1517,6 +1709,10 @@ onTagClick(scope, event) {
1517
1709
  font-size: 10px;
1518
1710
  }
1519
1711
 
1712
+ .custom-item__tag:empty {
1713
+ display: none;
1714
+ }
1715
+
1520
1716
  .custom-empty {
1521
1717
  padding: 6px 0;
1522
1718
  color: #dcdfe6;