hookehuyr

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

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