@liexx/form 0.0.1

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
File without changes
package/dist/index.cjs ADDED
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const t=require("vue"),n=require("element-plus"),d=(e,{model:o,setField:a})=>({modelValue:o[e.prop],"onUpdate:modelValue":c=>a(e.prop,c)}),B=(e,{model:o,setField:a})=>({fileList:o[e.prop],"onUpdate:fileList":c=>a(e.prop,c)}),b=e=>({disabled:e.disabled,...e.extends}),h=(e,o="输入")=>({placeholder:e.placeholder??`请${o}${e.label}`,...b(e)}),_=e=>e.options??[],C={input:(e,o)=>t.h(n.ElInput,{...d(e,o),...h(e)}),textarea:(e,o)=>t.h(n.ElInput,{...d(e,o),...h(e),type:"textarea"}),number:(e,o)=>t.h(n.ElInputNumber,{...d(e,o),...h(e)}),select:(e,o)=>t.h(n.ElSelect,{...d(e,o),clearable:!0,...h(e,"选择"),options:_(e)}),radio:(e,o)=>t.h(n.ElRadioGroup,{...d(e,o),...h(e),options:_(e)}),checkbox:(e,o)=>t.h(n.ElCheckboxGroup,{...d(e,o),...h(e),options:_(e)}),date:(e,o)=>t.h(n.ElDatePicker,{...d(e,o),...h(e,"选择日期"),type:"date"}),daterange:(e,o)=>t.h(n.ElDatePicker,{...d(e,o),...b(e),type:"daterange",startPlaceholder:"开始日期",endPlaceholder:"结束日期"}),time:(e,o)=>t.h(n.ElTimePicker,{...d(e,o),...h(e,"选择时间")}),cascader:(e,o)=>t.h(n.ElCascader,{...d(e,o),...h(e,"选择"),options:_(e)}),tree:(e,o)=>t.h(n.ElTreeSelect,{...d(e,o),...h(e,"选择"),data:_(e)}),rate:(e,o)=>t.h(n.ElRate,{...d(e,o),...b(e)}),switch:(e,o)=>t.h(n.ElSwitch,{...d(e,o),...b(e)}),file:(e,o)=>t.h(n.ElUpload,{...b(e),...B(e,o)},()=>t.h(n.ElButton,null,()=>"上传文件")),image:(e,o)=>t.h(n.ElUpload,{listType:"picture-card",...b(e),...B(e,o)})},j=t.defineComponent({props:{item:{type:Object,required:!0},model:{type:Object,required:!0},setField:{type:Function,required:!0}},setup(e){return()=>{var o;return((o=C[e.item.type])==null?void 0:o.call(C,e.item,e))??null}}}),L=e=>{const o=t.reactive(structuredClone(e??{}));return{model:o,setField:(l,r)=>{o[l]=r},getValue:()=>({...o}),setValue:l=>{Object.assign(o,l)}}},U=new Set(["select","date","daterange","time","cascader","tree","radio","checkbox"]),D={checkbox:"array",daterange:"array",file:"array",image:"array",number:"number",rate:"number",switch:"boolean"},I=e=>{const o=l=>l.map(r=>{var u;return JSON.stringify([r.prop,r.label,r.type,r.required??!1,(u=r.rules)==null?void 0:u.map(({regExp:i,message:m})=>[String(i),m])])}).join("|");let a="",c={};return{rules:t.computed(()=>{const l=e(),r=o(l);if(r===a)return c;const u={};return l.forEach(i=>{var E;const m=[],k=U.has(i.type)?"选择":"输入";i.required&&m.push({required:!0,type:D[i.type],message:`请${k}${i.label}`,trigger:["blur","change"]}),(E=i.rules)==null||E.forEach(({regExp:g,message:P})=>{m.push({validator:(V,v,y)=>g(v)?y():y(new Error(P)),trigger:["blur","change"]})}),m.length&&(u[i.prop]=m)}),a=r,c=u,u})}},$=e=>{const o=t.reactive({});return{items:t.computed(()=>e().map(s=>{const l=o[s.prop];if(!l)return s;const{extends:r,...u}=l;return{...s,...u,...r?{extends:{...s.extends,...r}}:{}}})),setProps:(s,l)=>{const r=o[s],{extends:u,...i}=l;o[s]={...r,...i,...u?{extends:{...r==null?void 0:r.extends,...u}}:{}}}}},G={key:0,class:"pro-form__required"},M={class:"form-item-tip"},W=t.defineComponent({__name:"index",props:{template:{default:()=>[]},gutter:{default:20},labelWidth:{default:"auto"},labelPosition:{default:"right"},scrollToError:{type:Boolean,default:!1},defaultValue:{default:()=>({})},tipPosition:{default:"bottom"}},emits:["change","init"],setup(e,{expose:o,emit:a}){const c=a,s=e,{model:l,setField:r,getValue:u,setValue:i}=L(s.defaultValue),{items:m,setProps:k}=$(()=>s.template),{rules:E}=I(()=>m.value),g=t.ref(),P=async()=>{var f;try{return await((f=g.value)==null?void 0:f.validate()),!0}catch{return!1}},V=()=>{var f;return(f=g.value)==null?void 0:f.resetFields()},v=()=>{var f;return(f=g.value)==null?void 0:f.clearValidate()},y=(f,x)=>{c("change",f,x)};return t.onMounted(()=>{c("init")}),o({model:l,getValue:u,setValue:i,setProps:k,validate:P,reset:V,clearValidate:v}),(f,x)=>{const w=t.resolveComponent("el-tooltip"),q=t.resolveComponent("el-form-item"),N=t.resolveComponent("el-col"),T=t.resolveComponent("el-row"),O=t.resolveComponent("el-form");return t.openBlock(),t.createBlock(O,{ref_key:"formRef",ref:g,class:"form","label-width":e.labelWidth,"label-position":e.labelPosition,model:t.unref(l),rules:t.unref(E),"scroll-to-error":e.scrollToError},{default:t.withCtx(()=>[t.createVNode(T,{gutter:e.gutter},{default:t.withCtx(()=>[(t.openBlock(!0),t.createElementBlock(t.Fragment,null,t.renderList(t.unref(m),p=>(t.openBlock(),t.createBlock(N,{key:p.prop,span:p.span||24},{default:t.withCtx(()=>[t.createVNode(q,{"hide-required-asterisk":!0,prop:p.prop},{label:t.withCtx(()=>[p.required?(t.openBlock(),t.createElementBlock("span",G,"*")):t.createCommentVNode("",!0),t.createElementVNode("span",null,t.toDisplayString(p.label),1),p.tip&&e.tipPosition==="left"?(t.openBlock(),t.createBlock(w,{key:1,content:p.tip,placement:"top"},{default:t.withCtx(()=>[...x[0]||(x[0]=[t.createElementVNode("i",{class:"ri-question-fill",style:{"font-size":"16px",color:"#f56c6c"}},null,-1)])]),_:1},8,["content"])):t.createCommentVNode("",!0)]),default:t.withCtx(()=>[t.createVNode(t.unref(j),{item:p,model:t.unref(l),"set-field":t.unref(r),onChange:R=>y(R,p)},null,8,["item","model","set-field","onChange"]),p.tip&&e.tipPosition==="bottom"?(t.openBlock(),t.createBlock(w,{key:0,class:"box-item",effect:"dark",content:p.tip,placement:"top-start"},{default:t.withCtx(()=>[t.createElementVNode("div",M,t.toDisplayString(p.tip),1)]),_:2},1032,["content"])):t.createCommentVNode("",!0)]),_:2},1032,["prop"])]),_:2},1032,["span"]))),128))]),_:1},8,["gutter"])]),_:1},8,["label-width","label-position","model","rules","scroll-to-error"])}}}),Y=(e,o)=>{const a=e.__vccOpts||e;for(const[c,s]of o)a[c]=s;return a},F=Y(W,[["__scopeId","data-v-121a6606"]]);function z(e){e.component("ProForm",F)}const S=Object.assign(F,{install:z});exports.ProForm=S;exports.default=S;
@@ -0,0 +1,174 @@
1
+ import { AllowedComponentProps } from 'vue';
2
+ import { App } from 'vue';
3
+ import { ComponentCustomProps } from 'vue';
4
+ import { ComponentOptionsBase } from 'vue';
5
+ import { ComponentOptionsMixin } from 'vue';
6
+ import { ComponentProvideOptions } from 'vue';
7
+ import { CreateComponentPublicInstanceWithMixins } from 'vue';
8
+ import { GlobalComponents } from 'vue';
9
+ import { GlobalDirectives } from 'vue';
10
+ import { PublicProps } from 'vue';
11
+ import { VNodeProps } from 'vue';
12
+
13
+ declare type FormModel_2 = Record<string, any>;
14
+
15
+ declare type FormProps_2 = {
16
+ template: FromItems_2; // 表单配置
17
+ gutter?: number; // 表单间距
18
+ labelWidth?: number | string; // 表单label宽度
19
+ labelPosition?: "left" | "right" | "top"; // 表单label位置
20
+ scrollToError?: boolean; // 校验不通过时滚动到第一个错误字段
21
+ defaultValue?: FormModel_2; // 表单默认值
22
+ tipPosition?: "left" | "bottom"; // 表单提示位置
23
+ };
24
+ export { FormProps_2 as FormProps }
25
+
26
+ declare type FormRule_2 = {
27
+ regExp: (value: any) => boolean;
28
+ message: string;
29
+ };
30
+
31
+ declare type FromItem_2 = {
32
+ label: string;
33
+ prop: string;
34
+ type:
35
+ | "input"
36
+ | "select"
37
+ | "date"
38
+ | "daterange"
39
+ | "cascader"
40
+ | "tree"
41
+ | "switch"
42
+ | "radio"
43
+ | "file"
44
+ | "image"
45
+ | "number"
46
+ | "textarea"
47
+ | "checkbox"
48
+ | "rate"
49
+ | "time"
50
+ | "file";
51
+ // 占位
52
+ span?: number;
53
+ // 输入框占位文本
54
+ placeholder?: string;
55
+ // 提示
56
+ tip?: string;
57
+ //是否必填
58
+ required?: boolean;
59
+ //自定义校验规则
60
+ rules?: FormRule_2[];
61
+ //是否禁用
62
+ disabled?: boolean;
63
+ //是否显示到表单
64
+ isForm?: boolean;
65
+ // 透传给组件的额外 props(如 select 的 options、daterange 的 type 等)
66
+ extends?: Record<string, any>;
67
+ // 字典值
68
+ dict?: string;
69
+ // 选项内容
70
+ options?: OptionItem_2[];
71
+ //通过api方式获取选择内容
72
+ optionsApi?: (params?: Record<string, any>) => Promise<Record<string, any>[]>;
73
+ };
74
+
75
+ declare type FromItems_2 = FromItem_2[];
76
+ export { FromItems_2 as FromItems }
77
+
78
+ /**
79
+ * 全局注册 ProForm 组件。
80
+ * 用法:app.use(ProForm)
81
+ */
82
+ declare function install(app: App): void;
83
+
84
+ declare type OptionItem_2 = {
85
+ label?: string;
86
+ value?: any;
87
+ children?: OptionItem_2[];
88
+ [key: string]: any; // 允许自定义字段,如 cascader 的 deptName/deptId
89
+ };
90
+
91
+ declare const ProForm: {
92
+ new (...args: any[]): CreateComponentPublicInstanceWithMixins<Readonly<FormProps_2> & Readonly<{
93
+ onChange?: ((...args: any[]) => any) | undefined;
94
+ onInit?: ((...args: any[]) => any) | undefined;
95
+ }>, {
96
+ model: FormModel_2;
97
+ getValue: () => FormModel_2;
98
+ setValue: (data: FormModel_2) => void;
99
+ setProps: (prop: string, partial: Partial<FromItem_2>) => void;
100
+ validate: () => Promise<boolean>;
101
+ reset: () => void | undefined;
102
+ clearValidate: () => void | undefined;
103
+ }, {}, {}, {}, ComponentOptionsMixin, ComponentOptionsMixin, {
104
+ change: (...args: any[]) => void;
105
+ init: (...args: any[]) => void;
106
+ }, PublicProps, {
107
+ template: FromItems_2;
108
+ defaultValue: FormModel_2;
109
+ gutter: number;
110
+ labelWidth: number | string;
111
+ labelPosition: "left" | "right" | "top";
112
+ scrollToError: boolean;
113
+ tipPosition: "left" | "bottom";
114
+ }, false, {}, {}, GlobalComponents, GlobalDirectives, string, {
115
+ formRef: unknown;
116
+ }, any, ComponentProvideOptions, {
117
+ P: {};
118
+ B: {};
119
+ D: {};
120
+ C: {};
121
+ M: {};
122
+ Defaults: {};
123
+ }, Readonly<FormProps_2> & Readonly<{
124
+ onChange?: ((...args: any[]) => any) | undefined;
125
+ onInit?: ((...args: any[]) => any) | undefined;
126
+ }>, {
127
+ model: FormModel_2;
128
+ getValue: () => FormModel_2;
129
+ setValue: (data: FormModel_2) => void;
130
+ setProps: (prop: string, partial: Partial<FromItem_2>) => void;
131
+ validate: () => Promise<boolean>;
132
+ reset: () => void | undefined;
133
+ clearValidate: () => void | undefined;
134
+ }, {}, {}, {}, {
135
+ template: FromItems_2;
136
+ defaultValue: FormModel_2;
137
+ gutter: number;
138
+ labelWidth: number | string;
139
+ labelPosition: "left" | "right" | "top";
140
+ scrollToError: boolean;
141
+ tipPosition: "left" | "bottom";
142
+ }>;
143
+ __isFragment?: never;
144
+ __isTeleport?: never;
145
+ __isSuspense?: never;
146
+ } & ComponentOptionsBase<Readonly<FormProps_2> & Readonly<{
147
+ onChange?: ((...args: any[]) => any) | undefined;
148
+ onInit?: ((...args: any[]) => any) | undefined;
149
+ }>, {
150
+ model: FormModel_2;
151
+ getValue: () => FormModel_2;
152
+ setValue: (data: FormModel_2) => void;
153
+ setProps: (prop: string, partial: Partial<FromItem_2>) => void;
154
+ validate: () => Promise<boolean>;
155
+ reset: () => void | undefined;
156
+ clearValidate: () => void | undefined;
157
+ }, {}, {}, {}, ComponentOptionsMixin, ComponentOptionsMixin, {
158
+ change: (...args: any[]) => void;
159
+ init: (...args: any[]) => void;
160
+ }, string, {
161
+ template: FromItems_2;
162
+ defaultValue: FormModel_2;
163
+ gutter: number;
164
+ labelWidth: number | string;
165
+ labelPosition: "left" | "right" | "top";
166
+ scrollToError: boolean;
167
+ tipPosition: "left" | "bottom";
168
+ }, {}, string, {}, GlobalComponents, GlobalDirectives, string, ComponentProvideOptions> & VNodeProps & AllowedComponentProps & ComponentCustomProps & {
169
+ install: typeof install;
170
+ };
171
+ export { ProForm }
172
+ export default ProForm;
173
+
174
+ export { }
package/dist/index.js ADDED
@@ -0,0 +1,301 @@
1
+ import { defineComponent as D, h as l, reactive as G, computed as W, ref as M, onMounted as Q, resolveComponent as E, openBlock as m, createBlock as V, unref as _, withCtx as h, createVNode as S, createElementBlock as j, Fragment as X, renderList as Z, createElementVNode as q, toDisplayString as B, createCommentVNode as T } from "vue";
2
+ import { ElUpload as N, ElButton as ee, ElSwitch as te, ElRate as oe, ElTreeSelect as re, ElCascader as le, ElTimePicker as ne, ElDatePicker as U, ElCheckboxGroup as se, ElRadioGroup as ae, ElSelect as ce, ElInputNumber as ue, ElInput as $ } from "element-plus";
3
+ const u = (e, { model: t, setField: s }) => ({
4
+ modelValue: t[e.prop],
5
+ "onUpdate:modelValue": (a) => s(e.prop, a)
6
+ }), I = (e, { model: t, setField: s }) => ({
7
+ fileList: t[e.prop],
8
+ "onUpdate:fileList": (a) => s(e.prop, a)
9
+ }), y = (e) => ({
10
+ disabled: e.disabled,
11
+ ...e.extends
12
+ }), f = (e, t = "输入") => ({
13
+ placeholder: e.placeholder ?? `请${t}${e.label}`,
14
+ ...y(e)
15
+ }), x = (e) => e.options ?? [], O = {
16
+ input: (e, t) => l($, { ...u(e, t), ...f(e) }),
17
+ textarea: (e, t) => l($, {
18
+ ...u(e, t),
19
+ ...f(e),
20
+ type: "textarea"
21
+ }),
22
+ number: (e, t) => l(ue, { ...u(e, t), ...f(e) }),
23
+ select: (e, t) => l(ce, {
24
+ ...u(e, t),
25
+ clearable: !0,
26
+ ...f(e, "选择"),
27
+ options: x(e)
28
+ }),
29
+ radio: (e, t) => l(ae, {
30
+ ...u(e, t),
31
+ ...f(e),
32
+ options: x(e)
33
+ }),
34
+ checkbox: (e, t) => l(se, {
35
+ ...u(e, t),
36
+ ...f(e),
37
+ options: x(e)
38
+ }),
39
+ date: (e, t) => l(U, {
40
+ ...u(e, t),
41
+ ...f(e, "选择日期"),
42
+ type: "date"
43
+ }),
44
+ daterange: (e, t) => l(U, {
45
+ ...u(e, t),
46
+ ...y(e),
47
+ type: "daterange",
48
+ startPlaceholder: "开始日期",
49
+ endPlaceholder: "结束日期"
50
+ }),
51
+ time: (e, t) => l(ne, {
52
+ ...u(e, t),
53
+ ...f(e, "选择时间")
54
+ }),
55
+ cascader: (e, t) => l(le, {
56
+ ...u(e, t),
57
+ ...f(e, "选择"),
58
+ options: x(e)
59
+ }),
60
+ tree: (e, t) => l(re, {
61
+ ...u(e, t),
62
+ ...f(e, "选择"),
63
+ data: x(e)
64
+ }),
65
+ rate: (e, t) => l(oe, { ...u(e, t), ...y(e) }),
66
+ switch: (e, t) => l(te, { ...u(e, t), ...y(e) }),
67
+ file: (e, t) => l(
68
+ N,
69
+ { ...y(e), ...I(e, t) },
70
+ () => l(ee, null, () => "上传文件")
71
+ ),
72
+ image: (e, t) => l(N, {
73
+ listType: "picture-card",
74
+ ...y(e),
75
+ ...I(e, t)
76
+ })
77
+ }, de = D({
78
+ props: {
79
+ item: { type: Object, required: !0 },
80
+ model: { type: Object, required: !0 },
81
+ setField: {
82
+ type: Function,
83
+ required: !0
84
+ }
85
+ },
86
+ setup(e) {
87
+ return () => {
88
+ var t;
89
+ return ((t = O[e.item.type]) == null ? void 0 : t.call(O, e.item, e)) ?? null;
90
+ };
91
+ }
92
+ }), ie = (e) => {
93
+ const t = G(structuredClone(e ?? {}));
94
+ return { model: t, setField: (r, o) => {
95
+ t[r] = o;
96
+ }, getValue: () => ({ ...t }), setValue: (r) => {
97
+ Object.assign(t, r);
98
+ } };
99
+ }, pe = /* @__PURE__ */ new Set([
100
+ "select",
101
+ "date",
102
+ "daterange",
103
+ "time",
104
+ "cascader",
105
+ "tree",
106
+ "radio",
107
+ "checkbox"
108
+ ]), fe = {
109
+ checkbox: "array",
110
+ daterange: "array",
111
+ file: "array",
112
+ image: "array",
113
+ number: "number",
114
+ rate: "number",
115
+ switch: "boolean"
116
+ }, ge = (e) => {
117
+ const t = (r) => r.map(
118
+ (o) => {
119
+ var c;
120
+ return JSON.stringify([
121
+ o.prop,
122
+ o.label,
123
+ o.type,
124
+ o.required ?? !1,
125
+ (c = o.rules) == null ? void 0 : c.map(({ regExp: d, message: g }) => [String(d), g])
126
+ ]);
127
+ }
128
+ ).join("|");
129
+ let s = "", a = {};
130
+ return { rules: W(() => {
131
+ const r = e(), o = t(r);
132
+ if (o === s) return a;
133
+ const c = {};
134
+ return r.forEach((d) => {
135
+ var P;
136
+ const g = [], F = pe.has(d.type) ? "选择" : "输入";
137
+ d.required && g.push({
138
+ required: !0,
139
+ type: fe[d.type],
140
+ message: `请${F}${d.label}`,
141
+ trigger: ["blur", "change"]
142
+ }), (P = d.rules) == null || P.forEach(({ regExp: b, message: w }) => {
143
+ g.push({
144
+ validator: (R, C, k) => b(C) ? k() : k(new Error(w)),
145
+ trigger: ["blur", "change"]
146
+ });
147
+ }), g.length && (c[d.prop] = g);
148
+ }), s = o, a = c, c;
149
+ }) };
150
+ }, he = (e) => {
151
+ const t = G({});
152
+ return { items: W(
153
+ () => e().map((n) => {
154
+ const r = t[n.prop];
155
+ if (!r) return n;
156
+ const { extends: o, ...c } = r;
157
+ return {
158
+ ...n,
159
+ ...c,
160
+ // extends 单独浅合并,避免整体替换丢掉原有透传 props
161
+ ...o ? { extends: { ...n.extends, ...o } } : {}
162
+ };
163
+ })
164
+ ), setProps: (n, r) => {
165
+ const o = t[n], { extends: c, ...d } = r;
166
+ t[n] = {
167
+ ...o,
168
+ ...d,
169
+ ...c ? { extends: { ...o == null ? void 0 : o.extends, ...c } } : {}
170
+ };
171
+ } };
172
+ }, be = {
173
+ key: 0,
174
+ class: "pro-form__required"
175
+ }, me = { class: "form-item-tip" }, _e = /* @__PURE__ */ D({
176
+ __name: "index",
177
+ props: {
178
+ template: { default: () => [] },
179
+ gutter: { default: 20 },
180
+ labelWidth: { default: "auto" },
181
+ labelPosition: { default: "right" },
182
+ scrollToError: { type: Boolean, default: !1 },
183
+ defaultValue: { default: () => ({}) },
184
+ tipPosition: { default: "bottom" }
185
+ },
186
+ emits: ["change", "init"],
187
+ setup(e, { expose: t, emit: s }) {
188
+ const a = s, n = e, { model: r, setField: o, getValue: c, setValue: d } = ie(n.defaultValue), { items: g, setProps: F } = he(() => n.template), { rules: P } = ge(() => g.value), b = M(), w = async () => {
189
+ var p;
190
+ try {
191
+ return await ((p = b.value) == null ? void 0 : p.validate()), !0;
192
+ } catch {
193
+ return !1;
194
+ }
195
+ }, R = () => {
196
+ var p;
197
+ return (p = b.value) == null ? void 0 : p.resetFields();
198
+ }, C = () => {
199
+ var p;
200
+ return (p = b.value) == null ? void 0 : p.clearValidate();
201
+ }, k = (p, v) => {
202
+ a("change", p, v);
203
+ };
204
+ return Q(() => {
205
+ a("init");
206
+ }), t({
207
+ model: r,
208
+ getValue: c,
209
+ setValue: d,
210
+ setProps: F,
211
+ validate: w,
212
+ reset: R,
213
+ clearValidate: C
214
+ }), (p, v) => {
215
+ const L = E("el-tooltip"), z = E("el-form-item"), A = E("el-col"), J = E("el-row"), H = E("el-form");
216
+ return m(), V(H, {
217
+ ref_key: "formRef",
218
+ ref: b,
219
+ class: "form",
220
+ "label-width": e.labelWidth,
221
+ "label-position": e.labelPosition,
222
+ model: _(r),
223
+ rules: _(P),
224
+ "scroll-to-error": e.scrollToError
225
+ }, {
226
+ default: h(() => [
227
+ S(J, { gutter: e.gutter }, {
228
+ default: h(() => [
229
+ (m(!0), j(X, null, Z(_(g), (i) => (m(), V(A, {
230
+ key: i.prop,
231
+ span: i.span || 24
232
+ }, {
233
+ default: h(() => [
234
+ S(z, {
235
+ "hide-required-asterisk": !0,
236
+ prop: i.prop
237
+ }, {
238
+ label: h(() => [
239
+ i.required ? (m(), j("span", be, "*")) : T("", !0),
240
+ q("span", null, B(i.label), 1),
241
+ i.tip && e.tipPosition === "left" ? (m(), V(L, {
242
+ key: 1,
243
+ content: i.tip,
244
+ placement: "top"
245
+ }, {
246
+ default: h(() => [...v[0] || (v[0] = [
247
+ q("i", {
248
+ class: "ri-question-fill",
249
+ style: { "font-size": "16px", color: "#f56c6c" }
250
+ }, null, -1)
251
+ ])]),
252
+ _: 1
253
+ }, 8, ["content"])) : T("", !0)
254
+ ]),
255
+ default: h(() => [
256
+ S(_(de), {
257
+ item: i,
258
+ model: _(r),
259
+ "set-field": _(o),
260
+ onChange: (K) => k(K, i)
261
+ }, null, 8, ["item", "model", "set-field", "onChange"]),
262
+ i.tip && e.tipPosition === "bottom" ? (m(), V(L, {
263
+ key: 0,
264
+ class: "box-item",
265
+ effect: "dark",
266
+ content: i.tip,
267
+ placement: "top-start"
268
+ }, {
269
+ default: h(() => [
270
+ q("div", me, B(i.tip), 1)
271
+ ]),
272
+ _: 2
273
+ }, 1032, ["content"])) : T("", !0)
274
+ ]),
275
+ _: 2
276
+ }, 1032, ["prop"])
277
+ ]),
278
+ _: 2
279
+ }, 1032, ["span"]))), 128))
280
+ ]),
281
+ _: 1
282
+ }, 8, ["gutter"])
283
+ ]),
284
+ _: 1
285
+ }, 8, ["label-width", "label-position", "model", "rules", "scroll-to-error"]);
286
+ };
287
+ }
288
+ }), ye = (e, t) => {
289
+ const s = e.__vccOpts || e;
290
+ for (const [a, n] of t)
291
+ s[a] = n;
292
+ return s;
293
+ }, Y = /* @__PURE__ */ ye(_e, [["__scopeId", "data-v-121a6606"]]);
294
+ function Ee(e) {
295
+ e.component("ProForm", Y);
296
+ }
297
+ const ke = Object.assign(Y, { install: Ee });
298
+ export {
299
+ ke as ProForm,
300
+ ke as default
301
+ };
package/dist/style.css ADDED
@@ -0,0 +1 @@
1
+ .form-item-tip[data-v-121a6606]{width:100%;margin-top:4px;font-size:12px;line-height:1.5;color:#f56c6c;font-weight:500;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}[data-v-121a6606] .el-form-item__label:before{display:none!important}.pro-form__required[data-v-121a6606]{color:#f56c6c;margin-left:4px;font-size:18px}.pro-form__tip-icon[data-v-121a6606]{margin-left:4px;font-size:14px;color:#909399;cursor:help;vertical-align:middle}[data-v-121a6606] .box-item{color:#f56c6c}[data-v-121a6606] .el-input-number,[data-v-121a6606] .el-cascader{width:100%!important}[data-v-121a6606] .el-select,[data-v-121a6606] .el-cascader,[data-v-121a6606] .el-tree-select,[data-v-121a6606] .el-date-picker,[data-v-121a6606] .el-input{width:100%}[data-v-121a6606] .el-upload{--el-upload-picture-card-size: 100px}[data-v-121a6606] .el-upload .el-upload--picture-card,[data-v-121a6606] .el-upload .el-upload-list--picture-card .el-upload-list__item{border-radius:8px}
@@ -0,0 +1,79 @@
1
+ /**
2
+ * @liexx/table/interface/client
3
+ *
4
+ * 表格类型全局声明。(由 scripts/sync-interface.mjs 从 types/pro-form.ts 自动生成,请勿手工修改)
5
+ * 在 tsconfig.app.json 的 compilerOptions.types 中添加 "@liexx/table/interface/client",
6
+ * 即可无需 import 直接使用这些类型。
7
+ */
8
+
9
+ declare type FromItems = FromItem[];
10
+
11
+ declare type OptionItem = {
12
+ label?: string;
13
+ value?: any;
14
+ children?: OptionItem[];
15
+ [key: string]: any; // 允许自定义字段,如 cascader 的 deptName/deptId
16
+ };
17
+
18
+ declare type FormModel = Record<string, any>;
19
+
20
+ declare type FormRule = {
21
+ regExp: (value: any) => boolean;
22
+ message: string;
23
+ };
24
+
25
+ declare type FormProps = {
26
+ template: FromItems; // 表单配置
27
+ gutter?: number; // 表单间距
28
+ labelWidth?: number | string; // 表单label宽度
29
+ labelPosition?: "left" | "right" | "top"; // 表单label位置
30
+ scrollToError?: boolean; // 校验不通过时滚动到第一个错误字段
31
+ defaultValue?: FormModel; // 表单默认值
32
+ tipPosition?: "left" | "bottom"; // 表单提示位置
33
+ };
34
+
35
+ declare type FromItem = {
36
+ label: string;
37
+ prop: string;
38
+ type:
39
+ | "input"
40
+ | "select"
41
+ | "date"
42
+ | "daterange"
43
+ | "cascader"
44
+ | "tree"
45
+ | "switch"
46
+ | "radio"
47
+ | "file"
48
+ | "image"
49
+ | "number"
50
+ | "textarea"
51
+ | "checkbox"
52
+ | "rate"
53
+ | "time"
54
+ | "file";
55
+ // 占位
56
+ span?: number;
57
+ // 输入框占位文本
58
+ placeholder?: string;
59
+ // 提示
60
+ tip?: string;
61
+ //是否必填
62
+ required?: boolean;
63
+ //自定义校验规则
64
+ rules?: FormRule[];
65
+ //是否禁用
66
+ disabled?: boolean;
67
+ //是否显示到表单
68
+ isForm?: boolean;
69
+ // 透传给组件的额外 props(如 select 的 options、daterange 的 type 等)
70
+ extends?: Record<string, any>;
71
+ // 字典值
72
+ dict?: string;
73
+ // 选项内容
74
+ options?: OptionItem[];
75
+ //通过api方式获取选择内容
76
+ optionsApi?: (params?: Record<string, any>) => Promise<Record<string, any>[]>;
77
+ };
78
+
79
+ declare type ProTableProps<T = any> = TableProps
@@ -0,0 +1,11 @@
1
+ /**
2
+ * @liexx/table/interface/form
3
+ *
4
+ * 表格类型全局声明。(由 scripts/sync-interface.mjs 从 types/pro-form.ts 自动生成,请勿手工修改)
5
+ * 在 tsconfig.app.json 的 compilerOptions.types 中添加 "@liexx/table/interface/form",
6
+ * 即可无需 import 直接使用这些类型。
7
+ */
8
+
9
+
10
+
11
+ declare type FormItems = TableFilter[]
package/package.json ADDED
@@ -0,0 +1,77 @@
1
+ {
2
+ "name": "@liexx/form",
3
+ "version": "0.0.1",
4
+ "description": "Enhanced form component for Vue 3 based on Element Plus",
5
+ "type": "module",
6
+ "license": "MIT",
7
+ "author": "ljc",
8
+ "packageManager": "pnpm@10.26.0",
9
+ "keywords": [
10
+ "vue",
11
+ "vue3",
12
+ "form",
13
+ "pro-form",
14
+ "element-plus"
15
+ ],
16
+ "main": "./dist/index.cjs",
17
+ "module": "./dist/index.js",
18
+ "types": "./dist/index.d.ts",
19
+ "files": [
20
+ "dist",
21
+ "interface"
22
+ ],
23
+ "sideEffects": [
24
+ "**/*.css"
25
+ ],
26
+ "exports": {
27
+ ".": {
28
+ "types": "./dist/index.d.ts",
29
+ "import": "./dist/index.js",
30
+ "require": "./dist/index.cjs"
31
+ },
32
+ "./interface/client": {
33
+ "types": "./interface/client.d.ts"
34
+ },
35
+ "./interface/form": {
36
+ "types": "./interface/form.d.ts"
37
+ },
38
+ "./style.css": "./dist/style.css",
39
+ "./package.json": "./package.json"
40
+ },
41
+ "scripts": {
42
+ "dev": "vite",
43
+ "sync:interface": "node scripts/sync-interface.mjs",
44
+ "build": "npm run sync:interface && vue-tsc --noEmit && vite build",
45
+ "preview": "vite preview",
46
+ "test": "vitest run",
47
+ "test:watch": "vitest",
48
+ "lint": "vue-tsc --noEmit",
49
+ "prepublishOnly": "npm run build"
50
+ },
51
+ "peerDependencies": {
52
+ "element-plus": "^2.13.7",
53
+ "vue": "^3.5.0"
54
+ },
55
+ "devDependencies": {
56
+ "@microsoft/api-extractor": "^7.59.1",
57
+ "@vitejs/plugin-vue": "^5.2.0",
58
+ "@vue/test-utils": "^2.4.6",
59
+ "@vue/tsconfig": "^0.7.0",
60
+ "element-plus": "^2.14.3",
61
+ "jsdom": "^25.0.0",
62
+ "sass-embedded": "^1.100.0",
63
+ "typescript": "~5.7.0",
64
+ "vite": "^6.0.0",
65
+ "vite-plugin-dts": "^4.5.0",
66
+ "vitest": "^2.1.0",
67
+ "vue": "^3.5.13",
68
+ "vue-tsc": "^2.2.0"
69
+ },
70
+ "publishConfig": {
71
+ "registry": "https://registry.npmjs.org",
72
+ "access": "public"
73
+ },
74
+ "dependencies": {
75
+ "remixicon": "^4.9.1"
76
+ }
77
+ }