xlzw-card-list 0.1.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.
package/README.md ADDED
@@ -0,0 +1,114 @@
1
+ # xlzw-card-list
2
+
3
+ 基于 Vue 3 + ant-design-vue 的可复用卡片列表组件。卡片列配置由外部注入(请求函数或直接传配置),组件本身不绑定任何后端接口。
4
+
5
+ ## 安装
6
+
7
+ ```bash
8
+ npm install xlzw-card-list
9
+ ```
10
+
11
+ 需要宿主项目自行提供(peerDependencies):
12
+
13
+ ```bash
14
+ npm install vue@^3.3.0 ant-design-vue@^4.0.0
15
+ ```
16
+
17
+ ## 引入
18
+
19
+ ```js
20
+ import { createApp } from "vue";
21
+ import CardList from "xlzw-card-list";
22
+ import "xlzw-card-list/style.css";
23
+
24
+ const app = createApp(App);
25
+ app.use(CardList); // 全局注册为 <CardList />
26
+ ```
27
+
28
+ 或按需局部引入:
29
+
30
+ ```vue
31
+ <script setup>
32
+ import { CardList } from "xlzw-card-list";
33
+ import "xlzw-card-list/style.css";
34
+ </script>
35
+ ```
36
+
37
+ ## 用法一:外部注入请求函数(推荐)
38
+
39
+ `fetchConfig(cardId)` 需返回 `Promise<{ propertys, width }>`:
40
+
41
+ ```vue
42
+ <template>
43
+ <CardList
44
+ :card="orderList"
45
+ :card-id="cardId"
46
+ :fetch-config="fetchCardConfig"
47
+ @select-item="onSelect"
48
+ @scroll="onLoadMore"
49
+ >
50
+ <template #action="{ item }">
51
+ <a-button size="small" @click.stop="onDetail(item)">详情</a-button>
52
+ </template>
53
+ </CardList>
54
+ </template>
55
+
56
+ <script setup>
57
+ import { getUiCardList } from "@/api/index";
58
+
59
+ async function fetchCardConfig(cardId) {
60
+ const res = await getUiCardList(cardId);
61
+ return {
62
+ propertys: res.data.propertys,
63
+ width: res.data.card.width,
64
+ };
65
+ }
66
+ </script>
67
+ ```
68
+
69
+ ## 用法二:直接传入配置
70
+
71
+ 不传 `fetchConfig`、直接传 `propertys` + `width` 时,组件只做展示:
72
+
73
+ ```vue
74
+ <CardList :card="list" :propertys="propertys" :width="320" />
75
+ ```
76
+
77
+ ## Props
78
+
79
+ | 名称 | 类型 | 默认值 | 说明 |
80
+ | --- | --- | --- | --- |
81
+ | `card` | `Array` | `[]` | 卡片展示数据 |
82
+ | `cardId` | `String \| Number` | `"0"` | 配置 id,配合 `fetchConfig` 使用 |
83
+ | `fetchConfig` | `(cardId) => Promise<{ propertys, width }>` | `null` | 外部注入的配置请求函数 |
84
+ | `propertys` | `Array` | `[]` | 直接传入的列配置,传入后优先于 `fetchConfig` |
85
+ | `width` | `Number` | `0` | 卡片宽度(px),配合 `propertys` 使用 |
86
+
87
+ ## Events
88
+
89
+ | 名称 | 参数 | 说明 |
90
+ | --- | --- | --- |
91
+ | `selectItem` | `item` | 点击某张卡片时触发 |
92
+ | `scroll` | - | 列表滚动到底部时触发(用于加载更多) |
93
+
94
+ ## Slots
95
+
96
+ | 名称 | 参数 | 说明 |
97
+ | --- | --- | --- |
98
+ | `action` | `{ item }` | 每张卡片的自定义操作区 |
99
+
100
+ ## Expose
101
+
102
+ | 名称 | 说明 |
103
+ | --- | --- |
104
+ | `selectItem(item, field?)` | 手动选中卡片;传 `field` 时按该字段匹配 |
105
+
106
+ ## 本地开发 / 发布
107
+
108
+ ```bash
109
+ cd packages/card-list
110
+ npm install
111
+ npm run build # 产物在 dist/,含 card-list.js / card-list.umd.cjs / style.css
112
+ npm pack # 本地打包,检查 tarball 内容
113
+ npm publish --access public # scope 包首次发布需带 --access public
114
+ ```
@@ -0,0 +1,262 @@
1
+ import { ref as k, computed as O, watch as $, resolveComponent as W, openBlock as d, createElementBlock as i, normalizeStyle as f, Fragment as A, renderList as M, createBlock as b, normalizeClass as q, withCtx as o, withDirectives as G, createCommentVNode as m, toDisplayString as y, createVNode as p, createElementVNode as w, vShow as J, renderSlot as P } from "vue";
2
+ function V(s) {
3
+ return s < 10 ? "0" + s : s;
4
+ }
5
+ function R(s) {
6
+ var h = new Date(s), _ = h.getFullYear(), u = h.getMonth() + 1, l = h.getDate(), v = _ + "/" + V(u) + "/" + V(l);
7
+ return v;
8
+ }
9
+ const T = (s, h) => {
10
+ const _ = s.__vccOpts || s;
11
+ for (const [u, l] of h)
12
+ _[u] = l;
13
+ return _;
14
+ }, j = {
15
+ key: 0,
16
+ class: "box__header"
17
+ }, K = ["src"], Q = {
18
+ key: 1,
19
+ class: "box__row"
20
+ }, U = {
21
+ key: 2,
22
+ class: "box__row"
23
+ }, X = {
24
+ key: 3,
25
+ class: "box__row"
26
+ }, L = /* @__PURE__ */ new Map(), x = /* @__PURE__ */ new Map(), S = /* @__PURE__ */ new Map(), Z = {
27
+ __name: "CardList",
28
+ props: {
29
+ card: {
30
+ type: Array,
31
+ default: () => []
32
+ },
33
+ cardId: {
34
+ type: [String, Number],
35
+ default: () => "0"
36
+ },
37
+ // 外部注入的配置请求函数:(cardId) => Promise<{ propertys, width }>
38
+ fetchConfig: {
39
+ type: Function,
40
+ default: null
41
+ },
42
+ // 不走请求时,可直接传入的配置(优先级高于 fetchConfig)
43
+ propertys: {
44
+ type: Array,
45
+ default: () => []
46
+ },
47
+ // 配合 propertys 使用的卡片宽度
48
+ width: {
49
+ type: Number,
50
+ default: 0
51
+ }
52
+ },
53
+ emits: ["selectItem", "scroll"],
54
+ setup(s, { expose: h, emit: _ }) {
55
+ const u = _, l = s, v = k("0"), C = k([]), D = k(0);
56
+ function F(t) {
57
+ if (t == null || t === "") return t;
58
+ if (S.has(t)) return S.get(t);
59
+ const a = R(t);
60
+ return S.set(t, a), a;
61
+ }
62
+ function Y(t) {
63
+ return Array.isArray(t) ? t.map((a) => {
64
+ if (a.fieldName === "state" && !a.parsedData && typeof a.data == "string")
65
+ try {
66
+ return { ...a, parsedData: JSON.parse(a.data) };
67
+ } catch {
68
+ return { ...a, parsedData: {} };
69
+ }
70
+ return a;
71
+ }) : t;
72
+ }
73
+ const z = O(() => C.value);
74
+ function N(t) {
75
+ C.value = Y(t.propertys) || [], D.value = t.width || 0;
76
+ }
77
+ const I = (t, a) => {
78
+ if (a) {
79
+ v.value = t[a];
80
+ return;
81
+ }
82
+ v.value = t.id, u("selectItem", t);
83
+ }, E = (t) => {
84
+ const { scrollHeight: a, scrollTop: n, clientHeight: r } = t.target;
85
+ n + r >= a && u("scroll");
86
+ };
87
+ return h({
88
+ selectItem: I
89
+ }), $(
90
+ () => [l.cardId, l.fetchConfig, l.propertys, l.width],
91
+ () => {
92
+ if (Array.isArray(l.propertys) && l.propertys.length > 0) {
93
+ N({ propertys: l.propertys, width: l.width });
94
+ return;
95
+ }
96
+ if (typeof l.fetchConfig != "function")
97
+ return;
98
+ const t = l.cardId;
99
+ if (t == "0")
100
+ return;
101
+ const a = L.get(t);
102
+ if (a) {
103
+ N(a);
104
+ return;
105
+ }
106
+ let n = x.get(t);
107
+ n || (n = Promise.resolve().then(() => l.fetchConfig(t)).then((r) => {
108
+ const c = {
109
+ // 预处理:state 字段 JSON 只解析一次,缓存后所有实例复用
110
+ propertys: r.propertys,
111
+ width: r.width
112
+ };
113
+ return L.set(t, c), x.delete(t), c;
114
+ }).catch((r) => {
115
+ throw x.delete(t), r;
116
+ }), x.set(t, n)), n.then((r) => {
117
+ N(r);
118
+ }).catch(() => {
119
+ C.value = [];
120
+ });
121
+ },
122
+ { immediate: !0 }
123
+ ), (t, a) => {
124
+ const n = W("a-col"), r = W("a-row");
125
+ return d(), i("div", {
126
+ class: "card-list",
127
+ onScroll: E,
128
+ style: f([{ width: D.value + "px" }, { height: "100%" }])
129
+ }, [
130
+ (d(!0), i(A, null, M(s.card, (c) => (d(), b(r, {
131
+ key: c.id,
132
+ class: q(["boxCard", { active: c.id == v.value }]),
133
+ onClick: (e) => I(c),
134
+ gutter: 24
135
+ }, {
136
+ default: o(() => [
137
+ (d(!0), i(A, null, M(z.value, (e, H) => G((d(), b(n, {
138
+ span: e.span,
139
+ key: H
140
+ }, {
141
+ default: o(() => [
142
+ e.type === "image" || e.fieldName === "name" ? (d(), i("div", j, [
143
+ e.type === "image" ? (d(), i("img", {
144
+ key: 0,
145
+ src: c[e.fieldName] == null ? e.defaultValue : c[e.fieldName],
146
+ width: "16px",
147
+ height: "16px"
148
+ }, null, 8, K)) : m("", !0),
149
+ e.type === "text" && e.fieldName === "name" ? (d(), i("span", {
150
+ key: 1,
151
+ class: "box__title",
152
+ style: f({ fontWeight: e.bold === 1 ? 500 : 400 })
153
+ }, y(c[e.fieldName]), 5)) : m("", !0)
154
+ ])) : m("", !0),
155
+ e.type === "text" && e.fieldName !== "name" ? (d(), i("div", Q, [
156
+ p(r, null, {
157
+ default: o(() => [
158
+ p(n, {
159
+ span: e.labelSpan
160
+ }, {
161
+ default: o(() => [
162
+ w("span", {
163
+ style: f({ fontWeight: e.bold === 1 ? 500 : 400 })
164
+ }, y(e.label) + ": ", 5)
165
+ ]),
166
+ _: 2
167
+ }, 1032, ["span"]),
168
+ e.fieldName == "state" ? (d(), b(n, {
169
+ key: 0,
170
+ span: e.wrapperSpan
171
+ }, {
172
+ default: o(() => [
173
+ w("span", {
174
+ style: f({ fontWeight: e.bold === 1 ? 500 : 400 })
175
+ }, y(e.parsedData[c[e.fieldName]]), 5)
176
+ ]),
177
+ _: 2
178
+ }, 1032, ["span"])) : (d(), b(n, {
179
+ key: 1,
180
+ span: e.wrapperSpan,
181
+ class: "box__txt"
182
+ }, {
183
+ default: o(() => [
184
+ w("span", {
185
+ style: f({ fontWeight: e.bold === 1 ? 500 : 400 })
186
+ }, y(c[e.fieldName]), 5)
187
+ ]),
188
+ _: 2
189
+ }, 1032, ["span"]))
190
+ ]),
191
+ _: 2
192
+ }, 1024)
193
+ ])) : m("", !0),
194
+ e.type === "date" ? (d(), i("div", U, [
195
+ p(r, null, {
196
+ default: o(() => [
197
+ p(n, {
198
+ span: e.labelSpan
199
+ }, {
200
+ default: o(() => [
201
+ w("span", {
202
+ style: f({ fontWeight: e.bold === 1 ? 500 : 400 })
203
+ }, y(e.label) + ": ", 5)
204
+ ]),
205
+ _: 2
206
+ }, 1032, ["span"]),
207
+ p(n, {
208
+ span: e.wrapperSpan,
209
+ class: "box__txt"
210
+ }, {
211
+ default: o(() => [
212
+ w("span", {
213
+ style: f({ fontWeight: e.bold === 1 ? 500 : 400 })
214
+ }, y(F(c[e.fieldName])), 5)
215
+ ]),
216
+ _: 2
217
+ }, 1032, ["span"])
218
+ ]),
219
+ _: 2
220
+ }, 1024)
221
+ ])) : m("", !0),
222
+ e.type === "progress" ? (d(), i("div", X, [
223
+ p(r, null, {
224
+ default: o(() => [
225
+ p(n, {
226
+ span: e.labelSpan
227
+ }, {
228
+ default: o(() => [
229
+ w("span", {
230
+ style: f({ fontWeight: e.bold === 1 ? 500 : 400 })
231
+ }, y(e.label) + ": ", 5)
232
+ ]),
233
+ _: 2
234
+ }, 1032, ["span"]),
235
+ p(n, {
236
+ span: e.wrapperSpan,
237
+ class: "box__txt"
238
+ }, null, 8, ["span"])
239
+ ]),
240
+ _: 2
241
+ }, 1024)
242
+ ])) : m("", !0)
243
+ ]),
244
+ _: 2
245
+ }, 1032, ["span"])), [
246
+ [J, e.show == "1"]
247
+ ])), 128)),
248
+ P(t.$slots, "action", { item: c }, void 0, !0)
249
+ ]),
250
+ _: 2
251
+ }, 1032, ["onClick", "class"]))), 128))
252
+ ], 36);
253
+ };
254
+ }
255
+ }, B = /* @__PURE__ */ T(Z, [["__scopeId", "data-v-6bcb7c73"]]);
256
+ B.install = (s) => {
257
+ s.component("CardList", B);
258
+ };
259
+ export {
260
+ B as CardList,
261
+ B as default
262
+ };
@@ -0,0 +1 @@
1
+ (function(i,e){typeof exports=="object"&&typeof module<"u"?e(exports,require("vue")):typeof define=="function"&&define.amd?define(["exports","vue"],e):(i=typeof globalThis<"u"?globalThis:i||self,e(i.CardList={},i.Vue))})(this,(function(i,e){"use strict";function C(r){return r<10?"0"+r:r}function b(r){var d=new Date(r),f=d.getFullYear(),p=d.getMonth()+1,o=d.getDate(),m=f+"/"+C(p)+"/"+C(o);return m}const B=(r,d)=>{const f=r.__vccOpts||r;for(const[p,o]of d)f[p]=o;return f},V={key:0,class:"box__header"},D=["src"],E={key:1,class:"box__row"},I={key:2,class:"box__row"},z={key:3,class:"box__row"},N=new Map,y=new Map,_=new Map,h=B({__name:"CardList",props:{card:{type:Array,default:()=>[]},cardId:{type:[String,Number],default:()=>"0"},fetchConfig:{type:Function,default:null},propertys:{type:Array,default:()=>[]},width:{type:Number,default:0}},emits:["selectItem","scroll"],setup(r,{expose:d,emit:f}){const p=f,o=r,m=e.ref("0"),w=e.ref([]),x=e.ref(0);function M(a){if(a==null||a==="")return a;if(_.has(a))return _.get(a);const n=b(a);return _.set(a,n),n}function W(a){return Array.isArray(a)?a.map(n=>{if(n.fieldName==="state"&&!n.parsedData&&typeof n.data=="string")try{return{...n,parsedData:JSON.parse(n.data)}}catch{return{...n,parsedData:{}}}return n}):a}const L=e.computed(()=>w.value);function k(a){w.value=W(a.propertys)||[],x.value=a.width||0}const S=(a,n)=>{if(n){m.value=a[n];return}m.value=a.id,p("selectItem",a)},A=a=>{const{scrollHeight:n,scrollTop:l,clientHeight:c}=a.target;l+c>=n&&p("scroll")};return d({selectItem:S}),e.watch(()=>[o.cardId,o.fetchConfig,o.propertys,o.width],()=>{if(Array.isArray(o.propertys)&&o.propertys.length>0){k({propertys:o.propertys,width:o.width});return}if(typeof o.fetchConfig!="function")return;const a=o.cardId;if(a=="0")return;const n=N.get(a);if(n){k(n);return}let l=y.get(a);l||(l=Promise.resolve().then(()=>o.fetchConfig(a)).then(c=>{const s={propertys:c.propertys,width:c.width};return N.set(a,s),y.delete(a),s}).catch(c=>{throw y.delete(a),c}),y.set(a,l)),l.then(c=>{k(c)}).catch(()=>{w.value=[]})},{immediate:!0}),(a,n)=>{const l=e.resolveComponent("a-col"),c=e.resolveComponent("a-row");return e.openBlock(),e.createElementBlock("div",{class:"card-list",onScroll:A,style:e.normalizeStyle([{width:x.value+"px"},{height:"100%"}])},[(e.openBlock(!0),e.createElementBlock(e.Fragment,null,e.renderList(r.card,s=>(e.openBlock(),e.createBlock(c,{key:s.id,class:e.normalizeClass(["boxCard",{active:s.id==m.value}]),onClick:t=>S(s),gutter:24},{default:e.withCtx(()=>[(e.openBlock(!0),e.createElementBlock(e.Fragment,null,e.renderList(L.value,(t,g)=>e.withDirectives((e.openBlock(),e.createBlock(l,{span:t.span,key:g},{default:e.withCtx(()=>[t.type==="image"||t.fieldName==="name"?(e.openBlock(),e.createElementBlock("div",V,[t.type==="image"?(e.openBlock(),e.createElementBlock("img",{key:0,src:s[t.fieldName]==null?t.defaultValue:s[t.fieldName],width:"16px",height:"16px"},null,8,D)):e.createCommentVNode("",!0),t.type==="text"&&t.fieldName==="name"?(e.openBlock(),e.createElementBlock("span",{key:1,class:"box__title",style:e.normalizeStyle({fontWeight:t.bold===1?500:400})},e.toDisplayString(s[t.fieldName]),5)):e.createCommentVNode("",!0)])):e.createCommentVNode("",!0),t.type==="text"&&t.fieldName!=="name"?(e.openBlock(),e.createElementBlock("div",E,[e.createVNode(c,null,{default:e.withCtx(()=>[e.createVNode(l,{span:t.labelSpan},{default:e.withCtx(()=>[e.createElementVNode("span",{style:e.normalizeStyle({fontWeight:t.bold===1?500:400})},e.toDisplayString(t.label)+": ",5)]),_:2},1032,["span"]),t.fieldName=="state"?(e.openBlock(),e.createBlock(l,{key:0,span:t.wrapperSpan},{default:e.withCtx(()=>[e.createElementVNode("span",{style:e.normalizeStyle({fontWeight:t.bold===1?500:400})},e.toDisplayString(t.parsedData[s[t.fieldName]]),5)]),_:2},1032,["span"])):(e.openBlock(),e.createBlock(l,{key:1,span:t.wrapperSpan,class:"box__txt"},{default:e.withCtx(()=>[e.createElementVNode("span",{style:e.normalizeStyle({fontWeight:t.bold===1?500:400})},e.toDisplayString(s[t.fieldName]),5)]),_:2},1032,["span"]))]),_:2},1024)])):e.createCommentVNode("",!0),t.type==="date"?(e.openBlock(),e.createElementBlock("div",I,[e.createVNode(c,null,{default:e.withCtx(()=>[e.createVNode(l,{span:t.labelSpan},{default:e.withCtx(()=>[e.createElementVNode("span",{style:e.normalizeStyle({fontWeight:t.bold===1?500:400})},e.toDisplayString(t.label)+": ",5)]),_:2},1032,["span"]),e.createVNode(l,{span:t.wrapperSpan,class:"box__txt"},{default:e.withCtx(()=>[e.createElementVNode("span",{style:e.normalizeStyle({fontWeight:t.bold===1?500:400})},e.toDisplayString(M(s[t.fieldName])),5)]),_:2},1032,["span"])]),_:2},1024)])):e.createCommentVNode("",!0),t.type==="progress"?(e.openBlock(),e.createElementBlock("div",z,[e.createVNode(c,null,{default:e.withCtx(()=>[e.createVNode(l,{span:t.labelSpan},{default:e.withCtx(()=>[e.createElementVNode("span",{style:e.normalizeStyle({fontWeight:t.bold===1?500:400})},e.toDisplayString(t.label)+": ",5)]),_:2},1032,["span"]),e.createVNode(l,{span:t.wrapperSpan,class:"box__txt"},null,8,["span"])]),_:2},1024)])):e.createCommentVNode("",!0)]),_:2},1032,["span"])),[[e.vShow,t.show=="1"]])),128)),e.renderSlot(a.$slots,"action",{item:s},void 0,!0)]),_:2},1032,["onClick","class"]))),128))],36)}}},[["__scopeId","data-v-6bcb7c73"]]);h.install=r=>{r.component("CardList",h)},i.CardList=h,i.default=h,Object.defineProperties(i,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}})}));
package/dist/style.css ADDED
@@ -0,0 +1 @@
1
+ [data-v-6bcb7c73]{font-family:思源黑体 CN-Normal,思源黑体 CN,sans-serif;font-weight:350;font-size:13px}.boxCard[data-v-6bcb7c73]{width:100%;color:#333;box-sizing:border-box;padding:18px 20px;cursor:pointer;text-align:left;background:#fff;border-top:1px solid #f0f0f0}.boxCard.active[data-v-6bcb7c73]{background-color:#ccc}.boxCard[data-v-6bcb7c73]:last-child{border-bottom:1px solid #f0f0f0}.box__title[data-v-6bcb7c73],.box__txt[data-v-6bcb7c73]{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;flex:1;display:inline-block;width:100%;box-sizing:border-box}.box__row[data-v-6bcb7c73]{margin-top:13px}.box__actions[data-v-6bcb7c73]{display:flex;justify-content:flex-end;color:#1084d0;margin-top:13px}.box__divider[data-v-6bcb7c73]{width:20px;text-align:center}.card-list[data-v-6bcb7c73]{overflow-y:auto}[data-v-6bcb7c73] .ant-row{margin:0!important}[data-v-6bcb7c73] .ant-col{padding:0!important}
package/package.json ADDED
@@ -0,0 +1,46 @@
1
+ {
2
+ "name": "xlzw-card-list",
3
+ "version": "0.1.0",
4
+ "description": "可复用的卡片列表组件(基于 Vue 3 + ant-design-vue),支持外部注入配置请求",
5
+ "type": "module",
6
+ "main": "./dist/card-list.umd.cjs",
7
+ "module": "./dist/card-list.js",
8
+ "unpkg": "./dist/card-list.umd.cjs",
9
+ "exports": {
10
+ ".": {
11
+ "import": "./dist/card-list.js",
12
+ "require": "./dist/card-list.umd.cjs"
13
+ },
14
+ "./style.css": "./dist/style.css",
15
+ "./dist/style.css": "./dist/style.css"
16
+ },
17
+ "files": [
18
+ "dist",
19
+ "README.md"
20
+ ],
21
+ "sideEffects": [
22
+ "**/*.css"
23
+ ],
24
+ "scripts": {
25
+ "build": "vite build",
26
+ "prepublishOnly": "vite build"
27
+ },
28
+ "peerDependencies": {
29
+ "vue": "^3.3.0",
30
+ "ant-design-vue": "^4.0.0"
31
+ },
32
+ "devDependencies": {
33
+ "@vitejs/plugin-vue": "^6.0.1",
34
+ "less": "^4.2.0",
35
+ "vite": "^7.1.2",
36
+ "vue": "^3.5.18"
37
+ },
38
+ "keywords": [
39
+ "vue",
40
+ "vue3",
41
+ "card-list",
42
+ "ant-design-vue",
43
+ "component"
44
+ ],
45
+ "license": "MIT"
46
+ }