Compare commits

...

10 Commits

@ -0,0 +1,9 @@
{
"permissions": {
"allow": [
"Read(//Users/mac/Documents/朗业/2025/m-迈柯唯访客/mkw-visit-cancel/**)"
],
"deny": [],
"ask": []
}
}

@ -2,5 +2,5 @@
ENV = 'development'
# base api
VUE_APP_BASE_API = https://bd-fangke.ali251.langye.net
VUE_APP_UPLOAD_API = https://bd-fangke.ali251.langye.net/api/admin/upload-file
VUE_APP_BASE_API = https://visitor-test.ali251.langye.net
VUE_APP_UPLOAD_API = https://visitor-test.ali251.langye.net/api/admin/upload-file

@ -2,5 +2,5 @@
ENV = 'production'
# base api
VUE_APP_BASE_API = https://bd-fangke.ali251.langye.net
VUE_APP_UPLOAD_API = https://bd-fangke.ali251.langye.net/api/admin/upload-file
VUE_APP_BASE_API = ''
VUE_APP_UPLOAD_API = /api/admin/upload-file

@ -0,0 +1,122 @@
## 访客与拜访功能 用户操作手册
本手册按系统菜单结构组织,面向最终使用者,帮助您快速完成日常操作。
---
### 资源中心
- 入口:资源中心(父级目录)
- 作用:承载拜访相关的规则与资料配置。
#### 拜访须知
- 用途:维护进出厂须知、注意事项等展示内容。
- 常用操作:
1. 进入页面后,点击“新增”或“编辑”。
2. 在编辑器中完善文字与图片,保存后即对前台生效。
#### 拜访时段管理
- 用途:设置可预约的拜访时间段(如工作日、节假日的开放时段)。
- 常用操作:
1. 点击“新增”,填写开始/结束时间、适用范围。
2. 可对已有时段进行启用/停用、编辑或删除。
#### 学习资料管理
- 用途:维护入厂前需学习的安全/制度资料(文档、视频等)。
- 常用操作:
1. 点击“新增”,上传资料并填写标题与说明。
2. 对已发布资料可编辑、下架或删除。
#### 学习记录
- 用途:查看访客学习情况记录,核对是否完成必学内容。
- 常用操作:
1. 按姓名、证件号、时间段等筛选。
2. 查看学习完成状态与时间;可导出。
---
### 参数设置
- 入口:参数设置(父级目录)
- 作用:维护场内区域基础数据。
#### 访客区域管理
- 用途:维护访客可进入的功能区域/楼栋/部门等划分。
- 常用操作:
1. 点击“新增”,填写区域名称、描述与是否启用。
2. 支持编辑、停用、删除。
#### 停车区域管理
- 用途:维护访客车辆可停放的车区/车位段。
- 常用操作:
1. 点击“新增”,填写区域名称、容量与说明。
2. 支持编辑、停用、删除。
---
### 拜访管理
- 入口:拜访管理(父级目录)
- 作用:完成访客预约、审核、进出场与黑名单等业务流程。
#### 拜访记录管理
- 用途:管理所有拜访记录(预约到离场全流程)。
- 列表字段:姓名、类型、状态、被访人、是否随访、预约时间、证件信息、手机号、单位名称、开始/结束时间、入场/离场时间、创建信息等。
- 常用操作:
- 查询与筛选:
- 关键词:支持姓名、手机号、证件号、单位名称。
- 状态:待学习、待审核、通过(待进厂)、驳回、已进厂、已离厂、已取消。
- 时间段:按预约日期选择起止时间。
- 点击“查询”执行检索。
- 分页:支持切换页码与每页条数。
- 新增:点击“新增”,选择访客类型(普通访客/施工人员/物流司机),填写表单并提交。
- 导出:按当前筛选条件导出为 CSV。
- 详情:查看完整信息。若存在多次进出,入场/离场时间将分行展示全部记录。
- 编辑/删除:对有权限的记录进行修改或删除(谨慎操作)。
#### 拜访记录审核
- 用途:审核新提交的拜访预约,决定通过或驳回。
- 常用操作:
1. 按条件筛选待审核记录。
2. 点击“审核”,核对预约信息与学习完成情况。
3. 选择“通过”或“驳回”,填写审核意见并提交。
#### 黑名单管理
- 用途:维护禁止入厂的人员信息。
- 常用操作:
1. 新增黑名单:录入姓名、证件号、原因、期限等。
2. 解除/编辑黑名单记录(需具备相应权限)。
#### 长期访客管理
- 用途:管理长周期、频繁入厂的访客(如驻场、长期合作方)。
- 常用操作:
1. 新增长期访客,设置有效期与权限范围。
2. 支持续期、变更信息与停用。
---
### 统计报表
- 入口:统计报表(父级目录)
- 作用:汇总各类维度的拜访数据,支持导出。
#### 月度统计
- 用途:按月份查看拜访总量、类型分布、进出趋势等。
- 常用操作:选择月份范围后生成统计图表与表格,可导出。
#### 时段统计
- 用途:按时间段(如日/周/时段)分析来访高峰与规律。
- 常用操作:选择时间粒度与区间,查看趋势图与明细,可导出。
#### 车辆统计
- 用途:统计车辆来访数量、车辆类型与停车占用情况。
- 常用操作:按时间范围与区域筛选,查看图表与列表,可导出。
---
### 使用小贴士
- 查询前先明确筛选条件(关键词、状态、时间段),能更快定位记录。
- 导出基于当前筛选条件。如需导出全部,请清空条件后导出。
- 多次进出的访客,在详情中会分行展示所有入场/离场时间,便于核对。

Binary file not shown.

Before

Width:  |  Height:  |  Size: 66 KiB

After

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

After

Width:  |  Height:  |  Size: 21 KiB

@ -512,6 +512,19 @@ export default {
let _this = this;
if (_this.auths?.length > 0) {
let btns = new Map();
btns.set(
"detail",
<i-button
style={{
"margin-right": "6px",
}}
type="info"
size="small"
onClick={() => _this.$emit('detail', scope.row)}
>
查看
</i-button>
);
btns.set(
"edit",
<i-button

@ -1,6 +1,6 @@
module.exports = {
title: 'BD访客管理系统',
title: '迈柯唯访客管理系统',
/**
* @type {boolean} true | false

@ -17,7 +17,8 @@ const getDefaultState = () => {
token: getToken(),
name: '',
avatar: '',
roles: []
roles: [],
myRoles:[]
}
}
@ -38,7 +39,11 @@ const mutations = {
},
SET_ROLES: (state, roles) => {
state.roles = roles
}
},
SET_MYROLES: (state, myRoles) => {
state.myRoles = myRoles
},
}
const actions = {
@ -79,17 +84,23 @@ const actions = {
if (!response) {
reject('身份验证失败请重新登录')
}
}
console.log("response",response)
response["myRoles"]=[]
response["role"].map(item=>{
response["myRoles"].push(item.name)
})
response["roles"] = ["admin"];
const {
const {
myRoles,
roles,
name,
avatar
} = response
commit('SET_ROLES', roles)
commit('SET_ROLES', roles)
commit('SET_MYROLES', myRoles)
commit('SET_NAME', name)
commit('SET_AVATAR', avatar)
resolve(response)

@ -11,7 +11,7 @@
transition: width 0.28s;
width: $sideBarWidth !important;
//background-color: $menuBg;
background: linear-gradient(180deg, #f27707, #f3a359);
background: linear-gradient(180deg, #182849, #4f607e);
box-shadow: 1px 1px 15px 0px rgba(17, 76, 157, 0.2);
height: 100%;
position: fixed;
@ -229,7 +229,7 @@
>.el-menu--popup {
max-height: 100vh;
overflow-y: auto;
background: #f27707 !important;
background: #182849 !important;
&::-webkit-scrollbar-track-piece {
background: #d3dce6;

@ -7,7 +7,7 @@
<i class="el-icon-user statIcon"></i>
</div>
<div class="bline"></div>
<div class="boxcontentsubtitle">总人数/总入厂人数</div>
<div class="boxcontentsubtitle">总人数/总入厂人数/总离厂人数</div>
<div class="boxcontent">
<div class="boxcontentitem">
<div class="boxcontentitem-big">
@ -19,13 +19,17 @@
<count-to separator="" :start-val="0" :end-val="totaldata.common_visit.enter_visit"
:duration="3600" />
</span>
<span>
<count-to separator="" :start-val="0" :end-val="totaldata.common_visit.leave_total"
:duration="3600" />
</span>
</div>
<div class="per">核销比{{toCaculateper(totaldata.common_visit.enter_visit,totaldata.common_visit.total)}}</div>
</div>
</div>
<div class="blinefull"></div>
<div class="boxcontentsubtitle">今日人数/今日入厂人数</div>
<div class="boxcontentsubtitle">今日人数/今日入厂人数/今日离厂人数</div>
<div class="boxcontent">
<div class="boxcontentitem">
<div class="boxcontentitem-big">
@ -36,6 +40,10 @@
<span>
<count-to separator="" :start-val="0" :end-val="totaldata.common_visit.today_enter_visit"
:duration="3600" />
</span>
<span>
<count-to separator="" :start-val="0" :end-val="totaldata.common_visit.today_leave_total"
:duration="3600" />
</span>
</div>
<div class="per">核销比{{toCaculateper(totaldata.common_visit.today_enter_visit,totaldata.common_visit.today_total)}}</div>
@ -46,11 +54,11 @@
<div class="box box2">
<div class="boxtitle">
<span>施工访客</span>
<span>施工人员</span>
<i class="iconfont icon-banqianguanli statIcon"></i>
</div>
<div class="bline"></div>
<div class="boxcontentsubtitle">总人数/核销人数</div>
<div class="boxcontentsubtitle">总人数/入厂人数/总离厂人数</div>
<div class="boxcontent">
<div class="boxcontentitem">
<div class="boxcontentitem-big">
@ -62,12 +70,16 @@
<count-to separator="" :start-val="0" :end-val="totaldata.work_visit.enter_visit"
:duration="3600" />
</span>
<span>
<count-to separator="" :start-val="0" :end-val="totaldata.work_visit.leave_total"
:duration="3600" />
</span>
</div>
<div class="per">核销比{{toCaculateper(totaldata.work_visit.enter_visit,totaldata.work_visit.total)}}</div>
</div>
</div>
<div class="blinefull"></div>
<div class="boxcontentsubtitle">今日人数/今日核销人数</div>
<div class="boxcontentsubtitle">今日人数/今日入厂人数/今日离厂人数</div>
<div class="boxcontent">
<div class="boxcontentitem">
<div class="boxcontentitem-big">
@ -79,6 +91,10 @@
<count-to separator="" :start-val="0" :end-val="totaldata.work_visit.today_enter_visit"
:duration="3600" />
</span>
<span>
<count-to separator="" :start-val="0" :end-val="totaldata.work_visit.today_leave_total"
:duration="3600" />
</span>
</div>
<div class="per">核销比{{toCaculateper(totaldata.work_visit.today_enter_visit,totaldata.work_visit.today_total)}}</div>
</div>
@ -87,11 +103,11 @@
<div class="box box4">
<div class="boxtitle">
<span>物流车辆</span>
<span>物流司机</span>
<i class="iconfont icon-cheliangdangan statIcon"></i>
</div>
<div class="bline"></div>
<div class="boxcontentsubtitle">总预约数/核销</div>
<div class="boxcontentsubtitle">总预约数/入厂人数/总离厂人</div>
<div class="boxcontent">
<div class="boxcontentitem">
<div class="boxcontentitem-big">
@ -103,12 +119,16 @@
<count-to separator="" :start-val="0" :end-val="totaldata.car_visit.enter_visit"
:duration="3600" />
</span>
<span>
<count-to separator="" :start-val="0" :end-val="totaldata.car_visit.leave_total"
:duration="3600" />
</span>
</div>
<div class="per">核销比{{toCaculateper(totaldata.car_visit.enter_visit,totaldata.car_visit.total)}}</div>
</div>
</div>
<div class="blinefull"></div>
<div class="boxcontentsubtitle">今日预约数/今日核销</div>
<div class="boxcontentsubtitle">今日预约数/今日入厂数/今日离厂人</div>
<div class="boxcontent">
<div class="boxcontentitem">
<div class="boxcontentitem-big">
@ -120,6 +140,10 @@
<count-to separator="" :start-val="0" :end-val="totaldata.car_visit.today_enter_visit"
:duration="3600" />
</span>
<span>
<count-to separator="" :start-val="0" :end-val="totaldata.car_visit.today_leave_total"
:duration="3600" />
</span>
</div>
<div class="per">核销比{{toCaculateper(totaldata.work_visit.today_enter_visit,totaldata.car_visit.today_total)}}</div>
</div>
@ -147,19 +171,25 @@
"enter_visit": 0,
"today_enter_visit": 0,
"today_total": 0,
"total":0
"total":0,
"leave_total":0,
"today_leave_total":0
},
"work_visit": {
"enter_visit": 0,
"today_enter_visit": 0,
"today_total": 0,
"total":0
"total":0,
"leave_total":0,
"today_leave_total":0
},
"car_visit": {
"enter_visit": 0,
"today_enter_visit": 0,
"today_total": 0,
"total":0
"total":0,
"leave_total":0,
"today_leave_total":0
}
}
}

@ -1,5 +1,25 @@
<template>
<div style="padding:20px">
<!-- 时间段筛选 -->
<div class="filter-container">
<el-date-picker
v-model="dateRange"
type="daterange"
align="right"
unlink-panels
range-separator="至"
start-placeholder="开始日期"
end-placeholder="结束日期"
:picker-options="pickerOptions"
value-format="yyyy-MM-dd"
@change="handleDateChange"
style="margin-right: 10px;"
>
</el-date-picker>
<el-button type="primary" icon="el-icon-search" @click="handleSearch"></el-button>
<el-button icon="el-icon-refresh" @click="handleReset"></el-button>
</div>
<PanelGroup :totaldata='list'></PanelGroup>
<div class="tCharts">
<PieChart :chartData="pieData" :width="'30%'"></PieChart>
@ -35,43 +55,89 @@
customerArr: [],
orderArr: [],
chartData: {},
//
dateRange: this.getDefaultDateRange(),
pickerOptions: {
shortcuts: [{
text: '最近一周',
onClick(picker) {
const end = new Date();
const start = new Date();
start.setTime(start.getTime() - 3600 * 1000 * 24 * 7);
picker.$emit('pick', [start, end]);
}
}, {
text: '最近一个月',
onClick(picker) {
const end = new Date();
const start = new Date();
start.setTime(start.getTime() - 3600 * 1000 * 24 * 30);
picker.$emit('pick', [start, end]);
}
}, {
text: '最近三个月',
onClick(picker) {
const end = new Date();
const start = new Date();
start.setTime(start.getTime() - 3600 * 1000 * 24 * 90);
picker.$emit('pick', [start, end]);
}
}]
},
pieData:{
// xArr:['访','访',''],
yArr:[
{
value:20,
name:"普通访客"
value: 0,
name:"普通访客",
itemStyle: {
color: '#D1AC7B' // 访
}
},{
value:40,
name:"施工访客"
value: 0,
name:"施工人员",
itemStyle: {
color: '#9193BC' //
}
},{
value:40,
name:"物流车辆"
value: 0,
name:"物流司机",
itemStyle: {
color: '#64A48E' //
}
}],
radiusArr:'50%'
},
LineData:{
xArr: ['9:00-10:00','10:00-11:00','11:00-12:00','12:00-13:00'],
legendArr: ["普通访客", "施工访客", "物流车辆"],
xArr: [],
legendArr: ["普通访客", "施工人员", "物流司机"],
series:[
{
name: '普通访客',
type: 'line',
stack: 'Total',
data: [20,10,40,70]
data: [],
itemStyle: {
color: '#D1AC7B' // 访
}
},
{
name: '施工访客',
name: '施工人员',
type: 'line',
stack: 'Total',
data: [15,75,35,45]
data: [],
itemStyle: {
color: '#9193BC' //
}
},
{
name: '物流车辆',
name: '物流司机',
type: 'line',
stack: 'Total',
data: [75,35,60,10]
data: [],
itemStyle: {
color: '#64A48E' //
}
}
]
}
@ -85,10 +151,118 @@
}
},
methods: {
async loadData() {
await getChartsHome().then((res) => {
console.log(res);
// 30
getDefaultDateRange() {
const today = new Date();
const thirtyDaysAgo = new Date();
thirtyDaysAgo.setDate(today.getDate() - 30);
return [
this.formatDate(thirtyDaysAgo),
this.formatDate(today)
];
},
// YYYY-MM-DD
formatDate(date) {
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, '0');
const day = String(date.getDate()).padStart(2, '0');
return `${year}-${month}-${day}`;
},
//
updatePieChartData(listData) {
if (listData && listData.common_visit && listData.work_visit && listData.car_visit) {
this.pieData.yArr = [
{
value: listData.common_visit.total || 0,
name: "普通访客",
itemStyle: {
color: '#D1AC7B' // 访
}
},
{
value: listData.work_visit.total || 0,
name: "施工人员",
itemStyle: {
color: '#9193BC' //
}
},
{
value: listData.car_visit.total || 0,
name: "物流司机",
itemStyle: {
color: '#64A48E' //
}
}
];
}
},
// 线
updateLineChartData(dateList) {
if (dateList && Array.isArray(dateList)) {
//
this.LineData.xArr = dateList.map(item => {
// -
const date = new Date(item.date);
const month = String(date.getMonth() + 1).padStart(2, '0');
const day = String(date.getDate()).padStart(2, '0');
return `${month}-${day}`;
});
// 访
this.LineData.series[0].data = dateList.map(item => item.common_visit || 0);
this.LineData.series[1].data = dateList.map(item => item.work_visit || 0);
this.LineData.series[2].data = dateList.map(item => item.car_visit || 0);
}
},
//
handleDateChange(value) {
console.log('选择的时间段:', value);
},
//
handleSearch() {
if (this.dateRange && this.dateRange.length === 2) {
console.log('查询时间段:', {
startDate: this.dateRange[0],
endDate: this.dateRange[1]
});
//
this.loadData({
start_date: this.dateRange[0],
end_date: this.dateRange[1]
});
this.$message.success('查询成功');
} else {
this.$message.warning('请选择时间段');
}
},
//
handleReset() {
// 30
this.dateRange = this.getDefaultDateRange();
console.log('重置时间筛选');
// 使
this.loadData({
start_date: this.dateRange[0],
end_date: this.dateRange[1]
});
this.$message.success('已重置');
},
async loadData(params = {}) {
await getChartsHome(params).then((res) => {
console.log('接口返回数据:', res);
this.list = res.list;
//
this.updatePieChartData(res.list);
// 线
this.updateLineChartData(res.all_date_list);
// this.chartData = res;
// let _business_data = [];
// let _collect_data = [];
@ -215,8 +389,11 @@
}
},
created() {
this.loadData();
// 使
this.loadData({
start_date: this.dateRange[0],
end_date: this.dateRange[1]
});
},
mounted() {
@ -236,6 +413,17 @@
</script>
<style lang="scss" scoped>
.filter-container {
background: #fff;
padding: 20px;
margin-bottom: 20px;
border-radius: 4px;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
display: flex;
justify-content: center;
align-items: center;
}
.statistics {
display: flex;

@ -1,37 +1,70 @@
<template>
<div>
<div class="gatewrap">
<div class="gateLeft">
<span @click='openList'>今日访客</span>
</div>
<div class="gateRight">
<span>
{{gateName}}<span @click="gateShow = true">切换</span>
</span>
<span @click='screen'>{{fullscreen?'取消全屏':'打开全屏'}}</span>
</div>
<div class="gatecode">
<div>
拜访日期
<el-date-picker v-model="selectRange" @change="selectRangeM" value-format="yyyy-MM-dd" type="daterange"
range-separator="至" start-placeholder="开始日期" end-placeholder="结束日期"
style="width:400px;vertical-align: middle;">
</el-date-picker>
<div class="gatewrap">
<!-- 头部导航 -->
<div class="gate-header">
<div class="gate-left">
<span @click='openList' class="today-visitors">今日访客</span>
</div>
<div>
核验销码
<el-input clearable ref='codeInput' size="mini" placeholder="请输入核销码或扫码" v-model="select.code"
style="width: 160px;margin-right: 10px;" @change='getList'></el-input>
<div class="gate-right">
<div class="gate-info">
<span class="gate-name">{{gateName}}</span>
<span @click="gateShow = true" class="switch-gate">切换</span>
</div>
<div class="fullscreen-btn" @click='screen'>
{{fullscreen?'取消全屏':'打开全屏'}}
</div>
</div>
<div>
身份证件
<el-input clearable ref='idInput' size="mini" placeholder="请输入身份证" v-model="select.idcard"
style="width: 160px;margin-right: 10px;"></el-input>
<el-button type="primary" @click='getIdcard'>查询身份证</el-button>
</div>
<div>
<el-button class="getButton" type="primary" @click='getList'>查询</el-button>
</div>
<!-- 主要内容区域 -->
<div class="gate-content">
<div class="form-container">
<div class="form-item">
<label class="form-label">拜访日期</label>
<el-date-picker
v-model="selectRange"
@change="selectRangeM"
value-format="yyyy-MM-dd"
type="daterange"
range-separator="至"
start-placeholder="开始日期"
end-placeholder="结束日期"
class="date-picker"
:popper-class="'mobile-date-picker'"
append-to-body>
</el-date-picker>
</div>
<div class="form-item">
<label class="form-label">核验销码</label>
<el-input
clearable
ref='codeInput'
placeholder="请输入核销码或扫码"
v-model="select.code"
class="form-input"
@change='getList'>
</el-input>
</div>
<div class="form-item">
<label class="form-label">身份证件</label>
<div class="id-input-group">
<el-input
clearable
ref='idInput'
placeholder="请输入身份证"
v-model="select.idcard"
class="form-input id-input">
</el-input>
<el-button type="primary" @click='getIdcard' class="id-btn">查询身份证</el-button>
</div>
</div>
<div class="form-item query-btn-container">
<el-button class="query-btn" type="primary" @click='getList'>查询</el-button>
</div>
</div>
</div>
</div>
@ -51,9 +84,9 @@
</div>
</template>
<script>
import Cookies from 'js-cookie'
import Cookies from 'js-cookie'
import axios from 'axios'
import showVisit from '@/views/visit/component/showVisit'
import showVisit from '@/views/visit/component/showVisit'
import list from '@/views/gate/components/list.vue'
import {
getList,
@ -61,9 +94,8 @@
} from '@/api/gate'
export default {
components: {
showVisit,
list
showVisit,
list
},
data() {
return {
@ -99,9 +131,9 @@
this.getToday()
// this.enterfullscreen()
},
methods: {
openList(){
this.$refs.list.listShow = true
methods: {
openList(){
this.$refs.list.listShow = true
},
getToday() {
let now = new Date()
@ -140,7 +172,7 @@
this.$refs['showVisit'].form = k
this.$refs['showVisit'].formDataType = 'coderecord'
this.$refs['showVisit'].gateAdminId = this.gateAdminId
this.$refs['showVisit'].isShow = true
this.$refs['showVisit'].isShow = true
return
} else {
this.$successMessage(k.audit_status_text, '', 'success')
@ -148,8 +180,8 @@
}
} else {
this.$successMessage("未查询到记录", '', 'warning')
}
this.select.code = ''
}
this.select.code = ''
this.select.idcard = ''
},
async getUserList() {
@ -187,27 +219,27 @@
})
this.gateShow = false
},
getIdcard() {
let that = this
axios.get('https://127.0.0.1:24011/ZKIDROnline/ScanReadIdCardInfo?OP-DEV=1&CMD-URL=4&REPEAT=1&READTYPE=1',{
'headers':{
"Content-Type":'application/json'
}
})
.then(res=>{
console.log(res)
console.log(res.data)
if(!res.data){
return
}
let data1 = res.data?res.data.split('"IDNumber"'):''
let data2= data1[1].split(",")
let data3 =data2[0].replace(/[^\d]/g, "")
that.select.idcard = data3
that.getList()
}).catch(err=>{
console.log(err)
this.$successMessage(err.statusText, '', 'warning')
getIdcard() {
let that = this
axios.get('https://127.0.0.1:24011/ZKIDROnline/ScanReadIdCardInfo?OP-DEV=1&CMD-URL=4&REPEAT=1&READTYPE=1',{
'headers':{
"Content-Type":'application/json'
}
})
.then(res=>{
console.log(res)
console.log(res.data)
if(!res.data){
return
}
let data1 = res.data?res.data.split('"IDNumber"'):''
let data2= data1[1].split(",")
let data3 =data2[0].replace(/[^\d]/g, "")
that.select.idcard = data3
that.getList()
}).catch(err=>{
console.log(err)
this.$successMessage(err.statusText, '', 'warning')
})
},
screen() {
@ -273,91 +305,365 @@
</script>
<style scoped>
.gatewrap {
background-color: #fff;
position: relative;
height: 100vh
/* 基础容器样式 */
.gatewrap {
background-color: #fff;
min-height: 100vh;
display: flex;
flex-direction: column;
}
/* 头部导航样式 */
.gate-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 15px 20px;
border-bottom: 1px solid #f0f0f0;
background: #fafafa;
@media (max-width: 767px) {
padding: 10px 15px;
flex-direction: column;
gap: 10px;
align-items: stretch;
}
}
.gate-left {
.today-visitors {
color: #004593;
font-size: 18px;
cursor: pointer;
@media (max-width: 767px) {
font-size: 16px;
}
&:hover {
text-decoration: underline;
}
}
}
.gate-right {
display: flex;
align-items: center;
gap: 20px;
@media (max-width: 767px) {
justify-content: space-between;
gap: 10px;
}
}
.gate-info {
display: flex;
align-items: center;
gap: 5px;
.gatecode {
font-size: 32px;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
text-align: left;
display: inline-block;
.gate-name {
font-size: 16px;
color: #333;
@media (max-width: 767px) {
font-size: 14px;
}
}
.gatecode>div {
margin-bottom: 40px;
.switch-gate {
color: #004593;
text-decoration: underline;
cursor: pointer;
font-size: 14px;
@media (max-width: 767px) {
font-size: 12px;
}
}
}
.fullscreen-btn {
color: #666;
cursor: pointer;
font-size: 14px;
.gatecode>div:last-child {
margin-bottom: 0px;
@media (max-width: 767px) {
font-size: 12px;
}
.gateRight {
position: absolute;
right: 20px;
top: 20px;
font-size: 20px;
&:hover {
color: #004593;
}
}
/* 主要内容区域 */
.gate-content {
flex: 1;
display: flex;
align-items: center;
justify-content: center;
padding: 20px;
.gateRight span {
margin-right: 10px;
margin-left: 5px;
@media (max-width: 767px) {
align-items: flex-start;
padding: 20px 15px;
}
.gateRight span>span {
text-decoration: underline;
color:#004593
}
.form-container {
width: 100%;
max-width: 500px;
@media (min-width: 768px) {
max-width: 600px;
}
.gateLeft{
position: absolute;
left: 20px;
top: 20px;
font-size: 20px;
color:#004593
}
.form-item {
margin-bottom: 25px;
@media (max-width: 767px) {
margin-bottom: 20px;
}
/deep/ .el-input {
width: 400px !important;
&:last-child {
margin-bottom: 0;
}
}
.form-label {
display: block;
font-size: 16px;
color: #333;
margin-bottom: 8px;
font-weight: 500;
/deep/ .el-input__inner {
font-size: 32px;
height: 45px;
width: 400px;
@media (max-width: 767px) {
font-size: 14px;
margin-bottom: 6px;
}
/deep/ .gatewrap .el-button {
vertical-align: top;
height: 45px;
width: 145px;
@media (min-width: 768px) {
font-size: 20px;
margin-bottom: 10px;
}
}
/deep/ .el-range-editor .el-range-input {
font-size: 20px;
.form-input {
width: 100%;
}
.date-picker {
width: 100%;
}
.id-input-group {
display: flex;
gap: 10px;
@media (max-width: 767px) {
flex-direction: column;
gap: 8px;
}
}
/deep/ .el-date-editor .el-range-separator {
font-size: 20px;
line-height: 36px;
.id-input {
flex: 1;
}
.id-btn {
@media (max-width: 767px) {
width: 100%;
}
/deep/ .el-date-editor .el-range__icon {
font-size: 18px;
line-height: 38px;
@media (min-width: 768px) {
min-width: 120px;
}
}
.query-btn-container {
text-align: center;
margin-top: 30px;
/deep/ .el-date-editor .el-range__close-icon {
@media (max-width: 767px) {
margin-top: 25px;
}
}
.query-btn {
width: 100%;
height: 50px;
font-size: 18px;
font-weight: 600;
@media (max-width: 767px) {
height: 44px;
font-size: 16px;
}
@media (min-width: 768px) {
height: 60px;
font-size: 24px;
}
}
/* Element UI 组件样式覆盖 */
::v-deep .el-input__inner {
height: 44px;
font-size: 16px;
@media (max-width: 767px) {
height: 40px;
font-size: 14px;
}
@media (min-width: 768px) {
height: 50px;
font-size: 18px;
line-height: 38px;
}
}
::v-deep .el-button {
height: 44px;
font-size: 14px;
@media (max-width: 767px) {
height: 40px;
font-size: 13px;
}
@media (min-width: 768px) {
height: 50px;
font-size: 16px;
}
}
::v-deep .el-date-editor {
width: 100%;
}
::v-deep .el-range-editor .el-range-input {
font-size: 14px;
@media (min-width: 768px) {
font-size: 16px;
}
}
::v-deep .el-date-editor .el-range-separator {
font-size: 14px;
@media (min-width: 768px) {
font-size: 16px;
}
}
::v-deep .el-date-editor .el-range__icon,
::v-deep .el-date-editor .el-range__close-icon {
font-size: 14px;
}
/* 对话框样式优化 */
::v-deep .el-dialog {
@media (max-width: 767px) {
width: 90% !important;
margin-top: 15vh !important;
}
}
.gatecode .getButton.el-button {
::v-deep .el-radio {
@media (max-width: 767px) {
width: 100%;
font-size: 32px;
height: 70px
margin-bottom: 10px;
}
}
/* 日期选择器输入框在移动端的样式调整 */
::v-deep .el-range-editor {
@media (max-width: 767px) {
.el-range-input {
width: 35% !important;
font-size: 13px !important;
}
.el-range-separator {
width: 15% !important;
font-size: 12px !important;
text-align: center;
}
.el-range__icon,
.el-range__close-icon {
font-size: 12px !important;
}
}
}
</style>
<!-- 不带scoped的样式专门处理日期选择器弹出层 -->
<style>
/* 移动端日期选择器弹出层优化 */
@media (max-width: 767px) {
.mobile-date-picker.el-picker-panel {
position: fixed !important;
left: 10px !important;
right: 10px !important;
top: 50% !important;
transform: translateY(-50%) !important;
width: auto !important;
max-width: none !important;
min-width: auto !important;
margin: 0 !important;
z-index: 9999 !important;
}
.mobile-date-picker.el-date-range-picker {
min-width: auto !important;
width: 100% !important;
}
.mobile-date-picker .el-picker-panel__body {
display: flex !important;
flex-direction: column !important;
min-width: auto !important;
width: 100% !important;
}
.mobile-date-picker .el-picker-panel__content {
display: flex !important;
flex-direction: column !important;
width: 100% !important;
}
.mobile-date-picker .el-picker-panel__content .el-date-table {
margin: 0 5px 10px 5px !important;
width: calc(100% - 10px) !important;
}
.mobile-date-picker .el-date-range-picker__time-header {
display: flex !important;
flex-direction: column !important;
gap: 5px !important;
padding: 5px !important;
}
.mobile-date-picker .el-picker-panel__sidebar {
width: 100% !important;
padding: 5px !important;
}
.mobile-date-picker .el-picker-panel__sidebar .el-picker-panel__shortcut {
display: inline-block !important;
margin: 2px !important;
padding: 3px 8px !important;
font-size: 12px !important;
}
.mobile-date-picker .el-picker-panel__footer {
text-align: center !important;
padding: 10px !important;
}
</style>
}
</style>

@ -45,7 +45,7 @@
size="small"
type="primary"
ghost
@click="form.audit_admin.splice(scope.$index, 1)"
@click="delRow(scope.$index)"
>删除</Button
>
</template>
@ -95,7 +95,7 @@
audit_admin:[],
remark:""
},
checkList:['一级审核人','二级审核人','三级审核人'],
checkList:[],
rules:{
name:[
{
@ -207,15 +207,65 @@
name:res?.name,
audit_admin:res?.audit_admin,
remark:res?.remark
}
let arr = []
if(res.audit_admin.length>0){
res.audit_admin.map((item,index)=>{
arr.push(`${this.indexToChinese(index)}级审核人`)
})
this.checkList = arr
}
},
addRow(){
if(this.form.audit_admin.length==3){
return
}
// if(this.form.audit_admin.length==3){
// return
// }
this.form.audit_admin.push({ type:'',admin_id:'',level:'',type_name:'',admin_name:'' })
let checkName = `${this.indexToChinese(this.form.audit_admin.length-1)}级审核人`
this.checkList.push(checkName)
console.log("this.checkList",this.checkList)
},
delRow(index){
this.form.audit_admin.splice(index, 1)
this.checkList.splice(index, 1)
let arr = []
this.checkList.map((item,index)=>{
arr.push(`${this.indexToChinese(index)}级审核人`)
})
this.checkList = arr
console.log("this.arr",this.checkList)
},
indexToChinese(index) {
const chineseNumbers = ['一', '二', '三', '四', '五', '六', '七', '八', '九', '十'];
if (index >= 0 && index < 10) {
return chineseNumbers[index];
} else if (index === 10) {
return '十';
} else if (index < 20) {
return '十' + chineseNumbers[index - 11];
} else {
const tens = Math.floor(index / 10);
const units = index % 10;
let result = '';
if (tens > 1) {
result += chineseNumbers[tens - 1] + '十';
} else {
result += '十';
}
if (units > 0) {
result += chineseNumbers[units - 1];
}
return result;
}
},
submit() {
if(this.form.audit_admin.length>0){
this.form.audit_admin.map((item,index)=>{
item.level = index+1
})
}
console.log(this.form)
// return
let that = this
@ -241,7 +291,8 @@
}
} else {
this.id = ''
this.type = ''
this.type = ''
this.checkList = []
this.$refs['dialog'].reset()
}
}

@ -1,7 +1,7 @@
<template>
<div style="padding: 0 20px">
<div ref="lxHeader">
<lx-header icon="md-apps" text="BD详情管理" style="margin-bottom: 10px; border: 0px; margin-top: 15px">
<lx-header icon="md-apps" text="访客须知" style="margin-bottom: 10px; border: 0px; margin-top: 15px">
<slot>
<div style="display: flex;align-items: center;">

@ -188,15 +188,15 @@ import xyTinymce from "@/components/XyTinymce/index.vue";
fileList: [],
types: [{
id: 1,
value: "访客"
value: "普通访客"
},
{
id: 2,
value: "施工"
value: "施工人员"
},
{
id: 3,
value: "车辆"
value: "物流司机"
}
],
form: {
@ -266,6 +266,9 @@ import xyTinymce from "@/components/XyTinymce/index.vue";
}, {
id: 270,
value: '九个月'
}, {
id: 365,
value: '一年'
}]
}

@ -72,7 +72,7 @@
sortable: false,
prop: 'type',
formatter: (cell, data, value) => {
return value=="1"?"普通访客":(value=="2"?"施工访客":"物流车辆")
return value=="1"?"普通访客":(value=="2"?"施工人员":"物流司机")
}
},
{

@ -8,12 +8,13 @@
<div class="box-center">
<pan-thumb :image="user.avatar" :height="'100px'" :width="'100px'" :hoverable="false">
<div>Hello</div>
{{ user.role }}
<!-- {{ user.role }} -->
{{ user.name }}
</pan-thumb>
</div>
<div class="box-center">
<div class="user-name text-center">{{ user.name }}</div>
<div class="user-role text-center text-muted">{{ user.role | uppercaseFirst }}</div>
<!-- <div class="user-role text-center text-muted">{{ user.role | uppercaseFirst }}</div> -->
</div>
</div>
@ -24,7 +25,7 @@
</div>
<div class="user-bio-section-body">
<div class="text-muted">
{{user.department||"暂无"}}
{{user.department?user.department.name:"暂无"}}
</div>
</div>
</div>
@ -115,4 +116,4 @@
}
}
}
</style>
</style>

@ -35,7 +35,7 @@
import {
getInfo
} from '../../api/user.js'
} from '../../api/user.js'
export default {
name: 'Profile',
@ -61,18 +61,19 @@
this.getUser()
},
methods: {
getUser() {
getInfo().then(res => {
this.user = {
name:res.name,
username:res.username,
role: this.roles.join(' | '),
avatar: this.avatar
}
getUser() {
getInfo().then(res => {
this.user = {
name:res.name,
username:res.username,
role: this.roles.join(' | '),
avatar: this.avatar,
department: res.department
}
})
}
}
}
</script>
</script>

@ -1,19 +1,29 @@
<template>
<div style="padding: 0 20px">
<div ref="lxHeader">
<lx-header icon="md-apps" text="拜访记录管理" style="margin-bottom: 10px; border: 0px; margin-top: 15px">
<slot>
<div style="display: flex;align-items: center;" class="selector">
<div style="margin-right: 10px;">关键词</div>
<el-input size="mini" placeholder="请输入关键词" v-model="select.keyword"
style="width: 160px;margin-right: 10px;"></el-input>
<div style="margin-right: 10px;">状态</div>
<el-select v-model="select.audit_status" clearable placeholder="请选择">
<el-option v-for="item in statusList" :key="item.id" :label="item.value" :value="item.id">
</el-option>
</el-select>
<div style="margin:0 10px;">只看自己被访记录</div>
<template>
<div style="padding: 0 20px">
<div ref="lxHeader">
<lx-header icon="md-apps" text="拜访记录审核" style="margin-bottom: 10px; border: 0px; margin-top: 15px">
<slot>
<div style="display: flex;align-items: center;" class="selector">
<!-- 模拟数据开关 -->
<div v-if="false" style="margin-right: 15px; padding: 5px 10px; background: #f0f0f0; border-radius: 4px; display: flex; align-items: center;">
<span style="margin-right: 8px; font-size: 12px; color: #666;">模拟数据:</span>
<el-switch
v-model="useMockData"
active-color="#13ce66"
inactive-color="#ff4949"
@change="getList">
</el-switch>
</div>
<div style="margin-right: 10px;">关键词</div>
<el-input size="mini" placeholder="请输入关键词" v-model="select.keyword"
style="width: 160px;margin-right: 10px;"></el-input>
<div style="margin-right: 10px;">状态</div>
<el-select v-model="select.audit_status" clearable placeholder="请选择">
<el-option v-for="item in statusList" :key="item.id" :label="item.value" :value="item.id">
</el-option>
</el-select>
<div style="margin:0 10px;">只看自己被访记录</div>
<el-switch
v-model="select.my_accept_admin"
active-color="#004593"
@ -22,8 +32,9 @@
:inactive-value="0"
>
</el-switch>
<div style="margin:0 10px;">只看自己审核记</div>
<div v-if="is_admin" style="margin:0 10px;"></div>
<el-switch
v-if="is_admin"
v-model="select.my_audit"
active-color="#004593"
inactive-color="#ddd"
@ -39,17 +50,17 @@
:active-value="1"
:inactive-value="0"
>
</el-switch>
<el-button @click="getList" slot="reference" size="medium" type="primary" style="margin-left: 10px">查询
</el-button>
</div>
</slot>
</lx-header>
</div>
<xy-table :table-item="table" :list="data" :total="total"
@pageSizeChange="e => {select.page_size = e;select.page = 1;getList()}"
</el-switch>
<el-button @click="getList" slot="reference" size="medium" type="primary" style="margin-left: 10px">查询
</el-button>
</div>
</slot>
</lx-header>
</div>
<xy-table :table-item="table" :list="data" :total="total"
@pageSizeChange="e => {select.page_size = e;select.page = 1;getList()}"
@pageIndexChange="e => {select.page = e;getList()}">
<template v-slot:btns>
<el-table-column fixed="right" label="操作" width="180" header-align="center">
@ -78,183 +89,387 @@
</Poptip>
</template>
</el-table-column>
</template>
</xy-table>
<showVisit ref="showVisit" @refresh="getList"></showVisit>
</div>
</template>
<script>
import {
getList,
destroy
</template>
</xy-table>
<showVisit ref="showVisit" @refresh="getList"></showVisit>
</div>
</template>
<script>
import {
getList,
destroy
} from '@/api/visit/record.js'
import showVisit from '@/views/visit/component/showVisit'
export default {
import showVisit from '@/views/visit/component/showVisit'
import store from "@/store/modules/user.js"
export default {
components: {
showVisit
},
data() {
return {
visible: false,
select: {
page: 1,
page_size: 10,
keyword: "",
audit_status: 0,
my_accept_admin: 0,
my_audit: 0,
my_self:0
},
selectRange: [],
statusList: [{
id: -1,
value: '待学习'
},
{
id: 0,
value: '待审核'
},
{
id: 1,
value: '通过(待进厂)'
},
{
id: 2,
value: '驳回'
},
{
id: 3,
value: '已进厂'
},
{
id: 4,
value: '已离厂'
},{
id: 5,
value: '已取消'
}
],
total: 0,
data: [],
table: [{
label: '序号',
type: "index",
fixed: "left",
width: 80
},
{
label: '姓名',
sortable: false,
prop: 'name',
fixed: "left",
width: 120
},
{
label: '类型',
sortable: false,
prop: 'type_text',
width: 120
},
{
label: '状态',
sortable: false,
prop: 'audit_status_text',
width: 120
},
{
label: '是否随访',
sortable: false,
prop: 'follw_people',
showVisit
},
data() {
return {
visible: false,
// 使
useMockData: false,
select: {
page: 1,
page_size: 10,
keyword: "",
audit_status: 0,
my_accept_admin: 0,
my_audit: 1,
my_self:0,
is_auth:0
},
is_admin:false,
selectRange: [],
statusList: [{
id: -1,
value: '待学习'
},
{
id: 0,
value: '待审核'
},
{
id: 1,
value: '通过(待进厂)'
},
{
id: 2,
value: '驳回'
},
{
id: 3,
value: '已进厂'
},
{
id: 4,
value: '已离厂'
},{
id: 5,
value: '已取消'
}
],
total: 0,
data: [],
//
mockData: [
{
id: 1,
name: '张三',
type: 1,
type_text: '普通访客',
audit_status: 0,
audit_status_text: '待审核',
accept_admin: { name: '李经理' },
follw_people: ['随行人员1', '随行人员2'],
date: '2024-10-14',
credent: 1,
idcard: '110101199001011234',
mobile: '13800138001',
company_name: '北京科技有限公司',
start_date: '2024-10-14 09:00:00',
end_date: '2024-10-14 18:00:00',
created_at: '2024-10-13 15:30:00',
admin: { name: '管理员A' },
vehicle_images_detail: [
{
id: 2001,
url: 'https://picsum.photos/300/400?random=11',
original_name: '访客正面照.png',
extension: 'png',
size: 2544
},
{
id: 2002,
url: 'https://picsum.photos/300/400?random=12',
original_name: '访客侧面照.png',
extension: 'png',
size: 2231
}
]
},
{
id: 2,
name: '李四',
type: 2,
type_text: '施工人员',
audit_status: 0,
audit_status_text: '待审核',
accept_admin: { name: '王主管' },
follw_people: [],
date: '2024-10-15',
credent: 1,
idcard: '110101199002025678',
mobile: '13800138002',
company_name: '建筑施工集团',
start_date: '2024-10-15 08:00:00',
end_date: '2024-10-15 20:00:00',
created_at: '2024-10-13 16:00:00',
admin: { name: '管理员B' },
vehicle_images_detail: [
{
id: 2003,
url: 'https://picsum.photos/300/400?random=13',
original_name: '施工人员照片.png',
extension: 'png',
size: 2784
}
]
},
{
id: 3,
name: '王五',
type: 3,
type_text: '物流司机',
audit_status: 0,
audit_status_text: '待审核',
accept_admin: { name: '赵总监' },
follw_people: ['司机助手'],
date: '2024-10-14',
credent: 1,
idcard: '110101199003033456',
mobile: '13800138003',
company_name: '顺达物流公司',
start_date: '2024-10-14 10:00:00',
end_date: '2024-10-14 16:00:00',
created_at: '2024-10-13 14:20:00',
admin: { name: '管理员C' },
vehicle_images_detail: [
{
id: 2004,
url: 'https://picsum.photos/400/300?random=14',
original_name: '车辆前方照片.png',
extension: 'png',
size: 2686
},
{
id: 2005,
url: 'https://picsum.photos/400/300?random=15',
original_name: '车辆侧面照片.png',
extension: 'png',
size: 2544
}
]
},
{
id: 4,
name: '赵六',
type: 1,
type_text: '普通访客',
audit_status: 0,
audit_status_text: '待审核',
accept_admin: { name: '刘经理' },
follw_people: [],
date: '2024-10-16',
credent: 2,
idcard: 'P123456789',
mobile: '13800138004',
company_name: '国际贸易公司',
start_date: '2024-10-16 09:00:00',
end_date: '2024-10-16 17:00:00',
created_at: '2024-10-14 08:30:00',
admin: { name: '管理员D' },
vehicle_images_detail: [
{
id: 2006,
url: 'https://picsum.photos/300/400?random=16',
original_name: '访客证件照.png',
extension: 'png',
size: 2544
}
]
},
{
id: 5,
name: '孙七',
type: 2,
type_text: '施工人员',
audit_status: 0,
audit_status_text: '待审核',
accept_admin: { name: '周主任' },
follw_people: ['施工队员1', '施工队员2'],
date: '2024-10-15',
credent: 1,
idcard: '110101199004047890',
mobile: '13800138005',
company_name: '装修工程队',
start_date: '2024-10-15 07:00:00',
end_date: '2024-10-15 19:00:00',
created_at: '2024-10-13 17:15:00',
admin: { name: '管理员E' },
vehicle_images_detail: [
{
id: 2007,
url: 'https://picsum.photos/300/400?random=17',
original_name: '施工人员照片.png',
extension: 'png',
size: 2784
}
]
}
],
table: [{
label: '序号',
type: "index",
fixed: "left",
width: 80
},
{
label: '姓名',
sortable: false,
prop: 'name',
fixed: "left",
width: 120
},
{
label: '类型',
sortable: false,
prop: 'type_text',
width: 120
},
{
label: '状态',
sortable: false,
prop: 'audit_status_text',
width: 120
},{
label: '被访人',
sortable: false,
prop: 'accept_admin.name',
width: 120,
},
{
label: '是否随访',
sortable: false,
prop: 'follw_people',
width: 80,
formatter:(cell, data, value)=>{
return value?'是':'否'
}
},
{
label: '预约时间',
sortable: false,
prop: 'date',
width: 120
},
{
label: '证件类型',
sortable: false,
prop: 'credent',
return value.length>0?'是':'否'
}
},
{
label: '预约时间',
sortable: false,
prop: 'date',
width: 120
},
{
label: '证件类型',
sortable: false,
prop: 'credent',
width: 120,
formatter:(cell, data, value)=>{
return value==1?'身份证':'护照'
},
},
{
label: '证件号',
sortable: false,
prop: 'idcard',
width: 180
},
{
label: '手机号',
sortable: false,
prop: 'mobile',
width: 120
},
{
label: '单位名称',
sortable: false,
prop: 'company_name',
width: 180
},
{
label: '开始时间',
sortable: false,
prop: 'start_date',
width: 180
},
{
label: '结束时间',
sortable: false,
prop: 'end_date',
width: 180
},
{
label: '创建时间',
sortable: false,
prop: 'created_at',
width: 180
},
{
label: '创建人',
sortable: false,
},
},
{
label: '证件号',
sortable: false,
prop: 'idcard',
width: 180
},
{
label: '手机号',
sortable: false,
prop: 'mobile',
width: 120
},
{
label: '单位名称',
sortable: false,
prop: 'company_name',
width: 180
},
{
label: '开始时间',
sortable: false,
prop: 'start_date',
width: 180
},
{
label: '结束时间',
sortable: false,
prop: 'end_date',
width: 180
},
{
label: '创建时间',
sortable: false,
prop: 'created_at',
width: 180
},
{
label: '创建人',
sortable: false,
prop: 'admin.name',
width: 120,
formatter(cell, data, value){
return value?value:''
}
}
]
}
},
computed: {},
mounted() {
this.getList()
},
methods: {
async getList() {
let res = await getList(this.select)
console.log(res)
this.data = res.data
this.total = res.total
},
}
}
]
}
},
computed: {},
mounted() {
const state = store.state
console.log("state",state)
if(state.myRoles && state.myRoles.includes('系统管理员')){
this.select.my_audit = 0
this.is_admin = true
}
console.log(this.is_admin,state.myRoles.includes('系统管理员'))
this.getList()
},
methods: {
async getList() {
// 使
if (this.useMockData) {
//
let filteredData = [...this.mockData]
//
if (this.select.keyword) {
filteredData = filteredData.filter(item =>
item.name.includes(this.select.keyword) ||
item.mobile.includes(this.select.keyword) ||
item.idcard.includes(this.select.keyword) ||
item.company_name.includes(this.select.keyword)
)
}
// check
if (this.select.audit_status !== '' && this.select.audit_status !== null && this.select.audit_status !== undefined) {
filteredData = filteredData.filter(item => item.audit_status === this.select.audit_status)
}
//
this.total = filteredData.length
const start = (this.select.page - 1) * this.select.page_size
const end = start + this.select.page_size
this.data = filteredData.slice(start, end)
console.log('使用模拟数据:', { total: this.total, data: this.data })
} else {
//
let res = await getList(this.select)
console.log(res)
this.data = res.data
this.total = res.total
}
},
deleteStudy(row) {
console.log(row)
destroy({
id: row.id
}).then(res => {
this.$successMessage('destroy', '拜访记录')
this.getList()
})
console.log(row)
destroy({
id: row.id
}).then(res => {
this.$successMessage('destroy', '拜访记录')
this.getList()
})
},
checkRecords(row){
this.$refs['showVisit'].id = row.id
@ -262,43 +477,44 @@
this.$refs['showVisit'].isShow = true
// this.$refs['checkRecord'].id = row.id
// this.$refs['checkRecord'].isShow = true
}
},
}
</script>
<style scoped lang="scss">
//::v-deep .el-button + .el-button{
// margin-left: 0 !important;
//}
::v-deep .el-button {
padding: 5px 8px !important;
}
.selector {
::v-deep .el-input--suffix .el-input__inner {
height: 28px;
}
::v-deep .el-select .el-input .el-select__caret {
line-height: 28px;
}
::v-deep .el-range-editor.el-input__inner {
height: 28px;
width: 250px
}
::v-deep .el-date-editor .el-range__icon {
line-height: 21px;
}
::v-deep .el-date-editor .el-range-separator {
line-height: 21px;
}
::v-deep .el-date-editor .el-range__close-icon {
line-height: 21px;
}
}
}
},
}
</script>
<style scoped lang="scss">
//::v-deep .el-button + .el-button{
// margin-left: 0 !important;
//}
::v-deep .el-button {
padding: 5px 8px !important;
}
.selector {
::v-deep .el-input--suffix .el-input__inner {
height: 28px;
}
::v-deep .el-select .el-input .el-select__caret {
line-height: 28px;
}
::v-deep .el-range-editor.el-input__inner {
height: 28px;
width: 250px
}
::v-deep .el-date-editor .el-range__icon {
line-height: 21px;
}
::v-deep .el-date-editor .el-range-separator {
line-height: 21px;
}
::v-deep .el-date-editor .el-range__close-icon {
line-height: 21px;
}
}
</style>

@ -259,7 +259,7 @@
<template v-slot:accept_goods_admin_id v-if="visitType==3">
<div class="xy-table-item">
<div class="xy-table-item-label">
<span style="color: red;font-weight: 600;padding-right: 4px;"></span>收货
<span style="color: red;font-weight: 600;padding-right: 4px;"></span>被访
</div>
<div class="xy-table-item-content">
<el-select filterable v-model="form.accept_goods_admin_id" @change='changeGoods' placeholder="请选择" style="width:100%">
@ -626,7 +626,7 @@
},
visitType(val) {
if (val) {
this.typeName = val == 1 ? '普通访客' : (val == 2 ? '施工访客' : (val == 3 ? '物流车辆' : ''))
this.typeName = val == 1 ? '普通访客' : (val == 2 ? '施工人员' : (val == 3 ? '物流司机' : ''))
}
}

@ -18,6 +18,39 @@
</div>
</template>
<template v-slot:end_date>
<div class="xy-table-item">
<div class="xy-table-item-label">
<span style="color: red;font-weight: 600;padding-right: 4px;"></span>结束日期
</div>
<div class="xy-table-item-content">
<el-date-picker style="width:300px" v-model="form.end_date" value-format="yyyy-MM-dd" type="date"
placeholder="选择结束日期">
</el-date-picker>
</div>
</div>
</template>
<template v-slot:time>
<div class="xy-table-item">
<div class="xy-table-item-label">
<span style="color: red;font-weight: 600;padding-right: 4px;">*</span>到访时间
</div>
<div class="xy-table-item-content">
<el-time-picker
v-model="form.time"
format="HH:mm"
value-format="HH:mm"
:picker-options="{
start: '08:30',
step: '00:30',
end: '17:00'
}"
placeholder="选择到访时间">
</el-time-picker>
</div>
</div>
</template>
<template v-slot:visit_time_id>
<div class="xy-table-item">
<div class="xy-table-item-label">
@ -73,9 +106,9 @@
<div class="xy-table-item-label">
车辆类型
</div>
<div class="xy-table-item-content">
<el-radio-group v-model="form.plate" style="width:300px">
<el-radio v-for="item in parkAreaList" :key="item.value" :label="item.value">{{item.value}}</el-radio>
<div class="xy-table-item-content">
<el-radio-group v-model="form.plate" style="width:300px">
<el-radio v-for="item in parkAreaList" :key="item.value" :label="item.value">{{item.value}}</el-radio>
</el-radio-group>
<!-- <el-input v-model="form.plate" placeholder="请输入车牌号"></el-input> -->
</div>
@ -150,75 +183,75 @@
<el-input v-model="form.company_name" placeholder="请输入单位名称"></el-input>
</div>
</div>
</template>
<template v-slot:cda v-if="visitType==1&&visitAreaText=='生产区'">
<div class="xy-table-item">
<div class="xy-table-item-label">
<span style="color: red;font-weight: 600;padding-right: 4px;">*</span>CDA编号
</div>
<div class="xy-table-item-content">
<el-input v-model="form.cda" placeholder="请输入CDA编号(如无注明原因)"></el-input>
</div>
</div>
</template>
<!-- <template v-slot:cars v-if="visitType==3">
<div class="xy-table-item">
<div class="xy-table-item-label">
<span style="color: red;font-weight: 600;padding-right: 4px;"></span>到访车辆
</div>
<div class="xy-table-item-content">
<div v-for="(item,index) in form.cars">
<el-input v-model="form.cars[index]" placeholder="请输入到访车辆"></el-input>
</div>
</div>
</div>
</template> -->
<template v-slot:cars v-if="visitType==3">
<div class="xy-table-item">
<div class="xy-table-item-label">
<span style="color: red;font-weight: 600;padding-right: 4px;">*</span>到访车辆
</div>
<div class="xy-table-item-content">
<Button type="primary" icon="md-add" style="margin-bottom: 10px"
@click="carsList.push({car:''})">新增到访车辆</Button>
<xy-table style="width: 620px" :height="180" :is-page="false" :list="carsList"
:table-item="carTable">
<template v-slot:btns>
<el-table-column label="操作" width="90" header-align="center" align="center">
<template v-slot:default="scope">
<Button size="small" type="primary" ghost
@click="carsList.splice(scope.$index, 1)">删除</Button>
</template>
</el-table-column>
</template>
</xy-table>
</div>
</div>
</template>
<template v-slot:carsno v-else>
<div class="xy-table-item">
<div class="xy-table-item-label">
<span style="color: red;font-weight: 600;padding-right: 4px;"></span>到访车辆
</div>
<div class="xy-table-item-content">
<Button type="primary" icon="md-add" style="margin-bottom: 10px"
@click="carsList.push({car:''})">新增到访车辆</Button>
<xy-table style="width: 620px" :height="180" :is-page="false" :list="carsList"
:table-item="carTable">
<template v-slot:btns>
<el-table-column label="操作" width="90" header-align="center" align="center">
<template v-slot:default="scope">
<Button size="small" type="primary" ghost
@click="carsList.splice(scope.$index, 1)">删除</Button>
</template>
</el-table-column>
</template>
</xy-table>
</div>
</div>
</template>
<!-- <template v-slot:cda v-if="visitType==1&&visitAreaText=='生产区'">
<div class="xy-table-item">
<div class="xy-table-item-label">
<span style="color: red;font-weight: 600;padding-right: 4px;">*</span>CDA编号
</div>
<div class="xy-table-item-content">
<el-input v-model="form.cda" placeholder="请输入CDA编号(如无注明原因)"></el-input>
</div>
</div>
</template> -->
<!-- <template v-slot:cars v-if="visitType==3">
<div class="xy-table-item">
<div class="xy-table-item-label">
<span style="color: red;font-weight: 600;padding-right: 4px;"></span>到访车辆
</div>
<div class="xy-table-item-content">
<div v-for="(item,index) in form.cars">
<el-input v-model="form.cars[index]" placeholder="请输入到访车辆"></el-input>
</div>
</div>
</div>
</template> -->
<template v-slot:cars v-if="visitType==3">
<div class="xy-table-item">
<div class="xy-table-item-label">
<span style="color: red;font-weight: 600;padding-right: 4px;">*</span>到访车辆
</div>
<div class="xy-table-item-content">
<Button type="primary" icon="md-add" style="margin-bottom: 10px"
@click="carsList.push({car:''})">新增到访车辆</Button>
<xy-table style="width: 620px" :height="180" :is-page="false" :list="carsList"
:table-item="carTable">
<template v-slot:btns>
<el-table-column label="操作" width="90" header-align="center" align="center">
<template v-slot:default="scope">
<Button size="small" type="primary" ghost
@click="carsList.splice(scope.$index, 1)">删除</Button>
</template>
</el-table-column>
</template>
</xy-table>
</div>
</div>
</template>
<template v-slot:carsno v-else>
<div class="xy-table-item">
<div class="xy-table-item-label">
<span style="color: red;font-weight: 600;padding-right: 4px;"></span>到访车辆
</div>
<div class="xy-table-item-content">
<Button type="primary" icon="md-add" style="margin-bottom: 10px"
@click="carsList.push({car:''})">新增到访车辆</Button>
<xy-table style="width: 620px" :height="180" :is-page="false" :list="carsList"
:table-item="carTable">
<template v-slot:btns>
<el-table-column label="操作" width="90" header-align="center" align="center">
<template v-slot:default="scope">
<Button size="small" type="primary" ghost
@click="carsList.splice(scope.$index, 1)">删除</Button>
</template>
</el-table-column>
</template>
</xy-table>
</div>
</div>
</template>
<template v-slot:follw_people v-if="visitType==1||visitType==2">
@ -245,7 +278,7 @@
</div>
</template>
<template v-slot:long_time>
<!-- <template v-slot:long_time>
<div class="xy-table-item">
<div class="xy-table-item-label">
<span style="color: red;font-weight: 600;padding-right: 4px;">*</span>长访客申请
@ -261,7 +294,7 @@
</div>
</div>
</div>
</template>
</template> -->
<template v-slot:visitorinfos v-if="visitType==1||visitType==2">
<div class="xy-table-item">
@ -283,31 +316,31 @@
</el-select>
</div>
</div>
</template>
<template v-slot:visitorinfos1 v-if="visitAreaText=='生产区'">
<div class="xy-table-item">
<div class="xy-table-item-content" style="width:400px">
陪同人信息
</div>
</div>
</template>
<template v-slot:accompany_id v-if="visitAreaText=='生产区'">
<div class="xy-table-item">
<div class="xy-table-item-label">
<span style="color: red;font-weight: 600;padding-right: 4px;">*</span>人员
</div>
<div class="xy-table-item-content">
<el-select filterable v-model="form.accompany_id" @change='changeAdmin' placeholder="请选择" style="width:100%">
<el-option v-for="item in adminList" :key="item.id" :label="item.name" :value="item.id">
</el-option>
</el-select>
</div>
</div>
</template>
<!-- <template v-slot:visitorinfos1 v-if="visitAreaText=='生产区'">
<div class="xy-table-item">
<div class="xy-table-item-content" style="width:400px">
陪同人信息
</div>
</div>
</template>
<template v-slot:accompany_id v-if="visitAreaText=='生产区'">
<div class="xy-table-item">
<div class="xy-table-item-label">
<span style="color: red;font-weight: 600;padding-right: 4px;">*</span>人员
</div>
<div class="xy-table-item-content">
<el-select filterable v-model="form.accompany_id" @change='changeAdmin' placeholder="请选择" style="width:100%">
<el-option v-for="item in adminList" :key="item.id" :label="item.name" :value="item.id">
</el-option>
</el-select>
</div>
</div>
</template> -->
<template v-slot:accept_goods_admin_id v-if="visitType==3">
<div class="xy-table-item">
<div class="xy-table-item-label">
<span style="color: red;font-weight: 600;padding-right: 4px;">*</span>收货人
<span style="color: red;font-weight: 600;padding-right: 4px;">*</span>被访
</div>
<div class="xy-table-item-content">
<el-select filterable v-model="form.accept_goods_admin_id" @change='changeGoods' placeholder="请选择" style="width:100%">
@ -350,12 +383,14 @@
type: 'add',
id: '',
visitType: "",
typeName: '',
typeName: '',
visitAreaText:"",
form: {
// type: 1,
visitinfo: "",
date: "",
end_date:'',
time:'',
visit_time_id: "",
visit_area_id: "",
workRange: "",
@ -367,24 +402,24 @@
mobile: "",
credent: 1,
idcard: "",
company_name: "",
cda:'',
cars: [],
company_name: "",
// cda:'',
cars: [],
carsno:[],
follw_people: [],
long_time: 0,
long_time: 0,
longrange: "",
visitorinfos: "",
accpet_department_id: "",
accept_admin_id: "",
visitorinfos1:'',
visitorinfos: "",
accpet_department_id: "",
accept_admin_id: "",
visitorinfos1:'',
accompany_id:'',
accept_goods_admin_id: ""
},
followList:[],
followList:[],
carsList:[],
visitTimeList: [],
visitAreaList: [],
visitAreaList: [],
parkAreaList: [],
reasonList: [],
credentList: [{
@ -406,17 +441,17 @@
},
],
departmentList: [],
adminList: [],
carTable:[{
label: "车牌号",
prop: "car",
// width: 200,
customFn: (row, scope) => {
return (<el-input type="text" placeholder = "请填写车牌号"
v-model={row.car}>
</el-input>
)
}
adminList: [],
carTable:[{
label: "车牌号",
prop: "car",
// width: 200,
customFn: (row, scope) => {
return (<el-input type="text" placeholder = "请填写车牌号"
v-model={row.car}>
</el-input>
)
}
}],
followTable: [{
label: "姓名",
@ -497,10 +532,10 @@
visit_area_id: [{
required: true,
message: '请选择到访区域'
}],
plate: [{
required: true,
message: '请选择停车区域'
}],
plate: [{
required: true,
message: '请选择停车区域'
}],
name: [{
required: true,
@ -514,31 +549,31 @@
pattern: /^[1][3-9][\d]{9}/,
message: "手机号格式错误",
}
],
company_name: [{
required: true,
message: '请输入单位名称'
}],
cda:[{
required: true,
message: '请输入CDA编号'
}],
cars: [{
required: true,
message: '请输入车牌号'
}],
accompany_id: [{
required: true,
message: '请选择陪同人'
}],
accept_admin_id: [{
required: true,
message: '请选被访人'
}],
accept_goods_admin_id: [{
required: true,
message: '请选择收货人'
}]
],
company_name: [{
required: true,
message: '请输入单位名称'
}],
// cda:[{
// required: true,
// message: 'CDA'
// }],
// cars: [{
// required: true,
// message: ''
// }],
// accompany_id: [{
// required: true,
// message: ''
// }],
accept_admin_id: [{
required: true,
message: '请选被访人'
}],
accept_goods_admin_id: [{
required: true,
message: '请选择被访人'
}]
},
pickerOptions: {
@ -579,39 +614,41 @@
const res = await show({
id: this.id
})
this.form = {
visitinfo: "",
date: res?.date,
visit_time_id: res?.visit_time_id,
visit_area_id: res?.visit_area_id,
workRange: res.work_start_time?[res.work_start_time,res.work_end_time]:"",
reason: res?.reason,
plate: res?.plate,
remark: res?.remark,
visitorinfo: "",
name: res?.name,
mobile: res?.mobile,
credent: res?.credent,
idcard: res?.idcard,
company_name: res?.company_name,
cda:res?.cda,
cars:[],
carsno: [],
follw_people: res?.follw_people,
long_time: res?.long_time,
longrange: res.start_date?[res.start_date,res.end_date]:"",
visitorinfos: "",
accpet_department_id: res?.accpet_department_id,
accept_admin_id: res?.accept_admin_id,
visitorinfos1:'',
accompany_id:res?.accompany_id,
accept_goods_admin_id: res?parseInt(res.accept_goods_admin_id):''
}
this.followList = res?.follw_people
for(var k of res?.cars){
this.carsList.push({car:k})
}
this.visitAreaText = res?.visit_area.name
this.form = {
visitinfo: "",
date: res?.date,
end_date: res?.end_date,
time:res?.time,
visit_time_id: res?.visit_time_id,
visit_area_id: res?.visit_area_id,
workRange: res.work_start_time?[res.work_start_time,res.work_end_time]:"",
reason: res?.reason,
plate: res?.plate,
remark: res?.remark,
visitorinfo: "",
name: res?.name,
mobile: res?.mobile,
credent: res?.credent,
idcard: res?.idcard,
company_name: res?.company_name,
// cda:res?.cda,
cars:[],
carsno: [],
follw_people: res?.follw_people,
long_time: res?.long_time,
longrange: res.start_date?[res.start_date,res.end_date]:"",
visitorinfos: "",
accpet_department_id: res?.accpet_department_id,
accept_admin_id: res?.accept_admin_id,
visitorinfos1:'',
accompany_id:res?.accompany_id,
accept_goods_admin_id: res?parseInt(res.accept_goods_admin_id):''
}
this.followList = res?.follw_people
for(var k of res?.cars){
this.carsList.push({car:k})
}
this.visitAreaText = res?.visit_area.name
console.log(this.followList,this.carsList)
},
async getLabel() {
@ -625,100 +662,101 @@
const reason = await getparameter({
number: "reasonList",
});
this.reasonList = reason?.detail;
const park = await getparameter({
number: "parkArea",
});
this.reasonList = reason?.detail;
const park = await getparameter({
number: "parkArea",
});
this.parkAreaList = park?.detail;
},
changeVisitArea(val){
console.log(val)
this.visitAreaList.map(item=>{
if(item.id==val){
this.visitAreaText = item.name
}
})
console.log(this.visitAreaText)
},
changelongrange(val){
this.form.start_date = val[0]
this.form.end_date = val[1]
},
changeworkrange(val){
this.form.work_start_time = val[0]
this.form.work_end_time = val[1]
},
changeAdmin(item){
if(item){
this.adminList.map(e=>{
if(e.id==item){
this.form.accompany_id = e.id
}
})
}
},
changeAdmin1(item){
if(item){
this.adminList.map(e=>{
if(e.id==item){
this.form.accept_admin_id = e.id
this.form.accpet_department_id = e.department_id
if(this.visitAreaText=='非生产区'){
this.form.accompany_id = e.id
}
}
})
}
},
changeGoods(item){
if(item){
this.adminList.map(e=>{
if(e.id==item){
this.form.accept_admin_id = e.id
this.form.accept_goods_admin_id = e.id
},
changeVisitArea(val){
console.log(val)
this.visitAreaList.map(item=>{
if(item.id==val){
this.visitAreaText = item.name
}
})
console.log(this.visitAreaText)
},
changelongrange(val){
this.form.start_date = val[0]
this.form.end_date = val[1]
},
changeworkrange(val){
this.form.work_start_time = val[0]
this.form.work_end_time = val[1]
},
changeAdmin(item){
if(item){
this.adminList.map(e=>{
if(e.id==item){
this.form.accompany_id = e.id
}
})
}
},
changeAdmin1(item){
if(item){
this.adminList.map(e=>{
if(e.id==item){
this.form.accept_admin_id = e.id
this.form.accpet_department_id = e.department_id
if(this.visitAreaText=='非生产区'){
this.form.accompany_id = e.id
}
}
})
}
this.form.accompany_id = e.id
// if(this.visitAreaText==''){
// this.form.accompany_id = e.id
// }
}
})
}
},
changeGoods(item){
if(item){
this.adminList.map(e=>{
if(e.id==item){
this.form.accept_admin_id = e.id
this.form.accept_goods_admin_id = e.id
this.form.accpet_department_id = e.department_id
if(this.visitAreaText=='非生产区'){
this.form.accompany_id = e.id
}
}
})
}
},
submit() {
let that = this
if(that.form.credent==1){
const regtest = /(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/
if(!regtest.test(that.form.idcard)){
this.$successMessage('身份证格式错误', '','warning')
return
}
}
if(that.form.credent==2){
const regtest = /^([a-zA-z]|[0-9]){5,17}$/
if(!regtest.test(that.form.idcard)){
this.$successMessage('护照格式错误', '','warning')
return
}
}
that.form.follw_people = that.followList
let _car = []
for(var k of that.carsList){
_car.push(k.car)
}
this.form.cars = _car
console.log("this.form.cars",this.form.cars)
// return
if(this.visitType==3){
this.form.accept_admin_id = this.form.accept_goods_admin_id
let that = this
if(that.form.credent==1){
const regtest = /(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/
if(!regtest.test(that.form.idcard)){
this.$successMessage('身份证格式错误', '','warning')
return
}
}
if(that.form.credent==2){
const regtest = /^([a-zA-z]|[0-9]){5,17}$/
if(!regtest.test(that.form.idcard)){
this.$successMessage('护照格式错误', '','warning')
return
}
}
that.form.follw_people = that.followList
let _car = []
for(var k of that.carsList){
_car.push(k.car)
}
this.form.cars = _car
console.log("this.form.cars",this.form.cars)
// return
if(this.visitType==3){
this.form.accept_admin_id = this.form.accept_goods_admin_id
}
if (this.type === 'editor') {
this.form.id = this.id
}else{
this.form.id = ""
}else{
this.form.id = ""
}
// return
save({
@ -732,9 +770,9 @@
},
watch: {
isShow(newVal) {
if (newVal) {
console.log("this.visitType",this.visitType)
this.form.type = this.visitType
if (newVal) {
console.log("this.visitType",this.visitType)
this.form.type = this.visitType
this.form.audit_status = 1
if (this.type === 'editor') {
this.getDetail()
@ -743,15 +781,15 @@
this.id = ''
this.type = ''
this.visitType = 1
this.followList = []
this.carsList = []
this.followList = []
this.carsList = []
this.visitAreaText=''
this.$refs['dialog'].reset()
}
},
visitType(val) {
if (val) {
this.typeName = val == 1 ? '普通访客' : (val == 2 ? '施工访客' : (val == 3 ? '物流车辆' : ''))
this.typeName = val == 1 ? '普通访客' : (val == 2 ? '施工人员' : (val == 3 ? '物流司机' : ''))
}
}
@ -775,11 +813,11 @@
position: absolute;
top: 4px;
right: 4px;
}
.carsitem{
width:450px;margin-bottom:10px;margin-bottom: 10px;display: flex;align-items: center;justify-content: space-between;
}
.carsitem Button{
margin-left:10px
}
</style>
.carsitem{
width:450px;margin-bottom:10px;margin-bottom: 10px;display: flex;align-items: center;justify-content: space-between;
}
.carsitem Button{
margin-left:10px
}
</style>

@ -28,11 +28,11 @@
核销状态
</div>
<div class="xy-table-item-content">
<div style="font-size: 32px;padding: 25px;width:400px">
<div v-for="item in codeTypeList">
<div v-if="item.id == codeForm.type">
{{item.value}}
</div>
<div style="font-size: 32px;padding: 25px;width:400px">
<div v-for="item in codeTypeList">
<div v-if="item.id == codeForm.type">
{{item.value}}
</div>
</div>
<!-- <el-radio-group v-model="codeForm.type">
<el-radio :label="item.id" >{{item.value}}</el-radio>
@ -50,11 +50,11 @@
<div class="xy-table-item-content">
<!-- <el-input style="font-size: 32px;padding: 25px;width:400px" v-model="codeForm.person_no"
placeholder="请输入入场牌"></el-input> -->
<xy-table style="width: 600px" :height="260" :is-page="false" :list="codeForm.person_no"
:table-item="codefollowTable">
<template v-slot:btns>
</template>
placeholder="请输入入场牌"></el-input> -->
<xy-table style="width: 600px" :height="260" :is-page="false" :list="codeForm.person_no"
:table-item="codefollowTable">
<template v-slot:btns>
</template>
</xy-table>
</div>
</div>
@ -67,12 +67,12 @@
<div class="xy-table-item-content">
<!-- <el-input style="font-size: 32px;padding: 25px;width:400px" v-model="codeForm.car_no"
placeholder="请输入停车牌"></el-input> -->
<xy-table style="width: 600px" :height="260" :is-page="false" :list="codeForm.car_no"
:table-item="carfollowTable">
<template v-slot:btns>
</template>
placeholder="请输入停车牌"></el-input> -->
<xy-table style="width: 600px" :height="260" :is-page="false" :list="codeForm.car_no"
:table-item="carfollowTable">
<template v-slot:btns>
</template>
</xy-table>
</div>
</div>
@ -91,6 +91,26 @@
{{form.date}}
</div>
</div>
</template>
<template v-slot:end_date>
<div class="xy-table-item">
<div class="xy-table-item-label">
<span style="color: red;font-weight: 600;padding-right: 4px;"></span>结束日期
</div>
<div class="xy-table-item-content">
{{form.end_date}}
</div>
</div>
</template>
<template v-slot:time>
<div class="xy-table-item">
<div class="xy-table-item-label">
<span style="color: red;font-weight: 600;padding-right: 4px;"></span>到访时间
</div>
<div class="xy-table-item-content">
{{form.time?form.time:''}}
</div>
</div>
</template>
<template v-slot:visit_time_id>
<div class="xy-table-item">
@ -208,17 +228,17 @@
{{form.company_name}}
</div>
</div>
</template>
<template v-slot:cda v-if="form.type==1 && form.visit_area && form.visit_area.name=='生产区'">
<div class="xy-table-item">
<div class="xy-table-item-label">
CDA编号
</div>
<div class="xy-table-item-content">
{{form.cda}}
</div>
</div>
</template>
<!-- <template v-slot:cda v-if="form.type==1 && form.visit_area && form.visit_area.name=='生产区'">
<div class="xy-table-item">
<div class="xy-table-item-label">
CDA编号
</div>
<div class="xy-table-item-content">
{{form.cda}}
</div>
</div>
</template> -->
<template v-slot:cars>
<div class="xy-table-item">
<div class="xy-table-item-label">
@ -246,7 +266,7 @@
</div>
</template>
<template v-slot:long_time>
<!-- <template v-slot:long_time>
<div class="xy-table-item">
<div class="xy-table-item-label">
<span style="color: red;font-weight: 600;padding-right: 4px;"></span>长访客申请
@ -258,46 +278,46 @@
</div>
</div>
</div>
</template>
<template v-slot:visitorinfos>
<div class="xy-table-item">
<div class="xy-table-item-content" style="width:400px">
被访人信息
</div>
</div>
</template>
<template v-slot:accept_admin_id>
<div class="xy-table-item">
<div class="xy-table-item-label">
<span style="color: red;font-weight: 600;padding-right: 4px;"></span>人员
</div>
<div class="xy-table-item-content">
{{form.accept_admin?form.accept_admin.name:''}}
</div>
</div>
</template>
<template v-slot:visitorinfos1 v-if="form.visit_area && form.visit_area.name=='生产区'">
<div class="xy-table-item">
<div class="xy-table-item-content" style="width:400px">
陪同人信息
</div>
</div>
</template>
<template v-slot:accompany_id v-if="form.visit_area && form.visit_area.name=='生产区'">
<div class="xy-table-item">
<div class="xy-table-item-label">
<span style="color: red;font-weight: 600;padding-right: 4px;"></span>人员
</div>
<div class="xy-table-item-content">
{{form.accompany?form.accompany.name:''}}
</div>
</div>
</template>
<template v-slot:visitorinfos>
<div class="xy-table-item">
<div class="xy-table-item-content" style="width:400px">
被访人信息
</div>
</div>
</template> -->
<template v-slot:accept_admin_id>
<div class="xy-table-item">
<div class="xy-table-item-label">
<span style="color: red;font-weight: 600;padding-right: 4px;"></span>人员
</div>
<div class="xy-table-item-content">
{{form.accept_admin?form.accept_admin.name:''}}
</div>
</div>
</template>
<!-- <template v-slot:visitorinfos1 v-if="form.visit_area && form.visit_area.name=='生产区'">
<div class="xy-table-item">
<div class="xy-table-item-content" style="width:400px">
陪同人信息
</div>
</div>
</template>
<template v-slot:accompany_id v-if="form.visit_area && form.visit_area.name=='生产区'">
<div class="xy-table-item">
<div class="xy-table-item-label">
<span style="color: red;font-weight: 600;padding-right: 4px;"></span>人员
</div>
<div class="xy-table-item-content">
{{form.accompany?form.accompany.name:''}}
</div>
</div>
</template> -->
<template v-slot:accept_goods_admin_id v-if="form.type==3">
<div class="xy-table-item">
<div class="xy-table-item-label">
<span style="color: red;font-weight: 600;padding-right: 4px;"></span>收货人
<span style="color: red;font-weight: 600;padding-right: 4px;"></span>被访
</div>
<div class="xy-table-item-content">
{{form.accept_goods_admin?form.accept_goods_admin.name:''}}
@ -342,7 +362,39 @@
</div>
</template>
<!-- 照片信息标题 -->
<template v-slot:photoinfo>
<div style="width:600px">
照片信息
</div>
</template>
<!-- 照片列表 -->
<template v-slot:photos>
<div class="photo-full-width" v-if="form.vehicle_images_detail && form.vehicle_images_detail.length > 0">
<div class="photo-list">
<div class="photo-item" v-for="(photo, index) in form.vehicle_images_detail" :key="index">
<div class="photo-wrapper">
<el-image
:src="photo.url"
:preview-src-list="form.vehicle_images_detail.map(p => p.url)"
:initial-index="index"
fit="cover"
class="photo-image">
<div slot="error" class="image-slot">
<i class="el-icon-picture-outline"></i>
</div>
</el-image>
<div class="photo-overlay">
<i class="el-icon-zoom-in"></i>
<span>点击预览</span>
</div>
</div>
<div class="photo-desc">{{ photo.original_name }}</div>
</div>
</div>
</div>
</template>
<template v-slot:footerContent>
@ -382,12 +434,14 @@
formDataType: '',
formData: {
checkcode: '',
codeType: "",
codeType: "",
person_no: '',
car_no: '',
visitinfo: "",
date: "",
date: "",
end_date:'',
time:'',
visit_time_id: "",
visit_area_id: "",
workRange: "",
@ -399,18 +453,20 @@
mobile: "",
credent: 1,
idcard: "",
company_name: "",
cda:'',
company_name: "",
// cda:'',
cars: "",
follw_people: [],
long_time: 0,
longrange: "",
visitorinfos: "",
accpet_department_id: "",
longrange: "",
visitorinfos: "",
accpet_department_id: "",
accept_admin_id: "",
visitorinfos1: "",
accompany_id:"",
accept_goods_admin_id: "",
photoinfo: "",
photos: [],
checkRecord: '',
checkForm: {},
checkText: ''
@ -425,9 +481,9 @@
car_no: [],
person_no: []
}, //
codeTypeList: [{
id:0,
value:'请提醒陪同人签字'
codeTypeList: [{
id:0,
value:'请提醒陪同人签字'
},{
id: 1,
value: '入场'
@ -436,36 +492,36 @@
value: '离场'
}],
gateAdminId: '',
check_admin_name: "",
carfollowTable: [{
label: "车牌",
prop: "car",
width: 200
},{
label: "停车牌",
prop: "car_no",
width: 400,
customFn: (row, scope) => {
return (<el-input type="text" placeholder = "请填写停车牌"
v-model={row.car_no}>
</el-input>
)
}
}],
codefollowTable: [{
label: "姓名",
prop: "name",
width: 200
},{
label: "入场牌",
prop: "person_no",
width: 400,
customFn: (row, scope) => {
return (<el-input type="text" placeholder = "请填写入场牌"
v-model={row.person_no}>
</el-input>
)
}
check_admin_name: "",
carfollowTable: [{
label: "车牌",
prop: "car",
width: 200
},{
label: "停车牌",
prop: "car_no",
width: 400,
customFn: (row, scope) => {
return (<el-input type="text" placeholder = "请填写停车牌"
v-model={row.car_no}>
</el-input>
)
}
}],
codefollowTable: [{
label: "姓名",
prop: "name",
width: 200
},{
label: "入场牌",
prop: "person_no",
width: 400,
customFn: (row, scope) => {
return (<el-input type="text" placeholder = "请填写入场牌"
v-model={row.person_no}>
</el-input>
)
}
}],
followTable: [{
label: "姓名",
@ -530,24 +586,24 @@
if (this.formDataType == 'coderecord') {
this.codeForm.code = this.form.code
this.codeForm.admin_id = parseInt(this.gateAdminId)
this.codeForm.type = this.form.audit_status == 1 ? 1 : (this.form.audit_status == 3 && this.form.accept_admin_sign ? 2 : 0)
if(this.codeForm.type==1){
this.codeForm.person_no.push({name:this.form.name,person_no:''})
for(var k of this.form.follw_people){
this.codeForm.person_no.push({name:k.name,person_no:''})
}
for(var m of this.form.cars){
this.codeForm.car_no.push({car:m,car_no:''})
}
}else{
for(var k of this.form.person_no){
this.codeForm.person_no.push(JSON.parse(k))
}
for(var m of this.form.car_no){
this.codeForm.car_no.push(JSON.parse(m))
}
}
this.codeForm.type = this.form.audit_status == 1 ? 1 : (this.form.audit_status == 3 && this.form.accept_admin_sign ? 2 : 0)
if(this.codeForm.type==1){
this.codeForm.person_no.push({name:this.form.name,person_no:''})
for(var k of this.form.follw_people){
this.codeForm.person_no.push({name:k.name,person_no:''})
}
for(var m of this.form.cars){
this.codeForm.car_no.push({car:m,car_no:''})
}
}else{
for(var k of this.form.person_no){
this.codeForm.person_no.push(JSON.parse(k))
}
for(var m of this.form.car_no){
this.codeForm.car_no.push(JSON.parse(m))
}
}
}
} else {
@ -584,13 +640,13 @@
that.checkForm.audit_admin_id = item.audit_admin_id
that.isCheck = true
return
} else {
} else {
that.checkText = "请等待"+item.audit_admin.name+"审核"
// that.checkLevel.map(item1 => {
// if (item.level == item1.id) {
// that.checkText = item1.value
// }else{
// }else{
// }
// })
that.isCheck = false
@ -607,10 +663,10 @@
this.formDataType = ''
this.checkForm = {}
this.check_admin_name = ''
this.codeForm = {
type: 1,
car_no: [],
person_no: []
this.codeForm = {
type: 1,
car_no: [],
person_no: []
}
this.codeType = ''
this.gateAdminId = ''
@ -632,13 +688,13 @@
},
codeSubmit() {
let that = this
console.log(this.codeForm)
console.log(this.codeForm.person_no)
if(this.codeForm.type==0){
this.$successMessage('请提醒陪同人签字','','warning')
this.isShow = false
return
}
console.log(this.codeForm)
console.log(this.codeForm.person_no)
// if(this.codeForm.type==0){
// this.$successMessage('','','warning')
// this.isShow = false
// return
// }
cancelCode({
...that.codeForm
}).then(res => {
@ -653,7 +709,7 @@
}
</script>
<style scoped>
<style scoped lang="scss">
.xy-table-item-label {
width: 180px !important;
}
@ -670,11 +726,198 @@
right: 4px;
}
/deep/ .el-radio__input {
::v-deep .el-radio__input {
vertical-align: super;
}
/deep/ .el-radio__label {
::v-deep .el-radio__label {
font-size: 32px;
}
</style>
//
.photo-full-width {
width: 100% !important;
max-width: none !important;
display: block !important;
margin: 0 !important;
padding: 0 !important;
// xy-dialog
position: relative;
left: -50%;
width: 200% !important;
margin-left: 50% !important;
}
//
.photo-list {
display: flex;
flex-wrap: wrap;
gap: 15px;
margin-top: 5px;
width: 100%;
justify-content: flex-start;
max-width: 100%;
.photo-item {
display: flex;
flex-direction: column;
align-items: center;
.photo-wrapper {
position: relative;
width: 120px;
height: 160px;
border-radius: 8px;
overflow: hidden;
.photo-image {
width: 100%;
height: 100%;
border: 2px solid #e4e7ed;
cursor: pointer;
transition: all 0.3s;
&:hover {
border-color: #409eff;
}
::v-deep .el-image__inner {
width: 100%;
height: 100%;
object-fit: cover;
transition: transform 0.3s;
}
.image-slot {
display: flex;
justify-content: center;
align-items: center;
width: 100%;
height: 100%;
background: #f5f7fa;
color: #909399;
i {
font-size: 40px;
}
}
}
.photo-overlay {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.6);
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
opacity: 0;
transition: opacity 0.3s;
pointer-events: none;
i {
font-size: 32px;
color: #fff;
margin-bottom: 8px;
}
span {
color: #fff;
font-size: 14px;
font-weight: 500;
}
}
&:hover {
.photo-overlay {
opacity: 1;
}
.photo-image ::v-deep .el-image__inner {
transform: scale(1.1);
}
}
}
.photo-desc {
margin-top: 8px;
font-size: 12px;
color: #909399;
text-align: center;
max-width: 120px;
word-break: break-all;
}
}
}
</style>
<style lang="scss">
//
.el-image-viewer__wrapper {
.el-image-viewer__close {
width: 50px !important;
height: 50px !important;
font-size: 28px !important;
background: rgba(0, 0, 0, 0.7) !important;
border-radius: 50% !important;
color: #fff !important;
top: 20px !important;
right: 20px !important;
display: flex !important;
align-items: center !important;
justify-content: center !important;
transition: all 0.3s !important;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.5) !important;
&:hover {
background: rgba(255, 73, 73, 0.9) !important;
transform: scale(1.1) rotate(90deg) !important;
}
}
//
.el-image-viewer__prev,
.el-image-viewer__next {
width: 50px !important;
height: 50px !important;
font-size: 28px !important;
background: rgba(0, 0, 0, 0.6) !important;
border-radius: 50% !important;
color: #fff !important;
transition: all 0.3s !important;
&:hover {
background: rgba(64, 158, 255, 0.9) !important;
transform: scale(1.1) !important;
}
}
//
.el-image-viewer__actions__inner {
background: rgba(0, 0, 0, 0.7) !important;
border-radius: 30px !important;
padding: 10px 20px !important;
i {
color: #fff !important;
font-size: 24px !important;
margin: 0 8px !important;
transition: all 0.3s !important;
&:hover {
color: #409eff !important;
transform: scale(1.2) !important;
}
}
}
//
.el-image-viewer__mask {
background: rgba(0, 0, 0, 0.85) !important;
}
}
</style>

File diff suppressed because it is too large Load Diff

@ -15,14 +15,52 @@
</lx-header>
</div>
<xy-table :table-item="table" :list="data" :total="total"
<xy-table :table-item="table" :list="data" :total="total"
:auths="[]"
@pageSizeChange="e => {select.page_size = e;select.page = 1;getList()}"
@pageIndexChange="e => {select.page = e;getList()}">
<template v-slot:btns>
<div></div>
@pageIndexChange="e => {select.page = e;getList()}">
<template v-slot:btns>
<el-table-column fixed="right" label="操作" width="180" header-align="center">
<template slot-scope="scope">
<el-button type="primary" size="medium" @click="showRecord(scope.row)"></el-button>
</template>
</el-table-column>
</template>
</xy-table>
<el-dialog
title="答题记录"
:visible.sync="recordVisible"
width="700px"
:close-on-click-modal="false">
<div v-if="currentRecord && currentRecord.length > 0" class="record-list">
<div
v-for="(question, index) in currentRecord"
:key="index"
class="record-item">
<div class="record-header">
<span class="record-index">{{ index + 1 }}.</span>
<span class="record-title">{{ question.title }}</span>
<span class="record-type">{{ getQuestionType(question.type) }}</span>
<span class="record-answer">正确答案{{ getCorrectAnswer(question) }}</span>
</div>
<div class="record-options" v-if="question.answer && question.answer.length">
<span
v-for="(option, optIdx) in question.answer"
:key="optIdx"
:class="['option-chip', getOptionClass(index, option)]">
{{ getOptionLabel(optIdx) }}. {{ option.content }}
</span>
</div>
<div class="record-options" v-else>
暂无选项
</div>
</div>
</div>
<div v-else style="text-align: center; color: #999;">暂无答题记录</div>
<span slot="footer" class="dialog-footer">
<el-button @click="recordVisible = false">关闭</el-button>
</span>
</el-dialog>
</div>
</template>
@ -40,6 +78,9 @@
},
total: 0,
data: [],
recordVisible: false,
currentRecord: [],
currentAnswers: [],
table: [{
label: '序号',
type: "index",
@ -51,53 +92,53 @@
sortable: false,
prop: 'user_id',
width: 120
},
{
label: '姓名',
sortable: false,
prop: 'name',
width: 120
},
{
label: '身份证',
sortable: false,
prop: 'idcard',
// width: 120
},
{
label: '联系方式',
sortable: false,
prop: 'mobile',
width: 120
},
{
label: '学习类型',
sortable: false,
prop: 'type',
width: 120,
formatter:(cell, data, value)=>{
if(value==1){
return '普通访客'
}else if(value==2){
return '施工访客'
}else if(value==3){
return '物流车辆'
}else{
return '未知'
}
}
},
{
label: '学习时间',
sortable: false,
prop: 'updated_at',
width: 180
},
{
label: '有效期',
sortable: false,
prop: 'expire_day',
width: 180
},
{
label: '姓名',
sortable: false,
prop: 'name',
width: 120
},
{
label: '身份证',
sortable: false,
prop: 'idcard',
// width: 120
},
{
label: '联系方式',
sortable: false,
prop: 'mobile',
width: 120
},
{
label: '学习类型',
sortable: false,
prop: 'type',
width: 120,
formatter:(cell, data, value)=>{
if(value==1){
return '普通访客'
}else if(value==2){
return '施工人员'
}else if(value==3){
return '物流司机'
}else{
return '未知'
}
}
},
{
label: '学习时间',
sortable: false,
prop: 'updated_at',
width: 180
},
{
label: '有效期',
sortable: false,
prop: 'expire_day',
width: 180
},
]
}
@ -112,6 +153,70 @@
console.log(res)
this.data = res.data
this.total = res.total
},
showRecord(row) {
this.currentRecord = Array.isArray(row.ask) ? row.ask : []
this.currentAnswers = Array.isArray(row.content) ? row.content : []
this.recordVisible = true
},
getQuestionType(type) {
if (type === 1) {
return '单选'
}
if (type === 2) {
return '多选'
}
return '未知'
},
getCorrectAnswer(question) {
if (!question.answer || !question.answer.length) {
return '-'
}
const correct = question.answer
.map((option, index) => option.result === 1 ? `${this.getOptionLabel(index)}. ${option.content}` : null)
.filter(Boolean)
return correct.length ? correct.join('') : '-'
},
getOptionLabel(index) {
return String.fromCharCode(65 + index)
},
getOptionClass(questionIndex, option) {
const answered = this.isQuestionAnswered(questionIndex)
const isCorrect = option.result === 1
const isSelected = this.isUserSelected(questionIndex, option.content)
if (answered && isCorrect) {
return 'is-correct'
}
if (answered && isSelected && !isCorrect) {
return 'is-wrong'
}
return ''
},
isUserSelected(questionIndex, optionContent) {
if (!this.currentAnswers || !this.currentAnswers.length) {
return false
}
const selection = this.currentAnswers[questionIndex]
if (Array.isArray(selection)) {
return selection.includes(optionContent)
}
if (typeof selection === 'string') {
return selection.split(',').map(item => item.trim()).includes(optionContent)
}
return false
},
isQuestionAnswered(questionIndex) {
if (!this.currentAnswers || !this.currentAnswers.length) {
return false
}
const selection = this.currentAnswers[questionIndex]
if (Array.isArray(selection)) {
return selection.length > 0
}
if (typeof selection === 'string') {
return selection.trim() !== ''
}
return Boolean(selection)
}
},
}
@ -151,4 +256,68 @@
line-height: 21px;
}
}
</style>
.record-list {
max-height: 60vh;
overflow-y: auto;
}
.record-item {
padding: 10px 0;
border-bottom: 1px solid #f0f0f0;
}
.record-item:last-child {
border-bottom: none;
}
.record-header {
display: flex;
flex-wrap: wrap;
align-items: baseline;
font-weight: 500;
color: #333;
}
.record-index {
margin-right: 6px;
}
.record-title {
margin-right: 6px;
}
.record-type {
margin-right: 10px;
color: #666;
}
.record-answer {
color: #0f9674;
}
.record-options {
margin-top: 6px;
display: flex;
flex-wrap: wrap;
gap: 6px 12px;
line-height: 22px;
}
.option-chip {
padding: 2px 6px;
border-radius: 4px;
background: #f5f5f5;
}
.option-chip.is-correct {
background: #e8f8f0;
color: #0f9674;
border: 1px solid #0f9674;
}
.option-chip.is-wrong {
background: #fdecec;
color: #d93025;
border: 1px solid #d93025;
}
</style>

@ -25,7 +25,7 @@ module.exports = {
* Detail: https://cli.vuejs.org/config/#publicpath
*/
publicPath: '/admin/',
outputDir: '/Users/mac/Documents/朗业/2023/b-bd智能访客系统/bd-fangke/public/admin',
outputDir: '../visitor/public/admin',
assetsDir: 'static',
css: {
loaderOptions: { // 向 CSS 相关的 loader 传递选项

Loading…
Cancel
Save