7 changed files with 1333 additions and 1295 deletions
@ -0,0 +1,431 @@ |
|||||
|
<template> |
||||
|
<div class="section"> |
||||
|
<div class="section-title">执法信息</div> |
||||
|
|
||||
|
<!-- 是否关联预告 --> |
||||
|
<van-field v-model="formData.relatedNotice" is-link readonly name="relatedNotice" label="是否关联预告" |
||||
|
placeholder="请选择" @click="$emit('showNoticePicker')" clearable /> |
||||
|
|
||||
|
<!-- 执法单位 --> |
||||
|
<van-field v-model="formData.enforcementUnit" name="enforcementUnit" label="执法单位" placeholder="请输入执法单位" |
||||
|
:rules="[{ required: true, message: '请填写执法单位' }]" required /> |
||||
|
|
||||
|
<!-- 执法人员 --> |
||||
|
<div class="form-row required"> |
||||
|
<div class="form-label"><span class="required-mark">*</span>执法人员</div> |
||||
|
<div class="form-value person-select"> |
||||
|
<div class="person-item default-person"> |
||||
|
<span>{{ defaultPerson?.name }} {{ defaultPerson?.id }}</span> |
||||
|
</div> |
||||
|
<div v-for="(person, index) in additionalPersons" :key="index" class="person-item-add"> |
||||
|
<span @click="$emit('openPersonPicker', index)" :class="{ placeholder: !person.name }"> |
||||
|
{{ person.name || '请选择' }} |
||||
|
</span> |
||||
|
<van-icon name="close" class="remove-icon" @click="$emit('removePerson', index)" /> |
||||
|
</div> |
||||
|
<div class="person-add"> |
||||
|
<span @click="$emit('openPersonPicker', -1)">请选择</span> |
||||
|
<van-icon name="add-o" class="add-circle-icon" @click="$emit('addPerson')" /> |
||||
|
</div> |
||||
|
</div> |
||||
|
|
||||
|
</div> |
||||
|
<!-- 隐藏字段用于验证执法人员 --> |
||||
|
<van-field v-model="hasPerson" name="enforcementPerson" :rules="[{ required: true, message: '请选择执法人员' }]" |
||||
|
style="display: none;" /> |
||||
|
|
||||
|
<!-- 执法类别 --> |
||||
|
<van-field v-model="formData.category" is-link readonly name="category" label="执法类别" placeholder="请选择" |
||||
|
@click="$emit('showCategoryPicker')" clearable :rules="[{ required: true, message: '请选择执法类别' }]" required /> |
||||
|
|
||||
|
<!-- 任务来源 --> |
||||
|
<van-field v-model="formData.taskSource" is-link readonly name="taskSource" label="任务来源" placeholder="请选择" |
||||
|
@click="$emit('showTaskSourcePicker')" clearable :rules="[{ required: true, message: '请选择任务来源' }]" |
||||
|
required /> |
||||
|
|
||||
|
<!-- 执法事项 --> |
||||
|
<van-field v-model="formData.enforcementMatter" name="enforcementMatter" label="执法事项" placeholder="请输入执法事项" |
||||
|
type="textarea" :rules="[{ required: true, message: '请填写执法事项' }]" required rows="3" maxlength="1000" |
||||
|
show-word-limit /> |
||||
|
|
||||
|
<!-- 执法依据 --> |
||||
|
<div class="basis-container"> |
||||
|
<div v-for="(basis, index) in formData.enforcementBases" :key="index" class="form-row basis-row"> |
||||
|
<div class="form-label">执法依据</div> |
||||
|
<div class="form-value basis-wrapper"> |
||||
|
<span @click="$emit('openBasisPicker', index)" :class="{ placeholder: !basis }"> |
||||
|
{{ basis || '请选择' }} |
||||
|
</span> |
||||
|
<van-icon v-if="index === formData.enforcementBases.length - 1" name="add-o" class="add-circle-icon" |
||||
|
@click.stop="$emit('addBasis')" /> |
||||
|
<van-icon v-else name="close" class="close-btn" @click.stop="$emit('removeBasis', index)" /> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
|
||||
|
<!-- 原因 --> |
||||
|
<van-field v-model="formData.reason" name="reason" label="原因" placeholder="请输入原因" readonly /> |
||||
|
|
||||
|
<!-- 执法时间 --> |
||||
|
<van-field v-model="formData.enforcementTime" name="enforcementTime" label="执法时间" placeholder="请选择执法时间" |
||||
|
readonly /> |
||||
|
<!-- <van-field v-model="formData.enforcementTime" name="enforcementTime" label="执法时间" placeholder="请选择执法时间" is-link |
||||
|
readonly :rules="[{ required: true, message: '请选择执法时间' }]" required /> --> |
||||
|
|
||||
|
<!-- 联合执法 --> |
||||
|
</div> |
||||
|
<div class="form-section"> |
||||
|
<div class=""> |
||||
|
<van-field name="radio" label="联合执法" required> |
||||
|
<template #input> |
||||
|
<van-radio-group v-model="formData.jointEnforcement" direction="horizontal"> |
||||
|
<van-radio name="0" shape="square">否</van-radio> |
||||
|
<van-radio name="1" shape="square">是</van-radio> |
||||
|
</van-radio-group> |
||||
|
</template> |
||||
|
</van-field> |
||||
|
<!-- <div class="form-label"><span class="required-mark">*</span>联合执法</div> |
||||
|
<div class="form-value radio-group"> |
||||
|
<label :class="['radio-option', { active: formData.jointEnforcement === false }]" |
||||
|
@click="formData.jointEnforcement = false"> |
||||
|
否 |
||||
|
</label> |
||||
|
<label :class="['radio-option', { active: formData.jointEnforcement === true }]" |
||||
|
@click="formData.jointEnforcement = true"> |
||||
|
是 |
||||
|
</label> |
||||
|
</div> --> |
||||
|
</div> |
||||
|
<!-- 隐藏字段用于验证联合执法 --> |
||||
|
<van-field v-model="jointEnforcementValue" name="jointEnforcement" |
||||
|
:rules="[{ required: true, message: '请选择联合执法' }]" style="display: none;" /> |
||||
|
</div> |
||||
|
<div class="form-entrusted"> |
||||
|
<!-- 受委托执法 --> |
||||
|
<div class="entrusted-enforcement"> |
||||
|
<van-field name="radio" label="受委托执法" required> |
||||
|
<template #input> |
||||
|
<van-radio-group v-model="formData.entrustedEnforcement" direction="horizontal"> |
||||
|
<van-radio name="0" shape="square">否</van-radio> |
||||
|
<van-radio name="1" shape="square">是</van-radio> |
||||
|
</van-radio-group> |
||||
|
</template> |
||||
|
</van-field> |
||||
|
<!-- <div class="form-label"><span class="required-mark">*</span>受委托执法</div> |
||||
|
<div class="form-value radio-group"> |
||||
|
<label :class="['radio-option', { active: formData.entrustedEnforcement === false }]" |
||||
|
@click="formData.entrustedEnforcement = false"> |
||||
|
否 |
||||
|
</label> |
||||
|
<label :class="['radio-option', { active: formData.entrustedEnforcement === true }]" |
||||
|
@click="formData.entrustedEnforcement = true"> |
||||
|
是 |
||||
|
</label> |
||||
|
</div> --> |
||||
|
</div> |
||||
|
<!-- 隐藏字段用于验证受委托执法 --> |
||||
|
<van-field v-model="entrustedEnforcementValue" name="entrustedEnforcement" |
||||
|
:rules="[{ required: true, message: '请选择受委托执法' }]" style="display: none;" /> |
||||
|
<div class="form-hint">本次执法是否为受委托事项</div> |
||||
|
|
||||
|
<!-- 附件 --> |
||||
|
<div class="file-upload-row"> |
||||
|
<div class="file-upload-label">附件 <span class="form-text">(不多于8张)</span></div> |
||||
|
<div class="uploader-wrapper"> |
||||
|
<van-uploader v-model="formData.fileList" multiple :max-count="8" :after-read="onAfterReadImage" /> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</template> |
||||
|
|
||||
|
<script setup name="EnforcementInfoSection"> |
||||
|
import { computed } from 'vue'; |
||||
|
import { uploadFile } from '@/util/fileUpload'; |
||||
|
|
||||
|
const props = defineProps({ |
||||
|
formData: { |
||||
|
type: Object, |
||||
|
required: true |
||||
|
}, |
||||
|
defaultPerson: { |
||||
|
type: Object, |
||||
|
default: null |
||||
|
}, |
||||
|
additionalPersons: { |
||||
|
type: Array, |
||||
|
default: () => [] |
||||
|
} |
||||
|
}); |
||||
|
|
||||
|
defineEmits([ |
||||
|
'showNoticePicker', |
||||
|
'openPersonPicker', |
||||
|
'removePerson', |
||||
|
'showCategoryPicker', |
||||
|
'showTaskSourcePicker', |
||||
|
'openBasisPicker', |
||||
|
'addBasis', |
||||
|
'removeBasis' |
||||
|
]); |
||||
|
|
||||
|
// 计算属性:是否有执法人员 |
||||
|
const hasPerson = computed(() => { |
||||
|
return props.defaultPerson?.name || props.additionalPersons.some(p => p.name); |
||||
|
}); |
||||
|
|
||||
|
// 联合执法值(用于验证) |
||||
|
const jointEnforcementValue = computed(() => { |
||||
|
return props.formData.jointEnforcement !== undefined ? '已选择' : ''; |
||||
|
}); |
||||
|
|
||||
|
// 受委托执法值(用于验证) |
||||
|
const entrustedEnforcementValue = computed(() => { |
||||
|
return props.formData.entrustedEnforcement !== undefined ? '已选择' : ''; |
||||
|
}); |
||||
|
|
||||
|
// 附件上传处理 |
||||
|
const onAfterReadImage = (file) => { |
||||
|
const files = Array.isArray(file) ? file : [file]; |
||||
|
files.forEach(f => { |
||||
|
uploadFile(f, (res) => { |
||||
|
const data = res && res.data ? res.data : res; |
||||
|
const filePath = typeof data === 'string' ? data : (data && (data.url || data.fileUrl || data.path)) || ''; |
||||
|
if (filePath) { |
||||
|
f.url = filePath; |
||||
|
f.status = 'done'; |
||||
|
} |
||||
|
}); |
||||
|
}); |
||||
|
}; |
||||
|
</script> |
||||
|
|
||||
|
<style lang="less" scoped> |
||||
|
.section { |
||||
|
background: #fff; |
||||
|
border-radius: 0.16rem; |
||||
|
margin-bottom: 0.24rem; |
||||
|
overflow: hidden; |
||||
|
|
||||
|
:deep(.van-field__label) { |
||||
|
margin-right: 6px; |
||||
|
color: #000; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.section-title { |
||||
|
padding: 0.28rem 0.32rem; |
||||
|
font-size: 16px; |
||||
|
font-weight: 600; |
||||
|
color: #000; |
||||
|
} |
||||
|
|
||||
|
.form-row { |
||||
|
display: flex; |
||||
|
justify-content: space-between; |
||||
|
// align-items: center; |
||||
|
padding: 0.32rem; |
||||
|
border-bottom: 1px solid #f0f0f0; |
||||
|
|
||||
|
&:last-child { |
||||
|
border-bottom: none; |
||||
|
} |
||||
|
|
||||
|
&.clickable { |
||||
|
&:active { |
||||
|
background: #f9f9f9; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
&.required .form-label { |
||||
|
position: relative; |
||||
|
padding-left: 0.1rem; |
||||
|
} |
||||
|
|
||||
|
&.radio-row { |
||||
|
padding-top: 0.24rem; |
||||
|
padding-bottom: 0.24rem; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
} |
||||
|
|
||||
|
.attachment-row {} |
||||
|
|
||||
|
.required-mark { |
||||
|
color: #ee0a24; |
||||
|
font-size: 0.32rem; |
||||
|
margin-right: 0.08rem; |
||||
|
font-weight: bold; |
||||
|
} |
||||
|
|
||||
|
.form-label { |
||||
|
font-size: 14px; |
||||
|
color: #333; |
||||
|
flex: none; |
||||
|
width: 2.4rem; |
||||
|
font-weight: 500; |
||||
|
} |
||||
|
|
||||
|
.form-value { |
||||
|
flex: 1; |
||||
|
font-size: 14px; |
||||
|
color: #333; |
||||
|
display: flex; |
||||
|
align-items: center; |
||||
|
|
||||
|
.placeholder { |
||||
|
color: #c8c9cc; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.person-select { |
||||
|
// margin-left: 30px; |
||||
|
display: block; |
||||
|
// flex-direction: column; |
||||
|
// align-items: flex-end; |
||||
|
// gap: 0.16rem; |
||||
|
} |
||||
|
|
||||
|
.person-item { |
||||
|
display: flex; |
||||
|
align-items: center; |
||||
|
font-size: 14px; |
||||
|
|
||||
|
&.default-person span { |
||||
|
color: #333; |
||||
|
font-size: 14px; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.person-item-add { |
||||
|
padding: 10px 10px 0px 0px; |
||||
|
display: flex; |
||||
|
justify-content: space-between; |
||||
|
align-items: center; |
||||
|
|
||||
|
.remove-icon { |
||||
|
font-size: 16px; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.person-add { |
||||
|
display: flex; |
||||
|
align-items: center; |
||||
|
justify-content: space-between; |
||||
|
align-items: center; |
||||
|
color: #c8c9cc; |
||||
|
font-size: 14px; |
||||
|
padding: 10px 10px 0px 0px; |
||||
|
|
||||
|
.add-circle-icon { |
||||
|
font-size: 16px; |
||||
|
color: #333; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.basis-container { |
||||
|
margin-bottom: 0.12rem; |
||||
|
margin-left: 6px; |
||||
|
} |
||||
|
|
||||
|
.basis-row { |
||||
|
padding: 0.24rem 0.32rem; |
||||
|
} |
||||
|
|
||||
|
.basis-wrapper { |
||||
|
margin-left: 8px; |
||||
|
display: flex; |
||||
|
align-items: end; |
||||
|
justify-content: space-between; |
||||
|
padding-right: 10px; |
||||
|
|
||||
|
.close-btn { |
||||
|
font-size: 16px; |
||||
|
} |
||||
|
|
||||
|
.add-circle-icon { |
||||
|
font-size: 16px; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.form-section { |
||||
|
margin-bottom: 10px; |
||||
|
|
||||
|
:deep(.van-field__value) { |
||||
|
display: flex; |
||||
|
justify-content: flex-end; |
||||
|
color: #000; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.form-entrusted { |
||||
|
height: 200px; |
||||
|
background-color: #fff; |
||||
|
|
||||
|
.entrusted-enforcement { |
||||
|
:deep(.van-field__value) { |
||||
|
display: flex; |
||||
|
justify-content: flex-end; |
||||
|
color: #000; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
} |
||||
|
|
||||
|
.radio-option { |
||||
|
padding: 0.12rem 0.48rem; |
||||
|
border: 1px solid #dcdee0; |
||||
|
border-radius: 0.06rem; |
||||
|
font-size: 0.3rem; |
||||
|
color: #666; |
||||
|
transition: all 0.2s; |
||||
|
|
||||
|
&:active { |
||||
|
transform: scale(0.95); |
||||
|
} |
||||
|
|
||||
|
&.active { |
||||
|
border-color: #1367fe; |
||||
|
color: #1367fe; |
||||
|
background: rgba(19, 103, 254, 0.05); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.form-hint { |
||||
|
font-size: 12px; |
||||
|
color: #999; |
||||
|
padding: 0.12rem 0.32rem 0.24rem; |
||||
|
text-align: right; |
||||
|
} |
||||
|
|
||||
|
.attachment-wrapper { |
||||
|
flex-direction: column; |
||||
|
align-items: flex-end; |
||||
|
gap: 0.16rem; |
||||
|
} |
||||
|
|
||||
|
.attachment-hint { |
||||
|
font-size: 0.26rem; |
||||
|
color: #999; |
||||
|
} |
||||
|
|
||||
|
.upload-icon { |
||||
|
font-size: 0.72rem; |
||||
|
color: #c8c9cc; |
||||
|
} |
||||
|
.file-upload-row{ |
||||
|
padding:0px 20px 20px 20px; |
||||
|
.file-upload-label{ |
||||
|
font-size: 14px; |
||||
|
color: #333; |
||||
|
margin-bottom: 0.16rem; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.uploader-wrapper { |
||||
|
:deep(.van-uploader__upload) { |
||||
|
background: #f5f7fa; |
||||
|
border-radius: 0.1rem; |
||||
|
} |
||||
|
} |
||||
|
</style> |
||||
@ -0,0 +1,76 @@ |
|||||
|
<template> |
||||
|
<div class="section"> |
||||
|
<div class="section-title">企业信息</div> |
||||
|
|
||||
|
<!-- 企业名称 --> |
||||
|
<van-field v-model="enterpriseName" :is-link="isSignMode" :readonly="true" name="enterpriseName" label="企业名称" |
||||
|
placeholder="请选择" @click="handleClick" clearable |
||||
|
:rules="isSignMode ? [{ required: true, message: '请选择企业名称' }] : []" :required="isSignMode" /> |
||||
|
|
||||
|
<!-- 统一社会信用代码 --> |
||||
|
<van-field v-model="enterpriseNumber" :is-link="isSignMode" :readonly="true" name="enterpriseNumber" |
||||
|
label="统一社会信用代码" placeholder="请选择" @click="handleClick" clearable |
||||
|
:rules="isSignMode ? [{ required: true, message: '请选择统一社会信用代码' }] : []" :required="isSignMode" /> |
||||
|
</div> |
||||
|
</template> |
||||
|
|
||||
|
<script setup name="EnterpriseInfoSection"> |
||||
|
import { computed } from 'vue'; |
||||
|
|
||||
|
const props = defineProps({ |
||||
|
enterpriseData: { |
||||
|
type: Object, |
||||
|
default: null |
||||
|
}, |
||||
|
isSignMode: { |
||||
|
type: Boolean, |
||||
|
default: false |
||||
|
} |
||||
|
}); |
||||
|
|
||||
|
const emit = defineEmits(['update:enterpriseData', 'open-picker']); |
||||
|
|
||||
|
// 计算属性:企业名称(支持双向绑定) |
||||
|
const enterpriseName = computed({ |
||||
|
get: () => props.enterpriseData?.enterpriseName || '', |
||||
|
set: (val) => { |
||||
|
emit('update:enterpriseData', { ...props.enterpriseData, enterpriseName: val }); |
||||
|
} |
||||
|
}); |
||||
|
|
||||
|
// 计算属性:统一社会信用代码(支持双向绑定) |
||||
|
const enterpriseNumber = computed({ |
||||
|
get: () => props.enterpriseData?.enterpriseNumber || '', |
||||
|
set: (val) => { |
||||
|
emit('update:enterpriseData', { ...props.enterpriseData, enterpriseNumber: val }); |
||||
|
} |
||||
|
}); |
||||
|
|
||||
|
const handleClick = () => { |
||||
|
emit('open-picker'); |
||||
|
}; |
||||
|
</script> |
||||
|
|
||||
|
<style lang="less" scoped> |
||||
|
.section { |
||||
|
background: #fff; |
||||
|
border-radius: 0.16rem; |
||||
|
margin-bottom: 0.24rem; |
||||
|
overflow: hidden; |
||||
|
|
||||
|
:deep(.van-field__label) { |
||||
|
width: 64px; |
||||
|
margin-right: 22px; |
||||
|
color: #000; |
||||
|
font-size: 14px; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.section-title { |
||||
|
padding: 0.28rem 0.32rem; |
||||
|
font-size: 16px; |
||||
|
font-weight: 600; |
||||
|
color: #000; |
||||
|
|
||||
|
} |
||||
|
</style> |
||||
@ -0,0 +1,461 @@ |
|||||
|
<template> |
||||
|
<div class="register-popups"> |
||||
|
<!-- 企业选择弹窗 --> |
||||
|
<van-popup v-model:show="localEnterprisePopup" position="bottom" :style="{ height: '80%' }" round> |
||||
|
<div class="enterprise-search-popup"> |
||||
|
<div class="popup-header"> |
||||
|
<span class="popup-title">选择企业</span> |
||||
|
<van-icon name="cross" class="close-icon" @click="localEnterprisePopup = false" /> |
||||
|
</div> |
||||
|
<div class="search-bar"> |
||||
|
<van-search v-model="enterpriseSearchKeyword" placeholder="请输入企业名称/统一信用代码搜索" |
||||
|
@search="handleEnterpriseSearch" @clear="clearEnterpriseSearch" /> |
||||
|
<van-button class="search-btn" type="primary" @click="handleEnterpriseSearch">搜索</van-button> |
||||
|
</div> |
||||
|
<div class="enterprise-list"> |
||||
|
<div v-for="(item, index) in enterpriseList" :key="index" class="enterprise-list-item" |
||||
|
@click="$emit('selectEnterprise', item)"> |
||||
|
<div class="enterprise-name">{{ item.enterpriseName }}</div> |
||||
|
<div class="enterprise-number">统一社会信用代码:{{ item.enterpriseNumber }}</div> |
||||
|
</div> |
||||
|
<van-empty v-if="enterpriseList.length === 0" description="暂无数据" /> |
||||
|
</div> |
||||
|
</div> |
||||
|
</van-popup> |
||||
|
|
||||
|
<!-- 预告查询弹窗 --> |
||||
|
<van-popup v-model:show="localNoticePopup" position="bottom" :style="{ height: '70%' }"> |
||||
|
<div class="notice-popup"> |
||||
|
<div class="popup-header"> |
||||
|
<span class="popup-title">预告查询</span> |
||||
|
<van-icon name="cross" class="close-icon" @click="localNoticePopup = false" /> |
||||
|
</div> |
||||
|
<div class="popup-content" @scroll="onNoticeScroll"> |
||||
|
<div v-for="(notice, index) in noticeList" :key="index" class="notice-item"> |
||||
|
<div class="notice-info"> |
||||
|
<div class="notice-matter">执法事项:{{ notice.matter }}</div> |
||||
|
<div class="notice-time">执法时间:{{ notice.time }}</div> |
||||
|
</div> |
||||
|
<van-button class="link-btn" type="primary" @click="$emit('linkNotice', notice)"> |
||||
|
一键关联 |
||||
|
</van-button> |
||||
|
</div> |
||||
|
<div v-if="loading" class="loading-more"> |
||||
|
<van-loading size="small" /> |
||||
|
<span>加载中...</span> |
||||
|
</div> |
||||
|
<div v-else-if="finished" class="no-more">没有更多了</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</van-popup> |
||||
|
|
||||
|
<!-- 类别选择弹窗 --> |
||||
|
<van-popup v-model:show="localCategoryPopup" round position="bottom"> |
||||
|
<van-picker :columns="options.categories" @cancel="localCategoryPopup = false" |
||||
|
@confirm="$emit('confirmCategory', $event)" /> |
||||
|
</van-popup> |
||||
|
|
||||
|
<!-- 任务来源弹窗 --> |
||||
|
<van-popup v-model:show="localTaskSourcePopup" round position="bottom"> |
||||
|
<van-picker :columns="options.taskSources" @cancel="localTaskSourcePopup = false" |
||||
|
@confirm="$emit('confirmTaskSource', $event)" /> |
||||
|
</van-popup> |
||||
|
|
||||
|
<!-- 人员查询弹窗 --> |
||||
|
<van-popup v-model:show="localPersonPopup" position="bottom" :style="{ height: '80%' }"> |
||||
|
<div class="person-search-popup"> |
||||
|
<div class="popup-header"> |
||||
|
<span class="popup-title">人员查询</span> |
||||
|
<van-icon name="cross" class="close-icon" @click="localPersonPopup = false" /> |
||||
|
</div> |
||||
|
<div class="search-bar"> |
||||
|
<van-search v-model="personSearchKeyword" placeholder="请输入姓名/执法证件号搜索" @search="handlePersonSearch" |
||||
|
@clear="clearPersonSearch" /> |
||||
|
<van-button class="search-btn" type="primary" @click="handlePersonSearch">搜索</van-button> |
||||
|
</div> |
||||
|
<div class="person-list"> |
||||
|
<div v-for="(person, index) in personList" :key="index" class="person-list-item" |
||||
|
@click="$emit('selectPerson', person)"> |
||||
|
<div class="person-name">{{ person.name }}</div> |
||||
|
<div class="person-id">执法证件号:{{ person.id }}</div> |
||||
|
</div> |
||||
|
<van-empty v-if="personList.length === 0" description="暂无数据" /> |
||||
|
</div> |
||||
|
</div> |
||||
|
</van-popup> |
||||
|
|
||||
|
<!-- 执法依据弹窗 --> |
||||
|
<van-popup v-model:show="localBasisPopup" position="bottom" :style="{ height: '80%' }"> |
||||
|
<div class="enforcement-basis-popup"> |
||||
|
<div class="popup-header"> |
||||
|
<span class="popup-title">执法依据</span> |
||||
|
<van-icon name="cross" class="close-icon" @click="localBasisPopup = false" /> |
||||
|
</div> |
||||
|
<div class="search-bar"> |
||||
|
<van-search v-model="basisSearchKeyword" placeholder="请输入关键字搜索" @search="handleBasisSearch" |
||||
|
@clear="clearBasisSearch" /> |
||||
|
<van-button class="search-btn" type="primary" @click="handleBasisSearch">搜索</van-button> |
||||
|
</div> |
||||
|
<div class="enforcement-basis-list"> |
||||
|
<div v-for="(item, index) in enforcementBasisList" :key="index" class="basis-list-item" |
||||
|
@click="$emit('selectBasis', item)"> |
||||
|
<div class="basis-name">{{ item.name }}</div> |
||||
|
</div> |
||||
|
<van-empty v-if="enforcementBasisList.length === 0" description="没有更多了" /> |
||||
|
</div> |
||||
|
</div> |
||||
|
</van-popup> |
||||
|
</div> |
||||
|
</template> |
||||
|
|
||||
|
<script setup name="RegisterPopups"> |
||||
|
import { ref, reactive, watch, computed } from 'vue'; |
||||
|
|
||||
|
const props = defineProps({ |
||||
|
visible: { |
||||
|
type: Object, |
||||
|
required: true |
||||
|
}, |
||||
|
options: { |
||||
|
type: Object, |
||||
|
default: () => ({ |
||||
|
categories: [], |
||||
|
taskSources: [] |
||||
|
}) |
||||
|
} |
||||
|
}); |
||||
|
|
||||
|
const emit = defineEmits([ |
||||
|
'close-popup', |
||||
|
'selectEnterprise', |
||||
|
'linkNotice', |
||||
|
'confirmCategory', |
||||
|
'confirmTaskSource', |
||||
|
'selectPerson', |
||||
|
'selectBasis' |
||||
|
]); |
||||
|
|
||||
|
// 使用 computed 创建可写的计算属性(自动同步 props,保证响应式) |
||||
|
const localEnterprisePopup = computed({ |
||||
|
get: () => props.visible.enterprise, |
||||
|
set: () => emit('close-popup', 'enterprise') |
||||
|
}); |
||||
|
|
||||
|
const localNoticePopup = computed({ |
||||
|
get: () => props.visible.notice, |
||||
|
set: () => emit('close-popup', 'notice') |
||||
|
}); |
||||
|
|
||||
|
const localCategoryPopup = computed({ |
||||
|
get: () => props.visible.category, |
||||
|
set: () => emit('close-popup', 'category') |
||||
|
}); |
||||
|
|
||||
|
const localTaskSourcePopup = computed({ |
||||
|
get: () => props.visible.taskSource, |
||||
|
set: () => emit('close-popup', 'taskSource') |
||||
|
}); |
||||
|
|
||||
|
const localPersonPopup = computed({ |
||||
|
get: () => props.visible.person, |
||||
|
set: () => emit('close-popup', 'person') |
||||
|
}); |
||||
|
|
||||
|
const localBasisPopup = computed({ |
||||
|
get: () => props.visible.basis, |
||||
|
set: () => emit('close-popup', 'basis') |
||||
|
}); |
||||
|
|
||||
|
// ========== 企业选择相关 ========== |
||||
|
const enterpriseSearchKeyword = ref(''); |
||||
|
const enterpriseList = ref([]); |
||||
|
|
||||
|
const initEnterpriseList = () => { |
||||
|
enterpriseList.value = [ |
||||
|
{ enterpriseName: '深圳市南山区椿立嘉源麻辣烫店', enterpriseNumber: '92440300MA5FXXXX1' }, |
||||
|
{ enterpriseName: '深圳伊腾迪新能源有限公司', enterpriseNumber: '91440300MA5FXXXX2' }, |
||||
|
{ enterpriseName: '深圳市永顺新绣花有限公司', enterpriseNumber: '91440300MA5FXXXX3' }, |
||||
|
{ enterpriseName: '深圳市中棋金业有限公司', enterpriseNumber: '91440300MA5FXXXX4' }, |
||||
|
{ enterpriseName: '深圳市百合隆科技有限公司', enterpriseNumber: '91440300MA5FXXXX5' }, |
||||
|
]; |
||||
|
}; |
||||
|
|
||||
|
const handleEnterpriseSearch = () => { |
||||
|
initEnterpriseList(); |
||||
|
if (enterpriseSearchKeyword.value.trim()) { |
||||
|
const keyword = enterpriseSearchKeyword.value.toLowerCase(); |
||||
|
enterpriseList.value = enterpriseList.value.filter(item => |
||||
|
item.enterpriseName.toLowerCase().includes(keyword) || |
||||
|
item.enterpriseNumber.toLowerCase().includes(keyword) |
||||
|
); |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
const clearEnterpriseSearch = () => { |
||||
|
enterpriseSearchKeyword.value = ''; |
||||
|
initEnterpriseList(); |
||||
|
}; |
||||
|
|
||||
|
watch(localEnterprisePopup, (val) => { |
||||
|
if (val) { |
||||
|
enterpriseSearchKeyword.value = ''; |
||||
|
initEnterpriseList(); |
||||
|
} |
||||
|
}); |
||||
|
|
||||
|
// ========== 人员查询相关 ========== |
||||
|
const personSearchKeyword = ref(''); |
||||
|
const personList = ref([]); |
||||
|
|
||||
|
const initPersonList = () => { |
||||
|
personList.value = [ |
||||
|
{ id: '19020011041', name: '刘倩琳' }, |
||||
|
{ id: '19020011042', name: '张明华' }, |
||||
|
{ id: '19020011043', name: '李晓东' }, |
||||
|
{ id: '19020011044', name: '王芳' }, |
||||
|
]; |
||||
|
}; |
||||
|
|
||||
|
const handlePersonSearch = () => { |
||||
|
initPersonList(); |
||||
|
if (personSearchKeyword.value.trim()) { |
||||
|
const keyword = personSearchKeyword.value.toLowerCase(); |
||||
|
personList.value = personList.value.filter(item => |
||||
|
item.name.toLowerCase().includes(keyword) || |
||||
|
item.id.toLowerCase().includes(keyword) |
||||
|
); |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
const clearPersonSearch = () => { |
||||
|
personSearchKeyword.value = ''; |
||||
|
initPersonList(); |
||||
|
}; |
||||
|
|
||||
|
watch(localPersonPopup, (val) => { |
||||
|
if (val) { |
||||
|
personSearchKeyword.value = ''; |
||||
|
initPersonList(); |
||||
|
} |
||||
|
}); |
||||
|
|
||||
|
// ========== 执法依据相关 ========== |
||||
|
const basisSearchKeyword = ref(''); |
||||
|
const enforcementBasisList = ref([]); |
||||
|
|
||||
|
const initBasisList = () => { |
||||
|
enforcementBasisList.value = [ |
||||
|
{ id: 1, name: '《中华人民共和国行政处罚法》' }, |
||||
|
{ id: 2, name: '《中华人民共和国行政许可法》' }, |
||||
|
{ id: 3, name: '《中华人民共和国行政强制法》' }, |
||||
|
{ id: 4, name: '《深圳市经济特区商事登记若干规定》' }, |
||||
|
{ id: 5, name: '《深圳经济特区优化营商环境条例》' }, |
||||
|
{ id: 6, name: '《中华人民共和国市场主体登记管理条例》' }, |
||||
|
]; |
||||
|
}; |
||||
|
|
||||
|
const handleBasisSearch = () => { |
||||
|
initBasisList(); |
||||
|
if (basisSearchKeyword.value.trim()) { |
||||
|
const keyword = basisSearchKeyword.value.toLowerCase(); |
||||
|
enforcementBasisList.value = enforcementBasisList.value.filter(item => |
||||
|
item.name.toLowerCase().includes(keyword) |
||||
|
); |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
const clearBasisSearch = () => { |
||||
|
basisSearchKeyword.value = ''; |
||||
|
initBasisList(); |
||||
|
}; |
||||
|
|
||||
|
watch(localBasisPopup, (val) => { |
||||
|
if (val) { |
||||
|
basisSearchKeyword.value = ''; |
||||
|
initBasisList(); |
||||
|
} |
||||
|
}); |
||||
|
|
||||
|
// ========== 预告查询相关 ========== |
||||
|
const noticeList = ref([]); |
||||
|
const noticePage = ref(1); |
||||
|
const loading = ref(false); |
||||
|
const finished = ref(false); |
||||
|
|
||||
|
const loadNotices = () => { |
||||
|
if (loading.value || finished.value) return; |
||||
|
loading.value = true; |
||||
|
|
||||
|
setTimeout(() => { |
||||
|
const mockData = [ |
||||
|
{ id: 1, matter: '例行检查', time: '2026-05-20 10:00' }, |
||||
|
{ id: 2, matter: '专项检查', time: '2026-05-19 14:30' }, |
||||
|
]; |
||||
|
|
||||
|
if (noticePage.value === 1) { |
||||
|
noticeList.value = mockData; |
||||
|
} else { |
||||
|
noticeList.value = [...noticeList.value, ...mockData]; |
||||
|
} |
||||
|
|
||||
|
loading.value = false; |
||||
|
|
||||
|
if (noticePage.value >= 1) { |
||||
|
finished.value = true; |
||||
|
} |
||||
|
|
||||
|
noticePage.value++; |
||||
|
}, 500); |
||||
|
}; |
||||
|
|
||||
|
const onNoticeScroll = () => { }; |
||||
|
|
||||
|
watch(localNoticePopup, (newVal) => { |
||||
|
if (newVal) { |
||||
|
noticePage.value = 1; |
||||
|
noticeList.value = []; |
||||
|
loading.value = false; |
||||
|
finished.value = false; |
||||
|
loadNotices(); |
||||
|
} |
||||
|
}); |
||||
|
</script> |
||||
|
|
||||
|
<style lang="less" scoped> |
||||
|
.register-popups { |
||||
|
// 容器样式(可选) |
||||
|
} |
||||
|
|
||||
|
.popup-header { |
||||
|
display: flex; |
||||
|
justify-content: space-between; |
||||
|
align-items: center; |
||||
|
padding: 0.3rem; |
||||
|
border-bottom: 1px solid #f5f5f5; |
||||
|
|
||||
|
.popup-title { |
||||
|
font-size: 0.4rem; |
||||
|
font-weight: 600; |
||||
|
color: #333; |
||||
|
} |
||||
|
|
||||
|
.close-icon { |
||||
|
font-size: 0.45rem; |
||||
|
color: #999; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.search-bar { |
||||
|
display: flex; |
||||
|
align-items: center; |
||||
|
margin: 0.3rem; |
||||
|
|
||||
|
// padding: 0.3rem; |
||||
|
:deep(.van-search) { |
||||
|
padding-right: 0px; |
||||
|
flex: 1; |
||||
|
height: 34px; |
||||
|
} |
||||
|
|
||||
|
.search-btn { |
||||
|
flex: none; |
||||
|
height: 34px; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.enterprise-search-popup, |
||||
|
.person-search-popup, |
||||
|
.enforcement-basis-popup { |
||||
|
height: 100%; |
||||
|
display: flex; |
||||
|
flex-direction: column; |
||||
|
} |
||||
|
|
||||
|
.enterprise-list, |
||||
|
.person-list, |
||||
|
.enforcement-basis-list { |
||||
|
flex: 1; |
||||
|
overflow-y: auto; |
||||
|
padding: 0 0.3rem; |
||||
|
} |
||||
|
|
||||
|
.enterprise-list-item, |
||||
|
.person-list-item, |
||||
|
.basis-list-item { |
||||
|
padding:20px 20px 14px 14px; |
||||
|
border-bottom: 1px solid #f5f5f5; |
||||
|
|
||||
|
&:active { |
||||
|
background: #f9f9f9; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.enterprise-name, |
||||
|
.person-name, |
||||
|
.basis-name { |
||||
|
font-size: 16px; |
||||
|
color: #333; |
||||
|
margin-bottom: 10px; |
||||
|
} |
||||
|
|
||||
|
.enterprise-number, |
||||
|
.person-id { |
||||
|
font-size: 14px; |
||||
|
color: #999; |
||||
|
} |
||||
|
|
||||
|
.notice-popup { |
||||
|
height: 100%; |
||||
|
display: flex; |
||||
|
flex-direction: column; |
||||
|
} |
||||
|
|
||||
|
.popup-content { |
||||
|
flex: 1; |
||||
|
overflow-y: auto; |
||||
|
padding: 0.3rem; |
||||
|
} |
||||
|
|
||||
|
.notice-item { |
||||
|
display: flex; |
||||
|
justify-content: space-between; |
||||
|
align-items: center; |
||||
|
padding: 0.3rem; |
||||
|
// background: #f9f9f9; |
||||
|
margin-bottom: 0.2rem; |
||||
|
border-bottom: 0.1px solid #ededed; |
||||
|
|
||||
|
.notice-info { |
||||
|
flex: 1; |
||||
|
} |
||||
|
|
||||
|
.notice-matter { |
||||
|
font-size: 16px; |
||||
|
color: #000; |
||||
|
margin-bottom: 10px; |
||||
|
} |
||||
|
|
||||
|
.notice-time { |
||||
|
font-size: 14px; |
||||
|
color: #999; |
||||
|
} |
||||
|
|
||||
|
.link-btn { |
||||
|
flex: none; |
||||
|
font-size: 12px; |
||||
|
height: 26px; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.loading-more, |
||||
|
.no-more { |
||||
|
text-align: center; |
||||
|
padding: 0.3rem; |
||||
|
font-size: 0.28rem; |
||||
|
color: #999; |
||||
|
display: flex; |
||||
|
align-items: center; |
||||
|
justify-content: center; |
||||
|
gap: 0.1rem; |
||||
|
} |
||||
|
</style> |
||||
File diff suppressed because it is too large
Loading…
Reference in new issue