widget.qw 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.
Files changed (115) hide show
  1. package/README.md +73 -0
  2. package/build/favicon.ico +0 -0
  3. package/build/style.css +763 -0
  4. package/build/widget.qw.es.js +20653 -0
  5. package/build/widget.qw.umd.js +20660 -0
  6. package/index.html +17 -0
  7. package/package.json +47 -0
  8. package/public/favicon.ico +0 -0
  9. package/src/App.vue +26 -0
  10. package/src/api/index.js +126 -0
  11. package/src/assets/avatar.png +0 -0
  12. package/src/assets/banner_handle.png +0 -0
  13. package/src/assets/bg_blue.png +0 -0
  14. package/src/assets/bg_white.png +0 -0
  15. package/src/assets/down.png +0 -0
  16. package/src/assets/home.jpg +0 -0
  17. package/src/assets/icon_box.png +0 -0
  18. package/src/assets/icon_dot.png +0 -0
  19. package/src/assets/icon_draw.png +0 -0
  20. package/src/assets/icon_file.png +0 -0
  21. package/src/assets/icon_fold.png +0 -0
  22. package/src/assets/icon_shield.png +0 -0
  23. package/src/assets/logo.png +0 -0
  24. package/src/components/AuditBar.vue +341 -0
  25. package/src/components/BillCard.vue +156 -0
  26. package/src/components/CheckGroup.vue +114 -0
  27. package/src/components/DatetimePicker/DatetimePop.vue +343 -0
  28. package/src/components/DatetimePicker/index.vue +113 -0
  29. package/src/components/DayDropdown.vue +57 -0
  30. package/src/components/FilePicker.vue +114 -0
  31. package/src/components/Input.vue +72 -0
  32. package/src/components/MonthDropdown.vue +52 -0
  33. package/src/components/MultiPicker.vue +124 -0
  34. package/src/components/ProjectDropdown.vue +62 -0
  35. package/src/components/ProjectPicker.vue +111 -0
  36. package/src/components/SecretNotify.js +6 -0
  37. package/src/components/Sheet.vue +93 -0
  38. package/src/components/SinglePicker.vue +103 -0
  39. package/src/components/SingleUserSelector.vue +425 -0
  40. package/src/components/Switch.vue +65 -0
  41. package/src/components/TreePicker.vue +113 -0
  42. package/src/components/UserPicker.vue +107 -0
  43. package/src/components/UserProfile.vue +128 -0
  44. package/src/components/UsersPicker.vue +118 -0
  45. package/src/components/YearDropdown.vue +60 -0
  46. package/src/components/data_selector.vue +281 -0
  47. package/src/components/image_picker.vue +115 -0
  48. package/src/components/images_picker.vue +140 -0
  49. package/src/components/index.js +157 -0
  50. package/src/components/mult_list_selector.vue +156 -0
  51. package/src/components/product_selector.vue +186 -0
  52. package/src/components/subdepartment_selector.vue +481 -0
  53. package/src/components/user_selector.vue +639 -0
  54. package/src/components/widget/DataPop.vue +96 -0
  55. package/src/components/widget/TreePop.vue +89 -0
  56. package/src/components/widget/UserPop.vue +347 -0
  57. package/src/env.d.ts +8 -0
  58. package/src/main.js +111 -0
  59. package/src/router/index.ts +165 -0
  60. package/src/util/array_util.js +32 -0
  61. package/src/util/auth_util.js +73 -0
  62. package/src/util/bool_util.js +6 -0
  63. package/src/util/bus.js +2 -0
  64. package/src/util/cache_util.js +19 -0
  65. package/src/util/errer_code.js +7 -0
  66. package/src/util/eval_util.js +20 -0
  67. package/src/util/icon_util.js +37 -0
  68. package/src/util/image_util.js +28 -0
  69. package/src/util/index.js +56 -0
  70. package/src/util/num_util.js +71 -0
  71. package/src/util/obj_util.js +29 -0
  72. package/src/util/request.js +74 -0
  73. package/src/util/request_json.js +72 -0
  74. package/src/util/request_json_mute.js +66 -0
  75. package/src/util/request_upload.js +79 -0
  76. package/src/util/route_util.js +32 -0
  77. package/src/util/str_util.js +144 -0
  78. package/src/util/time_util.js +407 -0
  79. package/src/util/toast_util.js +25 -0
  80. package/src/util/tree_util.js +120 -0
  81. package/src/util/validate.js +183 -0
  82. package/src/util/vue_filter.js +223 -0
  83. package/src/views/auditbar/index.vue +66 -0
  84. package/src/views/billcard/index.vue +46 -0
  85. package/src/views/checkgroup/index.vue +36 -0
  86. package/src/views/dataSelector/index.vue +49 -0
  87. package/src/views/datetimepicker/index.vue +35 -0
  88. package/src/views/daydropdown/index.vue +31 -0
  89. package/src/views/filepicker/index.vue +32 -0
  90. package/src/views/home/index.vue +64 -0
  91. package/src/views/imagepicker/index.vue +32 -0
  92. package/src/views/imagespicker/index.vue +32 -0
  93. package/src/views/input/index.vue +35 -0
  94. package/src/views/monthdropdown/index.vue +31 -0
  95. package/src/views/multListSelector/index.vue +61 -0
  96. package/src/views/multipicker/index.vue +37 -0
  97. package/src/views/productSelector/index.vue +35 -0
  98. package/src/views/projectdropdown/index.vue +31 -0
  99. package/src/views/projectpicker/index.vue +42 -0
  100. package/src/views/secretnotify/index.vue +28 -0
  101. package/src/views/sheet/index.vue +46 -0
  102. package/src/views/singlepicker/index.vue +36 -0
  103. package/src/views/subdepartmentSelector/index.vue +41 -0
  104. package/src/views/switch/index.vue +35 -0
  105. package/src/views/treepicker/index.vue +42 -0
  106. package/src/views/userSelector/index.vue +54 -0
  107. package/src/views/userSelectorNew/index.vue +45 -0
  108. package/src/views/userpicker/index.vue +43 -0
  109. package/src/views/userprofile/index.vue +30 -0
  110. package/src/views/userspicker/index.vue +43 -0
  111. package/src/views/yeardropdown/index.vue +32 -0
  112. package/src/vm/index.js +6 -0
  113. package/tsconfig.json +19 -0
  114. package/tsconfig.node.json +8 -0
  115. package/vite.config.ts +73 -0
@@ -0,0 +1,93 @@
1
+ <template>
2
+ <van-field :label="props.label" v-if="!isGone" :disabled="isDisabled" :required="isRequired"
3
+ :placeholder="props.placeholder">
4
+
5
+ <template #input>
6
+ <div class="actionbar" v-if="!isGone && !isDisabled && !isReadonly">
7
+ <van-button icon="plus" type="primary" size="mini" @click="onAdd(0)" />
8
+ </div>
9
+ <div class="item-box" v-for="(item, i) in modelValue" :key="i">
10
+ <slot name="item" :item="item" :auth="props.auth"></slot>
11
+ <div class="actionbar" v-if="!isGone && !isDisabled && !isReadonly">
12
+ <van-button icon="plus" type="primary" size="mini" @click="onAdd(i+1)" />
13
+ <van-button icon="cross" type="primary" size="mini" @click="onDelete(i)" />
14
+ </div>
15
+ </div>
16
+ </template>
17
+
18
+ </van-field>
19
+ </template>
20
+
21
+ <script setup>
22
+ import { ref, computed, onMounted, defineProps, defineEmits, watch } from "vue"
23
+ import { useVModel } from '@vueuse/core'
24
+ import util from '../util'
25
+
26
+ const props = defineProps({
27
+ modelValue: {
28
+ type: Array,
29
+ default: []
30
+ },
31
+ label: {
32
+ type: String,
33
+ default: ''
34
+ },
35
+ placeholder: {
36
+ type: String,
37
+ default: ''
38
+ },
39
+ readonly: {
40
+ type: Boolean,
41
+ default: true
42
+ },
43
+ required: {
44
+ type: Boolean,
45
+ default: false
46
+ },
47
+ auth: {
48
+ type: String,
49
+ default: ''
50
+ }
51
+ })
52
+ const emit = defineEmits(['update:modelValue'])
53
+ const modelValue = useVModel(props, 'modelValue', emit)
54
+ const { isRequired, isReadonly, isGone, isDisabled } = util.props2auth(props)
55
+
56
+ onMounted(() => {
57
+ })
58
+
59
+ const onAdd = (idx) => {
60
+ modelValue.value.splice(idx, 0, {})
61
+ }
62
+
63
+ const onDelete = (idx) => {
64
+ modelValue.value.splice(idx, 1)
65
+ }
66
+
67
+ watch(() => props.modelValue, (o, n) => {
68
+ if (!props.modelValue)
69
+ modelValue.value = []
70
+ }, { immediate: true })
71
+ </script>
72
+
73
+ <style lang="scss" scoped>
74
+ .item-box {
75
+ position: relative;
76
+ padding-bottom: 5px;
77
+ border-bottom: 1px solid #e1e1e1;
78
+ }
79
+
80
+ .actionbar {
81
+ display: flex;
82
+ justify-content: center;
83
+ margin-top: 5px;
84
+ }
85
+
86
+ :deep(.label) {
87
+ color: #000 !important;
88
+ }
89
+
90
+ :deep(.van-field__control--custom) {
91
+ display: block;
92
+ }
93
+ </style>
@@ -0,0 +1,103 @@
1
+ <template>
2
+ <van-field v-if="!isGone" v-model="modelValue" :is-link="!isDisabled" :disabled="isDisabled" readonly name="picker"
3
+ :label="label" label-class="label" :placeholder="props.placeholder" @click-input="onClick" :required="isRequired"
4
+ :rules="props.rules" />
5
+ <van-popup v-model:show="isShowPicker" position="bottom">
6
+ <van-picker :columns="totalOptions" @confirm="onConfirm" @cancel="isShowPicker = false" />
7
+ </van-popup>
8
+ </template>
9
+
10
+ <script setup>
11
+ import { ref, computed, onMounted, defineProps, defineEmits, watch } from "vue"
12
+ import util from "../util"
13
+ import { useVModel } from '@vueuse/core'
14
+
15
+ const props = defineProps({
16
+ id: String,
17
+ modelValue: String,
18
+ label: String,
19
+ placeholder:String,
20
+ readonly: {
21
+ type: Boolean,
22
+ default: true
23
+ },
24
+ required: {
25
+ type: Boolean,
26
+ default: false
27
+ },
28
+ auth: {
29
+ type: String,
30
+ default: ''
31
+ },
32
+ rules: {
33
+ type: Array,
34
+ default: null
35
+ }
36
+ })
37
+ const emit = defineEmits(['update:modelValue'])
38
+ const modelValue = useVModel(props, 'modelValue', emit)
39
+ const totalOptions = computed(() => {
40
+ if (!modelValue.value)
41
+ return columns.value
42
+
43
+ let ary = columns.value.filter(item => item.value == modelValue.value)
44
+ if (ary.length < 1)
45
+ ary = [{ text: modelValue.value, value: modelValue.value }, ...columns.value]
46
+ else
47
+ ary = [...columns.value]
48
+ return ary
49
+ })
50
+ const { isRequired, isGone, isDisabled,isReadonly } = util.props2auth(props)
51
+
52
+ const isShowPicker = ref(false)
53
+ const columns = ref([])
54
+
55
+ onMounted(() => {
56
+ query()
57
+ })
58
+
59
+ const query = async () => {
60
+ let params = {
61
+ id: props.id,
62
+ }
63
+ const res = await util.dictionary_dict(params)
64
+ console.log(res.data)
65
+ if (!res.data.parseValue) {
66
+ columns.value = []
67
+ return
68
+ }
69
+
70
+ columns.value = res.data.parseValue.map(item => {
71
+ return {
72
+ text: item.title,
73
+ value: item.code
74
+ }
75
+ })
76
+ }
77
+
78
+ const onClick = () => {
79
+ if (isDisabled.value)
80
+ return
81
+
82
+ isShowPicker.value = true
83
+ }
84
+
85
+ const onConfirm = ({ selectedOptions }) => {
86
+ console.log("selectedOptions: " + selectedOptions)
87
+ modelValue.value = selectedOptions[selectedOptions.length - 1].value
88
+ isShowPicker.value = false
89
+ }
90
+ </script>
91
+
92
+ <style lang="scss" scoped>
93
+ :deep(.label) {
94
+ color: #000 !important;
95
+ }
96
+
97
+ :deep(.van-field__control:disabled) {
98
+ color: #000 !important;
99
+ cursor: not-allowed;
100
+ opacity: 1;
101
+ -webkit-text-fill-color: #000;
102
+ }
103
+ </style>
@@ -0,0 +1,425 @@
1
+ <template>
2
+ <van-field v-if="!isGone" :is-link="isReadonly ? false : true" readonly :label="props.label"
3
+ :placeholder="props.placeholder" @click="show = !isReadonly" :model-value="selectedUserInfo" :required="isRequired"
4
+ :rules="props.rules" input-align="center" />
5
+ <van-popup v-model:show="show" round position="bottom" class="user-popup">
6
+ <div class="department-selector">
7
+ <div class="picker-header">
8
+ <div class="header-left">
9
+ <van-button @click="goBack" icon="arrow-left" size="small" v-show="currentPath !== '请选择部门'" />
10
+ </div>
11
+
12
+ <!-- 移除header-center包装,直接使用current-path -->
13
+ <div class="current-path">{{ currentPath }}</div>
14
+
15
+ <div class="header-right">
16
+ <van-button size="small" @click="handleClear" class="cancel-btn">清空</van-button>
17
+
18
+ <van-button type="primary" size="small" @click="confirmSelection" class="confirm-btn">确定</van-button>
19
+ </div>
20
+ </div>
21
+
22
+ <!-- 搜索框 -->
23
+ <van-search v-model="searchValue" placeholder="输入工号查询" @clear="clearSearch" @search="handleSearch"
24
+ @cancel="clearSearch" show-action>
25
+ <template #action>
26
+ <div @click="handleSearch">搜索</div>
27
+ </template>
28
+ </van-search>
29
+
30
+ <div class="scroll-container">
31
+ <!-- 遍历部门列表 -->
32
+ <van-cell-group>
33
+ <van-cell v-for="department in departments" :key="department.id" :title="department.name" is-link
34
+ @click="toggleDepartment(department)" />
35
+ </van-cell-group>
36
+
37
+ <!-- 遍历人员列表 -->
38
+ <van-radio-group v-model="tempSelectedUser">
39
+ <van-cell-group>
40
+ <van-cell v-for="user in userlist" :key="user.id" :title="user.name">
41
+ <template #right-icon>
42
+ <van-radio :name="user.userid" />
43
+ </template>
44
+ </van-cell>
45
+ </van-cell-group>
46
+ </van-radio-group>
47
+ </div>
48
+ </div>
49
+ </van-popup>
50
+ </template>
51
+ <script setup>
52
+ import { ref, onMounted, watch } from "vue";
53
+ import util from "../util"
54
+ import { useVModel } from '@vueuse/core'
55
+
56
+ // 弹出层
57
+ const show = ref(false);
58
+
59
+ const props = defineProps({
60
+ modelValue: {
61
+ type: String,
62
+ default: "",
63
+ },
64
+ label: {
65
+ type: String,
66
+ default: "选择人员",
67
+ },
68
+ placeholder: {
69
+ type: String,
70
+ default: "请选择人员",
71
+ },
72
+ required: {
73
+ type: Boolean,
74
+ default: false,
75
+ },
76
+ readonly: {
77
+ type: Boolean,
78
+ default: false,
79
+ },
80
+ rules: {
81
+ type: Array,
82
+ default: () => [],
83
+ },
84
+ // 默认查询所有组织机构
85
+ currentDeptId: {
86
+ type: String,
87
+ default: "1", //组织机构id
88
+ },
89
+ // 二级部门取值范围字典id
90
+ // 取dictionary库.dict的配置id
91
+ deptRangeId: {
92
+ type: String,
93
+ default: ''
94
+ },
95
+ auth: {
96
+ type: String,
97
+ default: "",
98
+ },
99
+ });
100
+ // 定义emit
101
+ const emit = defineEmits(["update:modelValue", "select"]);
102
+ const modelValue = useVModel(props, 'modelValue', emit)
103
+ const { isRequired, isReadonly, isGone, isDisabled } = util.props2auth(props);
104
+
105
+ // 部门列表
106
+ let departments = ref([]);
107
+ let departmentFulls = ref([])
108
+ const searchValue = ref("");
109
+ const currentPath = ref("请选择部门");
110
+ // 定义用户
111
+ const userlist = ref([]);
112
+ // 定义选择单选按钮的值
113
+ const tempSelectedUser = ref(null);
114
+ // 定义展示表单展示区的值
115
+ const selectedUserInfo = ref([]);
116
+
117
+ // 获得部门列表
118
+ const fetchAllDepartments = async () => {
119
+ // 查询所有部门
120
+ const response = await util.get_subdepartments({ departmentId: props.currentDeptId })
121
+ let level2Depts = response.data.subDepartments
122
+
123
+ // 取配置的二级部门取值范围
124
+ let level2DeptIds = []
125
+ if (props.deptRangeId) {
126
+ let res = await util.dictionary_dict({ id: props.deptRangeId })
127
+ if (res.data.parseValue && res.data.parseValue.length>0) {
128
+ level2DeptIds = res.data.parseValue
129
+ }
130
+
131
+ // 当前用户所在二级部门列表
132
+ const user = await getUserInfoById(props.modelValue)
133
+ if (user && user.department.id) {
134
+ level2DeptIds = [...level2DeptIds, user.department.id]
135
+ }
136
+ }
137
+
138
+ // 只保留指定二级部门列表、当前用户的二级部门
139
+ if (props.deptRangeId) {
140
+ if (level2DeptIds && level2DeptIds.length > 0) {
141
+ level2Depts = level2Depts.filter(item => {
142
+ return level2DeptIds.includes(item.id)
143
+ })
144
+ }
145
+ }
146
+
147
+ //departments
148
+ departments.value = getCurrentDepartments(level2Depts || [])
149
+ departmentFulls.value = departments.value;
150
+ };
151
+
152
+ //嵌套处理获得树形结构
153
+ const getCurrentDepartments = (data) => {
154
+ let result = data.map((item) => {
155
+ return {
156
+ id: item.id,
157
+ name: item.name,
158
+ subDepartments: getCurrentDepartments(item.subDepartments || []),
159
+ };
160
+ });
161
+ return result;
162
+ };
163
+ // 添加部门路径查找方法
164
+ function findDeptPath(deptId, tree, path = []) {
165
+ for (const dept of tree) {
166
+ if (dept.id === deptId) {
167
+ return [...path, dept];
168
+ }
169
+ if (dept.subDepartments?.length) {
170
+ const found = findDeptPath(deptId, dept.subDepartments, [...path, dept]);
171
+ if (found && found.length>0) return found;
172
+ }
173
+ }
174
+ return [];
175
+ }
176
+
177
+ // 获得人员列表
178
+ const fetchAllUsers = async (departmentId) => {
179
+ const response = await util.get_subdepartments_users({ departmentId });
180
+ return response.data.users || [];
181
+ };
182
+
183
+ // 通过id获得人员信息
184
+ const getUserInfoById = async (userId) => {
185
+ const response = await util.get_wxuser_by_id({ userId });
186
+ return response.data;
187
+ };
188
+
189
+ // 清空搜索
190
+ const clearSearch = () => {
191
+ searchValue.value = ""; // 清空搜索框
192
+ // 部门列表赋初始值
193
+ departments.value = departmentFulls.value;
194
+ };
195
+
196
+ // 搜索人员
197
+ const handleSearch = () => {
198
+ // 在这里可以处理搜索逻辑
199
+ if (searchValue.value) {
200
+ departments.value = []; // 清空部门列表
201
+ // 搜索用户
202
+ getUserInfoById(searchValue.value).then((user) => {
203
+ if (user) {
204
+ userlist.value = [user];
205
+ //更新currentPath显示用户部门
206
+ const path = findDeptPath(user.mainDepartment, departmentFulls.value);
207
+ console.log("path", path);
208
+ currentPath.value = "";
209
+ path.forEach((dept) => {
210
+ currentPath.value += dept.name + "/";
211
+ });
212
+ } else {
213
+ userlist.value = []; // 清空人员列表
214
+ }
215
+ });
216
+ }
217
+ };
218
+
219
+ // 切换部门
220
+ const toggleDepartment = (department) => {
221
+ console.log("选择了部门:", department.subDepartments);
222
+ departments.value = department.subDepartments;
223
+ // 在这里可以处理部门选择逻辑
224
+ console.log("选择的部门:", departments);
225
+ // 更新当前路径
226
+ if (currentPath.value === "请选择部门") {
227
+ currentPath.value = "";
228
+ }
229
+ currentPath.value += department.name + "/";
230
+ // 请求加载人员
231
+ fetchAllUsers(department.id).then((users) => {
232
+ // 在这里可以处理人员列表逻辑
233
+ userlist.value = users;
234
+ })
235
+ };
236
+
237
+ // 返回上一级部门
238
+ const goBack = () => {
239
+ searchValue.value = ""; // 清空搜索框
240
+ if (currentPath.value === "请选择部门") return;
241
+ currentPath.value = currentPath.value.replace(/\/+$/, "");
242
+ currentPath.value = currentPath.value.substring(
243
+ 0,
244
+ currentPath.value.lastIndexOf("/")
245
+ );
246
+
247
+ if (currentPath.value !== "") {
248
+ // 加载当前路径的部门列表
249
+ const departmentlist = departmentFulls.value.find(
250
+ (dept) => dept.name === currentPath.value.split("/")[0]
251
+ );
252
+ departments.value = departmentlist.subDepartments;
253
+ // 加载当前路径的人员列表
254
+ fetchAllUsers(departmentlist.id).then((users) => {
255
+ userlist.value = users;
256
+ });
257
+ } else {
258
+ currentPath.value = "请选择部门";
259
+ departments.value = departmentFulls.value;
260
+ }
261
+ };
262
+
263
+ // 确认按钮
264
+ const confirmSelection = () => {
265
+ modelValue.value = tempSelectedUser.value
266
+ //对应的人员信息
267
+ const selectedUser = userlist.value.find(
268
+ (user) => user.userid === tempSelectedUser.value
269
+ );
270
+
271
+ selectedUserInfo.value = selectedUser.name;
272
+
273
+ emit('select', selectedUser)
274
+
275
+ show.value = false;
276
+ };
277
+ // 清空按钮
278
+ const handleClear = () => {
279
+ tempSelectedUser.value = null;
280
+ selectedUserInfo.value = null;
281
+ // 清空人员列表
282
+ userlist.value = [];
283
+ show.value = false;
284
+ currentPath.value = "请选择部门";
285
+ departments.value = departmentFulls.value;
286
+ modelValue.value = tempSelectedUser.value
287
+ };
288
+
289
+ //首页加载
290
+ onMounted(async () => {
291
+ await fetchAllDepartments();
292
+ await initDepartment();
293
+ });
294
+
295
+ // 人员初始化
296
+ const initUser = async () => {
297
+ console.log('initUser', props.modelValue, departmentFulls.value)
298
+ if (!props.modelValue || !departmentFulls.value || departmentFulls.value.length < 1)
299
+ return
300
+
301
+ const user = await getUserInfoById(props.modelValue);
302
+ if (user) {
303
+ //更新currentPath显示用户部门
304
+ const path = findDeptPath(user.mainDepartment, departmentFulls.value);
305
+ currentPath.value = "";
306
+ path.forEach((dept) => {
307
+ currentPath.value += dept.name + "/";
308
+ });
309
+ // 清空部门列表
310
+ departments.value = []; // 清空部门列表
311
+ // 加载当前路径的人员列表
312
+ fetchAllUsers(user.mainDepartment).then((users) => {
313
+ userlist.value = users;
314
+ // 选中当前用户
315
+ tempSelectedUser.value = user.userid;
316
+ selectedUserInfo.value = user.name;
317
+ });
318
+ } else {
319
+ userlist.value = []; // 清空人员列表
320
+ }
321
+ };
322
+ // 部门初始化
323
+ const initDepartment = async () => {
324
+ //更新currentPath显示用户部门
325
+ const path = findDeptPath(props.currentDeptId, departmentFulls.value);
326
+ currentPath.value = "";
327
+ path.forEach((dept) => {
328
+ currentPath.value += dept.name + "/";
329
+ });
330
+ // 更新部门列表
331
+ departments.value = departmentFulls.value; // 重置部门列表
332
+ };
333
+
334
+ //监听searchValue变化
335
+ watch(searchValue, (newValue, oldValue) => {
336
+ if (newValue.length === 0) {
337
+ // 重新加载部门列表
338
+ departments.value = departmentFulls.value;
339
+ // 清空人员列表
340
+ userlist.value = [];
341
+ }
342
+ });
343
+ watch(() => modelValue.value, (n, o) => {
344
+ initUser()
345
+ }, {
346
+ immediate: true
347
+ })
348
+ watch(() => departmentFulls.value, (n, o) => {
349
+ initUser()
350
+ }, {
351
+ immediate: true
352
+ })
353
+ </script>
354
+
355
+ <style scoped>
356
+ .user-popup {
357
+ width: 100%;
358
+ overflow: hidden;
359
+ }
360
+
361
+ .department-selector {
362
+ padding: 10px;
363
+ }
364
+
365
+ .search-buttons {
366
+ display: flex;
367
+ gap: 10px;
368
+ }
369
+
370
+ .clear-btn {
371
+ background-color: #f2f3f5;
372
+ border: none;
373
+ border-radius: 4px;
374
+ padding: 4px 8px;
375
+ font-size: 14px;
376
+ }
377
+
378
+ .confirm-btn {
379
+ background-color: #1989fa;
380
+ color: white;
381
+ border: none;
382
+ border-radius: 4px;
383
+ padding: 4px 8px;
384
+ font-size: 14px;
385
+ }
386
+
387
+ .no-results {
388
+ text-align: center;
389
+ padding: 20px;
390
+ color: #969799;
391
+ }
392
+
393
+ .picker-header {
394
+ padding: 10px;
395
+ border-bottom: 1px solid #ebedf0;
396
+ display: flex;
397
+ justify-content: space-between;
398
+ align-items: center;
399
+ }
400
+
401
+ .current-path {
402
+ flex: 1;
403
+ font-size: 14px;
404
+ color: #323233;
405
+ white-space: nowrap;
406
+ overflow: hidden;
407
+ text-overflow: ellipsis;
408
+ }
409
+
410
+ .header-right {
411
+ display: flex;
412
+ gap: 8px;
413
+ margin-left: auto;
414
+ }
415
+
416
+ .cancel-btn {
417
+ color: #969799;
418
+ margin-right: 5px;
419
+ }
420
+
421
+ .scroll-container {
422
+ height: calc(80vh - 150px);
423
+ overflow-y: auto;
424
+ }
425
+ </style>
@@ -0,0 +1,65 @@
1
+ <template>
2
+ <van-field :label="props.label" v-if="!isGone" :disabled="isDisabled" :required="isRequired"
3
+ :placeholder="props.placeholder">
4
+ <template #input>
5
+ <van-switch v-model="modelValue" :disabled="isDisabled" />
6
+ </template>
7
+ </van-field>
8
+ </template>
9
+
10
+ <script setup>
11
+ import { ref, computed, onMounted, defineProps, defineEmits, watch } from "vue"
12
+ import { useVModel } from '@vueuse/core'
13
+ import util from '../util'
14
+
15
+ const props = defineProps({
16
+ modelValue: {
17
+ type: Boolean,
18
+ default: false
19
+ },
20
+ label: {
21
+ type: String,
22
+ default: ''
23
+ },
24
+ placeholder: {
25
+ type: String,
26
+ default: ''
27
+ },
28
+ readonly: {
29
+ type: Boolean,
30
+ default: true
31
+ },
32
+ required: {
33
+ type: Boolean,
34
+ default: false
35
+ },
36
+ auth: {
37
+ type: String,
38
+ default: ''
39
+ }
40
+ })
41
+ const emit = defineEmits(['update:modelValue'])
42
+ const modelValue = useVModel(props, 'modelValue', emit)
43
+ const { isRequired, isReadonly, isGone, isDisabled } = util.props2auth(props)
44
+
45
+ onMounted(() => {
46
+ })
47
+
48
+ watch(()=>props.modelValue,(o,n)=>{
49
+ if(!props.modelValue)
50
+ modelValue.value = false
51
+ },{immediate:true})
52
+ </script>
53
+
54
+ <style lang="scss" scoped>
55
+ :deep(.label) {
56
+ color: #000 !important;
57
+ }
58
+
59
+ :deep(.van-field__control:disabled) {
60
+ color: #000 !important;
61
+ cursor: not-allowed;
62
+ opacity: 1;
63
+ -webkit-text-fill-color: #000;
64
+ }
65
+ </style>