|
|
<template>
|
|
|
<view class="page">
|
|
|
<!-- 门岗访客管理页面 -->
|
|
|
<!-- 头部导航 -->
|
|
|
<view class="gate-header">
|
|
|
<view class="gate-left">
|
|
|
<view class="today-visitors" @click="openList">访客列表</view>
|
|
|
</view>
|
|
|
</view>
|
|
|
|
|
|
<!-- 主要内容区域 -->
|
|
|
<view class="gate-content">
|
|
|
<view class="form-container">
|
|
|
<view class="form-title">填写信息</view>
|
|
|
<!-- 拜访日期选择 - 时间段选择 -->
|
|
|
<view class="form-item">
|
|
|
<text class="form-label">※ 拜访日期:</text>
|
|
|
<view class="date-range-container">
|
|
|
<picker
|
|
|
mode="date"
|
|
|
:value="select.start_date"
|
|
|
@change="onStartDateChange"
|
|
|
class="date-picker"
|
|
|
>
|
|
|
<view class="form-input date-input">
|
|
|
<text>{{ select.start_date || "开始日期" }}</text>
|
|
|
</view>
|
|
|
</picker>
|
|
|
<view class="date-separator">至</view>
|
|
|
<picker
|
|
|
mode="date"
|
|
|
:value="select.end_date"
|
|
|
@change="onEndDateChange"
|
|
|
class="date-picker"
|
|
|
>
|
|
|
<view class="form-input date-input">
|
|
|
<text>{{ select.end_date || "结束日期" }}</text>
|
|
|
</view>
|
|
|
</picker>
|
|
|
</view>
|
|
|
</view>
|
|
|
|
|
|
<!-- 核验销码输入 -->
|
|
|
<view class="form-item">
|
|
|
<text class="form-label">※ 核验销码:</text>
|
|
|
<input
|
|
|
v-model="select.code"
|
|
|
placeholder="请扫描访客二维码"
|
|
|
@input="onCodeInput"
|
|
|
class="form-input input-field"
|
|
|
/>
|
|
|
</view>
|
|
|
|
|
|
<!-- 身份证输入 -->
|
|
|
<view class="form-item">
|
|
|
<text class="form-label">※ 身份证件:</text>
|
|
|
<view class="id-input-group idcard-group">
|
|
|
<input
|
|
|
v-model="select.idcard"
|
|
|
placeholder="请输入身份证"
|
|
|
class="form-input input-field"
|
|
|
/>
|
|
|
<!-- #ifdef H5 -->
|
|
|
<view class="id-action" @click="getIdcard">查询身份证</view>
|
|
|
<!-- #endif -->
|
|
|
</view>
|
|
|
</view>
|
|
|
|
|
|
<!-- ID卡输入 -->
|
|
|
<view class="form-item">
|
|
|
<text class="form-label">※ ID卡:</text>
|
|
|
<view class="id-input-group">
|
|
|
<input
|
|
|
v-model="select.person_no"
|
|
|
placeholder="请输入ID卡"
|
|
|
class="form-input input-field"
|
|
|
/>
|
|
|
<!-- <button @click="getIdcard" class="btn btn-primary id-btn">查询身份证</button> -->
|
|
|
</view>
|
|
|
</view>
|
|
|
|
|
|
<!-- 查询按钮 -->
|
|
|
<view class="form-item query-btn-container">
|
|
|
<button
|
|
|
@click="getList"
|
|
|
class="btn btn-primary query-btn"
|
|
|
:disabled="loading"
|
|
|
>
|
|
|
{{ loading ? "查询中..." : "查询" }}
|
|
|
</button>
|
|
|
</view>
|
|
|
</view>
|
|
|
</view>
|
|
|
|
|
|
<!-- 访客信息弹窗 -->
|
|
|
<view v-if="visitShow" class="modal-overlay" @click="closeVisitModal">
|
|
|
<view class="modal-content" @click.stop>
|
|
|
<view class="modal-header">
|
|
|
<text class="modal-title">访客信息</text>
|
|
|
</view>
|
|
|
<view class="modal-body">
|
|
|
<view class="visit-info" v-if="visitData">
|
|
|
<!-- 拜访信息 -->
|
|
|
<view class="info-section">
|
|
|
<text class="section-title">拜访信息</text>
|
|
|
<view class="info-item">
|
|
|
<text class="info-label">拜访类型:</text>
|
|
|
<text class="info-value">{{
|
|
|
getVisitTypeText(visitData.type)
|
|
|
}}</text>
|
|
|
</view>
|
|
|
<view class="info-item">
|
|
|
<text class="info-label">拜访日期:</text>
|
|
|
<text class="info-value">{{
|
|
|
getVisitDateRange(visitData)
|
|
|
}}</text>
|
|
|
</view>
|
|
|
<view class="info-item">
|
|
|
<text class="info-label">到访时间:</text>
|
|
|
<text class="info-value">{{
|
|
|
visitData.time ? visitData.time : ""
|
|
|
}}</text>
|
|
|
</view>
|
|
|
<view class="info-item" v-if="visitData.visit_time_detail">
|
|
|
<text class="info-label">到访时段:</text>
|
|
|
<text class="info-value"
|
|
|
>{{ visitData.visit_time_detail.start_time }} -
|
|
|
{{ visitData.visit_time_detail.end_time }}</text
|
|
|
>
|
|
|
</view>
|
|
|
<view class="info-item" v-if="visitData.visit_area_detail">
|
|
|
<text class="info-label">前往区域:</text>
|
|
|
<text class="info-value">{{
|
|
|
visitData.visit_area_detail.name
|
|
|
}}</text>
|
|
|
</view>
|
|
|
<view class="info-item" v-if="visitData.reason">
|
|
|
<text class="info-label">到访事由:</text>
|
|
|
<text class="info-value">{{ visitData.reason }}</text>
|
|
|
</view>
|
|
|
<view
|
|
|
class="info-item"
|
|
|
v-if="visitData.cars && visitData.cars.length > 0"
|
|
|
>
|
|
|
<text class="info-label">到访车辆:</text>
|
|
|
<text class="info-value">{{ visitData.cars.join(", ") }}</text>
|
|
|
</view>
|
|
|
<view class="info-item" v-if="visitData.plate">
|
|
|
<text class="info-label">车辆类型:</text>
|
|
|
<text class="info-value">{{ visitData.plate }}</text>
|
|
|
</view>
|
|
|
</view>
|
|
|
<!-- 被访人信息 -->
|
|
|
<view class="info-section">
|
|
|
<text class="section-title">被访人信息</text>
|
|
|
<view class="info-item">
|
|
|
<text class="info-label">被访人:</text>
|
|
|
<text class="info-value">{{
|
|
|
visitData.accept_admin ? visitData.accept_admin.name : "-"
|
|
|
}}</text>
|
|
|
</view>
|
|
|
<!-- <view class="info-item" v-if="visitData.accompanyName">
|
|
|
<text class="info-label">陪同人:</text>
|
|
|
<text class="info-value">{{ visitData.accompanyName }}</text>
|
|
|
</view>
|
|
|
<view class="info-item" v-if="visitData.goodsName">
|
|
|
<text class="info-label">收货人:</text>
|
|
|
<text class="info-value">{{ visitData.goodsName }}</text>
|
|
|
</view> -->
|
|
|
</view>
|
|
|
<!-- 拜访人信息 -->
|
|
|
<view class="info-section">
|
|
|
<text class="section-title">拜访人信息</text>
|
|
|
<view class="info-item">
|
|
|
<text class="info-label">姓名:</text>
|
|
|
<text class="info-value">{{ visitData.name }}</text>
|
|
|
</view>
|
|
|
<view class="info-item">
|
|
|
<text class="info-label">联系电话:</text>
|
|
|
<text class="info-value">{{ visitData.mobile }}</text>
|
|
|
</view>
|
|
|
<view class="info-item" v-if="visitData.credent">
|
|
|
<text class="info-label">证件类型:</text>
|
|
|
<text class="info-value">{{
|
|
|
visitData.credent == 1 ? "身份证" : "护照"
|
|
|
}}</text>
|
|
|
</view>
|
|
|
<view class="info-item" v-if="visitData.idcard">
|
|
|
<text class="info-label">{{
|
|
|
visitData.credent == 1 ? "身份证号:" : "护照号码:"
|
|
|
}}</text>
|
|
|
<text class="info-value">{{ visitData.idcard }}</text>
|
|
|
</view>
|
|
|
<view class="info-item" v-if="visitData.company_name">
|
|
|
<text class="info-label">单位名称:</text>
|
|
|
<text class="info-value">{{ visitData.company_name }}</text>
|
|
|
</view>
|
|
|
<view class="info-item">
|
|
|
<text class="info-label">状态:</text>
|
|
|
<text class="info-value status-badge"
|
|
|
:class="getStatusInfo(visitData.audit_status).class">
|
|
|
{{ getStatusInfo(visitData.audit_status).text }}</text>
|
|
|
</view>
|
|
|
<!-- 人员编号输入 -->
|
|
|
<view class="info-item">
|
|
|
<text class="info-label">ID卡:</text>
|
|
|
<view class="info-input-wrapper">
|
|
|
<input
|
|
|
v-model="personNoValue"
|
|
|
placeholder="请输入ID卡"
|
|
|
class="info-input"
|
|
|
/>
|
|
|
</view>
|
|
|
</view>
|
|
|
</view>
|
|
|
|
|
|
<!-- 随访人员信息 -->
|
|
|
<view
|
|
|
class="info-section"
|
|
|
v-if="visitData.follw_people && visitData.follw_people.length > 0"
|
|
|
>
|
|
|
<text class="section-title">随访人员</text>
|
|
|
<view
|
|
|
v-for="(person, index) in visitData.follw_people"
|
|
|
:key="index"
|
|
|
class="follow-person-item"
|
|
|
>
|
|
|
<view class="info-item">
|
|
|
<text class="info-label">姓名:</text>
|
|
|
<text class="info-value">{{ person.name }}</text>
|
|
|
</view>
|
|
|
<view class="info-item">
|
|
|
<text class="info-label">联系电话:</text>
|
|
|
<text class="info-value">{{ person.mobile }}</text>
|
|
|
</view>
|
|
|
<view class="info-item" v-if="person.credent">
|
|
|
<text class="info-label">证件类型:</text>
|
|
|
<text class="info-value">{{
|
|
|
person.credent == 1 ? "身份证" : "护照"
|
|
|
}}</text>
|
|
|
</view>
|
|
|
<view class="info-item" v-if="person.idcard">
|
|
|
<text class="info-label">{{
|
|
|
person.credent == 1 ? "身份证号:" : "护照号码:"
|
|
|
}}</text>
|
|
|
<text class="info-value">{{ person.idcard }}</text>
|
|
|
</view>
|
|
|
<!-- ID卡输入框 -->
|
|
|
<view class="info-item">
|
|
|
<text class="info-label">ID卡:</text>
|
|
|
<view class="info-input-wrapper">
|
|
|
<input
|
|
|
v-model="person.follw_people_person_no"
|
|
|
placeholder="请输入ID卡"
|
|
|
class="info-input"
|
|
|
/>
|
|
|
</view>
|
|
|
</view>
|
|
|
<view
|
|
|
class="separator"
|
|
|
v-if="index < visitData.follw_people.length - 1"
|
|
|
></view>
|
|
|
</view>
|
|
|
</view>
|
|
|
|
|
|
<!-- 备注输入 -->
|
|
|
<view class="info-item">
|
|
|
<text class="info-label">备注:</text>
|
|
|
<view class="info-input-wrapper">
|
|
|
<textarea
|
|
|
rows="3"
|
|
|
v-model="remarkValue"
|
|
|
placeholder="请输入备注信息"
|
|
|
class="info-textarea"
|
|
|
></textarea>
|
|
|
</view>
|
|
|
</view>
|
|
|
|
|
|
<!-- 车辆照片上传 (仅type==3时显示) -->
|
|
|
<view
|
|
|
v-if="visitData.type == 3"
|
|
|
class="info-item photo-upload-section"
|
|
|
>
|
|
|
<text class="info-label">车辆照片:</text>
|
|
|
<view class="photo-upload-container">
|
|
|
<!-- 照片列表 -->
|
|
|
<view class="uploaded-photos">
|
|
|
<!-- 已上传的照片 -->
|
|
|
<view
|
|
|
v-for="(image, index) in vehicleImages"
|
|
|
:key="index"
|
|
|
class="photo-item"
|
|
|
>
|
|
|
<image
|
|
|
:src="image.url"
|
|
|
class="photo-preview"
|
|
|
mode="aspectFill"
|
|
|
@click="previewImage(image.url)"
|
|
|
></image>
|
|
|
<view class="photo-delete" @click="removeImage(index)"
|
|
|
>×</view
|
|
|
>
|
|
|
</view>
|
|
|
|
|
|
<!-- 添加照片按钮(最多9张) -->
|
|
|
<view
|
|
|
v-if="vehicleImages.length < 9"
|
|
|
class="photo-item add-photo-btn"
|
|
|
@click="showPhotoOptions"
|
|
|
>
|
|
|
<view class="add-photo-icon">+</view>
|
|
|
<view class="add-photo-text">添加照片</view>
|
|
|
</view>
|
|
|
</view>
|
|
|
|
|
|
<!-- 底部选择弹窗 -->
|
|
|
<view v-if="showPhotoActionSheet" class="photo-action-sheet">
|
|
|
<view
|
|
|
class="action-sheet-overlay"
|
|
|
@click="hidePhotoOptions"
|
|
|
></view>
|
|
|
<view class="action-sheet-content">
|
|
|
<view class="action-sheet-item" @click="chooseImage">
|
|
|
<text class="action-sheet-text">选择照片</text>
|
|
|
</view>
|
|
|
<view class="action-sheet-item" @click="takePhoto">
|
|
|
<text class="action-sheet-text">拍照</text>
|
|
|
</view>
|
|
|
<view class="action-sheet-cancel" @click="hidePhotoOptions">
|
|
|
<text class="action-sheet-cancel-text">取消</text>
|
|
|
</view>
|
|
|
</view>
|
|
|
</view>
|
|
|
</view>
|
|
|
</view>
|
|
|
</view>
|
|
|
</view>
|
|
|
<view class="modal-footer">
|
|
|
<button @click="closeVisitModal" class="btn btn-secondary">
|
|
|
关闭
|
|
|
</button>
|
|
|
<button
|
|
|
@click="updateVisitInfo"
|
|
|
class="btn btn-primary"
|
|
|
:disabled="updating"
|
|
|
>
|
|
|
{{ updating ? "更新并核销中..." : "更新并核销" }}
|
|
|
</button>
|
|
|
</view>
|
|
|
</view>
|
|
|
</view>
|
|
|
|
|
|
<!-- 今日访客列表弹窗 -->
|
|
|
<view v-if="listShow" class="modal-overlay" @click="closeListModal">
|
|
|
<view class="modal-content" @click.stop>
|
|
|
<view class="modal-header">
|
|
|
<text class="modal-title">访客列表</text>
|
|
|
</view>
|
|
|
<view class="modal-body">
|
|
|
<view class="visitor-list">
|
|
|
<view v-if="todayVisitors.length === 0" class="empty-state">
|
|
|
<text>暂无访客记录</text>
|
|
|
</view>
|
|
|
<view v-else>
|
|
|
<view class="visitor-header">
|
|
|
<view class="visitor-col visitor-col-name">姓名</view>
|
|
|
<view class="visitor-col visitor-col-visited">被访人</view>
|
|
|
<view class="visitor-col visitor-col-status">状态</view>
|
|
|
</view>
|
|
|
<view
|
|
|
v-for="visitor in todayVisitors"
|
|
|
:key="visitor.id"
|
|
|
class="visitor-item"
|
|
|
>
|
|
|
<view class="visitor-name">{{ visitor.name }}</view>
|
|
|
<view class="visitor-visited">{{
|
|
|
visitor.accept_admin ? visitor.accept_admin.name : "-"
|
|
|
}}</view>
|
|
|
<view
|
|
|
class="visitor-status status-badge"
|
|
|
:class="getStatusInfo(visitor.audit_status).class"
|
|
|
>
|
|
|
{{ getStatusInfo(visitor.audit_status).text }}
|
|
|
</view>
|
|
|
</view>
|
|
|
</view>
|
|
|
</view>
|
|
|
</view>
|
|
|
<view class="modal-footer">
|
|
|
<button @click="closeListModal" size="mini" class="btn btn-primary">
|
|
|
关闭
|
|
|
</button>
|
|
|
</view>
|
|
|
</view>
|
|
|
</view>
|
|
|
</view>
|
|
|
</template>
|
|
|
|
|
|
<script>
|
|
|
import { openDevice, readIdCard, closeDevice } from "@/common/reader.js";
|
|
|
export default {
|
|
|
data() {
|
|
|
return {
|
|
|
fullscreen: false,
|
|
|
loading: false,
|
|
|
dateRangeText: "",
|
|
|
select: {
|
|
|
page: 1,
|
|
|
rows: 999,
|
|
|
keyword: "",
|
|
|
audit_status: "",
|
|
|
start_date: "",
|
|
|
end_date: "",
|
|
|
is_export: 0,
|
|
|
code: "",
|
|
|
idcard: "",
|
|
|
person_no: "", // ID卡
|
|
|
},
|
|
|
visitShow: false,
|
|
|
visitData: null,
|
|
|
vehicleImages: [], // 车辆照片数组
|
|
|
originalVehicleImageIds: [], // 进入弹窗时原有的车辆照片ID,用于识别新上传的照片
|
|
|
remarkValue: "", // 备注值
|
|
|
personNoValue: "", // 人员编号
|
|
|
uploading: false, // 上传状态
|
|
|
updating: false, // 更新状态
|
|
|
showPhotoActionSheet: false, // 控制照片选择弹窗显示
|
|
|
listShow: false,
|
|
|
todayVisitors: [],
|
|
|
// 提交的核销数据
|
|
|
codeForm: {
|
|
|
code: "",
|
|
|
type: "",
|
|
|
},
|
|
|
statusList: [
|
|
|
{
|
|
|
id: -1,
|
|
|
value: "待学习",
|
|
|
},
|
|
|
{
|
|
|
id: 0,
|
|
|
value: "待审核",
|
|
|
},
|
|
|
{
|
|
|
id: 1,
|
|
|
value: "通过(待进厂)",
|
|
|
},
|
|
|
{
|
|
|
id: 2,
|
|
|
value: "驳回",
|
|
|
},
|
|
|
{
|
|
|
id: 3,
|
|
|
value: "已进厂",
|
|
|
},
|
|
|
{
|
|
|
id: 4,
|
|
|
value: "已离厂",
|
|
|
},
|
|
|
{
|
|
|
id: 5,
|
|
|
value: "已取消",
|
|
|
},
|
|
|
],
|
|
|
};
|
|
|
},
|
|
|
onLoad() {
|
|
|
this.checkAuth();
|
|
|
},
|
|
|
onReachBottom() {
|
|
|
// 上拉加载更多
|
|
|
},
|
|
|
onPullDownRefresh() {
|
|
|
// 下拉刷新
|
|
|
this.getToday();
|
|
|
uni.stopPullDownRefresh();
|
|
|
},
|
|
|
methods: {
|
|
|
// 链接读卡器
|
|
|
connectReader() {
|
|
|
openDevice().then((res) => {
|
|
|
console.log("链接读卡器", res);
|
|
|
if (res.data.resultFlag == 0) {
|
|
|
uni.showToast({
|
|
|
title: "身份证读卡器链接成功",
|
|
|
icon: "none",
|
|
|
});
|
|
|
} else {
|
|
|
uni.showToast({
|
|
|
title: "身份证读卡器链接失败",
|
|
|
icon: "none",
|
|
|
});
|
|
|
}
|
|
|
});
|
|
|
},
|
|
|
// 检查认证状态
|
|
|
async checkAuth() {
|
|
|
try {
|
|
|
// 检查是否有token
|
|
|
const lifeData = uni.getStorageSync("mkwcancel_lifeData");
|
|
|
const token = lifeData?.vuex_token || this.$store.state.vuex_token;
|
|
|
|
|
|
if (!token) {
|
|
|
// 没有token,直接跳转到登录页
|
|
|
uni.reLaunch({
|
|
|
url: "/pages/login/index",
|
|
|
});
|
|
|
return;
|
|
|
}
|
|
|
// 链接读卡器
|
|
|
this.connectReader();
|
|
|
// 有token,验证token有效性
|
|
|
const userRes = await this.$u.api.user();
|
|
|
console.log("用户信息验证:", userRes);
|
|
|
|
|
|
if (userRes) {
|
|
|
// token有效,存储用户信息
|
|
|
this.$u.vuex("vuex_user", userRes);
|
|
|
this.$u.vuex("vuex_token", token); // 确保在vuex中
|
|
|
// 初始化页面数据
|
|
|
this.getToday();
|
|
|
} else {
|
|
|
// token无效(但这种情况应该在http.interceptor.js中处理)
|
|
|
this.redirectToLogin();
|
|
|
}
|
|
|
} catch (error) {
|
|
|
console.error("认证检查失败:", error);
|
|
|
// 错误情况下也跳转到登录页(通常由interceptor处理)
|
|
|
// 这里不需要手动跳转,因为40001错误会在interceptor中自动跳转
|
|
|
}
|
|
|
},
|
|
|
|
|
|
// 根据audit_status获取状态文本和样式类
|
|
|
getStatusInfo(auditStatus) {
|
|
|
const status = this.statusList.find((item) => item.id === auditStatus);
|
|
|
return {
|
|
|
text: status ? status.value : "未知状态",
|
|
|
class: this.getStatusClass(auditStatus),
|
|
|
};
|
|
|
},
|
|
|
|
|
|
// 根据audit_status获取样式类名
|
|
|
getStatusClass(auditStatus) {
|
|
|
const statusClasses = {
|
|
|
"-1": "status-study", // 待学习 - 橙色
|
|
|
0: "status-pending", // 待审核 - 蓝色
|
|
|
1: "status-approved", // 通过(待进厂) - 绿色
|
|
|
2: "status-rejected", // 驳回 - 红色
|
|
|
3: "status-entered", // 已进厂 - 深绿色
|
|
|
4: "status-left", // 已离厂 - 灰色
|
|
|
5: "status-cancelled", // 已取消 - 深灰色
|
|
|
};
|
|
|
return statusClasses[auditStatus.toString()] || "status-unknown";
|
|
|
},
|
|
|
|
|
|
// 根据type获取拜访类型文本
|
|
|
getVisitTypeText(type) {
|
|
|
const typeMap = {
|
|
|
1: "普通访客",
|
|
|
2: "施工访客",
|
|
|
3: "物流车辆",
|
|
|
};
|
|
|
return typeMap[type] || "未知类型";
|
|
|
},
|
|
|
|
|
|
// 获取拜访日期范围显示文本
|
|
|
getVisitDateRange(visitData) {
|
|
|
// 如果开始日期或结束日期为空,使用date字段
|
|
|
if (!visitData.start_date || !visitData.end_date) {
|
|
|
const date =
|
|
|
visitData.date || visitData.start_date || visitData.end_date;
|
|
|
return date ? `${date} 至 ${date}` : "-";
|
|
|
}
|
|
|
|
|
|
// 如果开始日期和结束日期相同,只显示一个日期
|
|
|
if (visitData.start_date === visitData.end_date) {
|
|
|
return visitData.start_date;
|
|
|
}
|
|
|
|
|
|
// 正常显示日期范围
|
|
|
return `${visitData.start_date} 至 ${visitData.end_date}`;
|
|
|
},
|
|
|
|
|
|
// 跳转到登录页
|
|
|
redirectToLogin() {
|
|
|
uni.reLaunch({
|
|
|
url: "/pages/login/index",
|
|
|
});
|
|
|
},
|
|
|
|
|
|
// 打开今日访客列表
|
|
|
openList() {
|
|
|
this.getTodayVisitors();
|
|
|
this.listShow = true;
|
|
|
},
|
|
|
|
|
|
// 获取今日日期
|
|
|
getToday() {
|
|
|
const now = new Date();
|
|
|
const year = now.getFullYear();
|
|
|
const month = String(now.getMonth() + 1).padStart(2, "0");
|
|
|
const day = String(now.getDate()).padStart(2, "0");
|
|
|
const today = `${year}-${month}-${day}`;
|
|
|
|
|
|
this.select.start_date = today;
|
|
|
this.select.end_date = today;
|
|
|
},
|
|
|
|
|
|
// 开始日期选择
|
|
|
onStartDateChange(e) {
|
|
|
const selectedDate = e.detail.value;
|
|
|
this.select.start_date = selectedDate;
|
|
|
|
|
|
// 如果结束日期早于开始日期,自动设置为开始日期
|
|
|
if (this.select.end_date && this.select.end_date < selectedDate) {
|
|
|
this.select.end_date = selectedDate;
|
|
|
}
|
|
|
},
|
|
|
|
|
|
// 结束日期选择
|
|
|
onEndDateChange(e) {
|
|
|
const selectedDate = e.detail.value;
|
|
|
|
|
|
// 如果结束日期早于开始日期,提示用户
|
|
|
if (this.select.start_date && selectedDate < this.select.start_date) {
|
|
|
uni.showToast({
|
|
|
title: "结束日期不能早于开始日期",
|
|
|
icon: "none",
|
|
|
});
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
this.select.end_date = selectedDate;
|
|
|
},
|
|
|
|
|
|
// 核销码输入变化
|
|
|
onCodeInput(e) {
|
|
|
this.select.code = e.detail.value;
|
|
|
if (this.select.code) {
|
|
|
this.getList();
|
|
|
}
|
|
|
},
|
|
|
|
|
|
// 清空输入
|
|
|
clearInputs() {
|
|
|
this.select.code = "";
|
|
|
this.select.idcard = "";
|
|
|
this.select.person_no = "";
|
|
|
},
|
|
|
|
|
|
// 查询访客信息
|
|
|
async getList() {
|
|
|
if (!this.select.code && !this.select.idcard && !this.select.person_no) {
|
|
|
uni.showToast({
|
|
|
title: "请输入核销码或身份证件或ID卡",
|
|
|
icon: "none",
|
|
|
});
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
this.loading = true;
|
|
|
try {
|
|
|
// 这里需要根据实际情况替换API调用
|
|
|
// 使用visitList接口查询访客
|
|
|
const searchParams = {
|
|
|
start_date: this.select.start_date,
|
|
|
end_date: this.select.end_date,
|
|
|
};
|
|
|
|
|
|
// 添加搜索条件
|
|
|
if (this.select.code) {
|
|
|
searchParams.code = this.select.code;
|
|
|
}
|
|
|
if (this.select.idcard) {
|
|
|
searchParams.idcard = this.select.idcard;
|
|
|
}
|
|
|
if (this.select.person_no) {
|
|
|
searchParams.person_no = this.select.person_no;
|
|
|
}
|
|
|
|
|
|
const res = await this.$u.api.visitList(searchParams);
|
|
|
|
|
|
if (res && res.data && res.data.length > 0) {
|
|
|
const visitor = res.data[0];
|
|
|
if (visitor.audit_status == 1 || visitor.audit_status == 3) {
|
|
|
// 设置访客数据,包含新增的拜访信息字段:
|
|
|
// type, start_date, end_date, visit_time_detail, visit_area_detail,
|
|
|
// reason, cars, plate, credent, idcard, company_name, cda,
|
|
|
// follw_people, accompanyName, goodsName
|
|
|
this.visitData = visitor;
|
|
|
|
|
|
// 确保每个随访人员都有follw_people_person_no字段
|
|
|
if (
|
|
|
this.visitData.follw_people &&
|
|
|
this.visitData.follw_people.length > 0
|
|
|
) {
|
|
|
this.visitData.follw_people.forEach((person) => {
|
|
|
if (!person.follw_people_person_no) {
|
|
|
person.follw_people_person_no = "";
|
|
|
}
|
|
|
});
|
|
|
}
|
|
|
this.personNoValue = visitor.person_no;
|
|
|
this.remarkValue = visitor.remark;
|
|
|
if (
|
|
|
visitor.vehicle_images_detail &&
|
|
|
visitor.vehicle_images_detail.length > 0
|
|
|
) {
|
|
|
let arr = [];
|
|
|
visitor.vehicle_images_detail.map((item) => {
|
|
|
arr.push({
|
|
|
id: item.id,
|
|
|
url: item.url,
|
|
|
});
|
|
|
});
|
|
|
this.vehicleImages = arr;
|
|
|
// 记录原始车辆照片ID列表,用于后续判断是否有新照片
|
|
|
this.originalVehicleImageIds = arr.map((item) => item.id);
|
|
|
} else {
|
|
|
this.vehicleImages = [];
|
|
|
this.originalVehicleImageIds = [];
|
|
|
}
|
|
|
// 核销的值
|
|
|
this.codeForm.code = visitor.code;
|
|
|
this.codeForm.type = visitor.audit_status == 1 ? 1 : 2; //(visitor.audit_status == 3 && visitor.accept_admin_sign ? 2 : 0) 离厂陪同人员签字
|
|
|
|
|
|
this.visitShow = true;
|
|
|
} else {
|
|
|
const statusInfo = this.getStatusInfo(visitor.audit_status);
|
|
|
uni.showToast({
|
|
|
title: statusInfo.text,
|
|
|
icon: "none",
|
|
|
});
|
|
|
}
|
|
|
} else {
|
|
|
uni.showToast({
|
|
|
title: "未查询到记录",
|
|
|
icon: "none",
|
|
|
});
|
|
|
}
|
|
|
} catch (error) {
|
|
|
uni.showToast({
|
|
|
title: "查询失败",
|
|
|
icon: "none",
|
|
|
});
|
|
|
} finally {
|
|
|
this.loading = false;
|
|
|
}
|
|
|
},
|
|
|
// 核销
|
|
|
cancelCode() {
|
|
|
console.log(this.codeForm);
|
|
|
if (this.codeForm.type == 0) {
|
|
|
uni.showToast({
|
|
|
title: "请提醒陪同人签字",
|
|
|
icon: "none",
|
|
|
});
|
|
|
return;
|
|
|
}
|
|
|
this.$u.api.visitCancel(this.codeForm).then((res) => {
|
|
|
// if (res.code == 200) {
|
|
|
// this.$successMessage(res.msg, '', 'success')
|
|
|
// }
|
|
|
console.log(res);
|
|
|
uni.showToast({
|
|
|
title: "核销成功",
|
|
|
icon: "none",
|
|
|
});
|
|
|
});
|
|
|
},
|
|
|
// 读取身份证
|
|
|
getIdcard() {
|
|
|
this.select.idcard = "";
|
|
|
readIdCard().then((res) => {
|
|
|
console.log("读取身份证", res);
|
|
|
if (res.data.resultFlag == 0) {
|
|
|
this.select.idcard = res.data.certNumber;
|
|
|
this.getList();
|
|
|
} else {
|
|
|
uni.showToast({
|
|
|
title: "读取身份证失败",
|
|
|
icon: "none",
|
|
|
});
|
|
|
}
|
|
|
});
|
|
|
},
|
|
|
|
|
|
// 切换全屏
|
|
|
toggleFullscreen() {
|
|
|
// #ifdef H5
|
|
|
const element = document.documentElement;
|
|
|
if (this.fullscreen) {
|
|
|
if (document.exitFullscreen) {
|
|
|
document.exitFullscreen();
|
|
|
} else if (document.webkitCancelFullScreen) {
|
|
|
document.webkitCancelFullScreen();
|
|
|
} else if (document.mozCancelFullScreen) {
|
|
|
document.mozCancelFullScreen();
|
|
|
} else if (document.msExitFullscreen) {
|
|
|
document.msExitFullscreen();
|
|
|
}
|
|
|
} else {
|
|
|
if (element.requestFullscreen) {
|
|
|
element.requestFullscreen();
|
|
|
} else if (element.webkitRequestFullScreen) {
|
|
|
element.webkitRequestFullScreen();
|
|
|
} else if (element.mozRequestFullScreen) {
|
|
|
element.mozRequestFullScreen();
|
|
|
} else if (element.msRequestFullscreen) {
|
|
|
element.msRequestFullscreen();
|
|
|
}
|
|
|
}
|
|
|
this.fullscreen = !this.fullscreen;
|
|
|
// #endif
|
|
|
},
|
|
|
|
|
|
// 关闭访客信息弹窗
|
|
|
closeVisitModal() {
|
|
|
this.visitShow = false;
|
|
|
this.visitData = null;
|
|
|
// 清空输入数据
|
|
|
this.vehicleImages = [];
|
|
|
this.originalVehicleImageIds = [];
|
|
|
this.remarkValue = "";
|
|
|
this.personNoValue = "";
|
|
|
this.uploading = false;
|
|
|
this.updating = false;
|
|
|
this.showPhotoActionSheet = false;
|
|
|
},
|
|
|
|
|
|
// 显示照片选择选项
|
|
|
showPhotoOptions() {
|
|
|
this.showPhotoActionSheet = true;
|
|
|
},
|
|
|
|
|
|
// 隐藏照片选择选项
|
|
|
hidePhotoOptions() {
|
|
|
this.showPhotoActionSheet = false;
|
|
|
},
|
|
|
|
|
|
// 选择照片
|
|
|
chooseImage() {
|
|
|
this.hidePhotoOptions();
|
|
|
const remainingCount = 9 - this.vehicleImages.length;
|
|
|
uni.chooseImage({
|
|
|
count: remainingCount, // 根据已上传数量动态计算
|
|
|
sizeType: ["original", "compressed"],
|
|
|
sourceType: ["album"],
|
|
|
success: (res) => {
|
|
|
this.uploadImages(res.tempFilePaths);
|
|
|
},
|
|
|
});
|
|
|
},
|
|
|
|
|
|
// 拍照
|
|
|
takePhoto() {
|
|
|
this.hidePhotoOptions();
|
|
|
uni.chooseImage({
|
|
|
count: 1,
|
|
|
sizeType: ["original", "compressed"],
|
|
|
sourceType: ["camera"],
|
|
|
success: (res) => {
|
|
|
this.uploadImages(res.tempFilePaths);
|
|
|
},
|
|
|
});
|
|
|
},
|
|
|
|
|
|
// 上传图片
|
|
|
async uploadImages(filePaths) {
|
|
|
if (!filePaths || filePaths.length === 0) return;
|
|
|
|
|
|
this.uploading = true;
|
|
|
|
|
|
try {
|
|
|
for (const filePath of filePaths) {
|
|
|
const uploadRes = await this.uploadSingleImage(filePath);
|
|
|
console.log("uploadRes123", uploadRes);
|
|
|
if (uploadRes && uploadRes.id) {
|
|
|
this.vehicleImages.push({
|
|
|
id: uploadRes.id,
|
|
|
url: uploadRes.url || filePath, // 使用返回的URL或本地路径
|
|
|
});
|
|
|
}
|
|
|
console.log("this.vehicleImages", this.vehicleImages);
|
|
|
}
|
|
|
|
|
|
uni.showToast({
|
|
|
title: "上传成功",
|
|
|
icon: "success",
|
|
|
});
|
|
|
} catch (error) {
|
|
|
console.error("上传失败:", error);
|
|
|
uni.showToast({
|
|
|
title: "上传失败",
|
|
|
icon: "none",
|
|
|
});
|
|
|
} finally {
|
|
|
this.uploading = false;
|
|
|
}
|
|
|
},
|
|
|
|
|
|
// 上传单张图片
|
|
|
uploadSingleImage(filePath) {
|
|
|
return new Promise((resolve, reject) => {
|
|
|
uni.uploadFile({
|
|
|
url: this.$u.http.config.baseUrl + "/api/admin/upload-file",
|
|
|
filePath: filePath,
|
|
|
name: "file",
|
|
|
header: {
|
|
|
Authorization: `Bearer ${this.$store.state.vuex_token}`,
|
|
|
},
|
|
|
success: (uploadRes) => {
|
|
|
try {
|
|
|
console.log("uploadRes", uploadRes);
|
|
|
const data = JSON.parse(uploadRes.data);
|
|
|
if (data && data.id) {
|
|
|
resolve(data);
|
|
|
} else {
|
|
|
reject("上传响应格式错误");
|
|
|
}
|
|
|
} catch (error) {
|
|
|
reject("解析上传响应失败");
|
|
|
}
|
|
|
},
|
|
|
fail: (error) => {
|
|
|
reject(error);
|
|
|
},
|
|
|
});
|
|
|
});
|
|
|
},
|
|
|
|
|
|
// 删除图片
|
|
|
removeImage(index) {
|
|
|
uni.showModal({
|
|
|
title: "确认删除",
|
|
|
content: "确定要删除这张照片吗?",
|
|
|
success: (res) => {
|
|
|
if (res.confirm) {
|
|
|
this.vehicleImages.splice(index, 1);
|
|
|
}
|
|
|
},
|
|
|
});
|
|
|
},
|
|
|
|
|
|
// 预览图片
|
|
|
previewImage(url) {
|
|
|
const urls = this.vehicleImages.map((img) => img.url);
|
|
|
uni.previewImage({
|
|
|
urls: urls,
|
|
|
current: url,
|
|
|
});
|
|
|
},
|
|
|
|
|
|
// 更新访客信息
|
|
|
async updateVisitInfo() {
|
|
|
if (this.updating) return;
|
|
|
|
|
|
// 验证必填字段 - 由于去除action,暂无必填验证
|
|
|
|
|
|
// 内部方法:执行更新
|
|
|
const performUpdate = async (alsoCancel) => {
|
|
|
this.updating = true;
|
|
|
try {
|
|
|
const updateParams = {
|
|
|
...this.visitData,
|
|
|
id: this.visitData.id,
|
|
|
remark: this.remarkValue,
|
|
|
person_no: this.personNoValue,
|
|
|
// follw_people 中包含了每个人员的 follw_people_person_no 字段
|
|
|
};
|
|
|
|
|
|
// 如果type==3,添加车辆照片数据(做空值防护)
|
|
|
if (this.visitData.type == 3) {
|
|
|
updateParams.vehicle_images = (this.vehicleImages || [])
|
|
|
.filter((img) => img && img.id)
|
|
|
.map((img) => img.id);
|
|
|
}
|
|
|
|
|
|
await this.$u.api.visitUpdate(updateParams);
|
|
|
|
|
|
uni.showToast({
|
|
|
title: "更新成功",
|
|
|
icon: "success",
|
|
|
});
|
|
|
|
|
|
if (alsoCancel) {
|
|
|
// 更新成功后直接核销并关闭弹窗
|
|
|
this.cancelCode();
|
|
|
setTimeout(() => {
|
|
|
this.closeVisitModal();
|
|
|
}, 800);
|
|
|
}
|
|
|
} catch (error) {
|
|
|
console.error("更新失败:", error);
|
|
|
uni.showToast({
|
|
|
title: "更新失败",
|
|
|
icon: "none",
|
|
|
});
|
|
|
} finally {
|
|
|
this.updating = false;
|
|
|
}
|
|
|
};
|
|
|
|
|
|
// 所有类型都弹出确认弹窗
|
|
|
const isVehicleType = this.visitData.type == 3; // 需要提交照片的类型
|
|
|
|
|
|
uni.showModal({
|
|
|
title: "提示",
|
|
|
content: "是否立即核销?",
|
|
|
cancelText: isVehicleType ? "仅提交照片" : "取消",
|
|
|
confirmText: "提交并核销",
|
|
|
success: async (res) => {
|
|
|
if (res.confirm) {
|
|
|
// 提交并核销(所有类型通用)
|
|
|
await performUpdate(true);
|
|
|
} else if (res.cancel && isVehicleType) {
|
|
|
// 仅提交照片(状态不变,仅对需要提交照片的类型生效)
|
|
|
await performUpdate(false);
|
|
|
}
|
|
|
// 其他类型点击“取消”不做任何处理,仅关闭确认弹窗
|
|
|
},
|
|
|
});
|
|
|
},
|
|
|
|
|
|
// 关闭访客列表弹窗
|
|
|
closeListModal() {
|
|
|
this.listShow = false;
|
|
|
},
|
|
|
|
|
|
// 获取今日访客列表
|
|
|
async getTodayVisitors() {
|
|
|
try {
|
|
|
// 这里需要根据实际情况替换API调用
|
|
|
const todayParam = {
|
|
|
start_date: this.select.start_date,
|
|
|
end_date: this.select.end_date,
|
|
|
};
|
|
|
const res = await this.$u.api.visitList(todayParam);
|
|
|
this.todayVisitors = res?.data || [];
|
|
|
} catch (error) {
|
|
|
console.error("获取今日访客列表失败:", error);
|
|
|
this.todayVisitors = [];
|
|
|
}
|
|
|
},
|
|
|
},
|
|
|
};
|
|
|
</script>
|
|
|
|
|
|
<style lang="scss" scoped>
|
|
|
.page {
|
|
|
background: url("../../static/cancel_bg.png") no-repeat center center;
|
|
|
background-size: cover;
|
|
|
min-height: 100vh;
|
|
|
padding: 0;
|
|
|
box-sizing: border-box;
|
|
|
}
|
|
|
|
|
|
/* 头部导航样式 */
|
|
|
.gate-header {
|
|
|
display: flex;
|
|
|
justify-content: center;
|
|
|
align-items: center;
|
|
|
padding: 4% 5%;
|
|
|
margin-bottom: 6%;
|
|
|
background: #18284b;
|
|
|
min-height: 12vh;
|
|
|
|
|
|
/* 移动端样式 */
|
|
|
@media (max-width: 750px) {
|
|
|
padding: 3% 4%;
|
|
|
margin-bottom: 5%;
|
|
|
min-height: 10vh;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
.gate-left {
|
|
|
.today-visitors {
|
|
|
color: #ffffff;
|
|
|
font-size: 36rpx;
|
|
|
font-weight: 600;
|
|
|
cursor: pointer;
|
|
|
|
|
|
@media (max-width: 750px) {
|
|
|
font-size: 32rpx;
|
|
|
}
|
|
|
|
|
|
&:active {
|
|
|
opacity: 0.7;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
.gate-right {
|
|
|
display: flex;
|
|
|
align-items: center;
|
|
|
gap: 40rpx;
|
|
|
|
|
|
@media (max-width: 750px) {
|
|
|
justify-content: space-between;
|
|
|
gap: 20rpx;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
.fullscreen-btn {
|
|
|
color: #ffffff;
|
|
|
cursor: pointer;
|
|
|
font-size: 28rpx;
|
|
|
|
|
|
@media (max-width: 750px) {
|
|
|
font-size: 24rpx;
|
|
|
}
|
|
|
|
|
|
&:active {
|
|
|
opacity: 0.7;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/* 主要内容区域 */
|
|
|
.gate-content {
|
|
|
width: 100%;
|
|
|
max-width: 1800rpx;
|
|
|
margin: 0 auto;
|
|
|
padding: 0 5%;
|
|
|
|
|
|
@media (max-width: 750px) {
|
|
|
max-width: 100%;
|
|
|
padding: 0 4%;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
.form-container {
|
|
|
width: 100%;
|
|
|
}
|
|
|
|
|
|
.form-title {
|
|
|
font-size: 32rpx;
|
|
|
font-weight: 600;
|
|
|
color: #333;
|
|
|
margin-bottom: 4%;
|
|
|
|
|
|
@media (max-width: 750px) {
|
|
|
font-size: 28rpx;
|
|
|
margin-bottom: 3%;
|
|
|
color: #fff;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
.form-item {
|
|
|
margin-bottom: 5%;
|
|
|
|
|
|
@media (max-width: 750px) {
|
|
|
margin-bottom: 4%;
|
|
|
}
|
|
|
|
|
|
&:last-child {
|
|
|
margin-bottom: 0;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
.form-label {
|
|
|
display: block;
|
|
|
font-size: 32rpx;
|
|
|
color: #333;
|
|
|
margin-bottom: 2%;
|
|
|
font-weight: 500;
|
|
|
|
|
|
@media (max-width: 750px) {
|
|
|
font-size: 28rpx;
|
|
|
margin-bottom: 1.5%;
|
|
|
color: #fff;
|
|
|
}
|
|
|
|
|
|
@media (min-width: 768px) {
|
|
|
font-size: 40rpx;
|
|
|
margin-bottom: 2.5%;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/* 统一输入框样式 */
|
|
|
.form-input {
|
|
|
width: 100%;
|
|
|
height: 88rpx;
|
|
|
padding: 0 24rpx;
|
|
|
border: 2rpx solid #e4e7ed;
|
|
|
border-radius: 0;
|
|
|
font-size: 32rpx;
|
|
|
background-color: #fff;
|
|
|
box-sizing: border-box;
|
|
|
transition: border-color 0.3s ease, box-shadow 0.3s ease;
|
|
|
|
|
|
@media (max-width: 750px) {
|
|
|
height: 76rpx;
|
|
|
font-size: 28rpx;
|
|
|
padding: 0 16rpx;
|
|
|
}
|
|
|
|
|
|
@media (min-width: 768px) {
|
|
|
height: 100rpx;
|
|
|
font-size: 36rpx;
|
|
|
padding: 0 28rpx;
|
|
|
}
|
|
|
|
|
|
&:focus {
|
|
|
border-color: #004593;
|
|
|
box-shadow: 0 0 0 2rpx rgba(0, 69, 147, 0.2);
|
|
|
outline: none;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/* 输入框类型的元素统一样式 */
|
|
|
.input-field {
|
|
|
color: #333;
|
|
|
|
|
|
&::placeholder {
|
|
|
color: #c0c4cc;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/* 日期输入框样式 */
|
|
|
.date-input {
|
|
|
display: flex;
|
|
|
align-items: center;
|
|
|
justify-content: center;
|
|
|
cursor: pointer;
|
|
|
text-align: center;
|
|
|
|
|
|
text {
|
|
|
font-size: 32rpx;
|
|
|
color: #333;
|
|
|
white-space: nowrap;
|
|
|
overflow: hidden;
|
|
|
text-overflow: ellipsis;
|
|
|
|
|
|
@media (max-width: 750px) {
|
|
|
font-size: 26rpx;
|
|
|
}
|
|
|
|
|
|
@media (min-width: 768px) {
|
|
|
font-size: 36rpx;
|
|
|
}
|
|
|
|
|
|
&.icon {
|
|
|
font-size: 24rpx;
|
|
|
color: #c0c4cc;
|
|
|
margin-left: 8rpx;
|
|
|
|
|
|
@media (max-width: 750px) {
|
|
|
font-size: 20rpx;
|
|
|
margin-left: 6rpx;
|
|
|
}
|
|
|
|
|
|
@media (min-width: 768px) {
|
|
|
font-size: 28rpx;
|
|
|
margin-left: 10rpx;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
&:active {
|
|
|
border-color: #004593;
|
|
|
box-shadow: 0 0 0 2rpx rgba(0, 69, 147, 0.2);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/* 日期范围选择器容器 */
|
|
|
.date-range-container {
|
|
|
display: flex;
|
|
|
align-items: center;
|
|
|
gap: 20rpx;
|
|
|
|
|
|
@media (max-width: 750px) {
|
|
|
gap: 12rpx;
|
|
|
}
|
|
|
|
|
|
.date-picker {
|
|
|
flex: 1;
|
|
|
min-width: 0; // 防止flex子项溢出
|
|
|
|
|
|
@media (max-width: 750px) {
|
|
|
flex: 1;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/* 日期分隔符 */
|
|
|
.date-separator {
|
|
|
font-size: 28rpx;
|
|
|
color: #666;
|
|
|
font-weight: 500;
|
|
|
min-width: 40rpx;
|
|
|
text-align: center;
|
|
|
white-space: nowrap;
|
|
|
flex-shrink: 0; // 防止压缩
|
|
|
|
|
|
@media (max-width: 750px) {
|
|
|
font-size: 24rpx;
|
|
|
min-width: 30rpx;
|
|
|
padding: 0 8rpx;
|
|
|
color: #fff;
|
|
|
}
|
|
|
|
|
|
@media (min-width: 768px) {
|
|
|
font-size: 32rpx;
|
|
|
min-width: 60rpx;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
.id-input-group {
|
|
|
display: flex;
|
|
|
gap: 20rpx;
|
|
|
|
|
|
@media (max-width: 750px) {
|
|
|
flex-direction: row;
|
|
|
align-items: center;
|
|
|
gap: 16rpx;
|
|
|
}
|
|
|
width: 100%;
|
|
|
}
|
|
|
|
|
|
/* 身份证输入占比宽度设置 */
|
|
|
/* 默认(含APP打包)身份证输入宽度100% */
|
|
|
.idcard-group .form-input {
|
|
|
width: 100%;
|
|
|
flex: 1 1 auto;
|
|
|
max-width: 100%;
|
|
|
}
|
|
|
|
|
|
/* #ifdef H5 */
|
|
|
/* H5下身份证输入宽度为70%,右侧显示查询入口 */
|
|
|
@media all {
|
|
|
.idcard-group .form-input {
|
|
|
width: 70%;
|
|
|
flex: 0 0 70%;
|
|
|
max-width: 70%;
|
|
|
}
|
|
|
.idcard-group .id-action {
|
|
|
width: 30%;
|
|
|
flex: 0 0 30%;
|
|
|
max-width: 30%;
|
|
|
}
|
|
|
}
|
|
|
/* #endif */
|
|
|
|
|
|
.id-input {
|
|
|
flex: 1;
|
|
|
|
|
|
@media (max-width: 750px) {
|
|
|
width: 100%;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
.id-btn {
|
|
|
@media (max-width: 750px) {
|
|
|
width: auto;
|
|
|
}
|
|
|
|
|
|
@media (min-width: 768px) {
|
|
|
min-width: 240rpx;
|
|
|
}
|
|
|
white-space: nowrap;
|
|
|
}
|
|
|
|
|
|
/* 身份证查询行为元素,等高于输入框 */
|
|
|
.id-action {
|
|
|
height: 88rpx;
|
|
|
padding: 0 24rpx;
|
|
|
display: flex;
|
|
|
align-items: center;
|
|
|
justify-content: center;
|
|
|
background-color: #18284b;
|
|
|
color: #fff;
|
|
|
font-size: 28rpx;
|
|
|
border-radius: 0;
|
|
|
white-space: nowrap;
|
|
|
cursor: pointer;
|
|
|
transition: background-color 0.2s ease;
|
|
|
|
|
|
@media (max-width: 750px) {
|
|
|
height: 76rpx;
|
|
|
font-size: 26rpx;
|
|
|
}
|
|
|
|
|
|
@media (min-width: 768px) {
|
|
|
height: 100rpx;
|
|
|
font-size: 32rpx;
|
|
|
}
|
|
|
|
|
|
&:active {
|
|
|
background-color: #0f1a3a;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
.query-btn-container {
|
|
|
text-align: center;
|
|
|
margin-top: 10%;
|
|
|
|
|
|
@media (max-width: 750px) {
|
|
|
margin-top: 20%;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
.query-btn {
|
|
|
width: 100%;
|
|
|
height: 100rpx;
|
|
|
font-size: 36rpx;
|
|
|
font-weight: 600;
|
|
|
|
|
|
@media (max-width: 750px) {
|
|
|
height: 88rpx;
|
|
|
font-size: 32rpx;
|
|
|
}
|
|
|
|
|
|
@media (min-width: 768px) {
|
|
|
height: 120rpx;
|
|
|
font-size: 48rpx;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/* 按钮样式 */
|
|
|
.btn {
|
|
|
padding: 20rpx 40rpx;
|
|
|
border: none;
|
|
|
border-radius: 0;
|
|
|
font-size: 28rpx;
|
|
|
cursor: pointer;
|
|
|
|
|
|
&.btn-primary {
|
|
|
background-color: #18284b;
|
|
|
color: #fff;
|
|
|
|
|
|
&:disabled {
|
|
|
background-color: #c0c4cc;
|
|
|
cursor: not-allowed;
|
|
|
}
|
|
|
|
|
|
&:active:not(:disabled) {
|
|
|
background-color: #0f1a3a;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@media (max-width: 750px) {
|
|
|
padding: 16rpx 32rpx;
|
|
|
font-size: 26rpx;
|
|
|
}
|
|
|
|
|
|
@media (min-width: 768px) {
|
|
|
padding: 24rpx;
|
|
|
font-size: 32rpx;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/* 弹窗样式 */
|
|
|
.modal-overlay {
|
|
|
position: fixed;
|
|
|
top: 0;
|
|
|
left: 0;
|
|
|
width: 100%;
|
|
|
height: 100%;
|
|
|
background-color: rgba(0, 0, 0, 0.5);
|
|
|
display: flex;
|
|
|
align-items: center;
|
|
|
justify-content: center;
|
|
|
z-index: 10; // 调低层级,避免遮挡系统弹窗(如 uni.showModal)
|
|
|
}
|
|
|
|
|
|
.modal-content {
|
|
|
background-color: #fff;
|
|
|
border-radius: 16rpx;
|
|
|
width: 95%;
|
|
|
max-width: 800rpx;
|
|
|
max-height: 85%;
|
|
|
overflow: hidden;
|
|
|
|
|
|
@media (max-width: 750px) {
|
|
|
width: 92%;
|
|
|
max-width: 700rpx;
|
|
|
}
|
|
|
|
|
|
@media (min-width: 768px) {
|
|
|
width: 75%;
|
|
|
max-width: 1000rpx;
|
|
|
}
|
|
|
|
|
|
@media (min-width: 1024px) {
|
|
|
width: 65%;
|
|
|
max-width: 1200rpx;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
.modal-header {
|
|
|
padding: 40rpx 40rpx 20rpx;
|
|
|
border-bottom: 1rpx solid #f0f0f0;
|
|
|
|
|
|
.modal-title {
|
|
|
font-size: 36rpx;
|
|
|
font-weight: 600;
|
|
|
color: #333;
|
|
|
|
|
|
@media (max-width: 750px) {
|
|
|
font-size: 32rpx;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
.modal-body {
|
|
|
padding: 40rpx;
|
|
|
max-height: 60vh;
|
|
|
overflow-y: auto;
|
|
|
}
|
|
|
|
|
|
.modal-footer {
|
|
|
padding: 20rpx 40rpx 40rpx;
|
|
|
display: flex;
|
|
|
gap: 20rpx;
|
|
|
justify-content: center;
|
|
|
border-top: 1rpx solid #f0f0f0;
|
|
|
|
|
|
.btn {
|
|
|
flex: 1;
|
|
|
max-width: 300rpx;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
.visit-info {
|
|
|
padding: 20rpx 0;
|
|
|
}
|
|
|
|
|
|
/* 信息区块样式 */
|
|
|
.info-section {
|
|
|
margin-bottom: 40rpx;
|
|
|
padding: 20rpx 0;
|
|
|
border-bottom: 1rpx solid #f0f0f0;
|
|
|
|
|
|
&:last-child {
|
|
|
border-bottom: none;
|
|
|
margin-bottom: 0;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
.section-title {
|
|
|
display: block;
|
|
|
font-size: 32rpx;
|
|
|
font-weight: 600;
|
|
|
color: #004593;
|
|
|
margin-bottom: 20rpx;
|
|
|
padding-bottom: 10rpx;
|
|
|
border-bottom: 2rpx solid #004593;
|
|
|
position: relative;
|
|
|
|
|
|
&::after {
|
|
|
content: "";
|
|
|
position: absolute;
|
|
|
bottom: -2rpx;
|
|
|
left: 0;
|
|
|
width: 60rpx;
|
|
|
height: 2rpx;
|
|
|
background-color: #004593;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
.info-item {
|
|
|
display: flex;
|
|
|
margin-bottom: 20rpx;
|
|
|
align-items: center;
|
|
|
|
|
|
&:last-child {
|
|
|
margin-bottom: 0;
|
|
|
}
|
|
|
|
|
|
/* 特殊布局处理 */
|
|
|
&.photo-upload-section {
|
|
|
align-items: flex-start;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/* 随访人员项样式 */
|
|
|
.follow-person-item {
|
|
|
background-color: #f8f9fa;
|
|
|
padding: 20rpx;
|
|
|
border-radius: 8rpx;
|
|
|
margin-bottom: 20rpx;
|
|
|
|
|
|
&:last-child {
|
|
|
margin-bottom: 0;
|
|
|
}
|
|
|
|
|
|
.info-item {
|
|
|
margin-bottom: 12rpx;
|
|
|
|
|
|
&:last-child {
|
|
|
margin-bottom: 0;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
.separator {
|
|
|
height: 1rpx;
|
|
|
background-color: #e8e8e8;
|
|
|
margin: 20rpx 0;
|
|
|
}
|
|
|
|
|
|
.info-label {
|
|
|
font-size: 28rpx;
|
|
|
color: #666;
|
|
|
min-width: 120rpx;
|
|
|
margin-right: 20rpx;
|
|
|
}
|
|
|
|
|
|
.info-value {
|
|
|
font-size: 28rpx;
|
|
|
color: #333;
|
|
|
flex: 1;
|
|
|
word-break: break-all;
|
|
|
|
|
|
/* 状态标签特殊处理 */
|
|
|
&.status-badge {
|
|
|
flex: none; // 取消flex伸缩
|
|
|
align-self: flex-start; // 左对齐
|
|
|
margin-left: 0;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
.visitor-list {
|
|
|
max-height: 60vh;
|
|
|
overflow-y: auto;
|
|
|
}
|
|
|
|
|
|
.visitor-header {
|
|
|
display: flex;
|
|
|
justify-content: space-between;
|
|
|
align-items: center;
|
|
|
padding: 12rpx 20rpx;
|
|
|
border-bottom: 1rpx solid #f0f0f0;
|
|
|
background-color: #fafafa;
|
|
|
color: #666;
|
|
|
font-size: 24rpx;
|
|
|
font-weight: 500;
|
|
|
position: sticky;
|
|
|
top: 0;
|
|
|
z-index: 1;
|
|
|
}
|
|
|
|
|
|
.visitor-col {
|
|
|
flex: 1;
|
|
|
}
|
|
|
|
|
|
.visitor-col-name {
|
|
|
flex: 1.2;
|
|
|
}
|
|
|
|
|
|
.visitor-col-visited {
|
|
|
flex: 1.2;
|
|
|
text-align: center;
|
|
|
}
|
|
|
|
|
|
.visitor-col-status {
|
|
|
flex: 0.8;
|
|
|
text-align: right;
|
|
|
}
|
|
|
|
|
|
.empty-state {
|
|
|
text-align: center;
|
|
|
padding: 60rpx 20rpx;
|
|
|
color: #999;
|
|
|
font-size: 28rpx;
|
|
|
}
|
|
|
|
|
|
.visitor-item {
|
|
|
display: flex;
|
|
|
justify-content: space-between;
|
|
|
align-items: center;
|
|
|
padding: 20rpx;
|
|
|
border-bottom: 1rpx solid #f0f0f0;
|
|
|
|
|
|
&:last-child {
|
|
|
border-bottom: none;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
.visitor-name {
|
|
|
flex: 1.2;
|
|
|
font-size: 28rpx;
|
|
|
color: #333;
|
|
|
font-weight: 500;
|
|
|
}
|
|
|
|
|
|
.visitor-visited {
|
|
|
flex: 1.2;
|
|
|
font-size: 26rpx;
|
|
|
color: #555;
|
|
|
text-align: center;
|
|
|
}
|
|
|
|
|
|
.visitor-status {
|
|
|
flex: 0.8;
|
|
|
font-size: 24rpx;
|
|
|
padding: 8rpx 16rpx;
|
|
|
border-radius: 12rpx;
|
|
|
text-align: right;
|
|
|
}
|
|
|
|
|
|
/* 状态标签样式 */
|
|
|
.status-badge {
|
|
|
display: inline-block;
|
|
|
padding: 6rpx 16rpx;
|
|
|
border-radius: 16rpx;
|
|
|
font-size: 24rpx;
|
|
|
font-weight: 500;
|
|
|
text-align: center;
|
|
|
|
|
|
@media (max-width: 750px) {
|
|
|
padding: 4rpx 12rpx;
|
|
|
font-size: 22rpx;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/* 待学习 - 橙色 */
|
|
|
.status-study {
|
|
|
background-color: #fff7e6;
|
|
|
color: #fa8c16;
|
|
|
border: 1rpx solid #ffd591;
|
|
|
}
|
|
|
|
|
|
/* 待审核 - 蓝色 */
|
|
|
.status-pending {
|
|
|
background-color: #e6f7ff;
|
|
|
color: #1890ff;
|
|
|
border: 1rpx solid #91d5ff;
|
|
|
}
|
|
|
|
|
|
/* 通过(待进厂) - 绿色 */
|
|
|
.status-approved {
|
|
|
background-color: #f6ffed;
|
|
|
color: #52c41a;
|
|
|
border: 1rpx solid #b7eb8f;
|
|
|
}
|
|
|
|
|
|
/* 驳回 - 红色 */
|
|
|
.status-rejected {
|
|
|
background-color: #fff2f0;
|
|
|
color: #ff4d4f;
|
|
|
border: 1rpx solid #ffb3b3;
|
|
|
}
|
|
|
|
|
|
/* 已进厂 - 深绿色 */
|
|
|
.status-entered {
|
|
|
background-color: #f0f9f0;
|
|
|
color: #389e0d;
|
|
|
border: 1rpx solid #95de64;
|
|
|
}
|
|
|
|
|
|
/* 已离厂 - 灰色 */
|
|
|
.status-left {
|
|
|
background-color: #f5f5f5;
|
|
|
color: #8c8c8c;
|
|
|
border: 1rpx solid #d9d9d9;
|
|
|
}
|
|
|
|
|
|
/* 已取消 - 深灰色 */
|
|
|
.status-cancelled {
|
|
|
background-color: #f0f0f0;
|
|
|
color: #595959;
|
|
|
border: 1rpx solid #bfbfbf;
|
|
|
}
|
|
|
|
|
|
/* 未知状态 - 默认样式 */
|
|
|
.status-unknown {
|
|
|
background-color: #fafafa;
|
|
|
color: #666;
|
|
|
border: 1rpx solid #e8e8e8;
|
|
|
}
|
|
|
|
|
|
/* 输入框相关样式 */
|
|
|
.info-input-wrapper {
|
|
|
flex: 1;
|
|
|
margin-left: 20rpx;
|
|
|
}
|
|
|
|
|
|
.info-input {
|
|
|
width: 100%;
|
|
|
height: 60rpx;
|
|
|
padding: 0 16rpx;
|
|
|
border: 1rpx solid #e4e7ed;
|
|
|
border-radius: 6rpx;
|
|
|
font-size: 26rpx;
|
|
|
background-color: #fff;
|
|
|
box-sizing: border-box;
|
|
|
}
|
|
|
|
|
|
.info-textarea {
|
|
|
width: 100%;
|
|
|
min-height: 80rpx;
|
|
|
padding: 12rpx 16rpx;
|
|
|
border: 1rpx solid #e4e7ed;
|
|
|
border-radius: 6rpx;
|
|
|
font-size: 26rpx;
|
|
|
background-color: #fff;
|
|
|
box-sizing: border-box;
|
|
|
resize: none;
|
|
|
}
|
|
|
|
|
|
/* 照片上传相关样式 */
|
|
|
.photo-upload-section {
|
|
|
flex-direction: column;
|
|
|
align-items: flex-start;
|
|
|
|
|
|
.info-label {
|
|
|
margin-bottom: 16rpx;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
.photo-upload-container {
|
|
|
width: 100%;
|
|
|
}
|
|
|
|
|
|
.uploaded-photos {
|
|
|
display: flex;
|
|
|
flex-wrap: wrap;
|
|
|
gap: 16rpx;
|
|
|
margin-bottom: 20rpx;
|
|
|
}
|
|
|
|
|
|
.photo-item {
|
|
|
position: relative;
|
|
|
width: 120rpx;
|
|
|
height: 120rpx;
|
|
|
}
|
|
|
|
|
|
.photo-preview {
|
|
|
width: 100%;
|
|
|
height: 100%;
|
|
|
border-radius: 8rpx;
|
|
|
border: 1rpx solid #e8e8e8;
|
|
|
}
|
|
|
|
|
|
.photo-delete {
|
|
|
position: absolute;
|
|
|
top: -8rpx;
|
|
|
right: -8rpx;
|
|
|
width: 32rpx;
|
|
|
height: 32rpx;
|
|
|
background-color: #ff4d4f;
|
|
|
color: #fff;
|
|
|
border-radius: 50%;
|
|
|
display: flex;
|
|
|
align-items: center;
|
|
|
justify-content: center;
|
|
|
font-size: 20rpx;
|
|
|
font-weight: bold;
|
|
|
cursor: pointer;
|
|
|
}
|
|
|
|
|
|
.upload-actions {
|
|
|
display: flex;
|
|
|
gap: 16rpx;
|
|
|
}
|
|
|
|
|
|
.upload-btn {
|
|
|
flex: 1;
|
|
|
height: 60rpx;
|
|
|
font-size: 26rpx;
|
|
|
/* 覆盖通用按钮的垂直选项,确保文字垂直居中 */
|
|
|
padding: 0 24rpx;
|
|
|
display: flex;
|
|
|
align-items: center;
|
|
|
justify-content: center;
|
|
|
}
|
|
|
|
|
|
/* 添加照片按钮样式 */
|
|
|
.add-photo-btn {
|
|
|
display: flex;
|
|
|
flex-direction: column;
|
|
|
align-items: center;
|
|
|
justify-content: center;
|
|
|
background-color: #f8f9fa;
|
|
|
border: 2rpx dashed #d0d0d0;
|
|
|
cursor: pointer;
|
|
|
transition: all 0.3s ease;
|
|
|
|
|
|
&:active {
|
|
|
background-color: #e9ecef;
|
|
|
border-color: #004593;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
.add-photo-icon {
|
|
|
font-size: 48rpx;
|
|
|
color: #666;
|
|
|
margin-bottom: 8rpx;
|
|
|
font-weight: 300;
|
|
|
}
|
|
|
|
|
|
.add-photo-text {
|
|
|
font-size: 24rpx;
|
|
|
color: #999;
|
|
|
}
|
|
|
|
|
|
/* 底部选择弹窗样式 */
|
|
|
.photo-action-sheet {
|
|
|
position: fixed;
|
|
|
top: 0;
|
|
|
left: 0;
|
|
|
width: 100%;
|
|
|
height: 100%;
|
|
|
z-index: 2000;
|
|
|
}
|
|
|
|
|
|
.action-sheet-overlay {
|
|
|
position: absolute;
|
|
|
top: 0;
|
|
|
left: 0;
|
|
|
width: 100%;
|
|
|
height: 100%;
|
|
|
background-color: rgba(0, 0, 0, 0.5);
|
|
|
}
|
|
|
|
|
|
.action-sheet-content {
|
|
|
position: absolute;
|
|
|
bottom: 0;
|
|
|
left: 0;
|
|
|
width: 100%;
|
|
|
background-color: #fff;
|
|
|
border-radius: 24rpx 24rpx 0 0;
|
|
|
padding: 0 0 40rpx 0;
|
|
|
animation: slideUp 0.3s ease-out;
|
|
|
}
|
|
|
|
|
|
.action-sheet-item {
|
|
|
padding: 40rpx;
|
|
|
text-align: center;
|
|
|
border-bottom: 1rpx solid #f0f0f0;
|
|
|
cursor: pointer;
|
|
|
transition: background-color 0.2s ease;
|
|
|
|
|
|
&:active {
|
|
|
background-color: #f8f9fa;
|
|
|
}
|
|
|
|
|
|
&:last-of-type {
|
|
|
border-bottom: none;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
.action-sheet-text {
|
|
|
font-size: 32rpx;
|
|
|
color: #333;
|
|
|
font-weight: 500;
|
|
|
}
|
|
|
|
|
|
.action-sheet-cancel {
|
|
|
padding: 40rpx;
|
|
|
text-align: center;
|
|
|
margin-top: 20rpx;
|
|
|
cursor: pointer;
|
|
|
transition: background-color 0.2s ease;
|
|
|
|
|
|
&:active {
|
|
|
background-color: #f8f9fa;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
.action-sheet-cancel-text {
|
|
|
font-size: 32rpx;
|
|
|
color: #999;
|
|
|
}
|
|
|
|
|
|
@keyframes slideUp {
|
|
|
from {
|
|
|
transform: translateY(100%);
|
|
|
}
|
|
|
to {
|
|
|
transform: translateY(0);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/* 按钮样式扩展 */
|
|
|
.btn-outline {
|
|
|
background-color: transparent;
|
|
|
color: #004593;
|
|
|
border: 1rpx solid #004593;
|
|
|
|
|
|
&:active:not(:disabled) {
|
|
|
background-color: rgba(0, 69, 147, 0.1);
|
|
|
}
|
|
|
|
|
|
&:disabled {
|
|
|
color: #c0c4cc;
|
|
|
border-color: #c0c4cc;
|
|
|
cursor: not-allowed;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
.btn-secondary {
|
|
|
background-color: #f5f7fa;
|
|
|
color: #606266;
|
|
|
border: 1rpx solid #dcdfe6;
|
|
|
|
|
|
&:active:not(:disabled) {
|
|
|
background-color: #e4e7ed;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/* 响应式样式优化 */
|
|
|
@media (max-width: 750px) {
|
|
|
.form-container {
|
|
|
padding: 20rpx;
|
|
|
}
|
|
|
|
|
|
.modal-content {
|
|
|
margin: 20rpx;
|
|
|
width: calc(100% - 40rpx);
|
|
|
}
|
|
|
}
|
|
|
</style> |