widget.qw 1.0.92 → 1.0.95

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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "widget.qw",
3
3
  "private": false,
4
- "version": "1.0.92",
4
+ "version": "1.0.95",
5
5
  "description": "marqstree Vue3组件库",
6
6
  "main": "build/widget.qw.es.js",
7
7
  "keywords": [
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <van-field v-if="!isGone" name="image" :label="props.label" :required="isRequired" :rules="rules"
2
+ <van-field v-if="!isGone" name="image" :label="props.label" :required="isRequired" :rules="rules" :modelValue="modelValue"
3
3
  label-class="label" :placeholder="props.placeholder">
4
4
  <template #input>
5
5
  <div class="file-box">
@@ -1,17 +1,32 @@
1
1
  <template>
2
- <van-field
3
- :label="props.label"
4
- v-model.number="modelValue"
5
- v-if="!isGone && props.type === 'number'"
2
+ <!-- 数字类型 -->
3
+ <van-field :label="props.label" v-model.number="modelValue" v-if="!isGone && props.type === 'number'"
6
4
  :disabled="isDisabled" :required="isRequired" :placeholder="props.placeholder" :type="props.type"
7
- :rows="props.rows" :autosize="props.autosize" :rules="rules" />
5
+ :rows="props.rows" :autosize="props.autosize" :rules="rules">
6
+ <!-- 右侧插槽按钮 -->
7
+ <template #button>
8
+ <van-button size="small" @click="onCalc">
9
+ +
10
+ </van-button>
11
+ </template>
12
+ </van-field>
13
+ <van-popup v-model:show="data.isShowPop" position="bottom" round>
14
+ <van-field v-model="data.express" placeholder="请输入+/-数字" type="text">
15
+ <template #button>
16
+ <van-button size="small" @click="onSubmit">
17
+ 确定
18
+ </van-button>
19
+ </template>
20
+ </van-field>
21
+ </van-popup>
22
+ <!-- 文本类型 -->
8
23
  <van-field :label="props.label" v-model="modelValue" v-if="!isGone && props.type != 'number'" :disabled="isDisabled"
9
24
  :required="isRequired" :placeholder="props.placeholder" :type="props.type" :rows="props.rows"
10
25
  :autosize="props.autosize" :rules="rules" />
11
26
  </template>
12
27
 
13
28
  <script setup>
14
- import { ref, computed, onMounted, defineProps, defineEmits, watch } from "vue"
29
+ import { ref, computed, onMounted, defineProps, defineEmits, watch, reactive } from "vue"
15
30
  import { useVModel } from '@vueuse/core'
16
31
  import util from '../util'
17
32
 
@@ -65,6 +80,29 @@ const props = defineProps({
65
80
  const emit = defineEmits(['update:modelValue'])
66
81
  const modelValue = useVModel(props, 'modelValue', emit)
67
82
  const { isRequired, isReadonly, isGone, isDisabled, rules } = util.props2auth(props)
83
+ const data = reactive({
84
+ isShowPop: false,
85
+ express: ''
86
+ })
87
+
88
+ const onCalc = () => {
89
+ data.isShowPop = true
90
+ data.express = '+'
91
+ }
92
+
93
+ const onSubmit = () => {
94
+ // 简单校验只允许数字 +- .
95
+ if (!/^[\d\.+-]+$/.test(data.express)) {
96
+ throw new Error("非法表达式");
97
+ }
98
+
99
+ let fullExpress = modelValue.value+''+data.express
100
+
101
+ modelValue.value = eval(fullExpress)
102
+
103
+ data.isShowPop = false
104
+ data.express = ''
105
+ }
68
106
 
69
107
  onMounted(() => {
70
108
  })
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <van-field v-if="!isGone" :label="props.label" :required="isRequired" :rules="rules" :disabled="isDisabled"
2
+ <van-field v-if="!isGone" :label="props.label" :required="isRequired" :rules="rules" :disabled="isDisabled" :modelValue="modelValue"
3
3
  :placeholder="props.placeholder" :is-link="isReadonly ? false : true" @click="data.isShowPop = !isReadonly"
4
4
  label-class="label">
5
5
  <template #input v-if="selectOptions.length>0">
@@ -1,9 +1,10 @@
1
1
  <template>
2
2
  <van-field :label="props.label" v-if="!isGone" :disabled="isDisabled" :required="isRequired"
3
- :placeholder="props.placeholder" :rules="rules">
3
+ :modelValue="modelValue" :placeholder="props.placeholder" :rules="rules">
4
4
  <template #input>
5
5
  <div class="widget-box">
6
6
  <div class="option" v-for="(item, index) in modelValue" :key="index">
7
+ <!-- 浏览状态的元素,显示元素的值 -->
7
8
  <div v-if="index != data.selectIndex" style=" display: flex;align-items: center;">
8
9
  <van-icon name="arrow-left" @click.stop="onForward(index)" />
9
10
  <div style="padding: 5px 5px;">
@@ -30,12 +31,15 @@
30
31
  </div>
31
32
  </div>
32
33
 
34
+ <!-- 编辑状态的元素,显示编辑输入框 -->
33
35
  <van-form v-if="data.isShowInput && index == data.selectIndex" :model="data.inputValue">
36
+ <!-- 列出schema中定义的字段的输入框 -->
34
37
  <van-field v-for="(key, i) in keys" :key="i" :label="props.schema[key].label"
35
38
  v-show="props.schema[key].auth != 'gone'" :required="props.schema[key].auth === 'required'"
36
39
  :disabled="props.schema[key].auth === 'readonly'">
37
40
 
38
41
  <template #input>
42
+ <!-- 根据字段的类型,显示对应的输入框 -->
39
43
  <van-field
40
44
  v-if="props.schema[key].type == 'String' && !props.schema[key]?.schema?.options"
41
45
  :disabled="props.schema[key].auth === 'readonly'" v-model="data.inputValue[key]"
@@ -119,16 +123,19 @@ const props = defineProps({
119
123
  schema: {
120
124
  type: Object,
121
125
  default: {
122
- type: "String",
123
- label: '名称',
124
- default: '',
125
- //权限取值范围: required 必填 option 选填 readonly 只读 gone 隐藏
126
- auth: 'option'
126
+ title: {
127
+ type: "String",
128
+ label: '标题',
129
+ default: '',
130
+ //权限取值范围: required 必填 option 选填 readonly 只读 gone 隐藏
131
+ auth: 'option',
132
+ submit: null
133
+ }
127
134
  }
128
135
  }
129
136
  })
130
137
 
131
- const emit = defineEmits(['update:modelValue'])
138
+ const emit = defineEmits(['update:modelValue','submitItem'])
132
139
  const modelValue = useVModel(props, 'modelValue', emit)
133
140
  const { isRequired, isReadonly, isGone, isDisabled, rules } = util.props2auth(props)
134
141
 
@@ -138,7 +145,9 @@ const data = reactive({
138
145
  selectIndex: -1,
139
146
  oldModelValue: []
140
147
  })
141
- const keys = Object.keys(props.schema)
148
+
149
+ //过滤掉提交添加/修改/删除的元素回调函数
150
+ const keys = Object.keys(props.schema).filter(k=> k != 'submitItem' && k!='deleteItem')
142
151
  const visiableKeys = keys.filter(k => props.schema[k].auth != 'gone')
143
152
 
144
153
  watch(() => JSON.stringify(modelValue.value), (n, o) => {
@@ -179,6 +188,11 @@ const onBack = (index) => {
179
188
 
180
189
  const onDelete = (index) => {
181
190
  modelValue.value.splice(index, 1)
191
+
192
+ //执行删除数组元素回调
193
+ if(props.schema.deleteItem){
194
+ props.schema.deleteItem(index)
195
+ }
182
196
  }
183
197
 
184
198
  const key2name = (key) => {
@@ -249,7 +263,7 @@ const onNewOption = () => {
249
263
  })
250
264
  }
251
265
 
252
- const onInputConfirm = () => {
266
+ const onInputConfirm = (selectIndex, key, label) => {
253
267
  let idx = modelValue.value.indexOf(item => JSON.stringify(item) === JSON.stringify(data.inputValue))
254
268
  if (idx > -1 && idx != data.selectIndex) {
255
269
  util.warnToast('重复添加')
@@ -264,8 +278,22 @@ const onInputConfirm = () => {
264
278
  return
265
279
  }
266
280
 
281
+ //更新v-model的值
267
282
  modelValue.value[data.selectIndex] = data.inputValue
268
283
 
284
+ //执行每个输入框值提交回调
285
+ keys.forEach(key => {
286
+ if (props.schema[key].submitValue) {
287
+ props.schema[key].submitValue(data.inputValue[key])
288
+ }
289
+ })
290
+
291
+ //执行每个数组元素提交回调
292
+ if(props.schema.submitItem){
293
+ props.schema.submitItem(data.inputValue)
294
+ }
295
+
296
+ //输入框恢复到默认值
269
297
  data.isShowInput = false
270
298
  data.inputValue = makeDefaultValue()
271
299
  data.selectIndex = -1
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <van-field :label="props.label" v-if="!isGone" :disabled="isDisabled" :required="isRequired" :rules="rules"
2
+ <van-field :label="props.label" v-if="!isGone" :disabled="isDisabled" :required="isRequired" :rules="rules" :modelValue="modelValue"
3
3
  :placeholder="props.placeholder">
4
4
 
5
5
  <template #input>
@@ -1,12 +1,8 @@
1
1
  <template>
2
2
  <div class="widget">
3
- <van-field v-if="!isGone" v-model="formatLabel"
4
- :is-link="!isReadonly && !isDisabled"
5
- :label="props.label"
6
- :placeholder="props.placeholder"
7
- :rules="rules"
8
- readonly
9
- :required="isRequired" :disabled="isDisabled" @click="onShow" />
3
+ <van-field v-if="!isGone" v-model="formatLabel" :is-link="!isReadonly && !isDisabled" :label="props.label"
4
+ :placeholder="props.placeholder" :rules="rules" readonly :required="isRequired" :disabled="isDisabled"
5
+ @click="onShow" />
10
6
  <van-popup v-model:show="data.isShow" destroy-on-close round position="bottom">
11
7
  <van-picker :columns="props.options" @cancel="onCancel" @confirm="onConfirm" />
12
8
  </van-popup>
@@ -19,6 +15,10 @@ import util from '../util'
19
15
  import { useVModel } from '@vueuse/core'
20
16
 
21
17
  const props = defineProps({
18
+ modelValue: {
19
+ type: String,
20
+ default: null
21
+ },
22
22
  label: {
23
23
  type: String,
24
24
  default: ''
@@ -40,7 +40,7 @@ const props = defineProps({
40
40
  default: "",
41
41
  },
42
42
  options: {
43
- type:Array,
43
+ type: Array,
44
44
  default: []
45
45
  }
46
46
  })
@@ -59,8 +59,8 @@ const formatLabel = computed(() => {
59
59
  onMounted(() => {
60
60
  })
61
61
 
62
- const onShow=()=>{
63
- if(isReadonly.value || isDisabled.value || isGone.value)
62
+ const onShow = () => {
63
+ if (isReadonly.value || isDisabled.value || isGone.value)
64
64
  return
65
65
 
66
66
  data.isShow = true
@@ -1,6 +1,6 @@
1
1
  <template>
2
2
  <van-field v-if="!isGone"
3
- :label="props.label" :required="isRequired" :rules="rules" :disabled="isDisabled"
3
+ :label="props.label" :required="isRequired" :rules="rules" :disabled="isDisabled" :modelValue="modelValue"
4
4
  :placeholder="props.placeholder" :is-link="isReadonly ? false : true" @click="data.isShowPop = !isReadonly"
5
5
  label-class="label">
6
6
  <template #input>
@@ -1,7 +1,7 @@
1
1
  <template>
2
2
  <van-field v-if="!isGone" :label="props.label" :required="isRequired" :rules="rules" :disabled="isDisabled"
3
3
  :placeholder="props.placeholder" :is-link="isReadonly ? false : true" @click="data.isShowPop = !isReadonly"
4
- label-class="label">
4
+ label-class="label" :modelValue="modelValue">
5
5
  <template #input>
6
6
  <van-tag class="user" v-if="modelValue" :closeable="!isDisabled" type="primary" plain
7
7
  @close.stop="onDelete">
@@ -1,6 +1,6 @@
1
1
  <template>
2
2
  <van-field v-if="!isGone"
3
- :label="props.label" :required="isRequired" :rules="rules" :disabled="isDisabled"
3
+ :label="props.label" :required="isRequired" :rules="rules" :disabled="isDisabled" :modelValue="modelValue"
4
4
  :placeholder="props.placeholder" :is-link="isReadonly ? false : true" @click="data.isShowPop = !isReadonly"
5
5
  label-class="label">
6
6
  <template #input>
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <van-field v-if="!isGone" name="image" :label="props.label" :required="isRequired" :rules="rules"
2
+ <van-field v-if="!isGone" name="image" :label="props.label" :required="isRequired" :rules="rules" :modelValue="modelValue"
3
3
  label-class="label" :placeholder="props.placeholder">
4
4
  <template #input>
5
5
  <div class="image-box">
@@ -4,7 +4,8 @@
4
4
  :required="isRequired"
5
5
  :rules="rules"
6
6
  label-class="label"
7
- :placeholder="props.placeholder">
7
+ :placeholder="props.placeholder"
8
+ :modelValue="modelValue">
8
9
  <template #input>
9
10
  <div class="image-box">
10
11
  <van-uploader v-if="props.capture && (!isReadonly && !isDisabled)" v-model="files" multiple
@@ -9,91 +9,130 @@ import { onMounted, reactive, watch } from "vue";
9
9
 
10
10
  const data = reactive({
11
11
  schema: {
12
+ // name: {
13
+ // label: '房型',
14
+ // type: 'String',
15
+ // default: '',
16
+ // auth: 'required',
17
+ // schema: {
18
+ // options: [
19
+ // {
20
+ // label: "a",
21
+ // value: "a",
22
+ // materials: [
23
+ // {
24
+ // materialId: "jiFdBeVT",
25
+ // quantity: 1,
26
+ // },
27
+ // {
28
+ // materialId: "v6tjBw4R",
29
+ // quantity: 2,
30
+ // }
31
+ // ]
32
+ // },
33
+ // {
34
+ // label: "b",
35
+ // value: "b",
36
+ // materials: [
37
+ // {
38
+ // materialId: "jiFdBeVT",
39
+ // quantity: 1,
40
+ // },
41
+ // {
42
+ // materialId: "v6tjBw4R",
43
+ // quantity: 2,
44
+ // }
45
+ // ]
46
+ // }
47
+ // ]
48
+ // }
49
+ // },
50
+ // quantity: {
51
+ // label: '金额',
52
+ // type: 'Number',
53
+ // default: 0,
54
+ // auth: 'required',
55
+ // },
56
+ // images: {
57
+ // label: '图片',
58
+ // type: 'Images',
59
+ // default: [],
60
+ // auth: 'required',
61
+ // },
12
62
  name: {
13
- label: '房型',
63
+ label: '名称',
14
64
  type: 'String',
15
65
  default: '',
16
66
  auth: 'required',
17
- schema: {
18
- options: [
19
- {
20
- label: "a",
21
- value: "a",
22
- materials: [
23
- {
24
- materialId: "jiFdBeVT",
25
- quantity: 1,
26
- },
27
- {
28
- materialId: "v6tjBw4R",
29
- quantity: 2,
30
- }
31
- ]
32
- },
33
- {
34
- label: "b",
35
- value: "b",
36
- materials: [
37
- {
38
- materialId: "jiFdBeVT",
39
- quantity: 1,
40
- },
41
- {
42
- materialId: "v6tjBw4R",
43
- quantity: 2,
44
- }
45
- ]
46
- }
47
- ]
48
- }
49
- },
50
- quantity: {
51
- label: '数量',
52
- type: 'Number',
53
- default: 1,
54
- auth: 'readonly',
55
- },
56
- images: {
57
- label: '图片',
58
- type: 'Images',
59
- default: [],
60
- auth: 'required',
61
67
  },
62
68
  materials: {
63
- label: '材料表',
64
- type: 'Array',
69
+ type: "Array",
70
+ label: "金额",
65
71
  default: [],
66
72
  auth: 'required',
67
73
  schema: {
68
- materialId: {
69
- label: '材料id',
74
+ title: {
75
+ label: '标题',
70
76
  type: 'String',
71
77
  default: '',
72
78
  auth: 'required',
73
- schema: {
74
- options: [
75
- {
76
- "name": "保温棉",
77
- "materialId": "jiFdBeVT",
78
- "specification": "6mm",
79
- "unit": "m"
80
- },
81
- {
82
- "name": "保温棉",
83
- "materialId": "v6tjBw4R",
84
- "specification": "8mm",
85
- "unit": "m"
86
- }]
87
- }
88
79
  },
89
- quantity: {
90
- label: '数量',
80
+ price: {
81
+ label: '金额(元)',
91
82
  type: 'Number',
92
83
  default: 0,
93
- auth: 'required'
84
+ auth: 'required',
85
+ submitValue: (value) => {
86
+ console.log('++++++submit value price')
87
+ console.log(value)
88
+ },
89
+ },
90
+ submitItem: (value) => {
91
+ console.log('++++++submit item materials')
92
+ console.log(value)
93
+ },
94
+ deleteItem: (index) => {
95
+ console.log('++++++delete item materials')
96
+ console.log(index)
94
97
  }
95
- }
96
- },
98
+ },
99
+ }
100
+
101
+ // materials: {
102
+ // label: '材料表',
103
+ // type: 'Array',
104
+ // default: [],
105
+ // auth: 'required',
106
+ // schema: {
107
+ // materialId: {
108
+ // label: '材料id',
109
+ // type: 'String',
110
+ // default: '',
111
+ // auth: 'required',
112
+ // schema: {
113
+ // options: [
114
+ // {
115
+ // "name": "保温棉",
116
+ // "materialId": "jiFdBeVT",
117
+ // "specification": "6mm",
118
+ // "unit": "m"
119
+ // },
120
+ // {
121
+ // "name": "保温棉",
122
+ // "materialId": "v6tjBw4R",
123
+ // "specification": "8mm",
124
+ // "unit": "m"
125
+ // }]
126
+ // }
127
+ // },
128
+ // quantity: {
129
+ // label: '数量',
130
+ // type: 'Number',
131
+ // default: 0,
132
+ // auth: 'required'
133
+ // }
134
+ // }
135
+ // },
97
136
  },
98
137
  // schema: {
99
138
  // id:{
@@ -256,6 +295,11 @@ const data = reactive({
256
295
  datas: null,
257
296
  })
258
297
 
298
+ const onSubmit = (params) => {
299
+ console.log('+++onSubmit+++++++')
300
+ console.log(params)
301
+ }
302
+
259
303
  watch(() => data.datas, (n, o) => {
260
304
  console.log('>>>>', n)
261
305
  }, {