hookehuyr

feat(person-picker): 新增人员筛选组件并完善开发配置

新增完整的PersonPickerField人员筛选组件,支持搜索、多选、类型筛选及黑名单展示
封装搜索人员的后端API接口
调整开发环境默认反向代理目标地址至开发服务器
在首页添加临时测试字段方便联调测试
1 -###
2 - # @Date: 2023-02-13 14:56:34
3 - # @LastEditors: hookehuyr hookehuyr@gmail.com
4 - # @LastEditTime: 2025-11-27 16:16:59
5 - # @FilePath: /data-table/.env.development
6 - # @Description: 文件描述
7 -###
8 # 资源公共路径 1 # 资源公共路径
9 VITE_BASE = / 2 VITE_BASE = /
10 3
...@@ -23,11 +16,11 @@ VITE_PIN = ...@@ -23,11 +16,11 @@ VITE_PIN =
23 16
24 # 反向代理服务器地址 17 # 反向代理服务器地址
25 # VITE_PROXY_TARGET = https://oa.anxinchashi.com/ 18 # VITE_PROXY_TARGET = https://oa.anxinchashi.com/
26 -# VITE_PROXY_TARGET = http://oa-dev.onwall.cn 19 +VITE_PROXY_TARGET = http://oa-dev.onwall.cn
27 # VITE_PROXY_TARGET = http://oa.onwall.cn 20 # VITE_PROXY_TARGET = http://oa.onwall.cn
28 # VITE_PROXY_TARGET = https://www.wxgzjs.cn/ 21 # VITE_PROXY_TARGET = https://www.wxgzjs.cn/
29 # VITE_PROXY_TARGET = https://oa.baorongsi.com/ 22 # VITE_PROXY_TARGET = https://oa.baorongsi.com/
30 -VITE_PROXY_TARGET = https://oa.jcedu.org/ 23 +# VITE_PROXY_TARGET = https://oa.jcedu.org/
31 24
32 # PC端地址 25 # PC端地址
33 VITE_MOBILE_URL = http://localhost:5173/ 26 VITE_MOBILE_URL = http://localhost:5173/
......
1 /* 1 /*
2 * @Date: 2022-06-17 14:54:29 2 * @Date: 2022-06-17 14:54:29
3 * @LastEditors: hookehuyr hookehuyr@gmail.com 3 * @LastEditors: hookehuyr hookehuyr@gmail.com
4 - * @LastEditTime: 2024-06-05 10:12:06 4 + * @LastEditTime: 2026-05-25 13:48:13
5 * @FilePath: /data-table/src/api/component.js 5 * @FilePath: /data-table/src/api/component.js
6 * @Description: 组件接口 6 * @Description: 组件接口
7 */ 7 */
...@@ -12,6 +12,7 @@ const Api = { ...@@ -12,6 +12,7 @@ const Api = {
12 FLOW_DEPT_LIST: '/srv/?a=flow_setting&t=flow_dept_list', 12 FLOW_DEPT_LIST: '/srv/?a=flow_setting&t=flow_dept_list',
13 FLOW_ROLE_LIST: '/srv/?a=flow_setting&t=flow_role_list', 13 FLOW_ROLE_LIST: '/srv/?a=flow_setting&t=flow_role_list',
14 SEARCH_USER_DEPT_ROLE: '/srv/?a=flow_setting&t=search_user_dept_role', 14 SEARCH_USER_DEPT_ROLE: '/srv/?a=flow_setting&t=search_user_dept_role',
15 + SEARCH_PERSON_PICKER: '/srv/?a=person_picker_search',
15 } 16 }
16 17
17 /** 18 /**
...@@ -42,3 +43,14 @@ export const getFlowRoleListAPI = (params) => fn(fetch.get(Api.FLOW_ROLE_LIST, p ...@@ -42,3 +43,14 @@ export const getFlowRoleListAPI = (params) => fn(fetch.get(Api.FLOW_ROLE_LIST, p
42 * @param: word 搜索内容 43 * @param: word 搜索内容
43 */ 44 */
44 export const searchUserDeptRoleAPI = (params) => fn(fetch.get(Api.SEARCH_USER_DEPT_ROLE, params)); 45 export const searchUserDeptRoleAPI = (params) => fn(fetch.get(Api.SEARCH_USER_DEPT_ROLE, params));
46 +
47 +/**
48 + * @description: 搜索人员
49 + * @param: form_code 表单code
50 + * @param: field_name 字段名
51 + * @param: keyword 搜索关键字
52 + * @param: type volunteer=义工、contact=联系人
53 + * @param: page 页码,从0开始
54 + * @param: limit 每页数量
55 + */
56 +export const searchPersonPickerAPI = (params) => fn(fetch.get(Api.SEARCH_PERSON_PICKER, params));
......
This diff is collapsed. Click to expand it.
1 +<!--
2 + * @Date: 2026-05-25 17:10:00
3 + * @LastEditors: Codex
4 + * @LastEditTime: 2026-05-25 17:10:00
5 + * @FilePath: /data-table/src/components/PersonPickerField/index.vue
6 + * @Description: 人员筛选控件
7 +-->
8 +<template>
9 + <div v-if="HideShow" class="person-picker-field-page">
10 + <div :class="[isGroup ? 'group-label' : 'label']">
11 + <span v-if="item.component_props.disabled_show"><van-icon name="https://cdn.ipadbiz.cn/custom_form/icon/closed-eye1.png" /></span>
12 + <span v-if="item.component_props.required" style="color: red">&nbsp;*</span>
13 + <span :class="[ReadonlyShow ? 'readonly-show' : '']">{{ item.component_props.label }}</span>
14 + </div>
15 +
16 + <van-field :name="item.key" :rules="rules" style="padding: 0 1rem;">
17 + <template #input>
18 + <my-component />
19 + </template>
20 + </van-field>
21 + </div>
22 +</template>
23 +
24 +<script setup>
25 +import { useRoute } from 'vue-router';
26 +import MyComponent from './MyComponent.vue';
27 +
28 +const $route = useRoute();
29 +const props = defineProps({
30 + item: Object,
31 +});
32 +
33 +// 注入子组件属性,复用现有字段组件的表单接入方式。
34 +provide('props', props.item);
35 +
36 +// 隐藏显示
37 +const HideShow = computed(() => {
38 + return !props.item.component_props.disabled;
39 +});
40 +
41 +// 只读显示-流程模式
42 +const ReadonlyShow = computed(() => {
43 + return ($route.query.page_type === 'flow' || $route.query.page_type === 'edit') && !props.item.component_props.readonly;
44 +});
45 +
46 +// 集合组标识
47 +const isGroup = computed(() => {
48 + return props.item.component_props.is_field_group;
49 +});
50 +
51 +const required = props.item.component_props.required;
52 +const validator = (val) => {
53 + if (!required) {
54 + return true;
55 + }
56 + return Array.isArray(val) && val.length > 0;
57 +};
58 +const validatorMessage = (val, rule) => {
59 + if (required && (!Array.isArray(val) || !val.length)) {
60 + return '选择不能为空';
61 + }
62 +};
63 +const rules = [{ validator, message: validatorMessage }];
64 +</script>
65 +
66 +<style lang="less" scoped>
67 +.person-picker-field-page {
68 + .label {
69 + padding: 1rem 1rem 0 1rem;
70 + font-size: 0.9rem;
71 + font-weight: bold;
72 + }
73 +
74 + .group-label {
75 + padding: 0.75rem 0 0.75rem 1rem;
76 + font-size: 0.9rem;
77 + font-weight: bold;
78 + background-color: #f9f9f9;
79 + color: #666;
80 + border-top: 1px solid #eee;
81 + border-bottom: 1px solid #eee;
82 +
83 + span {
84 + color: red;
85 + }
86 + }
87 +}
88 +</style>
...@@ -33,6 +33,7 @@ import AppointmentField from '@/components/AppointmentField/index.vue'; ...@@ -33,6 +33,7 @@ import AppointmentField from '@/components/AppointmentField/index.vue';
33 import CustomField from '@/components/CustomField/index.vue'; 33 import CustomField from '@/components/CustomField/index.vue';
34 import GroupField from '@/components/GroupField/index.vue'; 34 import GroupField from '@/components/GroupField/index.vue';
35 import OrgPickerField from '@/components/OrgPickerField/index.vue'; 35 import OrgPickerField from '@/components/OrgPickerField/index.vue';
36 +import PersonPickerField from '@/components/PersonPickerField/index.vue';
36 import VolunteerGroupField from '@/components/VolunteerGroupField/index.vue'; 37 import VolunteerGroupField from '@/components/VolunteerGroupField/index.vue';
37 38
38 /** 39 /**
...@@ -66,6 +67,7 @@ import VolunteerGroupField from '@/components/VolunteerGroupField/index.vue'; ...@@ -66,6 +67,7 @@ import VolunteerGroupField from '@/components/VolunteerGroupField/index.vue';
66 * @type appointment 预约控件 AppointmentField 67 * @type appointment 预约控件 AppointmentField
67 * @type group 组集合输入控件 GroupField 68 * @type group 组集合输入控件 GroupField
68 * @type org_picker 树形选择控件 OrgPickerField 69 * @type org_picker 树形选择控件 OrgPickerField
70 + * @type person_picker 人员筛选控件 PersonPickerField
69 * @type volunteer_group 义工组别选择控件 VolunteerGroupField 71 * @type volunteer_group 义工组别选择控件 VolunteerGroupField
70 * @type table 表格控件 TableField 72 * @type table 表格控件 TableField
71 */ 73 */
...@@ -183,6 +185,9 @@ export function createComponentType(data) { ...@@ -183,6 +185,9 @@ export function createComponentType(data) {
183 if (item.component_props.tag === 'org_picker') { 185 if (item.component_props.tag === 'org_picker') {
184 item.component = OrgPickerField; 186 item.component = OrgPickerField;
185 } 187 }
188 + if (item.component_props.tag === 'person_picker') {
189 + item.component = PersonPickerField;
190 + }
186 if (item.component_props.tag === 'volunteer_group') { 191 if (item.component_props.tag === 'volunteer_group') {
187 item.component = VolunteerGroupField; 192 item.component = VolunteerGroupField;
188 } 193 }
......
1 <!-- 1 <!--
2 * @Date: 2022-07-18 10:22:22 2 * @Date: 2022-07-18 10:22:22
3 * @LastEditors: hookehuyr hookehuyr@gmail.com 3 * @LastEditors: hookehuyr hookehuyr@gmail.com
4 - * @LastEditTime: 2025-11-27 16:25:10 4 + * @LastEditTime: 2026-05-25 13:58:52
5 * @FilePath: /data-table/src/views/index.vue 5 * @FilePath: /data-table/src/views/index.vue
6 * @Description: 首页 6 * @Description: 首页
7 --> 7 -->
...@@ -509,6 +509,25 @@ onMounted(async () => { ...@@ -509,6 +509,25 @@ onMounted(async () => {
509 // "interaction_type": "h5edit" 509 // "interaction_type": "h5edit"
510 // }) 510 // })
511 511
512 + // 临时测试字段:直接挂到页面渲染链里,方便联调人员搜索多选组件。
513 + page_form.push({
514 + tag: 'person_picker',
515 + name: 'person_picker_temp',
516 + index: 999999,
517 + label: '人员筛选(临时测试)',
518 + unique: false,
519 + default: [],
520 + disabled: false,
521 + field_id: 999999,
522 + readonly: false,
523 + required: false,
524 + data_type: 'text',
525 + field_name: 'field_person_picker_temp',
526 + placeholder: '请输入关键词后搜索人员',
527 + interaction_type: 'h5edit',
528 + person_type: '',
529 + });
530 +
512 formData.value = formatData(page_form); 531 formData.value = formatData(page_form);
513 // TAG: 构建分页组件 532 // TAG: 构建分页组件
514 if (page_type === 'add' || page_type === undefined || model === 'preview') { 533 if (page_type === 'add' || page_type === undefined || model === 'preview') {
......