vue3中,父子组件props传函数写法-传动态接口 & 特殊字符校验 & 封装公共input组件
效果
代码
1、主页面
index.vue
<template>
<div>
<el-form ref="formRef" label-width="132px" :model="formInline">
<el-form-item
label="项目名称:"
:rules="[
{
validator: validateCommonText,
trigger: ['blur', 'change'],
},
]"
>
<el-input
v-model="formInline.prjName"
:disabled="route.query.type === 'edit' || route.query.type === 'view'"
maxlength="100"
placeholder="请选择项目"
@click="handlePrjName"
>
<template #prefix>
<el-icon class="el-input__icon"><search /></el-icon>
</template>
</el-input>
</el-form-item>
</el-form>
<SelectProject
v-model:dataType="dataType"
v-model:dialogVisible="dialogProject"
v-model:prjData="formInline"
:prj-category="1"
:request-url="queryPrjNoPlan"
/>
</div>
</template>
<script setup>
import { queryPrjNoPlan } from "@/api/process/maven";
import SelectProject from "@/components/SelectProject";
import { validateCommonText } from "@src/utils/validate";
const router = useRouter();
const route = useRoute();
const formRef = ref();
const dataType = ref("project");
const formInline = ref({
prjName: "",
});
const dialogProject = ref(false);
const handlePrjName = () => {
dialogProject.value = true;
};
</script>
接口文件
src\app\science\api\process\maven.js
import request from '@src/utils/request'
import { sciencePostUrl } from '@/config'
//选择项目
export const queryPrjNoPlan = (data) => {
return request({
url: `${sciencePostUrl}/supvis/queryPrjNoPlan`,
method: 'post',
data,
})
}
方法文件
src\utils\validate.ts
/**
* @description form表单特定字符校验
* @param value
* @returns {boolean}
*/
export function validateCommonText(rule: any, value: any, callback: any) {
const noChars = "[`~!#$^&*\"()=|{}': ; ',\\[\\].<>/?~!#¥……&*()——|{}【】‘;:”“'。,、?]‘'@ /%"
const v = value || ''
for (let i = 0; i < noChars.length; i++) {
const char = noChars[i]
if (v.indexOf(char) != -1) {
// callback(new Error('不能使用字符:' + noChars))
callback(new Error('不能使用特殊字符'))
return
}
}
2、组件界面
src\app\science\components\SelectProject.vue
<!--
dialogVisible // 弹窗显隐
dataType // 弹窗数据类型 project项目数据
prjData // 选择后项目数据
prjCategory // 项目分类 1 公司级,2 国家级,3 各单位自管, 100可研申报
emit-select // 项目选择后回调方法
requestUrl // 新的项目请求接口
-->
<template>
<el-dialog
v-model="dialogVisible"
class="diaStyle"
:modal="false"
style="height: 80vh; overflow-y: auto"
:title="dataType === 'project' ? '选择项目' : ''"
>
<el-form
ref="formRef"
class="inline-form"
:inline="true"
label-position="right"
label-width="100px"
:model="formInline"
>
<el-form-item
label="项目名称:"
prop="prjName"
:rules="[
{
validator: validateCommonText,
trigger: ['blur', 'change'],
},
]"
>
<el-input
v-model="formInline.prjName"
maxlength="100"
placeholder="请输入"
/>
</el-form-item>
<el-form-item
label="牵头单位:"
prop="leadUnit"
:rules="[
{
validator: validateCommonText,
trigger: ['blur', 'change'],
},
]"
>
<unitSelect v-model="formInline.leadUnit" />
</el-form-item>
<el-form-item class="search_btn" style="float: right">
<el-button type="primary" @click="onSubmit">查询</el-button>
<el-button plain type="primary" @click="resetForm">重置</el-button>
</el-form-item>
</el-form>
<el-table
ref="multipleTable"
:data="tableData"
highlight-current-row
@row-click="onSelect"
@select-all="onSelectAll"
@selection-change="selectItem"
>
<el-table-column width="55">
<template #default="{ row }">
<el-radio v-model="templateSelete" :label="row.id">{{ '' }}</el-radio>
</template>
</el-table-column>
<el-table-column label="项目名称" prop="prjName" />
<el-table-column label="牵头单位" prop="leadUnitName" />
<el-table-column label="项目负责人" prop="prjHeadName" />
</el-table>
<el-pagination
background
:current-page="page.currentPage"
layout="total,size,prev,pager,next,jumper"
:page-size="page.pageSize"
:total="page.total"
@current-change="hanleCurrentChange"
/>
<template #footer>
<span class="dialog-footer">
<el-button plain type="primary" @click="cancelDialog">取消</el-button>
<el-button type="primary" @click="submitDialog">确定</el-button>
</span>
</template>
</el-dialog>
</template>
<script setup>
import { projectData, feasStuPage } from '@/api/projectChange/index'
import unitSelect from '@src/components/unitSelect'
import { validateCommonText } from '@src/utils/validate'
const multipleTable = ref(null)
const formRef = ref(null)
const multipleSelection = ref()
const props = defineProps({
dialogVisible: {
default: null,
type: Boolean,
},
dataType: {
default: null,
type: String,
},
prjData: {
default: null,
type: Object,
},
prjCategory: {
default: null,
type: Number,
},
requestUrl: {
default: null,
type: Function,
},
})
const { dataType, prjCategory, requestUrl } = toRefs(props)
const emit = defineEmits([
'update:dialogVisible',
'update:prjData',
'emit-select',
])
const dialogVisible = computed({
get: () => props.dialogVisible,
set: (val) => emit('update:dialogVisible', val),
})
const page = reactive({
pageSize: 10,
currentPage: 1,
total: 0,
})
const templateSelete = ref('')
const tableData = ref([])
//查询
const formInline = ref({
prjName: '',
techFieldName: '',
leadUnit: '',
})
if (dialogVisible) {
formInline.value = {
prjName: '',
techFieldName: '',
leadUnit: '',
}
}
//重置
const resetForm = () => {
// if (!formEl) return
formRef.value.resetFields()
onLoad()
}
const onSubmit = async () => {
page.currentPage = 1
onLoad()
}
const hanleCurrentChange = (val) => {
page.currentPage = val
onLoad()
}
const onLoad = async () => {
const formData = {
size: page.pageSize,
current: page.currentPage,
prjCategory: prjCategory.value,
...formInline.value,
state: '4',
}
if (requestUrl.value) {
await requestUrl.value(formData).then((res) => {
tableData.value = res.data.data
page.pageSize = res.data.pageSize
page.total = Number(res.data.total)
page.currentPage = res.data.pageNumber
})
} else if (prjCategory.value == 100) {
formData.processState = '4'
formData.leadUnitId = formData.leadUnit
await feasStuPage(formData).then((res) => {
res.data.records.forEach((el) => {
el.leadUnitName = el.leadUnitId
el.prjHeadName = el.headName
})
tableData.value = res.data.records
page.pageSize = res.data.pageSize
page.total = res.data.total
page.currentPage = res.data.pageNumber
})
} else {
await projectData(formData).then((res) => {
tableData.value = res.data.records
page.pageSize = res.data.pageSize
page.total = res.data.total
page.currentPage = res.data.pageNumber
})
}
}
onLoad()
const onSelectAll = () => {
multipleTable.value.clearSelection()
}
const selectItem = (rows) => {
if (rows.length > 1) {
const newRows = rows.filter((it, index) => {
if (index === rows.length - 1) {
multipleTable.value.toggleRowSelection(it, true)
return true
} else {
multipleTable.value.toggleRowSelection(it, false)
return false
}
})
multipleSelection.value = newRows
} else {
multipleSelection.value = rows
}
}
const onSelect = (row) => {
templateSelete.value = row.id
multipleTable.value.clearSelection()
multipleTable.value.toggleRowSelection(row, true)
multipleSelection.value = []
multipleSelection.value.push(row)
}
const cancelDialog = () => {
emit('update:dialogVisible', false)
}
const submitDialog = async () => {
if (multipleSelection.value) {
multipleSelection.value[0].prjId = multipleSelection.value[0].id
emit('update:prjData', multipleSelection.value[0])
emit('update:dialogVisible', false)
emit('emit-select', multipleSelection.value)
} else {
ElMessage.error('请选择项目')
}
}
</script>
<style lang="scss" scoped></style>
接口文件
src\app\science\api\projectChange\index.js
import request from '@src/utils/request'
import { sciencePostUrl } from '@/config'
//变更管理-项目-选择项目审核通过的
export const projectData = (data) => {
return request({
url: `${sciencePostUrl}/prjChange/queryItem`,
method: 'post',
data,
})
}
//可研申报-项目-选择项目审核通过的
export const feasStuPage = (data) => {
return request({
url: `${sciencePostUrl}/feasStu/feasStuPage`,
method: 'post',
data,
})
}
3、子组件界面
src\components\unitSelect.vuesrc\components\unitSelect.vue
<!--
modelValue //select的值 code值
disabled //是否编辑
contrUnitName //回显是select的name 值
change-unit //回调方法: 参数为选择后单位相关的数据
labelCode //二级单位数据传对应labelCode
orgcode //组织树下拉数据筛选条件
-->
<template>
<div style="width: 100%">
<el-select
v-if="labelCode"
v-model="unitValue"
:disabled="disabled"
filterable
placeholder="请选择单位"
@change="selectUnitEvent"
>
<el-option
v-for="item in companyLabelData"
:key="item.id"
:label="item.orgObjMdmName"
:value="item.orgObjCode"
/>
</el-select>
<el-select
v-else-if="orgcode"
v-model="unitValue"
:disabled="disabled"
filterable
placeholder="请选择单位"
@change="selectUnitEvent"
>
<el-option
v-for="item in companyData"
:key="item.id"
:label="item.orgObjMdmName"
:value="item.orgObjCode"
/>
</el-select>
<el-select
v-else
v-model="unitValue"
clearable
:disabled="disabled"
filterable
:loading="loading"
placeholder="请搜索单位"
remote
:remote-method="remoteMethod"
reserve-keyword
@change="selectUnitEvent"
>
<template #prefix>
<el-icon class="el-input__icon"><search /></el-icon>
</template>
<el-option
v-for="item in companyData"
:key="item.id"
:label="item.orgObjMdmName"
:value="item.orgObjCode"
/>
</el-select>
</div>
</template>
<script setup>
import { getUnits, getLabelUnits } from '@src/api/common/base'
import { Search } from '@element-plus/icons-vue'
const props = defineProps({
modelValue: {
default: null,
type: Number,
},
contrUnitName: {
default: null,
type: String,
},
labelCode: {
default: null,
type: Array,
},
disabled: {
default: false,
type: Boolean,
},
orgcode: {
default: '',
type: String,
},
})
const ruleForm = ref({
orgObjMdmNameLike: '',
current: '1',
size: 100,
})
const { labelCode, disabled, orgcode } = toRefs(props)
const emit = defineEmits(['update:modelValue', 'change-unit'])
const companyData = ref()
const companyLabelData = ref()
onMounted(() => {
watch(
() => props.modelValue,
(newVal) => {
if (newVal) {
nextTick(() => {
if (props.labelCode && !companyLabelData.value.length) {
getLabelUnitsList()
} else if (props.orgcode && !companyData.value.length) {
getUnitsList()
} else if (!props.orgcode) {
companyData.value = [
{
orgObjMdmName: props.contrUnitName,
orgObjCode: props.modelValue,
},
]
}
})
}
},
{ immediate: true }
)
})
//接口文档调取
const getUnitsList = async () => {
ruleForm.value.porgObjCodeInner = orgcode.value
const pattern = /[_]$/
if (!pattern.test(ruleForm.value.orgObjMdmNameLike)) {
await getUnits(ruleForm.value).then((res) => {
companyData.value = res.data.list
})
}
}
const getLabelUnitsList = async () => {
await getLabelUnits({ labelCode: labelCode.value }).then((res) => {
companyLabelData.value = res.data
})
}
if (labelCode.value && labelCode.value.length) {
getLabelUnitsList()
} else if (orgcode.value && orgcode.value.length) {
getUnitsList()
}
const unitValue = toRef(props, 'modelValue')
const selectUnitEvent = (val) => {
emit('update:modelValue', val)
let obj
if (labelCode.value && labelCode.value.length) {
obj = val
? companyLabelData.value.find(function (item) {
return item.orgObjCode === val
})
: { orgObjCode: '', orgObjMdmName: '' }
} else {
obj = val
? companyData.value.find(function (item) {
return item.orgObjCode === val
})
: { orgObjCode: '', orgObjMdmName: '' }
}
emit('change-unit', obj)
}
//过滤筛选关键字数据
const loading = ref(false)
const remoteMethod = (query) => {
if (query) {
ruleForm.value.orgObjMdmNameLike = query
loading.value = true
setTimeout(() => {
loading.value = false
getUnitsList()
}, 200)
} else {
companyData.value = []
}
}
</script>
接口文件
src\api\common\base.js
import request from '@src/utils/request'
//枚举值查询 process.env.VUE_APP_URL--> apiUrl
const configInfo = sessionStorage.getItem('configInfo') || '{}'
const apiUrl = JSON.parse(configInfo)?.baseApiUrl || 'http://27.76.34.99/kjapi'
//模糊搜索单位下拉数据
export const getUnits = (data) => {
return request({
url: `${apiUrl}/srbm-bas-mdm-front/member/feignDataRel/org/page`,
method: 'post',
data,
})
}
//二级单位数据
export const getLabelUnits = (data) => {
return request({
url: `${apiUrl}/srbm-bas-mdm-front/member/feignDataRel/org/search`,
method: 'post',
data,
})
}