11 changed files with 1529 additions and 3 deletions
@ -0,0 +1,11 @@ |
|||
import { _get, _post } from "@/http/index"; |
|||
|
|||
const baseUrl = "/app-enf"; |
|||
|
|||
// 公共api
|
|||
// 执法端-查询企业信息以及二维码地址
|
|||
export const queryListAndQrInfo = (params, success, error) => _post(baseUrl + "/enterpriseInfo/queryListAndQrInfo", params, success, error); |
|||
// 执法端-分页查询用户
|
|||
export const queryUsersByPage = (params, success, error) => _get(baseUrl + "/system/queryUsersByPage", params, success, error); |
|||
// 查询执依据告列表
|
|||
export const queryAccordingList = (params, success, error) => _get(baseUrl + "/according/list", params, success, error); |
|||
@ -0,0 +1,35 @@ |
|||
import { _get, _post } from "@/http/index"; |
|||
|
|||
const baseUrl = "/app-enf"; |
|||
|
|||
// enf 测试单 Demo:GET /nosapi/enforcementcode/enfDemo/list -> TableDataInfo { rows, total }
|
|||
export const listEnfDemo = (params) => |
|||
_get("/enforcementcode/enfDemo/list", params); |
|||
|
|||
// 非现场api
|
|||
// 新增非现场执法任务
|
|||
export const nosAddApi = (params, success, error) => _post("/app-enf/nos-law-enforcement-task/add", params, success, error); |
|||
// 分页查询非现场执法任务
|
|||
export const nosListPageApi = (params, success, error) => _post("/app-enf/nos-law-enforcement-task/page", params, success, error); |
|||
// 获取非现场执法任务详情
|
|||
export const nosInfoApi = (params, success, error) => _get("/app-enf/nos-law-enforcement-task/detail", params, success, error); |
|||
// 审核非现场执法任务
|
|||
export const nosApproveApi = (params, success, error) => _post("/app-enf/nos-law-enforcement-task/approve", params, success, error); |
|||
// 查询非现场执法项目任务类别
|
|||
export const nosTypeApi = (params, success, error) => _post("/app-enf/nos-law-enforcement-task/type", params, success, error); |
|||
//查询非现场执法项目任务来源列表
|
|||
export const nosTaskSourceListApi = (params, success, error) => _post("/app-enf/task-source/list", params, success, error); |
|||
|
|||
//查询已评价的任务
|
|||
export const nosTaskHasCommentPageApi = (params, success, error) => _post("/app-enf/nos-law-enforcement-task/has-comment/page", params, success, error); |
|||
|
|||
//获取当前用户所属执法单位备案
|
|||
export const isFilingApi = (params, success, error) => _get("/enf-app/nos-law-enforcement-filing/detail", params, success, error); |
|||
|
|||
//开启云笔录
|
|||
export const cloudRecordStartApi = (params, success, error) => _get("/app-enf/nos-law-enforcement-task/start/digital-voice-logging", params, success, error); |
|||
//查询云笔录详情
|
|||
export const cloudRecordDetailApi = (params, success, error) => _get("/app-enf/nos-law-enforcement-task/digital-voice-logging/detail", params, success, error); |
|||
//确认云笔录材料
|
|||
export const cloudRecordConfirmApi = (params, success, error) => _post("/app-enf/nos-law-enforcement-task/digital-voice-logging/confirm", params, success, error); |
|||
|
|||
@ -0,0 +1,189 @@ |
|||
<template> |
|||
<div class="section"> |
|||
<div class="section-title">通知/公告</div> |
|||
|
|||
<!-- 附件 --> |
|||
<div class="file-upload-row label-required-placeholder"> |
|||
<div class="file-upload-label">附 件 <span class="form-text">(仅限于PDF文档,50M以下,最多五个文件)</span></div> |
|||
<div class="uploader-wrapper"> |
|||
<van-uploader |
|||
v-model="proclamation" |
|||
capture="false" |
|||
accept=".pdf" |
|||
multiple |
|||
:max-count="5" |
|||
:max-size="50 * 1024 * 1024" |
|||
@oversize="onOversize" |
|||
:before-read="onBeforeRead" |
|||
:after-read="onAfterReadImage" |
|||
/> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- 任务来源 --> |
|||
<van-field |
|||
:class="taskTypeId == 5 ? 'usci-code-field' : ''" |
|||
:model-value="taskSourceName" |
|||
is-link |
|||
readonly |
|||
name="taskSourceId" |
|||
label="任务来源" |
|||
placeholder="请选择" |
|||
@click="$emit('showTaskSourcePicker')" |
|||
clearable |
|||
:rules="[{ required: taskTypeId != 5, message: '请选择任务来源' }]" |
|||
:required="taskTypeId != 5" |
|||
/> |
|||
</div> |
|||
</template> |
|||
|
|||
<script setup name="AttachmentTaskSource"> |
|||
import { computed } from 'vue'; |
|||
import { uploadFile } from '@/util/fileUpload'; |
|||
import { toFullFileUrl } from '@/util/fileUrl'; |
|||
import { showToast } from 'vant'; |
|||
import 'vant/es/toast/style'; |
|||
|
|||
const proclamation = defineModel('proclamation', { default: () => [] }); |
|||
const taskSourceId = defineModel('taskSourceId', { default: '' }); |
|||
const taskTypeId = defineModel('taskTypeId', { default: null }); |
|||
|
|||
const props = defineProps({ |
|||
taskSourceOptions: { |
|||
type: Array, |
|||
default: () => [] |
|||
} |
|||
}); |
|||
|
|||
const taskSourceName = computed(() => { |
|||
const option = props.taskSourceOptions.find((item) => item.value === taskSourceId.value); |
|||
return option?.text || ''; |
|||
}); |
|||
|
|||
defineEmits(['showTaskSourcePicker']); |
|||
|
|||
const showUploadToast = (message) => { |
|||
showToast({ |
|||
message, |
|||
className: 'attachment-upload-toast' |
|||
}); |
|||
}; |
|||
|
|||
// 附件上传前校验 |
|||
const onBeforeRead = (file) => { |
|||
const files = Array.isArray(file) ? file : [file]; |
|||
let isValid = true; |
|||
for (const item of files) { |
|||
const isPdf = item.name.toLowerCase().endsWith('.pdf'); |
|||
const isTypeMatch = item.type === 'application/pdf'; |
|||
|
|||
if (!isPdf || !isTypeMatch) { |
|||
showUploadToast('仅支持上传 PDF 格式文件'); |
|||
isValid = false; |
|||
break; |
|||
} |
|||
} |
|||
return isValid; |
|||
}; |
|||
|
|||
// 文件大小超出限制 |
|||
const onOversize = () => { |
|||
showUploadToast('文件大小不能超过 50MB'); |
|||
}; |
|||
|
|||
// 附件上传处理 |
|||
const onAfterReadImage = (file) => { |
|||
const files = Array.isArray(file) ? file : [file]; |
|||
files.forEach((f) => { |
|||
f.status = 'uploading'; |
|||
f.message = '上传中...'; |
|||
uploadFile(f, (res) => { |
|||
const filePath = res.url; |
|||
if (filePath) { |
|||
f.url = toFullFileUrl(filePath); |
|||
f.name = f.name || f.file?.name || ''; |
|||
f.status = 'done'; |
|||
f.message = '上传成功'; |
|||
} else { |
|||
f.status = 'failed'; |
|||
f.message = '上传失败'; |
|||
} |
|||
}); |
|||
}); |
|||
}; |
|||
</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; |
|||
} |
|||
.file-upload-row { |
|||
padding: 0px 20px 20px 20px; |
|||
.file-upload-label { |
|||
font-size: 14px; |
|||
color: #333; |
|||
margin-bottom: 0.16rem; |
|||
.form-text { |
|||
font-weight: 400; |
|||
font-size: 12px; |
|||
color: #b9b9b9; |
|||
text-align: left; |
|||
font-style: normal; |
|||
} |
|||
} |
|||
} |
|||
|
|||
.uploader-wrapper { |
|||
:deep(.van-uploader__upload) { |
|||
background: #f5f7fa; |
|||
border-radius: 0.1rem; |
|||
} |
|||
} |
|||
:deep(.van-cell) { |
|||
padding-left: 10px; |
|||
padding-right: 10px; |
|||
} |
|||
.label-required-placeholder .form-label { |
|||
position: relative; |
|||
padding-left: 0.1rem; |
|||
|
|||
&::before { |
|||
content: '*'; |
|||
color: transparent; |
|||
font-size: 0.32rem; |
|||
margin-right: 0.08rem; |
|||
font-weight: bold; |
|||
} |
|||
} |
|||
:deep(.usci-code-field .van-field__label) { |
|||
padding-left: 8px; // 按需调整 |
|||
box-sizing: border-box; |
|||
} |
|||
|
|||
:global(.attachment-upload-toast) { |
|||
color: #fff !important; |
|||
background: rgba(0, 0, 0, 0.75) !important; |
|||
} |
|||
|
|||
:global(.attachment-upload-toast .van-toast__text) { |
|||
color: #fff !important; |
|||
} |
|||
|
|||
</style> |
|||
@ -0,0 +1,539 @@ |
|||
<template> |
|||
<div class="section"> |
|||
<div class="section-title">{{ formData.taskTypeId == 1 ? '执法信息' : '巡查信息' }}</div> |
|||
|
|||
<!-- 执法单位 --> |
|||
<van-field |
|||
v-model="formData.lawEnforcementAgency" |
|||
name="lawEnforcementAgency" |
|||
:label="formData.taskTypeId == 1 ?'执法单位' : '巡查单位'" |
|||
:placeholder="formData.taskTypeId == 1 ? '请输入执法单位' : '请输入巡查单位'" |
|||
:class="formData.taskTypeId == 5 ? 'usci-code-field' : ''" |
|||
:required="formData.taskTypeId != 5" |
|||
readonly /> |
|||
|
|||
<!-- 执法人员 --> |
|||
<div class="form-row required"> |
|||
<div class="form-label"><span class="required-mark" :class="{ 'required-mark--placeholder': formData.taskTypeId == 5 }">*</span>{{ formData.taskTypeId == 1 ? '执法人员' : '参与人员' }}</div> |
|||
<div class="form-value person-select"> |
|||
<div class="person-item default-person"> |
|||
<span>{{ defaultPerson?.lawEnforcerName }} {{ defaultPerson?.lawEnforcerIdCard ?? defaultPerson?.lawEnforcerPhone }}</span> |
|||
</div> |
|||
<div v-for="(person, index) in additionalPersons" :key="index" class="person-item-add"> |
|||
<span @click="$emit('openPersonPicker', index)" :class="{ placeholder: !person.lawEnforcerName }"> |
|||
{{ person.lawEnforcerName || "请选择" }} {{ person.lawEnforcerIdCard ?? person.lawEnforcerPhone }} |
|||
</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> |
|||
<!-- 隐藏字段用于验证执法人员 --> |
|||
<van-field |
|||
v-if="formData.taskTypeId != 5" |
|||
v-model="hasPerson" |
|||
name="enforcementPerson" |
|||
label=" " |
|||
:rules="[{ required: true, message: '请选择执法人员' }]" |
|||
class="error-only-field" /> |
|||
</div> |
|||
|
|||
<!-- 执法类别 --> |
|||
<van-field |
|||
:model-value="category" |
|||
:is-link="!categoryDisabled" |
|||
readonly |
|||
name="taskTypeId" |
|||
class="usci-code-field" |
|||
label="类 别" |
|||
placeholder="请选择" |
|||
@click="onCategoryClick" |
|||
:clearable="!categoryDisabled" |
|||
/> |
|||
|
|||
<!-- 执法事项 --> |
|||
<van-field |
|||
v-model="formData.lawEnforcementMatters" |
|||
name="lawEnforcementMatters" |
|||
v-if="formData.taskTypeId == 1 || formData.taskTypeId == 5" |
|||
:label="formData.taskTypeId == 1 ? '执法事项' : '巡查事项'" |
|||
:placeholder="formData.taskTypeId == 1 ? '请输入执法事项' : '请输入巡查事项'" |
|||
type="textarea" |
|||
class="usci-code-field" |
|||
rows="2" |
|||
autosize |
|||
maxlength="1000" |
|||
show-word-limit /> |
|||
|
|||
<!-- 检查要求 / 备案文件 / 验证文件 --> |
|||
<template v-if="requirementLabel"> |
|||
<div class="form-row required material-header-row"> |
|||
<div class="form-label"><span class="required-mark" :class="{ 'required-mark--placeholder': formData.taskTypeId == 5 }">*</span>{{ requirementLabel }}</div> |
|||
<div class="form-value"> |
|||
<span class="material-hint">指定企业要上传的材料名称(例如:营业执照)</span> |
|||
</div> |
|||
</div> |
|||
<div class="form-row material-input-row"> |
|||
<div class="form-label"></div> |
|||
<div class="form-value material-select"> |
|||
<div v-for="(item, index) in formData.checkItemList" :key="index" class="material-item"> |
|||
<input v-model="formData.checkItemList[index]" class="material-input" type="text" placeholder="请输入" maxlength="100" /> |
|||
<van-icon v-if="index === formData.checkItemList.length - 1" name="add-o" class="add-circle-icon" @click.stop="addMaterialRow" /> |
|||
<van-icon v-else name="close" class="remove-icon" @click.stop="removeMaterialRow(index)" /> |
|||
</div> |
|||
</div> |
|||
<van-field |
|||
v-if="formData.taskTypeId != 5" |
|||
v-model="hasMaterialRequirement" |
|||
name="checkItemList" |
|||
label=" " |
|||
:rules="[{ required: true, message: `请输入${requirementLabel}` }]" |
|||
class="error-only-field" /> |
|||
</div> |
|||
</template> |
|||
|
|||
<!-- 执法依据 / 依据 --> |
|||
<van-field |
|||
v-if="formData.taskTypeId == 5" |
|||
v-model="formData.legalBasis[0]" |
|||
name="legalBasis" |
|||
label="依 据" |
|||
placeholder="请输入依据" |
|||
type="textarea" |
|||
class="usci-code-field" |
|||
rows="2" |
|||
autosize |
|||
maxlength="1000" |
|||
show-word-limit /> |
|||
|
|||
<div v-else class="form-row required"> |
|||
<div class="form-label"><span class="required-mark">*</span>执法依据</div> |
|||
<div class="form-value basis-select"> |
|||
<div v-for="(basis, index) in formData.legalBasis" :key="index" class="basis-item-add"> |
|||
<span @click="$emit('openBasisPicker', index)" :class="{ placeholder: !basis }"> |
|||
{{ basis || "请选择" }} |
|||
</span> |
|||
<van-icon v-if="index === formData.legalBasis.length - 1" name="add-o" class="add-circle-icon" @click.stop="$emit('addBasis')" /> |
|||
<van-icon v-else name="close" class="remove-icon" @click.stop="$emit('removeBasis', index)" /> |
|||
</div> |
|||
</div> |
|||
<van-field |
|||
v-if="formData.taskTypeId != 5" |
|||
v-model="hasLegalBasis" |
|||
name="legalBasis" |
|||
label=" " |
|||
:rules="[{ required: true, message: '请选择执法依据' }]" |
|||
class="error-only-field" /> |
|||
</div> |
|||
|
|||
<!-- 原因 --> |
|||
<!-- <van-field v-model="formData.reason" name="reason" label="原因" placeholder="请输入原因" readonly /> --> |
|||
|
|||
<!-- 执法时间 --> |
|||
|
|||
<van-field |
|||
v-model="formData.deadline" |
|||
name="deadline" |
|||
:class="formData.taskTypeId == 5 ? 'usci-code-field' : ''" |
|||
label="截止时间" |
|||
placeholder="请选择截止时间" |
|||
is-link |
|||
readonly |
|||
:rules="[{ required: formData.taskTypeId != 5, message: '请选择截止时间' }]" |
|||
@click="$emit('showTimePicker')" |
|||
:required="formData.taskTypeId != 5" /> |
|||
|
|||
<!-- 联合执法 --> |
|||
</div> |
|||
</template> |
|||
|
|||
<script setup name="EnforcementInfoSection"> |
|||
const formData = defineModel('formData', { required: true }); |
|||
const additionalPersons = defineModel('additionalPersons', { default: () => [] }); |
|||
|
|||
const props = defineProps({ |
|||
defaultPerson: { |
|||
type: Object, |
|||
default: null |
|||
}, |
|||
categoryDisabled: { |
|||
type: Boolean, |
|||
default: false |
|||
}, |
|||
category: { |
|||
type: String, |
|||
default: '' |
|||
} |
|||
}); |
|||
|
|||
const emit = defineEmits(['openPersonPicker', 'removePerson', 'addPerson', 'showCategoryPicker', 'showTaskSourcePicker', 'showTimePicker', 'openBasisPicker', 'addBasis', 'removeBasis']); |
|||
|
|||
const onCategoryClick = () => { |
|||
if (!props.categoryDisabled) { |
|||
emit('showCategoryPicker'); |
|||
} |
|||
}; |
|||
|
|||
const CATEGORY_REQUIREMENT_LABEL_MAP = { |
|||
行政检查: '检查要求', |
|||
材料备案: '备案文件', |
|||
材料验证: '验证文件', |
|||
巡查: '巡查要求' |
|||
}; |
|||
|
|||
// 根据类别动态显示 label(独立 category prop,避免 keep-alive 下嵌套对象追踪失效) |
|||
const requirementLabel = computed(() => { |
|||
return CATEGORY_REQUIREMENT_LABEL_MAP[props.category] || ''; |
|||
}); |
|||
|
|||
// 计算属性:是否有执法人员 |
|||
const hasPerson = computed(() => { |
|||
return (props.defaultPerson?.lawEnforcerName || additionalPersons.value.some((p) => p.lawEnforcerName)) ? '已填写' : ''; |
|||
}); |
|||
|
|||
// 是否已填写检查项 |
|||
const hasMaterialRequirement = computed(() => { |
|||
return formData.value.checkItemList?.some((item) => item?.trim()) ? '已填写' : ''; |
|||
}); |
|||
|
|||
// 是否已填写执法依据 |
|||
const hasLegalBasis = computed(() => { |
|||
return formData.value.legalBasis?.some((item) => item?.trim()) ? '已填写' : ''; |
|||
}); |
|||
|
|||
const addMaterialRow = () => { |
|||
formData.value.checkItemList.push(''); |
|||
}; |
|||
|
|||
const removeMaterialRow = (index) => { |
|||
if (formData.value.checkItemList.length > 1) { |
|||
formData.value.checkItemList.splice(index, 1); |
|||
} |
|||
}; |
|||
</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: 10px; |
|||
border-bottom: 1px solid #f0f0f0; |
|||
flex-wrap: wrap; |
|||
|
|||
&:last-child { |
|||
border-bottom: none; |
|||
} |
|||
|
|||
&.clickable { |
|||
&:active { |
|||
background: #f9f9f9; |
|||
} |
|||
} |
|||
|
|||
&.required .form-label { |
|||
position: relative; |
|||
} |
|||
|
|||
&.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; |
|||
|
|||
&--placeholder { |
|||
visibility: hidden; |
|||
} |
|||
} |
|||
|
|||
|
|||
|
|||
.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-select { |
|||
display: block; |
|||
} |
|||
|
|||
.basis-item-add { |
|||
padding: 10px 10px 0 0; |
|||
display: flex; |
|||
justify-content: space-between; |
|||
align-items: center; |
|||
|
|||
&:first-child { |
|||
padding-top: 0; |
|||
} |
|||
|
|||
.remove-icon, |
|||
.add-circle-icon { |
|||
font-size: 16px; |
|||
color: #333; |
|||
} |
|||
} |
|||
|
|||
.material-header-row { |
|||
padding-bottom: 0.12rem; |
|||
border-bottom: none; |
|||
} |
|||
|
|||
.material-hint { |
|||
font-size: 12px; |
|||
color: #999; |
|||
line-height: 1.4; |
|||
} |
|||
|
|||
.material-input-row { |
|||
padding-top: 0; |
|||
align-items: flex-start; |
|||
} |
|||
|
|||
.material-select { |
|||
display: block; |
|||
} |
|||
|
|||
.material-item { |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: space-between; |
|||
gap: 8px; |
|||
padding: 10px 10px 0 0; |
|||
|
|||
&:first-child { |
|||
padding-top: 0; |
|||
} |
|||
|
|||
:deep(.van-checkbox) { |
|||
flex: none; |
|||
} |
|||
|
|||
.material-input { |
|||
flex: 1; |
|||
min-width: 0; |
|||
max-width: 100%; |
|||
border: none; |
|||
outline: none; |
|||
font-size: 14px; |
|||
color: #333; |
|||
background: transparent; |
|||
padding-right: 0; |
|||
// text-align: right; |
|||
|
|||
&::placeholder { |
|||
color: #c8c9cc; |
|||
} |
|||
} |
|||
|
|||
.remove-icon, |
|||
.add-circle-icon { |
|||
flex: none; |
|||
font-size: 16px; |
|||
color: #333; |
|||
} |
|||
} |
|||
|
|||
.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; |
|||
} |
|||
} |
|||
:deep(.van-cell){ |
|||
padding-left: 10px; |
|||
padding-right: 10px; |
|||
} |
|||
:deep(.usci-code-field .van-field__label) { |
|||
padding-left: 8px; // 按需调整 |
|||
box-sizing: border-box; |
|||
} |
|||
|
|||
.error-only-field { |
|||
width: 100%; |
|||
padding-top: 0; |
|||
padding-bottom: 0; |
|||
margin-top: -5px; |
|||
margin-bottom: -10px; |
|||
background: transparent; |
|||
&::after { |
|||
display: none; |
|||
} |
|||
:deep(.van-field__label) { |
|||
display: none; |
|||
} |
|||
:deep(.van-field__value) { |
|||
padding-left: 2.4rem; |
|||
} |
|||
:deep(.van-field__value .van-field__body) { |
|||
display: none; |
|||
} |
|||
:deep(.van-field__error-message) { |
|||
padding-bottom: 10px; |
|||
text-align: left; |
|||
} |
|||
} |
|||
</style> |
|||
@ -0,0 +1,85 @@ |
|||
<template> |
|||
<div class="section"> |
|||
<div class="section-title">检查对象</div> |
|||
|
|||
<!-- 企业名称 --> |
|||
<van-field |
|||
v-model="enterpriseData.enterpriseName" |
|||
:is-link="isSignMode" |
|||
:readonly="true" |
|||
name="enterpriseName" |
|||
label="企业名称" |
|||
placeholder="请选择" |
|||
@click="handleClick" |
|||
clearable |
|||
:rules="isSignMode ? [{ required: true, message: '请选择企业名称' }] : []" |
|||
:required="isSignMode" /> |
|||
|
|||
<!-- 统一社会信用代码 --> |
|||
<van-field |
|||
class="usci-code-field" |
|||
v-model="enterpriseData.usciCode" |
|||
:is-link="isSignMode" |
|||
:readonly="true" |
|||
name="usciCode" |
|||
label="统一社会信用代码" |
|||
placeholder="请选择" |
|||
@click="handleClick" |
|||
clearable |
|||
:rules="isSignMode ? [{ required: true, message: '请选择统一社会信用代码' }] : []" /> |
|||
</div> |
|||
</template> |
|||
|
|||
<script setup name="EnterpriseInfoSection"> |
|||
const enterpriseData = defineModel({ |
|||
default: () => ({ |
|||
enterpriseName: '', |
|||
usciCode: '', |
|||
enterpriseId: '' |
|||
}) |
|||
}); |
|||
|
|||
defineProps({ |
|||
isSignMode: { |
|||
type: Boolean, |
|||
default: false |
|||
} |
|||
}); |
|||
|
|||
const emit = defineEmits(['open-picker']); |
|||
|
|||
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; |
|||
} |
|||
:deep(.van-cell) { |
|||
padding-left: 10px; |
|||
padding-right: 10px; |
|||
} |
|||
:deep(.usci-code-field .van-field__label) { |
|||
padding-left: 8px; // 按需调整 |
|||
box-sizing: border-box; |
|||
} |
|||
</style> |
|||
@ -0,0 +1,619 @@ |
|||
<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> |
|||
<van-list v-model:loading="enterpriseLoading" :finished="enterpriseFinished" :immediate-check="false" |
|||
finished-text="没有更多了" @load="loadEnterpriseList" 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.usciCode }}</div> |
|||
</div> |
|||
<van-empty v-if="enterpriseList.length === 0 && !enterpriseLoading" description="暂无数据" /> |
|||
</van-list> |
|||
</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> |
|||
<van-list v-model:loading="personLoading" :finished="personFinished" :immediate-check="false" |
|||
finished-text="没有更多了" @load="loadPersonList" class="person-list"> |
|||
<div v-for="(person, index) in personList" :key="index" class="person-list-item" |
|||
@click="handleSelectPerson(person)"> |
|||
<div class="person-name">{{ person.userName }}</div> |
|||
<div class="person-id">执法证件号:{{ person.lawEnforcerIdCard ?? person.lawEnforcerPhone }}</div> |
|||
</div> |
|||
<van-empty v-if="personList.length === 0 && !personLoading" description="暂无数据" /> |
|||
</van-list> |
|||
</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> |
|||
<van-list v-model:loading="basisLoading" :finished="basisFinished" :immediate-check="false" |
|||
finished-text="没有更多了" @load="loadBasisList" 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 && !basisLoading" description="暂无数据" /> |
|||
</van-list> |
|||
</div> |
|||
</van-popup> |
|||
|
|||
<!-- 执法时间弹窗(仅年月日,不可选今天及以前) --> |
|||
<van-popup v-model:show="localTimePopup" destroy-on-close round position="bottom"> |
|||
<van-date-picker v-model="timePickerDate" title="选择执法时间" :min-date="minDate" @confirm="handleTimeConfirm" @cancel="localTimePopup = false" /> |
|||
</van-popup> |
|||
</div> |
|||
</template> |
|||
|
|||
<script setup name="RegisterPopups"> |
|||
import { ref, reactive, watch, computed } from "vue" |
|||
import { queryListAndQrInfo, queryUsersByPage, queryAccordingList } from "@/api/nos/common" |
|||
|
|||
const props = defineProps({ |
|||
visible: { |
|||
type: Object, |
|||
required: true |
|||
}, |
|||
options: { |
|||
type: Object, |
|||
default: () => ({ |
|||
categories: [], |
|||
taskSources: [] |
|||
}) |
|||
}, |
|||
/** 当前截止时间,用于弹窗回显,格式:YYYY-MM-DD */ |
|||
deadline: { |
|||
type: String, |
|||
default: "" |
|||
} |
|||
}) |
|||
|
|||
const emit = defineEmits(["close-popup", "selectEnterprise", "confirmCategory", "confirmTaskSource", "selectPerson", "selectBasis", "selectTime"]) |
|||
|
|||
const timePickerDate = ref([]) |
|||
|
|||
const pad2 = (n) => String(n).padStart(2, "0") |
|||
|
|||
/** 最小可选日期:明天(今天之后) */ |
|||
const createMinDate = () => { |
|||
const d = new Date() |
|||
d.setHours(0, 0, 0, 0) |
|||
d.setDate(d.getDate() + 1) |
|||
return d |
|||
} |
|||
|
|||
const minDate = ref(createMinDate()) |
|||
|
|||
const dateToPickerValues = (date) => [String(date.getFullYear()), pad2(date.getMonth() + 1), pad2(date.getDate())] |
|||
|
|||
const getDefaultPickerDate = () => dateToPickerValues(createMinDate()) |
|||
|
|||
const pickerValuesToDate = ([y, m, d]) => new Date(Number(y), Number(m) - 1, Number(d)) |
|||
|
|||
const parseDeadline = (str) => { |
|||
if (!str?.trim()) { |
|||
return getDefaultPickerDate() |
|||
} |
|||
const datePart = str.trim().split(" ")[0] |
|||
const [y, m, d] = datePart.split("-") |
|||
if (!y || !m || !d) { |
|||
return getDefaultPickerDate() |
|||
} |
|||
const selected = pickerValuesToDate([y, m, d]) |
|||
if (selected < minDate.value) { |
|||
return getDefaultPickerDate() |
|||
} |
|||
return [y, pad2(m), pad2(d)] |
|||
} |
|||
|
|||
const formatDeadline = (dateValues) => { |
|||
const [y, m, d] = dateValues |
|||
return `${y}-${pad2(m)}-${pad2(d)}` |
|||
} |
|||
|
|||
const initTimePicker = () => { |
|||
minDate.value = createMinDate() |
|||
timePickerDate.value = parseDeadline(props.deadline) |
|||
} |
|||
|
|||
const handleTimeConfirm = ({ selectedValues }) => { |
|||
emit("selectTime", formatDeadline(selectedValues)) |
|||
} |
|||
// 使用 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 localTimePopup = computed({ |
|||
get: () => props.visible.time, |
|||
set: () => emit("close-popup", "time") |
|||
}) |
|||
|
|||
// ========== 企业选择相关 ========== |
|||
const enterpriseSearchKeyword = ref("") |
|||
const enterpriseList = ref([]) |
|||
const enterpriseLoading = ref(false) |
|||
const enterpriseFinished = ref(false) |
|||
const enterprisePageNum = ref(1) |
|||
const enterprisePageSize = ref(10) |
|||
|
|||
const loadEnterpriseList = () => { |
|||
if (enterpriseFinished.value) return |
|||
enterpriseLoading.value = true |
|||
|
|||
queryListAndQrInfo( |
|||
{ |
|||
pageSize: enterprisePageSize.value, |
|||
pageNum: enterprisePageNum.value, |
|||
enterpriseName: enterpriseSearchKeyword.value || undefined, |
|||
}, |
|||
(res) => { |
|||
console.log(res) |
|||
if (res.code === 200) { |
|||
const data = res.rows.map(item => ({ |
|||
enterpriseName: item.enterpriseName, |
|||
usciCode: item.enterpriseNumber, |
|||
enterpriseId: item.id |
|||
})) |
|||
const total = res.total || 0 |
|||
|
|||
if (enterprisePageNum.value === 1) { |
|||
enterpriseList.value = data |
|||
} else { |
|||
enterpriseList.value = [...enterpriseList.value, ...data] |
|||
} |
|||
|
|||
if (total <= enterprisePageSize.value * enterprisePageNum.value) { |
|||
enterpriseFinished.value = true |
|||
} else { |
|||
enterprisePageNum.value++ |
|||
} |
|||
} else { |
|||
enterpriseFinished.value = true |
|||
} |
|||
enterpriseLoading.value = false |
|||
}, |
|||
(err) => { |
|||
console.log(err) |
|||
enterpriseLoading.value = false |
|||
enterpriseFinished.value = true |
|||
} |
|||
) |
|||
} |
|||
|
|||
const initEnterpriseList = () => { |
|||
enterpriseFinished.value = false |
|||
enterprisePageNum.value = 1 |
|||
enterpriseList.value = [] |
|||
enterpriseLoading.value = false |
|||
loadEnterpriseList() |
|||
} |
|||
|
|||
const handleEnterpriseSearch = () => { |
|||
initEnterpriseList() |
|||
} |
|||
|
|||
const clearEnterpriseSearch = () => { |
|||
enterpriseSearchKeyword.value = "" |
|||
initEnterpriseList() |
|||
} |
|||
|
|||
watch(localEnterprisePopup, (val) => { |
|||
if (val) { |
|||
enterpriseSearchKeyword.value = "" |
|||
initEnterpriseList() |
|||
} |
|||
}) |
|||
|
|||
// ========== 人员查询相关 ========== |
|||
const personSearchKeyword = ref("") |
|||
const personList = ref([]) |
|||
const personLoading = ref(false) |
|||
const personFinished = ref(false) |
|||
const personPageNum = ref(1) |
|||
const personPageSize = ref(10) |
|||
|
|||
const loadPersonList = () => { |
|||
if (personFinished.value) return |
|||
personLoading.value = true |
|||
|
|||
queryUsersByPage( |
|||
{ |
|||
pageSize: personPageSize.value, |
|||
pageNum: personPageNum.value, |
|||
lawEnforcerName: personSearchKeyword.value || undefined, |
|||
}, |
|||
(res) => { |
|||
console.log(res) |
|||
if (res.code === 200) { |
|||
const data = res.rows.map(item => ({ |
|||
userId: item.userId, |
|||
userName: item.userName, |
|||
phonenumber: item.phonenumber, |
|||
lawEnforcerIdCard: item.lawCertificateNum, |
|||
lawEnforcerId: item.userId, |
|||
lawEnforcerName: item.userName, |
|||
lawEnforcerPhone: item.phonenumber, |
|||
})) |
|||
const total = res.total || res.count || 0 |
|||
|
|||
if (personPageNum.value === 1) { |
|||
personList.value = data |
|||
} else { |
|||
personList.value = [...personList.value, ...data] |
|||
} |
|||
|
|||
if (total <= personPageSize.value * personPageNum.value) { |
|||
personFinished.value = true |
|||
} else { |
|||
personPageNum.value++ |
|||
} |
|||
} else { |
|||
personFinished.value = true |
|||
} |
|||
personLoading.value = false |
|||
}, |
|||
(err) => { |
|||
console.log(err) |
|||
personLoading.value = false |
|||
personFinished.value = true |
|||
} |
|||
) |
|||
} |
|||
|
|||
const initPersonList = () => { |
|||
personFinished.value = false |
|||
personPageNum.value = 1 |
|||
personList.value = [] |
|||
personLoading.value = false |
|||
loadPersonList() |
|||
} |
|||
|
|||
const handleSelectPerson = (person) => { |
|||
emit('selectPerson', person) |
|||
} |
|||
|
|||
const handlePersonSearch = () => { |
|||
initPersonList() |
|||
} |
|||
|
|||
const clearPersonSearch = () => { |
|||
personSearchKeyword.value = "" |
|||
initPersonList() |
|||
} |
|||
|
|||
watch(localPersonPopup, (val) => { |
|||
if (val) { |
|||
personSearchKeyword.value = "" |
|||
initPersonList() |
|||
} |
|||
}) |
|||
|
|||
// ========== 执法依据相关 ========== |
|||
const basisSearchKeyword = ref("") |
|||
const enforcementBasisList = ref([]) |
|||
const basisLoading = ref(false) |
|||
const basisFinished = ref(false) |
|||
const basisPageNum = ref(1) |
|||
const basisPageSize = ref(10) |
|||
|
|||
const loadBasisList = () => { |
|||
if (basisFinished.value) return |
|||
basisLoading.value = true |
|||
|
|||
queryAccordingList( |
|||
{ |
|||
pageSize: basisPageSize.value, |
|||
pageNum: basisPageNum.value, |
|||
name: basisSearchKeyword.value || undefined, |
|||
}, |
|||
(res) => { |
|||
console.log(res) |
|||
if (res.code === 200) { |
|||
const data = res.rows.map(item => ({ |
|||
id: item.id, |
|||
name: `《${item.lawName}》`, |
|||
})) |
|||
const total = res.total || res.count || 0 |
|||
|
|||
if (basisPageNum.value === 1) { |
|||
enforcementBasisList.value = data |
|||
} else { |
|||
enforcementBasisList.value = [...enforcementBasisList.value, ...data] |
|||
} |
|||
|
|||
if (total <= basisPageSize.value * basisPageNum.value) { |
|||
basisFinished.value = true |
|||
} else { |
|||
basisPageNum.value++ |
|||
} |
|||
} else { |
|||
basisFinished.value = true |
|||
} |
|||
basisLoading.value = false |
|||
}, |
|||
(err) => { |
|||
console.log(err) |
|||
basisLoading.value = false |
|||
basisFinished.value = true |
|||
} |
|||
) |
|||
} |
|||
|
|||
const initBasisList = () => { |
|||
basisFinished.value = false |
|||
basisPageNum.value = 1 |
|||
enforcementBasisList.value = [] |
|||
basisLoading.value = false |
|||
loadBasisList() |
|||
} |
|||
|
|||
const handleBasisSearch = () => { |
|||
initBasisList() |
|||
} |
|||
|
|||
const clearBasisSearch = () => { |
|||
basisSearchKeyword.value = "" |
|||
initBasisList() |
|||
} |
|||
|
|||
watch(localBasisPopup, (val) => { |
|||
if (val) { |
|||
basisSearchKeyword.value = "" |
|||
initBasisList() |
|||
} |
|||
}) |
|||
|
|||
watch(localTimePopup, (val) => { |
|||
if (val) { |
|||
initTimePicker() |
|||
} |
|||
}) |
|||
|
|||
// ========== 预告查询相关 ========== |
|||
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> |
|||
@ -0,0 +1,39 @@ |
|||
import { baseUrl } from "@/config/env" |
|||
|
|||
const isAbsoluteUrl = (path) => typeof path === "string" && /^https?:\/\//i.test(path) |
|||
|
|||
const getApiBase = () => (baseUrl || "").replace(/\/+$/, "") |
|||
|
|||
/** |
|||
* 去掉 VITE_BASE_URL 多余前缀,支持重复前缀,得到相对路径,如 /profile/2026/... |
|||
*/ |
|||
export const toRelativeFilePath = (path) => { |
|||
if (typeof path !== "string" || !path) return "" |
|||
if (isAbsoluteUrl(path)) return path |
|||
|
|||
const prefix = getApiBase() |
|||
let p = path.startsWith("/") ? path : `/${path}` |
|||
|
|||
if (prefix) { |
|||
const normalizedPrefix = prefix.startsWith("/") ? prefix : `/${prefix}` |
|||
while (p === normalizedPrefix || p.startsWith(`${normalizedPrefix}/`)) { |
|||
p = p.slice(normalizedPrefix.length) || "/" |
|||
if (!p.startsWith("/")) p = `/${p}` |
|||
} |
|||
} |
|||
|
|||
return p |
|||
} |
|||
|
|||
/** |
|||
* 拼接为前端可访问路径,如 /profile/2026/06/12/xxx.pdf |
|||
*/ |
|||
export const toFullFileUrl = (path) => { |
|||
if (typeof path !== "string" || !path) return "" |
|||
if (isAbsoluteUrl(path)) return path |
|||
|
|||
const prefix = getApiBase() |
|||
const relative = toRelativeFilePath(path) |
|||
if (!prefix) return relative |
|||
return prefix + relative |
|||
} |
|||
Loading…
Reference in new issue