asai-vue-host-form 0.2.15 → 0.2.16

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 CHANGED
@@ -1,214 +1,98 @@
1
- # asai-vue-host-form — 动态表单渲染插件
2
-
3
- ## 概述
4
-
5
- `asai-vue-host-form` 是一个**动态表单渲染引擎**,支持根据 JSON 配置动态生成表单。它提供输入控件、标签、展示、JSON 编辑、图片上传裁剪等丰富功能,适用于低代码/动态数据编辑场景。
6
-
7
- ## 功能
8
-
9
- - 📝 **动态表单渲染**:根据配置数据递归生成表单
10
- - 🏷️ **标签系统**:带语言/国际化支持的标签展示
11
- - 📋 **列表编辑**:支持数组/列表形式的数据编辑
12
- - 👁️ **只读展示**:仅展示模式(AsaiFormShow)
13
- - ✏️ **输入控件**:文本、数字、多行文本等
14
- - 🖼️ **图片上传裁剪**:支持图片裁剪后上传
15
- - 📄 **JSON 编辑器**:JSON 格式文本编辑
16
- - 🔒 **规则控制**:字段可见性/可编辑性规则
17
- - 🚫 **编辑/添加权限控制**:独立控制编辑和添加模式
18
-
19
- ## 文件结构
20
-
21
- ```
22
- asai-vue-host-form/
23
- ├── src/
24
- │ └── components/
25
- │ ├── index.ts # 插件安装入口
26
- │ └── asui/
27
- │ └── form/
28
- │ ├── AsaiFormLi.vue # 列表表单渲染
29
- │ ├── AsaiFormLabel.vue # 表单标签组件
30
- │ ├── AsaiFormLabelArea.vue # 标签区域组件
31
- │ ├── AsaiFormShow.vue # 只读表单展示
32
- │ ├── AsaiTextarea.vue # 多行文本输入
33
- │ ├── AsaiTextJson.vue # JSON 文本编辑
34
- │ ├── AsaiUploadImgCut.vue # 图片上传裁剪
35
- │ └── AsaiUploadImgCutPop.vue # 图片裁剪弹窗
36
- └── README.md
37
- ```
38
-
39
- ## 使用说明
40
-
41
- ```vue
42
- <AsaiFormLi
43
- :ujt="ujt"
44
- :asaidata="formConfig"
45
- :formdata="formData"
46
- :opt="{ isedit: true }"
47
- />
48
- ```
49
-
50
- ## 核心组件
51
-
52
- ### AsaiFormLi — 表单列表渲染器
53
-
54
- 表单的核心递归组件,遍历 `formdata` 对象,根据 `asaidata.rule` 的配置决定每个字段的渲染方式。
55
-
56
- #### Props
57
-
58
- | 参数 | 类型 | 说明 |
59
- |------|------|------|
60
- | `ujt` | `Object` | 全局上下文 |
61
- | `asaidata` | `Object` | 表单配置 |
62
- | `formdata` | `Object` | 表单数据(双向绑定) |
63
- | `opt.isedit` | `boolean` | 是否为编辑模式 |
64
-
65
- #### 渲染逻辑
66
-
67
- 1. 如果字段规则中 `noedit`/`noadd` == 2 → 显示为只读展示(AsaiFormShow)
68
- 2. 如果字段规则为空 → 正常渲染
69
- - 有自定义组件 使用自定义组件
70
- - 值为对象 递归渲染(AsaiFormObject
71
- - 值为基本类型 使用 AsaiInput
72
- 3. 如果字段 `noadd`/`noedit` == 1 隐藏该字段
73
-
74
- ### AsaiFormLabel — 表单标签
75
-
76
- 根据配置显示字段名称标签,支持:
77
- - 国际化键值(`asaidata.lang[formkey]`)
78
- - 必须字段标记(`rule[key].require`)
79
- - 类型指示图标(数组/数字)
80
-
81
- ### AsaiFormShow — 只读展示
82
-
83
- 以只读方式显示字段值,支持:
84
- - 字符串类型加引号显示(JSON 风格)
85
- - 数字类型直显
86
- - 自定义输入属性通过 `rule[key].opt` 传递
87
-
88
- ### AsaiUploadImgCut 图片上传裁剪
89
-
90
- 提供完整的图片裁切功能:
91
- - 拖拽移动裁剪框
92
- - 四角拖拽调整大小
93
- - 适应/超出图片边界控制
94
- - 裁剪后自动缩放(如果设置了 `rule[key].data` 的尺寸限制)
95
- - 下载裁剪结果和确认上传
96
-
97
- ### AsaiUploadImgCutPop — 图片裁剪弹窗
98
-
99
- 将 `AsaiUploadImgCut` 封装在 `PopBox` 弹窗中,通过 `$global.pop['popupload' + formkey]` 控制显示。
100
-
101
- ### AsaiTextarea — 多行文本输入
102
-
103
- 多行文本输入组件,用于长文本编辑。
104
-
105
- ### AsaiTextJson — JSON 文本编辑
106
-
107
- 专门用于编辑 JSON 格式文本的组件。
108
-
109
- ## 配置参数
110
-
111
- ### asaidata 表单配置结构
112
-
113
- | 参数 | 类型 | 说明 |
114
- |------|------|------|
115
- | `rule` | `Object` | 字段规则配置 |
116
- | `rule[key].noedit` | `0\|1\|2` | 编辑模式控制(0=可编辑, 1=隐藏, 2=只读) |
117
- | `rule[key].noadd` | `0\|1\|2` | 添加模式控制(同上) |
118
- | `rule[key].require` | `boolean` | 是否必填 |
119
- | `rule[key].type` | `string` | 输入类型(text/number 等) |
120
- | `rule[key].max` | `number` | 最大值 |
121
- | `rule[key].min` | `number` | 最小值 |
122
- | `rule[key].opt` | `Object` | 额外选项(传递给输入组件) |
123
- | `rule[key].data` | `Object` | 裁剪图片最大尺寸限制 |
124
- | `lang` | `Object` | 字段标签文字(国际化) |
125
- | `lang[key]` | `string` | 各字段的显示标签 |
126
- | `eq` | `number` | 显示格式(>2 显示引号,>0 显示冒号) |
127
- | `ic` | `number` | 图标样式控制(>1 显示字段图标) |
128
- | `notit` | `boolean` | 是否隐藏标题 |
129
- | `cmComp(key)` | `function` | 返回自定义组件(按需) |
130
-
131
- ### 规则值说明
132
-
133
- | 值 | 说明 |
134
- |----|------|
135
- | `0` 或 `undefined` | 正常显示和编辑 |
136
- | `1` | 隐藏该字段 |
137
- | `2` | 显示为只读(不可编辑) |
138
-
139
- ## 技术细节
140
-
141
- - 递归渲染:对象类型字段自动递归渲染子表单
142
- - 自定义组件:通过 `cmComp(key)` 钩子支持自定义字段组件
143
- - 与 `asai-vue-host-popbox` 集成:图片裁剪使用弹窗展示
144
- - 响应式绑定:`formdata` 直接绑定,修改即时生效
145
-
146
- ## 代码优化分析
147
-
148
- ### 已做优化
149
- - ✅ 递归渲染:对象类型字段自动递归渲染子表单
150
- - ✅ 自定义组件钩子:`cmComp(key)` 支持按字段注入自定义组件
151
- - ✅ 只读/编辑/隐藏三种模式通过配置控制,灵活度高
152
- - ✅ 图片裁剪支持拖拽移动、四角缩放
153
-
154
- ### 可优化点
155
-
156
- #### 1. 图片裁剪 Canvas 缩放计算
157
- ```typescript
158
- const canvasWidth = Math.min(cropParams.value.width * scaleX, img.naturalWidth);
159
- ```
160
- **问题**:裁剪后输出的图片质量仅使用 `0.9`,且格式固定为 PNG。对于大图裁剪,PNG 体积会非常大。
161
-
162
- **建议**:支持 JPEG 格式和可配置的质量参数:
163
- ```typescript
164
- const format = props.params.format || 'image/jpeg';
165
- const quality = props.params.quality || 0.92;
166
- croppedImage.value = canvas.toDataURL(format, quality);
167
- ```
168
-
169
- #### 2. 裁剪尺寸限制的二次缩放
170
- ```typescript
171
- if (maxSize.width < canvasWidth || maxSize.height < canvasHeight) {
172
- // 再次绘制到更小的 canvas
173
- const ctx1: any = canvas1.getContext('2d');
174
- ctx1.drawImage(cutmg, 0, 0, cutSize.width, cutSize.height);
175
- }
176
- ```
177
- **问题**:先用原始尺寸裁剪,再缩放到目标尺寸,**做了两次 Canvas 绘制**。可以直接在第一次 `drawImage` 时就指定目标尺寸。
178
-
179
- #### 3. 表单规则中的 `noedit`/`noadd` 魔数
180
- ```typescript
181
- if (props.asaidata.rule?.[key]?.[props.opt?.isedit ? 'noedit' : 'noadd'] == 2)
182
- ```
183
- **问题**:数字 0/1/2 的含义没有文档说明,新人需要阅读源码才能理解。建议改为枚举:
184
- ```typescript
185
- enum FieldMode {
186
- Visible = 0, // 正常显示编辑
187
- Hidden = 1, // 隐藏
188
- Readonly = 2, // 只读
189
- }
190
- ```
191
-
192
- #### 4. AsaiFormLi 中的条件渲染链过长
193
- 模板中有 `v-for` 嵌套多级 `v-if/v-else-if/v-else`,可读性差。建议提取为独立组件:
194
- - `AsaiFormFieldRenderer` — 单字段渲染
195
- - `AsaiFormObjectRenderer` — 对象类型递归渲染
196
-
197
- #### 5. 缺少表单校验能力
198
- 当前表单系统支持 `require` 标记,但缺少:
199
- - 自定义校验规则(正则、函数)
200
- - 校验失败的错误消息显示
201
- - 整体表单校验通过/失败的状态
202
-
203
- 建议注入校验框架,参考 VeeValidate 或自实现。
204
-
205
- #### 6. 上传裁剪缺少文件类型/大小限制
206
- 当前 `AsaiUploadImgCut` 直接接收 base64Data,没有对上传文件的类型、大小进行校验。建议在组件内增加文件选择校验。
207
-
208
- #### 7. AsaiFormLabelArea 使用 `<label>` 包裹所有内容
209
- ```vue
210
- <label v-else :class="...">
211
- <slot></slot>
212
- </label>
213
- ```
214
- **问题**:如果 slot 内容包含可交互元素(input/select),点击 label 会触发关联 input 的 focus,可能产生意外的表单行为。
1
+ # asai-vue-host-form — 动态表单渲染插件
2
+
3
+ ## 包信息
4
+
5
+ | 建议 npm | 入口文件 | $fn / 注入键 | 类型 |
6
+ |------------|---------|-------------|------|
7
+ | `@estun/asai-vue-host-form` | `src/components/index.ts` | —(全局组件) | Host |
8
+
9
+ ## 概述
10
+
11
+ `asai-vue-host-form` 是**动态表单渲染引擎**,根据 JSON 配置递归生成表单,支持输入、只读展示、JSON 编辑、图片上传裁剪与字段规则控制。
12
+
13
+ ## 集成方式
14
+
15
+ ```typescript
16
+ // monorepo — webclient/src/utils/index.ts
17
+ import AsaiVueHostForm from '../plugs/asai-vue-host-form/src/components/index';
18
+ // import '/node_modules/asai-vue-host-form/dist/asai-vue-host-form.css';
19
+ // npm
20
+ // import AsaiVueHostForm from '@estun/asai-vue-host-form';
21
+
22
+ app.use(AsaiVueHostForm, lib);
23
+ ```
24
+
25
+ ```vue
26
+ <AsaiFormLi :ujt="ujt" :asaidata="formConfig" :formdata="formData" :opt="{ isedit: true }" />
27
+ ```
28
+
29
+ ## 独立性约束
30
+
31
+ - **禁止** cross-import 其它 `plugs/*`。
32
+ - 图片裁剪弹窗通过 `$global.pop` 与 PopBox **运行时**集成,不 import `asai-vue-host-popbox`。
33
+
34
+ ## 主要 API / 导出
35
+
36
+ | 组件 | 说明 |
37
+ |------|------|
38
+ | `AsaiFormLi` | 表单列表递归渲染器 |
39
+ | `AsaiFormLabel` / `AsaiFormLabelArea` | 标签与区域 |
40
+ | `AsaiFormShow` | 只读展示 |
41
+ | `AsaiTextarea` / `AsaiTextJson` | 多行 / JSON 编辑 |
42
+ | `AsaiUploadImgCut` / `AsaiUploadImgCutPop` | 图片裁剪与弹窗 |
43
+
44
+ ## 性能说明
45
+
46
+ - 全局组件 **lazy** 加载(`loadvue` eager: false),首次使用表单时才拉 chunk。
47
+ - 递归渲染大对象时注意字段数量;自定义组件通过 `cmComp(key)` 按需注入。
48
+
49
+ ## peerDependencies 建议
50
+
51
+ ```json
52
+ {
53
+ "peerDependencies": {
54
+ "vue": "^3.4.0",
55
+ "@estun/asai-vue-host": "^1.0.0",
56
+ "@estun/asai-vue-host-popbox": "^1.0.0"
57
+ }
58
+ }
59
+ ```
60
+
61
+ ---
62
+
63
+ ## 核心组件
64
+
65
+ ### AsaiFormLi
66
+
67
+ | Props | 说明 |
68
+ |-------|------|
69
+ | `ujt` | 全局上下文 |
70
+ | `asaidata` | 表单配置(rule、lang |
71
+ | `formdata` | 表单数据(双向) |
72
+ | `opt.isedit` | 编辑 / 添加模式 |
73
+
74
+ **渲染逻辑:**
75
+
76
+ 1. `noedit`/`noadd` == 2 → 只读(AsaiFormShow)
77
+ 2. 值为对象 → 递归;基本类型 → AsaiInput
78
+ 3. `noadd`/`noedit` == 1 → 隐藏
79
+
80
+ ### asaidata 配置
81
+
82
+ | 参数 | 说明 |
83
+ |------|------|
84
+ | `rule[key].noedit/noadd` | 0=正常, 1=隐藏, 2=只读 |
85
+ | `rule[key].require` | 必填 |
86
+ | `rule[key].type` | text/number 等 |
87
+ | `lang[key]` | 字段标签 |
88
+ | `cmComp(key)` | 自定义组件钩子 |
89
+
90
+ ## 文件结构
91
+
92
+ ```
93
+ asai-vue-host-form/
94
+ ├── src/components/asui/form/
95
+ │ ├── AsaiFormLi.vue / AsaiFormShow.vue
96
+ │ └── AsaiUploadImgCut*.vue
97
+ └── README.md
98
+ ```
@@ -8,7 +8,7 @@ const A = { class: "as-form-area" }, f = /* @__PURE__ */ p({
8
8
  },
9
9
  setup(e) {
10
10
  const a = e, { $fn: s } = a.ujt, { get: r, clear: m } = s.createComponentLoader({
11
- files: /* @__PURE__ */ Object.assign({ "./AsaiFormLabel.vue": () => import("./AsaiFormLabel-BAXvUybW.mjs"), "./AsaiFormLabelArea.vue": () => import("./AsaiFormLabelArea-CmjCZFfF.mjs"), "./AsaiFormLi.vue": () => import("./AsaiFormLi-B-Po6qaB.mjs"), "./AsaiFormObject.vue": () => import("./AsaiFormObject-B8WHlNwq.mjs"), "./AsaiFormShow.vue": () => import("./AsaiFormShow-Da4NJXK7.mjs"), "./AsaiInput.vue": () => import("./AsaiInput-D4BZoHDc.mjs"), "./AsaiRichEditor.vue": () => import("./AsaiRichEditor-DDOCr12f.mjs"), "./AsaiSelect.vue": () => import("./AsaiSelect-B4KZbNRO.mjs"), "./AsaiSelectCl.vue": () => import("./AsaiSelectCl-Cl6N0v40.mjs"), "./AsaiSelectLv.vue": () => import("./AsaiSelectLv-DNjfTp67.mjs"), "./AsaiTextJson.vue": () => import("./AsaiTextJson-Dr7yX0_I.mjs"), "./AsaiTextarea.vue": () => import("./AsaiTextarea-O38xA-tq.mjs"), "./AsaiUpBinary.vue": () => import("./AsaiUpBinary-DFmYr2_2.mjs"), "./AsaiUpload.vue": () => import("./AsaiUpload-D4kzZ5_G.mjs"), "./AsaiUploadImg.vue": () => import("./AsaiUploadImg-D8mMVNdc.mjs"), "./AsaiUploadImgCut.vue": () => import("./AsaiUploadImgCut-B3Y2hppn.mjs"), "./AsaiUploadImgCutPop.vue": () => import("./AsaiUploadImgCutPop-0gVLGw9m.mjs") }),
11
+ files: /* @__PURE__ */ Object.assign({ "./AsaiFormLabel.vue": () => import("./AsaiFormLabel-BAXvUybW.mjs"), "./AsaiFormLabelArea.vue": () => import("./AsaiFormLabelArea-CmjCZFfF.mjs"), "./AsaiFormLi.vue": () => import("./AsaiFormLi-B-Po6qaB.mjs"), "./AsaiFormObject.vue": () => import("./AsaiFormObject-B8WHlNwq.mjs"), "./AsaiFormShow.vue": () => import("./AsaiFormShow-Da4NJXK7.mjs"), "./AsaiInput.vue": () => import("./AsaiInput-D4BZoHDc.mjs"), "./AsaiRichEditor.vue": () => import("./AsaiRichEditor-H9WK-q7h.mjs"), "./AsaiRichEditorToolbar.vue": () => import("./AsaiRichEditorToolbar-BleVnkxV.mjs"), "./AsaiSelect.vue": () => import("./AsaiSelect-B4KZbNRO.mjs"), "./AsaiSelectCl.vue": () => import("./AsaiSelectCl-Cl6N0v40.mjs"), "./AsaiSelectLv.vue": () => import("./AsaiSelectLv-DNjfTp67.mjs"), "./AsaiTextJson.vue": () => import("./AsaiTextJson-Dr7yX0_I.mjs"), "./AsaiTextarea.vue": () => import("./AsaiTextarea-O38xA-tq.mjs"), "./AsaiUpBinary.vue": () => import("./AsaiUpBinary-CBV4sACD.mjs"), "./AsaiUpload.vue": () => import("./AsaiUpload-BQTw42KS.mjs"), "./AsaiUploadImg.vue": () => import("./AsaiUploadImg-CSQXvm8H.mjs"), "./AsaiUploadImgCut.vue": () => import("./AsaiUploadImgCut-DTWuaOl8.mjs"), "./AsaiUploadImgCutPop.vue": () => import("./AsaiUploadImgCutPop-0gVLGw9m.mjs") }),
12
12
  // 扫描当前目录下所有.vue文件
13
13
  eager: !1,
14
14
  // 异步加载(按需加载)
@@ -0,0 +1,125 @@
1
+ import { defineComponent as H, defineAsyncComponent as U, ref as m, onMounted as j, onBeforeUnmount as z, createElementBlock as y, openBlock as v, normalizeStyle as g, createVNode as B, createElementVNode as x, unref as w, createCommentVNode as _, withDirectives as N, vModelText as F, nextTick as T } from "vue";
2
+ import { _ as S } from "./_plugin-vue_export-helper-CHgC5LLL.mjs";
3
+ const W = { class: "as-richtext-content" }, O = ["placeholder"], P = /* @__PURE__ */ H({
4
+ __name: "AsaiRichEditor",
5
+ props: {
6
+ ujt: {},
7
+ asaidata: {},
8
+ formdata: {},
9
+ formkey: {}
10
+ },
11
+ setup(E) {
12
+ const C = U({
13
+ loader: () => import("./AsaiRichEditorToolbar-BleVnkxV.mjs"),
14
+ delay: 120
15
+ }), t = E, { $global: L } = t.ujt, u = {
16
+ img: { maxWidth: 288, quality: 0.8 },
17
+ imgurls: {}
18
+ }, p = m(null), o = m(null), M = m(null), r = m(t.asaidata?.rule?.[t.formkey]?.editorty || 0);
19
+ let d = null, h = null, c = null;
20
+ async function s() {
21
+ return d || (h || (h = import("./useRichEditorMedia-BOIU0Dbf.mjs").then((a) => (d = a.createRichEditorMedia(u), d))), h);
22
+ }
23
+ j(() => {
24
+ k(), s();
25
+ }), z(() => {
26
+ c && clearTimeout(c);
27
+ });
28
+ function k() {
29
+ o.value && (o.value.innerHTML = t.formdata[t.formkey]);
30
+ }
31
+ function R() {
32
+ const a = window.prompt("请输入链接地址");
33
+ a && f("createLink", { target: { value: a } });
34
+ }
35
+ function b(a) {
36
+ p.value.accept = `${a}/*`, T(() => p.value?.click());
37
+ }
38
+ async function D(a) {
39
+ const e = a.target.files?.[0];
40
+ if (!e) return;
41
+ const n = await s();
42
+ let i, l = "";
43
+ e.type.startsWith("image") ? (i = await n.compressFile(e), l = `<img src="${i}" style="max-width:100%">`) : (e.size > 1024 * 1024 ? i = URL.createObjectURL(e) : i = await n.compressFile(e), l = e.type.startsWith("video") ? `<video controls src="${i}" style="max-width:100%"></video>` : `<a href="${i}" download="${e.name}">${e.name}</a>`), f("insertHTML", { target: { value: l } });
44
+ }
45
+ async function V() {
46
+ const a = await s(), e = Object.keys(u.imgurls);
47
+ for (let n = 0; n < e.length; n++) {
48
+ const i = e[n];
49
+ u.imgurls[i] === "1" && a.compressImage(i).then((l) => {
50
+ u.imgurls[i] = l, t.formdata[t.formkey] = t.formdata[t.formkey].replaceAll(i, l);
51
+ });
52
+ }
53
+ }
54
+ async function $(a) {
55
+ a.preventDefault();
56
+ const e = await s(), n = a.clipboardData?.getData("text/html") || "", i = e.sanitize(n, 1) || a.clipboardData?.getData("text/plain") || "";
57
+ f("insertHTML", { target: { value: i } });
58
+ }
59
+ function A() {
60
+ if (!o.value) return;
61
+ const a = o.value.innerHTML;
62
+ t.formdata[t.formkey] = a, c && clearTimeout(c), c = setTimeout(() => {
63
+ s().then((e) => {
64
+ o.value && (t.formdata[t.formkey] = e.sanitize(o.value.innerHTML));
65
+ });
66
+ }, 300);
67
+ }
68
+ function f(a, e = null) {
69
+ if (o.value) {
70
+ if (e?.target?.tagName === "SELECT" && e?.target?.value) {
71
+ document.execCommand(a, !1, e.target.value);
72
+ return;
73
+ }
74
+ document.execCommand(a, !1, e?.target?.value);
75
+ }
76
+ }
77
+ function I() {
78
+ r.value++, r.value > 2 && (r.value = 0), T(k);
79
+ }
80
+ return (a, e) => (v(), y("div", {
81
+ class: "as-richtext-area",
82
+ style: g(t.asaidata.rule?.[t.formkey]?.style || {})
83
+ }, [
84
+ B(w(C), {
85
+ lang: w(L).lang.richtexteditor,
86
+ onExec: f,
87
+ onMedia: b,
88
+ onLink: R,
89
+ onUploadImg: V,
90
+ onChangeView: I
91
+ }, null, 8, ["lang"]),
92
+ x("div", W, [
93
+ r.value != 1 ? (v(), y("div", {
94
+ key: 0,
95
+ style: g({ width: r.value > 1 ? "50%" : "100%" }),
96
+ ref_key: "rfRichEditor",
97
+ ref: o,
98
+ contenteditable: "true",
99
+ onPaste: $,
100
+ onInput: A
101
+ }, null, 36)) : _("", !0),
102
+ r.value > 0 ? N((v(), y("textarea", {
103
+ key: 1,
104
+ placeholder: t?.opt?.placeholder || "",
105
+ ref_key: "rfRichCode",
106
+ ref: M,
107
+ "onUpdate:modelValue": e[0] || (e[0] = (n) => t.formdata[t.formkey] = n),
108
+ style: g({ width: r.value > 1 ? "50%" : "100%" })
109
+ }, null, 12, O)), [
110
+ [F, t.formdata[t.formkey]]
111
+ ]) : _("", !0)
112
+ ]),
113
+ x("input", {
114
+ ref_key: "fileInput",
115
+ ref: p,
116
+ type: "file",
117
+ hidden: "",
118
+ onChange: D
119
+ }, null, 544)
120
+ ], 4));
121
+ }
122
+ }), J = /* @__PURE__ */ S(P, [["__scopeId", "data-v-5c6cb195"]]);
123
+ export {
124
+ J as default
125
+ };
@@ -0,0 +1,135 @@
1
+ import { defineComponent as k, createElementBlock as u, openBlock as s, createElementVNode as n, toDisplayString as l, Fragment as r, renderList as b } from "vue";
2
+ import { _ as v } from "./_plugin-vue_export-helper-CHgC5LLL.mjs";
3
+ const y = { class: "as-richtext-toolbar" }, C = { value: "" }, g = ["value"], p = { value: "p" }, x = ["value"], m = ["title"], f = ["title"], $ = ["title"], a = ["title"], L = ["title"], I = ["title"], j = ["title"], B = ["title"], E = /* @__PURE__ */ k({
4
+ __name: "AsaiRichEditorToolbar",
5
+ props: {
6
+ lang: {}
7
+ },
8
+ emits: ["exec", "media", "link", "uploadImg", "changeView"],
9
+ setup(i, { emit: d }) {
10
+ const o = d;
11
+ return (z, t) => (s(), u("div", y, [
12
+ n("select", {
13
+ onChange: t[0] || (t[0] = (e) => o("exec", "fontSize", e))
14
+ }, [
15
+ n("option", C, l(i.lang.fontsize), 1),
16
+ (s(), u(r, null, b(7, (e) => n("option", {
17
+ key: "size" + e,
18
+ value: e + 1
19
+ }, l((e + 1) * 2 + 6) + "px", 9, g)), 64))
20
+ ], 32),
21
+ n("select", {
22
+ onChange: t[1] || (t[1] = (e) => o("exec", "formatBlock", e))
23
+ }, [
24
+ n("option", p, l(i.lang.paragraph), 1),
25
+ (s(), u(r, null, b(6, (e) => n("option", {
26
+ key: "h" + e,
27
+ value: "h" + e
28
+ }, l(i.lang.title) + l(e), 9, x)), 64))
29
+ ], 32),
30
+ n("button", {
31
+ type: "button",
32
+ onClick: t[2] || (t[2] = (e) => o("exec", "bold")),
33
+ title: i.lang.bold
34
+ }, "B", 8, m),
35
+ n("button", {
36
+ type: "button",
37
+ onClick: t[3] || (t[3] = (e) => o("exec", "underline")),
38
+ title: i.lang.underline
39
+ }, "U", 8, f),
40
+ n("button", {
41
+ type: "button",
42
+ onClick: t[4] || (t[4] = (e) => o("exec", "italic")),
43
+ title: i.lang.italic
44
+ }, "I", 8, $),
45
+ n("button", {
46
+ type: "button",
47
+ onClick: t[5] || (t[5] = (e) => o("exec", "strikethrough")),
48
+ title: i.lang.strikethrough
49
+ }, "S", 8, a),
50
+ n("input", {
51
+ type: "color",
52
+ onInput: t[6] || (t[6] = (e) => o("exec", "foreColor", e)),
53
+ title: i.lang.foreColor
54
+ }, null, 40, L),
55
+ n("input", {
56
+ type: "color",
57
+ onInput: t[7] || (t[7] = (e) => o("exec", "backColor", e)),
58
+ title: i.lang.backColor
59
+ }, null, 40, I),
60
+ n("button", {
61
+ type: "button",
62
+ onClick: t[8] || (t[8] = (e) => o("exec", "insertOrderedList")),
63
+ title: i.lang.insertOrderedList
64
+ }, "有", 8, j),
65
+ n("button", {
66
+ type: "button",
67
+ onClick: t[9] || (t[9] = (e) => o("exec", "insertUnorderedList")),
68
+ title: i.lang.insertUnorderedList
69
+ }, "无", 8, B),
70
+ n("button", {
71
+ type: "button",
72
+ onClick: t[10] || (t[10] = (e) => o("exec", "justifyCenter")),
73
+ title: "居中"
74
+ }, "中"),
75
+ n("button", {
76
+ type: "button",
77
+ onClick: t[11] || (t[11] = (e) => o("exec", "justifyFull")),
78
+ title: "两端对齐"
79
+ }, "两"),
80
+ n("button", {
81
+ type: "button",
82
+ onClick: t[12] || (t[12] = (e) => o("exec", "justifyRight")),
83
+ title: "右对齐"
84
+ }, "右"),
85
+ n("button", {
86
+ type: "button",
87
+ onClick: t[13] || (t[13] = (e) => o("exec", "justifyLeft")),
88
+ title: "左对齐"
89
+ }, "左"),
90
+ n("button", {
91
+ type: "button",
92
+ onClick: t[14] || (t[14] = (e) => o("exec", "delete")),
93
+ title: "删除"
94
+ }, "删"),
95
+ n("button", {
96
+ type: "button",
97
+ onClick: t[15] || (t[15] = (e) => o("link")),
98
+ title: "链接"
99
+ }, "链"),
100
+ n("button", {
101
+ type: "button",
102
+ onClick: t[16] || (t[16] = (e) => o("exec", "unlink")),
103
+ title: "删除链接"
104
+ }, "除"),
105
+ n("button", {
106
+ type: "button",
107
+ onClick: t[17] || (t[17] = (e) => o("media", "image")),
108
+ title: "图片"
109
+ }, "🖼️"),
110
+ n("button", {
111
+ type: "button",
112
+ onClick: t[18] || (t[18] = (e) => o("media", "video")),
113
+ title: "视频"
114
+ }, "🎬"),
115
+ n("button", {
116
+ type: "button",
117
+ onClick: t[19] || (t[19] = (e) => o("media", "file")),
118
+ title: "文件"
119
+ }, "📎"),
120
+ n("button", {
121
+ type: "button",
122
+ onClick: t[20] || (t[20] = (e) => o("uploadImg")),
123
+ title: "上传"
124
+ }, "上"),
125
+ n("button", {
126
+ type: "button",
127
+ onClick: t[21] || (t[21] = (e) => o("changeView")),
128
+ title: "切换"
129
+ }, "HTML")
130
+ ]));
131
+ }
132
+ }), T = /* @__PURE__ */ v(E, [["__scopeId", "data-v-bf97b430"]]);
133
+ export {
134
+ T as default
135
+ };
@@ -81,7 +81,7 @@ const b = ["accept"], j = { key: 0 }, x = ["src", "alt", "title"], I = ["title"]
81
81
  }, 8, ["ujt", "asaidata", "formdata", "formkey"]);
82
82
  };
83
83
  }
84
- }), z = /* @__PURE__ */ U($, [["__scopeId", "data-v-535f25e7"]]);
84
+ }), z = /* @__PURE__ */ U($, [["__scopeId", "data-v-e9910494"]]);
85
85
  export {
86
86
  z as default
87
87
  };
@@ -90,7 +90,7 @@ const w = { key: 0 }, x = ["src", "alt", "title"], B = ["title"], I = ["title"],
90
90
  }, 8, ["ujt", "asaidata", "formdata", "formkey"]);
91
91
  };
92
92
  }
93
- }), P = /* @__PURE__ */ U(L, [["__scopeId", "data-v-a305b28a"]]);
93
+ }), P = /* @__PURE__ */ U(L, [["__scopeId", "data-v-50ddd40b"]]);
94
94
  export {
95
95
  P as default
96
96
  };
@@ -1,4 +1,4 @@
1
- import { defineComponent as j, ref as u, onMounted as F, resolveComponent as y, createElementBlock as m, openBlock as p, Fragment as A, createVNode as k, withCtx as C, createElementVNode as c, withModifiers as I, normalizeClass as U, toDisplayString as _ } from "vue";
1
+ import { defineComponent as j, ref as f, onMounted as F, resolveComponent as y, createElementBlock as m, openBlock as p, Fragment as A, createVNode as k, withCtx as C, createElementVNode as c, withModifiers as I, normalizeClass as U, toDisplayString as _ } from "vue";
2
2
  import { _ as b } from "./_plugin-vue_export-helper-CHgC5LLL.mjs";
3
3
  const w = { key: 0 }, x = ["src"], L = ["title"], D = /* @__PURE__ */ j({
4
4
  __name: "AsaiUploadImg",
@@ -9,14 +9,14 @@ const w = { key: 0 }, x = ["src"], L = ["title"], D = /* @__PURE__ */ j({
9
9
  formkey: {}
10
10
  },
11
11
  setup(e) {
12
- const a = e, { $fn: d, $global: o } = a.ujt, r = u(null), f = u(null), n = u("+");
12
+ const a = e, { $fn: d, $global: o } = a.ujt, r = f(null), u = f(null), n = f("+");
13
13
  F(() => {
14
14
  const l = "popupload" + a.formkey;
15
15
  o.pop[l] || (o.pop[l] = { stat: 0, full: 0, tit: "", params: {} });
16
16
  });
17
17
  const v = async (l) => {
18
18
  if (r.value.value) {
19
- if (f.value = l.target.files[0], r.value.value = "", !f.value) {
19
+ if (u.value = l.target.files[0], r.value.value = "", !u.value) {
20
20
  n.value = d.lg("asai.fail");
21
21
  return;
22
22
  }
@@ -37,7 +37,7 @@ const w = { key: 0 }, x = ["src"], L = ["title"], D = /* @__PURE__ */ j({
37
37
  } catch (s) {
38
38
  n.value = d.lg("asai.fail") + " " + s.message;
39
39
  }
40
- }, t.readAsDataURL(f.value);
40
+ }, t.readAsDataURL(u.value);
41
41
  }
42
42
  };
43
43
  function g() {
@@ -89,7 +89,7 @@ const w = { key: 0 }, x = ["src"], L = ["title"], D = /* @__PURE__ */ j({
89
89
  ], 64);
90
90
  };
91
91
  }
92
- }), B = /* @__PURE__ */ b(D, [["__scopeId", "data-v-0bfdd149"]]);
92
+ }), B = /* @__PURE__ */ b(D, [["__scopeId", "data-v-36b7ec3b"]]);
93
93
  export {
94
94
  B as default
95
95
  };