Commit f13f920d authored by 夏敏伟's avatar 夏敏伟

首次修改

parent 849c265f
Pipeline #507 canceled with stages
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
<meta charset="UTF-8" /> <meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/logo.png" /> <link rel="icon" type="image/svg+xml" href="/logo.png" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>旅馆项目</title> <title>xxx_phaseTwo_web</title>
<style> <style>
html,body{ html,body{
width: 100%; width: 100%;
......
import request from "@/utils/request";
/**
* @param data请求接口传递的参数
* @return {Promise}
*/
//获取所有国家
export const getAllCountry = () => {
return request({
url: '/agile/rest/index/api/default/queryNationalityType',
method: 'GET'
});
}
//获取签证类型
export const getAllVisa = () => {
return request({
url: '/agile/rest/index/api/default/queryVisaType',
method: 'GET'
});
}
//获取性别
export const getAllGender = () => {
return request({
url: '/agile/rest/index/api/default/queryGenderType',
method: 'GET'
});
}
//获取外宾证件种类
export const getAllForeignGuest = () => {
return request({
url: '/agile/rest/index/api/default/queryForeignGuestType',
method: 'GET'
});
}
//获取内宾证件种类
export const getAllInternalGuest = () => {
return request({
url: '/agile/rest/index/api/default/queryInternalGuestType',
method: 'GET'
});
}
//获取车牌类型
export const getAllPlateNumber = () => {
return request({
url: '/agile/rest/index/api/default/queryPlateNumberType',
method: 'GET'
});
}
//入境事由
export const getAllReasonEntry = () => {
return request({
url: '/agile/rest/index/api/default/queryReasonEntryType',
method: 'GET'
});
}
//查询省市县
export const getAllProvinciaUrbanAreas = () => {
return request({
url: '/agile/rest/index/api/default/queryProvincialUrbanAreas',
method: 'GET'
});
}
//查询民族
export const getAllNation = () => {
return request({
url: '/agile/rest/index/api/default/queryNationType',
method: 'GET'
});
}
//查询房间类型
export const getAllRoomType = () => {
return request({
url: '/agile/rest/index/api/default/queryRoomType',
method: 'GET'
});
}
//查询所有字典
export const getAllCode = () => {
return request({
url: '/rest/hotel/code/queryList',
method: 'GET'
});
}
//图片上传
export const uploadImg = (data) => {
return request({
url: '/rest/file/upload?bucket=PHOTO',
method: 'POST',
data
});
}
//查看图片路径
export const getImgByUrl = (params) => {
return request({
url: '/rest/file/pathPhoto',
method: 'POST',
params
});
}
\ No newline at end of file
import request from "@/utils/request";
/**
* @param data请求接口传递的参数
* @return {Promise}
*/
//获取派出所组织机构
export const getDeptTree = () => {
return request({
url: '/rest/hotel/dept/queryTree',
method: 'GET'
});
}
\ No newline at end of file
import request from "@/utils/request";
/**
* @param data请求接口传递的参数
* @return {Promise}
*/
/**内宾分页查询 */
export const inlandQuery = (data) => {
return request({
url: '/rest/hotel/domesticGuestCheckIn/queryListByParams',
method: 'POST',
data
});
}
/**内宾单个查询 */
export const inlandQueryOne = (params) => {
return request({
url: '/rest/hotel/domesticGuestCheckIn/queryDomesticGuestDetail',
method: 'GET',
params
});
}
/**内宾登记 */
export const inlandAdd = (data) => {
return request({
url: '/rest/hotel/domesticGuestCheckIn/add',
method: 'POST',
data
});
}
/**内宾更新 */
export const inlandEdit = (data) => {
return request({
url: '/rest/hotel/domesticGuestCheckIn/updateInfo',
method: 'POST',
data
});
}
/**内宾删除 */
export const inlandDelete = (data) => {
return request({
url: '/rest/hotel/domesticGuestCheckIn/bulkRemove',
method: 'POST',
data
});
}
/**内宾离店 */
export const inlandCheckOut = (data) => {
return request({
url: '/rest/hotel/domesticGuestCheckIn/departure',
method: 'POST',
data
});
}
// /**内宾个人信息查询 */
// export const inlandOneQuery = params => {
// return request({
// url: '/rest/hotel/domesticGuestCheckIn/departure',
// method: 'GET',
// params
// });
// }
/**字典查询 */
export const inlandGender = params => {
return request({
url: '/agile/rest/index/api/default/queryGenderType',
method: 'GET',
params
});
}
import request from "@/utils/request";
/**
* @param data请求接口传递的参数
* @return {Promise}
*/
//新增外宾
export const addForeignGuestCheckIn = (data) => {
return request({
url: '/rest/hotel/foreignGuestCheckIn/add',
method: 'POST',
data
});
}
//查询外宾
export const getForeignGuestCheckInList = (data) => {
return request({
url: '/rest/hotel/foreignGuestCheckIn/queryListByParams',
method: 'POST',
data
});
}
//外宾离店
export const departureForeignGuestCheckIn = (data) => {
return request({
url: '/rest/hotel/foreignGuestCheckIn/departure',
method: 'POST',
data
});
}
//更新外宾
export const updateForeignGuestCheckInList = (data) => {
return request({
url: '/rest/hotel/foreignGuestCheckIn/updateInfo',
method: 'POST',
data
});
}
//查询外宾详情
export const queryForeignGuestDetail = (params) => {
return request({
url: '/rest/hotel/foreignGuestCheckIn/queryForeignGuestDetail',
method: 'GET',
params
});
}
\ No newline at end of file
import request from "@/utils/request";
/**
* @param data请求接口传递的参数
* @return {Promise}
*/
//根据派出所编号查找旅馆
export const queryHotelByDept = (params) => {
return request({
url: '/rest/hotel/hotel/queryList',
method: 'GET',
params
});
}
//根据旅馆编号查找旅馆信息
export const queryHotel = (params) => {
return request({
url: '/rest/hotel/hotel/queryHotelInfo',
method: 'POST',
params
});
}
//修改旅馆基本信息
export const updateHotel = (data) => {
return request({
url: '/rest/hotel/hotel/updateInfo',
method: 'POST',
data
});
}
//多图片上传
export const upLoadArrayImage = (data) => {
return request({
url: "/rest/hotel/hotel/uploadImage",
method: 'POST',
data
})
}
//删除旅馆单图片上传的图片
export const removeArrayImage = (data) => {
return request({
url: "/rest/file/batchRemove",
method: 'POST',
data
})
}
import request from "@/utils/request";
/**
* @param data请求接口传递的参数
* @return {Promise}
*/
//查询主页面菜单
export const getTree = (data) => {
return request({
url: '/rest/system/menu/queryTree',
method: "POST",
data
})
};
\ No newline at end of file
import request from "@/utils/request";
/**
* @param data请求接口传递的参数
* @return {Promise}
*/
/**恢复内宾 */
export const restoreDomesticGuestsToStay = (data) => {
return request({
url: '/rest/hotel/domesticGuestCheckIn/restoreDomesticGuestsToStay',
method: 'POST',
data
});
}
/**恢复外宾 */
export const restoreForeignGuestsToStay = (data) => {
return request({
url: '/rest/hotel/foreignGuestCheckIn/restoreForeignGuestsToStay',
method: 'POST',
data
});
}
\ No newline at end of file
import request from "@/utils/request";
/**
* @param data请求接口传递的参数
* @return {Promise}
*/
//权限查询
export const queryRole = () => {
return request({
url: '/rest/system/role/queryList',
method: 'GET'
})
}
//权限菜单提交
export const grantMenuRole = (data,roleId) => {
return request({
url: '/rest/system/role/grantMenu/'+roleId,
method: 'POST',
data
})
}
//角色新增
export const addRoles = (data) => {
return request({
url: '/rest/system/role/add',
method: 'POST',
data
})
}
//角色编辑
export const updateRoles = (data) => {
return request({
url: '/rest/system/role/updateInfo',
method: 'POST',
data
})
}
//角色删除
export const bulkRemoveRoles = (data) => {
return request({
url: '/rest/system/role/bulkRemove',
method: 'POST',
data
})
}
import request from "@/utils/request";
/**
* @param data请求接口传递的参数
* @return {Promise}
*/
//获取所有房间号
export const getAllRoom = params => {
return request({
url: '/rest/hotel/room/queryList',
method: 'GET',
params
});
}
//新增房间号
export const addRooms = data => {
return request({
url: '/rest/hotel/room/batchAddRoom',
method: 'POST',
data
});
}
//预览新增房间号
export const previewRooms = data => {
return request({
url: '/rest/hotel/room/createRooms',
method: 'POST',
data
});
}
//分页查询房间
export const getRooms = data=>{
return request({
url:'/rest/hotel/room/queryListByParams',
method:'POST',
data
})
}
//编辑房间
export const updateRoomsInfo = data=>{
return request({
url:'/rest/hotel/room/updateInfo',
method:'POST',
data
})
}
//删除房间
export const bulkRemoveRooms = data=>{
return request({
url:'/rest/hotel/room/bulkRemove',
method:'POST',
data
})
}
//查询房间状态 上部分
export const queryRoomStatus = params=>{
return request({
url:'/rest/hotel/hotelManger/statistics',
method:'POST',
params
})
}
//查询房间状态 下部分
export const queryStatisticsRoomStatus = params=>{
return request({
url:'/rest/hotel/hotelManger/statisticsRoomStatus',
method:'POST',
params
})
}
\ No newline at end of file
import request from "@/utils/request";
/**
* @param data请求接口传递的参数
* @return {Promise}
*/
//入境事由
export const getAllTeam = (params) => {
return request({
url: '/rest/hotel/team/queryList',
method: 'GET',
params
});
}
\ No newline at end of file
import request from "@/utils/request";
/**
* @param data请求接口传递的参数
* @return {Promise}
*/
//获取验证码
export const getVerifyCode = (params) => {
return request({
url: "/rest/system/user/verifyCode",
method: "GET",
params,
responseType: 'arraybuffer'
});
};
//查询用户列表
export const getUserList = (data) => {
return request({
url: '/rest/system/user/queryList',
method: "POST",
data
})
}
//用户登录
export const login = (data) => {
return request({
url: '/rest/system/user/login',
method: 'POST',
data
})
}
//用户注册
export const register = (data) => {
return request({
url: '/rest/system/user/add',
method: 'POST',
data
});
}
//修改用户密码
export const editPassword = params => {
return request({
url: "/rest/system/user/updatePassword",
method: 'GET',
params
})
}
//重置密码
export const resetPassword = params => {
return request({
url: "/rest/system/user/resetPassword",
method: 'GET',
params
})
}
//图片上传
export const upLoadImg = (data) => {
return request({
url: "/rest/file/uploadPhoto",
method: 'POST',
data
})
}
//用户新增
export const addPersonnel = (data) => {
return request({
url: "/rest/system/user/add",
method: 'POST',
data
})
}
//用户更新
export const updatePersonnel = (data) => {
return request({
url: "/rest/system/user/updateInfo",
method: 'POST',
data
})
}
//删除用户
export const removePersonnel = (params) => {
return request({
url: "/rest/system/user/remove",
method: 'GET',
params
})
}
\ No newline at end of file
import request from "@/utils/request";
/**
* @param data请求接口传递的参数
* @return {Promise}
*/
//新增访客
export const addVisitorRegist = (data) => {
return request({
url: '/rest/hotel/visitorRegist/add',
method: 'POST',
data
});
}
//查询访客
export const getVisitorList = (data) => {
return request({
url: '/rest/hotel/visitorRegist/queryListByParams',
method: 'POST',
data
});
}
//编辑访客
export const updateVisitorRegist = (data) => {
return request({
url: '/rest/hotel/visitorRegist/updateInfo',
method: 'POST',
data
});
}
//离店访客
export const departureVisitorRegist = (data) => {
return request({
url: '/rest/hotel/visitorRegist/departure',
method: 'POST',
data
});
}
//查询访客详情
export const queryVisitorRegistDetail = (params) => {
return request({
url: '/rest/hotel/visitorRegist/queryVisitorRegistDetail',
method: 'GET',
params
});
}
\ No newline at end of file
...@@ -16,85 +16,18 @@ const router = createRouter({ ...@@ -16,85 +16,18 @@ const router = createRouter({
// createWebHashHistory路由模式路径带#号 // createWebHashHistory路由模式路径带#号
history: createWebHashHistory(), history: createWebHashHistory(),
routes: [{ routes: [{
path: "/login", path: "/login",
name: "login", name: "login",
component: () => import("../views/login/login.vue"), component: () => import("../views/login/login.vue"),
}, },
{ {
path: "/", path: "/",
name: "homepage", name: "homepage",
component: () => import("../views/homePage/homepage.vue"), component: () => import("../views/homePage/homepage.vue"),
redirect: '/inland/inlandAdd', meta: {
meta: { keepAlive: false
keepAlive: false }
}, },
children: [{
path: "/hotel/index",
name: "旅馆概况",
component: () => import("@/views/hotel/index.vue"),
},
{
path: "/inland/inland",
name: "内宾基本情况",
component: () => import("@/views/inland/inland.vue"),
},
{
path: "/inland/inlandAdd",
name: "内宾入住",
component: () => import("@/views/inland/inlandAdd.vue"),
},
{
path: "/abroad/abroad",
name: "外宾基本情况",
component: () => import("@/views/abroad/abroad.vue"),
},
{
path: "/abroad/abroadAdd",
name: "外宾入住",
component: () => import("@/views/abroad/abroadAdd.vue"),
},
{
path: "/room/room",
name: "房号管理",
component: () => import("@/views/room/room.vue"),
},
{
path: "/visitor/visitor",
name: "访客管理",
component: () => import("@/views/visitor/visitor.vue"),
},
{
path: "/visitor/visitorAdd",
name: "访客登记",
component: () => import("@/views/visitor/visitorAdd.vue"),
},
{
path: "/departure/departure",
name: "离店",
component: () => import("@/views/departure/departure.vue"),
},
{
path: "/hotel/hotelEdit",
name: "旅馆基础信息管理",
component: () => import("@/views/hotel/hotelEdit.vue"),
},
{
path: "/restoreCheckIn/restoreCheckIn",
name: "酒店误操作恢复在住",
component: () => import("@/views/restoreCheckIn/restoreCheckIn.vue"),
},
{
path: "/employeeManagement/personnelManagement",
name: "人员管理",
component: () => import("@/views//employeeManagement/personnelManagement.vue"),
},
{
path: "/employeeManagement/rolesManagement",
name: "角色管理",
component: () => import("@/views//employeeManagement/rolesManagement.vue"),
}
]
},
], ],
}); });
// 全局前置守卫 // 全局前置守卫
......
import {
defineStore
} from 'pinia';
export const websocketStore = defineStore('websocket', () => {
const identityInformation = ref({});
return {
identityInformation
}
}, {
persist: true
})
\ No newline at end of file
import {
websocketStore
} from "@/store/websocketStore.js";
const myWebsocketStore = websocketStore();
class initWebsocket {
constructor() {
this.obj = {
certificatecardid: '',
msg: '',
cardinfo: '',
cardName: '',
str: '',
devicetype: '',
statusbar: '',
certificatePhoto: ''
};
this.websocket = null;
}
connect() {
try {
var readyState = new Array("on connection", "Connection established",
"Closing connection", "Close connection");
var host = "ws://127.0.0.1:90/echo/";
this.websocket = new WebSocket(host);
this.websocket.onopen = () => {
this.obj.statusbar = readyState[this.websocket.readyState];
this.websocket.send(18601);
this.websocket.send(18402);
}
this.websocket.onmessage = (event) => {
var str = event.data;
var strsub = str;
//此处要加多种扫描仪
var deviceArr = new Array();
deviceArr[0] = "D300+";
deviceArr[1] = "D800II";
deviceArr[2] = "D120+";
deviceArr[3] = "L1250+";
deviceArr[4] = "L1250";
deviceArr[5] = "B660";
deviceArr[6] = "M110";
deviceArr[7] = "E2000";
deviceArr[8] = "CR620+";
deviceArr[9] = "DSL3100";
deviceArr[10] = "AVA5";
deviceArr[11] = "B6680";
deviceArr[12] = "AW570";
deviceArr[13] = "M1260";
deviceArr[14] = "DSL62";
deviceArr[15] = "U350II";
deviceArr[16] = "L7280+";
deviceArr[17] = "AVA5+";
deviceArr[18] = "D800II+";
deviceArr[19] = "AVA5 Plus";
if (this.IsInArray(deviceArr, str)) {
//此处可更换为自己使用的扫描仪型号
this.obj.devicetype = "scanner";
return;
}
if (strsub != "") {
str = strsub.replace(/\*/g, "\r\n");
this.obj.str = str; //传入textarea中
//console.log('Message state', websocket.readyState);
}
this.tup() //对返回信息进行处理,显示到页面
}
this.websocket.onclose = () => {
this.obj.statusbar = readyState[this.websocket.readyState];
}
setInterval(() => {
this.AutoPhotoAndRecog()
}, 1000);
} catch (exception) {
this.obj.statusbar = "Error";
}
}
//判断字符串是否在数组中方法
IsInArray(arr, val) {
let testStr = ',' + arr.join(",") + ",";
return testStr.indexOf("," + val + ",") != -1;
}
send() {
try {
this.websocket.send("181026150"); //发送护照芯片内容读取设置指令,固定指令,请勿变动
this.websocket.send("1810331"); //设置保存图片类型,18103+31 表示所有图片都保存
this.websocket.send("181041"); //是否识别识读区,请勿变动
this.websocket.send("181061"); //是否返回base64格式图片
this.websocket.send("1810731"); //哪些图片返回base64,默认所有图片都返回
} catch (exception) {
this.obj.msg = "Error sending data";
}
}
AutoPhotoAndRecog() {
var str = this.obj.devicetype;
if (str = "scanner") {
setInterval(() => {
this.getInformation()
}, 2000);
} else {
this.getInformation();
}
}
getInformation() {
if (this.websocket != null) {
this.websocket.send("11112");
}
}
tup() {
var str = this.obj.str;
//字符分割
var seek = str.split("data:image/jpeg;base64,");
var len = seek.length; //没有找到报头 此时会返回原串,长度也为1
if (len > 1) //有证件信息和图像,当只有一张图片的时候,有一个base64的头,会分割成两段,第一段为空,第二段会去掉头的图像base64串
{
var seek0 = seek[0]; //身份信息数据
//alert(seek0);
var strhead = "";
var strChipHead = "";
for (var i = 1; i < len; i++) //头像数据//头像数据 data:image/jpeg;base64,xx.... xx 表示图片的类型 01 为白光,以此类推
{
if (seek[i].length > 2) {
var strType = seek[i][0] + seek[i][1];
seek[i] = seek[i].substr(2);
if (strType == "01") //白光
{
seek[i] = "data:image/jpeg;base64," + seek[i];
} else if (strType == "02") //红外
{
seek[i] = "data:image/jpeg;base64," + seek[i];
} else if (strType == "04") //紫外
{
seek[i] = "data:image/jpeg;base64," + seek[i];
} else if (strType == "08") //版面头像
{
strhead = seek[i];
seek[i] = "data:image/jpeg;base64," + seek[i];
} else if (strType == "16") //芯片头像
{
strChipHead = seek[i];
seek[i] = "data:image/jpeg;base64," + seek[i];
}
}
}
//优先显示芯片头像
let seek1 = null;
if (strChipHead != "") {
seek1 = "data:image/jpeg;base64," + strChipHead;
this.obj.certificatePhoto = seek1;
} else {
seek1 = "data:image/jpeg;base64," + strhead;
}
if (seek0 != "") {
seek0 = seek0.replace(/\*/g, "\r\n");
this.obj.msg = "Receive information:" + seek0;
this.getcardInfo();
}
} else {
//var strsub = str.substr(1);
if (str != "") {
str = str.replace(/\*/g, "\r\n");
this.obj.msg = "Receive information:" + str;
//getcardInfo();
}
}
}
singlerecog() {
var str = this.obj.msg;
if (str == "scanner") {
this.websocket.send("1000" + this.obj.certificateType + "02");
}
this.websocket.send("18201" + this.obj.certificateType);
}
getcardInfo() {
var str = this.obj.msg;
var cardid = str.substring(str.indexOf(":") + 1, str.indexOf("\r\n")); //获取返回信息中的证件类型编号IDCardID
if (cardid == "二代证读卡") {
this.obj.cardinfo = "二代证读芯片";
myWebsocketStore.identityInformation = {};
myWebsocketStore.identityInformation = this.obj;
return;
}
var card1by1;
var cardname;
for (var i = 0; i < 80; i++) {
if (this.obj.certificateType) {
card1by1 = this.obj.certificatecardid;
}
if (card1by1 == cardid) {
cardname = this.obj.cardName;
break;
}
this.obj.msg = "证件类型:" + cardid + "\n" + "证件名称:" + cardname;
myWebsocketStore.identityInformation = this.obj;
return this.obj;
}
}
close() {
// 关闭连接
this.websocket.close()
// 销毁 websocket 实例对象
this.websocket = null;
}
}
export default initWebsocket;
\ No newline at end of file
<template>
<div class="abroad">
<a-spin :spinning="loading">
<div class="titleBox">
<div>
<span class="sign">外宾登记信息列表</span>
</div>
</div>
<div style="margin: 0px 25px">
<a-form ref="formRef" name="advanced_search" class="ant-advanced-search-form" :model="formState">
<a-row :gutter="24">
<a-col :span="4">
<a-form-item name="name" label="姓名">
<a-input v-model:value="formState.name" placeholder="请输入姓名" :allowClear="true"></a-input>
</a-form-item>
</a-col>
<a-col :span="3">
<a-form-item name="gender" label="性别">
<a-select v-model:value="formState.gender" :allowClear="true" show-search placeholder="请选择性别" :options="dictionaryAll.allGender" optionLabelProp="name" :filter-option="filterOption" :fieldNames="{value:'code',label:'name'}" :notFoundContent="'暂无数据'"></a-select>
</a-form-item>
</a-col>
<a-col :span="5">
<a-form-item label="出生日期">
<a-range-picker v-model:value="csrq" :allowClear="true" @change="(data, dateString) => handleChangeTime(data, dateString, 1)" />
</a-form-item>
</a-col>
<a-col :span="4">
<a-form-item name="nationalityCode" label="国籍(地区)">
<a-select v-model:value="formState.nationalityCode" :allowClear="true" show-search placeholder="请选择国籍(地区)" :options="dictionaryAll.allCountry" :filter-option="filterOption" :fieldNames="{value:'code',label:'name'}" :notFoundContent="'暂无数据'" optionLabelProp="name"></a-select>
</a-form-item>
</a-col>
<a-col :span="4">
<a-form-item name="certificateType" label="证件类型">
<a-select v-model:value="formState.certificateType" :allowClear="true" show-search placeholder="请选择证件类型" :options="dictionaryAll.allForeignGuest" :filter-option="filterOption" :fieldNames="{value:'code',label:'name'}" :notFoundContent="'暂无数据'" optionLabelProp="name"></a-select>
</a-form-item>
</a-col>
<a-col :span="4">
<a-form-item name="certificateNumber" label="证件号码">
<a-input v-model:value="formState.certificateNumber" :allowClear="true" placeholder="请输入证件号码"></a-input>
</a-form-item>
</a-col>
<a-col :span="3">
<a-form-item name="visaType" label="签证种类">
<a-select v-model:value="formState.visaType" :allowClear="true" show-search placeholder="请选择签证种类" :options="dictionaryAll.allVisa" :filter-option="filterOption" :fieldNames="{value:'code',label:'name'}" :notFoundContent="'暂无数据'" optionLabelProp="name"></a-select>
</a-form-item>
</a-col>
<a-col :span="3">
<a-form-item name="state" label="旅客状态">
<a-select v-model:value="formState.state" :allowClear="true" show-search placeholder="请选择旅客状态" :options="dictionaryAll.allCheckInState" :filter-option="filterOption" :fieldNames="{value:'code',label:'name'}" :notFoundContent="'暂无数据'" optionLabelProp="name"></a-select>
</a-form-item>
</a-col>
<a-col :span="6">
<a-form-item name="checkinTime" label="入住时间">
<a-range-picker v-model:value="rzsj" :allowClear="true" show-time @change="(data, dateString) => handleChangeTime(data, dateString, 2)" />
</a-form-item>
</a-col>
<a-col :span="6">
<a-form-item name="checkOutTime" label="离店时间">
<a-range-picker v-model:value="ldsj" :allowClear="true" show-time @change="(data, dateString) => handleChangeTime(data, dateString, 3)" />
</a-form-item>
</a-col>
<a-col :span="3">
<a-form-item name="roomId" label="房号">
<a-select show-search v-model:value="formState.roomId" :filter-option="filterOption" placeholder="请选择房间号" :options="dictionaryAll.allRoom" :allowClear="true" optionLabelProp="name" :fieldNames="{ label: 'name', value: 'id' }"></a-select>
</a-form-item>
</a-col>
<a-col style="text-align: right">
<a-button type="primary" html-type="submit" @click="searchForeignGuest">搜索</a-button>
<a-button style="margin: 0 8px" @click="qx()">清除</a-button>
</a-col>
</a-row>
</a-form>
</div>
<div style="margin: 0px 25px; height: calc(100% - 210px)">
<a-table :row-selection="{selectedRowKeys: state.selectedRowKeys,onChange: onSelectChange}" :columns="columns" :data-source="data" :pagination="false" :scroll="{y:450}"><template #bodyCell="{ column, record }">
<template v-if="column.dataIndex === 'cz'">
<a-space :size="0">
<a-button type="link" primary size="small" style="color:#52c41a" @click="eyes(record)">
<template #icon>
<eye-filled />
</template>
查看
</a-button>
<a-button type="link" primary size="small" style="color:#faad14" @click="edit(record)">
<template #icon>
<edit-filled />
</template>
修改
</a-button>
<a-popconfirm title="是否离店?" @confirm="checkOut(record)" v-if="record.state=='DEPART'?false:true">
<a-button type="link" primary size="small" style="color:#ff4d1f">
<template #icon>
<swap-outlined />
</template>
离店
</a-button>
</a-popconfirm>
<a-button type="link" primary size="small" @click="visitorJump(record)">
<template #icon>
<contacts-filled />
</template>
访客登记
</a-button>
</a-space>
</template>
</template>
</a-table>
<a-pagination v-model:current="formState.current" show-quick-jumper show-size-changer :total="total" v-show="data.length > 0" size="small" :show-total="(total) => `总数共: ${total} 条`" @change="onChangePagination" style="margin: 20px 0px" />
</div>
<AbroadInfo v-if="abroadInfoVisible" :flogStatus="operateStatus" :visible="abroadInfoVisible" :dictionaryAll="dictionaryAllInfo" :formData="abroadInfo" @change-Cancel="changeCancel" :visibleEdit="hotelFormVisible_edit_s" />
</a-spin>
</div>
</template>
<script setup>
import { onMounted, reactive, ref } from "vue";
import { useStore } from '@/store/index.js';
import { getForeignGuestCheckInList, departureForeignGuestCheckIn } from '@/api/foreignGuestCheckIn.js';
import AbroadInfo from '@/views/abroad/abroadInfo.vue'
import { message } from "ant-design-vue";
import router from "../../router";
import { getAllTeam } from '@/api/team.js'
const loading = ref(false);
const userstore = useStore();
const operateStatus = ref(false);
const hotelFormVisible_edit_s = ref(false);
const formRef = ref();
const formState = reactive({
hotelId: userstore.hotelInfo.hotelId,
roomId: '',
checkinTime: '',
nationalityCode: '',
certificateNumber: '',
certificateType: '',
checkinTimeEnd: '',
checkinTimeStart: '',
name: '',
gender: '',
dateBirth: '',
visaType: '',
state: '',
checkOutTime: '',
dateBirthEnd: '',
dateBirthStart: '',
departureTimeEnd: '',
departureTimeStart: '',
state:'',
current: 1,
pageSize: 10,
});
const dictionaryAll = reactive({
allRoom: userstore.roomAll,
allCountry: userstore.returnCode(9),
allVisa: userstore.returnCode(8),
allGender: userstore.returnCode(5),
allForeignGuest: userstore.returnCode(4),
allCheckInState: userstore.returnCode(2),
allReasonEntry:userstore.returnCode(7),
allTeam:[],
});
/**时间变化 */
const handleChangeTime = (data, dataArr, type) => {
if (dataArr && dataArr.length > 0) {
if (type == 1) {
formState.dateBirthEnd = dataArr[1];
formState.dateBirthStart = dataArr[0];
} else if (type == 2) {
formState.checkinTimeEnd = dataArr[1];
formState.checkinTimeStart = dataArr[0];
} else {
formState.departureTimeEnd = dataArr[1];
formState.departureTimeStart = dataArr[0];
}
} else {
if (type == 1) {
formState.dateBirthEnd = "";
formState.dateBirthStart = "";
} else if (type == 2) {
formState.checkinTimeEnd = "";
formState.checkinTimeStart = "";
} else {
formState.departureTimeEnd = "";
formState.departureTimeStart = "";
}
}
};
const csrq = ref(undefined);
const rzsj = ref(undefined);
const ldsj = ref(undefined);
/**清除 */
const qx = ()=>{
formRef.value.resetFields();
csrq.value = undefined;
rzsj.value = undefined;
ldsj.value = undefined;
formState.dateBirthEnd = "";
formState.dateBirthStart = "";
formState.checkinTimeEnd = "";
formState.checkinTimeStart = "";
formState.departureTimeEnd = "";
formState.departureTimeStart = "";
}
//搜索
const data = ref([]);
const total = ref();
const searchForeignGuest = () => {
loading.value = true;
getForeignGuestCheckInList(formState).then(res => {
if (res?.code == 9000) {
data.value = res.data.records;
total.value = res.data.total;
}
loading.value = false;
}).catch(error => {
loading.value = false;
})
}
/**下拉框筛选 */
const filterOption = (input, option) => {
return option.name.toLowerCase().indexOf(input.toLowerCase()) >= 0;
};
/**表格 */
const columns = [
// {
// title: "序号",
// dataIndex: 'key',
// },
{
title: "姓名",
dataIndex: "chineseName",
},
{
title: "证件号码",
dataIndex: "certificateNumber",
},
{
title: "性别",
dataIndex: "genderName",
},
{
title: "出生日期",
dataIndex: 'dateBirth',
},
{
title: "国籍地区",
dataIndex: "nationalityCodeName",
},
{
title: "房号",
dataIndex: "roomName",
},
{
title: "所属团队",
dataIndex: "teamName",
},
{
title: "入住时间",
dataIndex: "checkinTime",
},
{
title: "离店时间",
dataIndex: 'departureTime',
},
{
title: "旅客状态",
dataIndex: "stateName",
},
{
title: "证件核验",
dataIndex: "verificationState",
},
{
title: "操作",
dataIndex: "cz",
fixed: "right",
width: 320,
}
];
const state = reactive({
selectedRowKeys: [],
loading: false,
});
const onSelectChange = (selectedRowKeys) => {
state.selectedRowKeys = selectedRowKeys;
};
/**分页 */
const onChangePagination = (page, pageSize) => {
formState.current = page;
formState.pageSize = pageSize;
searchForeignGuest();
};
/**访客登记跳转 */
const visitorJump = (record) => {
// if(record.roomId==''||record.roomId==undefined){
// message.warning('该旅馆暂未入住')
// }
router.push({ path: '/visitor/visitorAdd', query: { roomId: record.roomId, name: record.firstName + record.lastName } });//使用英文姓和英文名拼接
}
/**查看 */
const abroadInfo = ref({});
const dictionaryAllInfo = ref({});
const abroadInfoVisible = ref(false);
/**查看 */
const eyes = (e) => {
abroadInfo.value = e;
abroadInfoVisible.value = true;
dictionaryAllInfo.value = dictionaryAll;
operateStatus.value = true;
hotelFormVisible_edit_s.value = true;
}
const changeCancel = () => {
abroadInfoVisible.value = false;
}
//编辑
const edit = (e) => {
abroadInfo.value = e;
abroadInfoVisible.value = true;
dictionaryAllInfo.value = dictionaryAll;
operateStatus.value = false;
hotelFormVisible_edit_s.value = true;
}
//离店
const checkOut = async (record) => {
loading.value = true;
await departureForeignGuestCheckIn([record.id])
.then((res) => {
loading.value = false;
if (res?.code == 9000) {
message.success("离店成功");
searchForeignGuest();
}
})
.catch((res) => {
loading.value = false;
message.warning("离店失败");
});
}
onMounted(() => {
getAllTeam({ hotelid: userstore.hotelInfo.hotelId }).then(res => {
dictionaryAll.allTeam = res.data;
})
searchForeignGuest();
});
</script>
<style lang="less">
.abroad {
width: 100%;
height: 100%;
padding: 0%;
margin: 0px;
// overflow-y: auto;
.titleBox {
display: flex;
justify-content: space-between;
align-items: center;
background: #fafafa;
border-radius: 0px 0px 2px 2px;
border: 1px solid #e9e9e9;
padding: 10px;
margin: 25px 5px;
}
.sign {
display: inline-block;
font-size: 16px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: rgba(0, 0, 0, 0.85);
line-height: 16px;
&::before {
content: "";
display: inline-block;
width: 4px;
height: 12px;
background: #3162f5;
border-radius: 2px;
margin-right: 8px;
}
}
}
</style>
\ No newline at end of file
<template>
<a-spin :spinning="loading">
<div class="abroadAddFrom">
<div class="titleBox">
<div>
<span class="sign">外宾登记表</span>
</div>
</div>
<div style="margin: 0px 5px">
<a-form class="form" ref="formRef" :model="formState" :labelCol="{ span: 8 }" :wrapper-col="{ span: 16 }" layout="inline" :rules="rules">
<table class="form-tables">
<tr>
<td colspan="3">
<a-form-item name="roomId" :label="`房间号`">
<a-select v-model:value="formState.roomId" show-search placeholder="请选择房间号" :options="dictionaryAll.allRoom" :filter-option="filterOption" :fieldNames="{value:'id',label:'name'}" :notFoundContent="'暂无数据'"></a-select>
</a-form-item>
</td>
<td colspan="3">
<a-form-item name="checkinTime" :label="`入住时间`">
<a-date-picker v-model:value="formState.checkinTime" value-format="YYYY-MM-DD HH:mm:ss" show-time placeholder="请选择入住时间" @change="onChange" @ok="onOk" style="width: 100%;"/>
</a-form-item>
</td>
<td colspan="2" rowspan="9">
<div class="img-pub">
<div class="img-wp">
<div class="img-div">
<div class="img-span">
<span>证件人像</span>
</div>
</div>
<div class="check-div">
<a-radio v-model:checked="checked_value1" @click="dx_click(1)">截取头像</a-radio>
</div>
</div>
<div class="img-wp">
<div class="img-div">
<div class="img-span" v-if="formState.sitePhoto == ''">
<span>现场人像</span>
</div>
<a-image :width="`100%`" :height="`100%`" :src="formState.sitePhoto" v-else />
</div>
<div class="check-div" @click="OnCamera()">
<a-button type="primary" size="small">获取头像</a-button>
</div>
<div class="check-div" style="text-align: center;margin-top: 10px;">
<a-upload name="file" @change="handleChange" :showUploadList="false" :before-upload="beforeUpload">
<a-button>
选择头像
</a-button>
</a-upload>
</div>
</div>
</div>
<div class="img-pub">
<div class="img-wp">
<div class="img-div">
<div class="img-span1">
<span>资料页</span>
</div>
</div>
<div class="check-div">
<a-radio v-model:checked="checked_value2" @click="dx_click(2)">截取资料页</a-radio>
</div>
</div>
</div>
<div class="img-pub">
<div class="img-wp">
<div class="img-div">
<div class="img-span1">
<span>资料页</span>
</div>
</div>
<div class="check-div">
<a-radio v-model:checked="checked_value3" @click="dx_click(3)">截取签证页</a-radio>
</div>
</div>
</div>
</td>
</tr>
<tr>
<td colspan="3">
<a-form-item name="nationalityCode" :label="`国籍(地区)`">
<a-select v-model:value="formState.nationalityCode" show-search placeholder="请选择国籍(地区)" :options="dictionaryAll.allCountry" :filter-option="filterOption" :fieldNames="{value:'code',label:'name'}" :notFoundContent="'暂无数据'"></a-select>
</a-form-item>
</td>
<td colspan="3">
<a-form-item name="certificateNumber" :label="`证件号码`">
<a-input v-model:value="formState.certificateNumber" placeholder="请输入证件号码" :allowClear="true" />
</a-form-item>
</td>
</tr>
<tr>
<td colspan="3">
<a-form-item name="certificateType" :label="`证件类型`">
<a-select v-model:value="formState.certificateType" show-search placeholder="请选择证件类型" :options="dictionaryAll.allForeignGuest" :filter-option="filterOption" :fieldNames="{value:'code',label:'name'}" :notFoundContent="'暂无数据'"></a-select>
</a-form-item>
</td>
<td colspan="3">
<a-form-item name="chineseName" :label="`中文姓名`">
<a-input v-model:value="formState.chineseName" placeholder="请输入中文姓名" :allowClear="true" />
</a-form-item>
</td>
</tr>
<tr>
<td colspan="3">
<a-form-item name="firstName" :label="`英文姓`">
<a-input v-model:value="formState.firstName" placeholder="请输入英文姓" :allowClear="true" />
</a-form-item>
</td>
<td colspan="3">
<a-form-item name="lastName" :label="`英文名`">
<a-input v-model:value="formState.lastName" placeholder="请输入英文名" :allowClear="true" />
</a-form-item>
</td>
</tr>
<tr>
<td colspan="3">
<a-form-item name="gender" :label="`性别`">
<a-select v-model:value="formState.gender" show-search placeholder="请选择性别" :options="dictionaryAll.allGender" :filter-option="filterOption" :fieldNames="{value:'code',label:'name'}" :notFoundContent="'暂无数据'"></a-select>
</a-form-item>
</td>
<td colspan="3">
<a-form-item name="dateBirth" v-model:value="formState.dateBirth" :label="`出生日期`">
<a-date-picker v-model:value="formState.dateBirth" value-format="YYYY-MM-DD" :disabled-date="disabledDateMax" placeholder="请选择出生日期" style="width: 100%;"/>
</a-form-item>
</td>
</tr>
<tr>
<td colspan="3">
<a-form-item name="visaType" :label="`签证种类`">
<a-select v-model:value="formState.visaType" show-search placeholder="请选择签证种类" :options="dictionaryAll.allVisa" :filter-option="filterOption" :fieldNames="{value:'code',label:'name'}" :notFoundContent="'暂无数据'"></a-select>
</a-form-item>
</td>
<td colspan="3">
<a-form-item name="periodStay" :label="`停留期至`">
<a-date-picker v-model:value="formState.periodStay" placeholder="请选择时间" value-format="YYYY-MM-DD HH:mm:ss" :disabled-date="disabledDateMin" style="width: 100%;"/>
</a-form-item>
</td>
</tr>
<tr>
<td colspan="3">
<a-form-item name="reasonEntry" :label="`入境事由`">
<a-select v-model:value="formState.reasonEntry" show-search placeholder="请选择入境事由" :options="dictionaryAll.allReasonEntry" :filter-option="filterOption" :fieldNames="{value:'code',label:'name'}" :notFoundContent="'暂无数据'"></a-select>
</a-form-item>
</td>
<td colspan="3">
<a-form-item name="receptionUnit" :label="`接待单位`">
<a-input v-model:value="formState.receptionUnit" placeholder="请输入接待单位" :allowClear="true" />
</a-form-item>
</td>
</tr>
<tr>
<td colspan="3">
<a-form-item name="emergencyContact" :label="`紧急情况联系人`">
<a-input v-model:value="formState.emergencyContact" placeholder="请输入紧急情况联系人" :allowClear="true" />
</a-form-item>
</td>
<td colspan="3">
<a-form-item name="emergencyPhoneNumber" :label="`紧急情况联系电话`" :rules="[
{ message:'联系电话最多11位有效数字',max: 11,},
{ pattern:new RegExp('^[0-9]{1,}$','g'),message:'只允许包含数字'}]">
<a-input v-model:value="formState.emergencyPhoneNumber" placeholder="请输入紧急情况联系电话" :allowClear="true" />
</a-form-item>
</td>
</tr>
<tr>
<td colspan="3">
<a-form-item name="phoneNumber" :label="`国内邀请人或本人联系电话`" :rules="[
{ required: true,message:'联系电话最多11位有效数字',max: 11,},
{ pattern:new RegExp('^[0-9]{1,}$','g'),message:'只允许包含数字'}]">
<a-input v-model:value="formState.phoneNumber" placeholder="请输入国内邀请人或本人联系电话" :allowClear="true" />
</a-form-item>
</td>
<td colspan="3">
<a-form-item name="teamId" :label="`所属团队`">
<a-select v-model:value="formState.teamId" show-search placeholder="请选择所属团队" :options="dictionaryAll.allTeam" :filter-option="filterOption" :fieldNames="{value:'id',label:'name'}" :notFoundContent="'暂无数据'"></a-select>
</a-form-item>
</td>
</tr>
<tr>
<td colspan="3">
<a-form-item name="hotelAdress" :label="`旅馆地址`">
<a-input v-model:value="formState.hotelAddress" :allowClear="true" placeholder="请输入旅馆地址" :disabled="true" />
</a-form-item>
</td>
<td colspan="3">
<a-form-item name="remark" :label="`备注`">
<a-input v-model:value="formState.remark" :allowClear="true" placeholder="请输入备注" />
</a-form-item>
</td>
</tr>
</table>
</a-form>
</div>
<div class="titleBox">
<div style="margin: 0 auto">
<a-space :size="10">
<a-button type="primary" size="large">扫描证件</a-button>
<a-button type="primary" size="large">读取外国人永久居留证</a-button>
<a-button type="primary" size="large" @click="saveInfo"><template #icon>
<file-protect-outlined />
</template>
保存</a-button>
<a-button size="large" @click="qk()"><template #icon>
<reload-outlined />
</template>
清空</a-button>
</a-space>
</div>
</div>
<Camera v-if="hotelFormVisible" :visible="hotelFormVisible" :title="`现场人像`" @handle-submit="onSubmit" @change-Cancel="changeCancel" />
<Cropper :imageSrc="imageSrc" v-if="hotelFormVisibles" :visible="hotelFormVisibles" :title="`截图`" @handle-submit="onSubmit_s" @change-Cancel="changeCancel_s" @handle-retake="handleRetake" />
</div>
</a-spin>
</template>
<script setup>
import { onMounted } from "vue";
import Camera from "@/components/Camera.vue";
import { useStore } from '@/store/index.js'
import { getAllTeam } from '@/api/team.js'
import { validatePhoneTwo } from '@/utils/validates.js';
import { addForeignGuestCheckIn } from '@/api/foreignGuestCheckIn.js';
import { uploadImg } from '@/api/default.js';
import { file_img_src } from '@/utils/http_util.js';
import { message } from 'ant-design-vue';
import dayjs from 'dayjs';
const userstore = useStore();
const dictionaryAll = reactive({
allRoom: userstore.roomAll,
allCountry: userstore.returnCode(9).filter(item=>{return item.code!='44'}),
allVisa: userstore.returnCode(8),
allGender: userstore.returnCode(5),
allForeignGuest: userstore.returnCode(4),
allReasonEntry: userstore.returnCode(7),
allTeam: []
});
const loading = ref(false);
const formRef = ref();
const formState = reactive({
hotelId: userstore.hotelInfo.hotelId,
roomId: '',
checkinTime: '',
nationalityCode: '',
certificateNumber: '',
certificateType: '',
chineseName: '',
firstName: '',
lastName: '',
gender: '',
dateBirth: '',
visaType: '',
periodStay: '',
reasonEntry: '',
receptionUnit: '',
emergencyContact: '',
emergencyPhoneNumber: '',
phoneNumber: '',
teamId: '',
hotelAddress: userstore.hotelInfo.hotelAddress,
remark: '',
certificatePhoto: '',
sitePhoto: '',
informationPhoto: '',
visasPhoto: '',
state: "ARRIVE",
});
const rules = {
roomId: [
{
required: true,
message: '请输入房间号'
}
],
checkinTime: [
{
required: true,
message: '请选择入住时间'
}
],
nationalityCode: [
{
required: true,
message: '请选择国籍(地区)'
},
],
certificateNumber: [
{
required: true,
message: '请输入证件号码'
},
],
certificateType: [
{
required: true,
message: '请输入证件类型'
}
],
gender: [
{
required: true,
message: '请选择性别'
}
],
dateBirth: [
{
required: true,
message: '请选择出生日期'
},
],
visaType: [
{
required: true,
message: '请选择签证种类'
},
],
reasonEntry: [
{
required: true,
message: '请选择入境事由'
},
],
phoneNumber: [
{
required: true,
message: '请输入国内邀请人或本人联系电话'
}
],
teamId: [
{
required: true,
message: '请选择所属团队'
}
],
// hotelAdress: [
// {
// required: true,
// message: '请输入旅馆地址'
// },
// ]
};
/**设置最小时间为今天 */
const disabledDateMin = current => {
// Can not select days before today and today
return current && current < dayjs().subtract(1, 'day').endOf('day');
};
/**设置最大时间为今天 */
const disabledDateMax = current => {
// Can not select days before today and today
return current && current > dayjs().endOf('day');
};
/**摄像头调用 */
const hotelFormVisible = ref(false);
const screenshot_url = ref("");
const onSubmit = (e) => {
hotelFormVisible.value = false;
imageSrc.value = e.value;
hotelFormVisibles.value = true;
};
const changeCancel = () => {
hotelFormVisible.value = false;
};
/**开启摄像头 */
const OnCamera = () => {
hotelFormVisible.value = true;
};
/**截图 */
const hotelFormVisibles = ref(false);
const imageSrc = ref("");
const onSubmit_s = (e) => {
screenshot_url.value = e.value;
hotelFormVisibles.value = false;
};
const changeCancel_s = () => {
hotelFormVisibles.value = false;
};
const handleRetake = () => {
changeCancel_s();
OnCamera();
};
/**清空 */
const qk = () => {
formRef.value.resetFields();
formState.sitePhoto = '';
}
/**选择头像 */
const handleChange = info => {
const isPNG = info.file.type === 'image/png' || info.file.type === 'image/jpg' || info.file.type === 'image/jpeg';
if (!isPNG) {
message.error(`${info.file.name} 不是图片格式,请上传PNG||JPG||JPEG`);
} else {
const reader = new FileReader();
reader.readAsDataURL(info.file);
reader.onload = () => {
formState.sitePhoto = reader.result;
};
}
};
/**不让文件直接上传 */
const beforeUpload = (file) => {
return false;
};
/**右侧切换截取图片 */
const checked_value1 = ref(true);
const checked_value2 = ref(false);
const checked_value3 = ref(false);
/**提交事件 */
const handleOk = async () => {
formRef.value?.validateFields().then(async (values) => {
// await emit("handleSubmit", values);
});
};
/**关闭弹框事件 */
const handleCancel = async () => {
// await emit("changeform", false);
};
const dx_click = (e) => {
if (e == 1) {
checked_value1.value = true;
checked_value2.value = false;
checked_value3.value = false;
} else if (e == 2) {
checked_value1.value = false;
checked_value2.value = true;
checked_value3.value = false;
} else {
checked_value1.value = false;
checked_value2.value = false;
checked_value3.value = true;
}
};
/**下拉框筛选 */
const filterOption = (input, option) => {
return option.name.toLowerCase().indexOf(input.toLowerCase()) >= 0;
};
const onChange = (value, dateString) => {
formState.pass = dateString;
};
const onOk = (value, dateString) => {
formState.pass = dateString;
};
const handleMenuClick = (e) => {
};
//上报信息
const saveInfo = () => {
formRef.value?.validateFields().then((values) => {
/**批量操作上传图片 */
const arr_http = [];
if (formState.sitePhoto != "") {
arr_http.push(file_img_src(formState.sitePhoto, userstore.hotelInfo.hotelId, 'FOREIGN_GUEST'));
} else {
arr_http.push("");
}
// if (formState.certificatePhoto != "") {
// arr_http.push(file_img_src(formState.certificatePhoto,userstore.hotelInfo.hotelId,'FOREIGN_GUEST'));
// } else {
// arr_http.push("");
// }
loading.value = true;
Promise.all(arr_http).then(([res1, res2]) => {
const arr = { ...formState };
if (formState.sitePhoto != "") {
arr.sitePhoto = res1;
}
// if (formState.certificatePhoto != "") {
// arr.certificatePhoto = res2;
// }
addForeignGuestCheckIn(arr)
.then((res) => {
if (res.code == 9000) {
message.success("入住成功");
reset();
}
loading.value = false;
})
.catch((res) => {
message.warning("入住失败");
loading.value = false;
});
});
});
}
const reset = () => {
formRef.value.resetFields();
formState.certificatePhoto = "";
formState.sitePhoto = "";
};
onMounted(() => {
//查询所属团队
getAllTeam({ hotelid: userstore.hotelInfo.hotelId }).then(res => {
dictionaryAll.allTeam = res.data;
})
})
</script>
<style lang="less">
.abroadAddFrom {
width: 100%;
height: 100%;
padding: 0px;
margin: 0px;
overflow-y:auto;
.form {
.ant-form-item-with-help {
margin-bottom: 0px;
}
.ant-form-item-label {
flex: auto;
}
}
.form-tables {
width: 100%;
border-collapse: collapse;
tr {
width: 100%;
height: 60px;
td {
border: 1px solid #e7e7e7;
max-width: 222px;
.img-pub {
display: flex;
flex-direction: row;
justify-content: space-around;
flex-wrap: wrap;
margin: 10px;
.img-wp {
width: 140px;
height: 170px;
border: 1px solid #a5a5a5;
.img-div {
border-image-source: radial-gradient(
60% 60%,
transparent 0px,
transparent 100%,
#6691ef 100%
);
border-image-slice: 1;
border-width: 1px;
border-style: solid;
border-image-outset: 0px;
width: calc(100% - 50px);
height: calc(100% - 50px);
margin: 9px 25px 13px;
.img-span {
margin: 0px auto;
width: 14px;
line-height: 29px;
font-weight: 400;
font-size: 15px;
}
.img-span1 {
height: 100%;
display: flex;
flex-direction: row;
flex-wrap: nowrap;
justify-content: center;
align-items: center;
letter-spacing: 6px;
font-weight: 400;
font-size: 15px;
}
}
.check-div {
width: 100%;
text-align: center;
.ant-radio-wrapper {
margin-right: 0px;
}
}
}
}
}
}
}
.titleBox {
display: flex;
justify-content: space-between;
align-items: center;
background: #fafafa;
border-radius: 0px 0px 2px 2px;
border: 1px solid #e9e9e9;
padding: 10px;
margin: 25px 5px;
}
.sign {
display: inline-block;
font-size: 16px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: rgba(0, 0, 0, 0.85);
line-height: 16px;
&::before {
content: "";
display: inline-block;
width: 4px;
height: 12px;
background: #3162f5;
border-radius: 2px;
margin-right: 8px;
}
}
}
</style>
\ No newline at end of file
<template>
<a-modal :visible="visible" title="查看详情" width="80%" @cancel="handleCancel">
<a-spin :spinning="loading">
<div class="visitorFrom">
<div style="margin: 0px 5px">
<a-form class="form" ref="formRef" :model="formState" :labelCol="{ span: 8 }" :wrapper-col="{ span: 16 }" layout="inline" :rules="rules">
<table class="form-tables">
<tr>
<td colspan="3">
<a-form-item name="roomId" :label="`房间号`">
<a-select v-model:value="formState.roomId" show-search placeholder="请选择房间号" :options="defaultTypeAll.allRoom" :filter-option="filterOption" :fieldNames="{value:'id',label:'name'}" :notFoundContent="'暂无数据'" :disabled="operateStatus?true:false"></a-select>
</a-form-item>
</td>
<td colspan="3">
<a-form-item name="checkinTime" :label="`入住时间`">
<a-date-picker v-model:value="formState.checkinTime" value-format="YYYY-MM-DD HH:mm:ss" show-time placeholder="请选择入住时间" style="width: 100%;" :disabled="operateStatus?true:false" />
</a-form-item>
</td>
<td colspan="2" rowspan="9">
<div class="img-pub">
<div class="img-wp">
<div class="img-div">
<div class="img-span">
<span>证件人像</span>
</div>
</div>
<div class="check-div">
<a-radio v-model:checked="checked_value1" @click="dx_click(1)">截取头像</a-radio>
</div>
</div>
<div class="img-wp">
<div class="img-div">
<div class="img-span" v-if="formState.sitePhotoPath == ''||formState.sitePhotoPath==null">
<span>现场人像</span>
</div>
<a-image :width="`100%`" :height="`100%`" :src="formState.sitePhotoPath" :fallback="default_img" v-else />
</div>
<div class="check-div" @click="OnCamera()" v-if="visibleEdit">
<a-button type="primary" size="small" :disabled="operateStatus?true:false">获取头像</a-button>
</div>
<div class="check-div" style="text-align: center;margin-top: 10px;" v-if="!operateStatus">
<a-upload name="file" @change="handleChange" :showUploadList="false" :before-upload="beforeUpload">
<a-button>
选择头像
</a-button>
</a-upload>
</div>
</div>
</div>
<div class="img-pub">
<div class="img-wp">
<div class="img-div">
<div class="img-span1">
<span>资料页</span>
</div>
</div>
<div class="check-div">
<a-radio v-model:checked="checked_value2" @click="dx_click(2)">截取资料页</a-radio>
</div>
</div>
</div>
<div class="img-pub">
<div class="img-wp">
<div class="img-div">
<div class="img-span1">
<span>资料页</span>
</div>
</div>
<div class="check-div">
<a-radio v-model:checked="checked_value3" @click="dx_click(3)">截取签证页</a-radio>
</div>
</div>
</div>
</td>
</tr>
<tr>
<td colspan="3">
<a-form-item name="nationalityCode" :label="`国籍(地区)`">
<a-select v-model:value="formState.nationalityCode" show-search placeholder="请选择国籍(地区)" :options="defaultTypeAll.allCountry" :filter-option="filterOption" :fieldNames="{value:'code',label:'name'}" :notFoundContent="'暂无数据'" :disabled="operateStatus?true:false"></a-select>
</a-form-item>
</td>
<td colspan="3">
<a-form-item name="certificateNumber" :label="`证件号码`">
<a-input v-model:value="formState.certificateNumber" placeholder="请输入证件号码" :allowClear="true" :disabled="operateStatus?true:false" />
</a-form-item>
</td>
</tr>
<tr>
<td colspan="3">
<a-form-item name="certificateType" :label="`证件类型`">
<a-select v-model:value="formState.certificateType" show-search placeholder="请选择证件类型" :options="defaultTypeAll.allForeignGuest" :filter-option="filterOption" :fieldNames="{value:'code',label:'name'}" :notFoundContent="'暂无数据'" :disabled="operateStatus?true:false"></a-select>
</a-form-item>
</td>
<td colspan="3">
<a-form-item name="chineseName" :label="`中文姓名`">
<a-input v-model:value="formState.chineseName" placeholder="请输入中文姓名" :allowClear="true" :disabled="operateStatus?true:false" />
</a-form-item>
</td>
</tr>
<tr>
<td colspan="3">
<a-form-item name="firstName" :label="`英文姓`">
<a-input v-model:value="formState.firstName" placeholder="请输入英文姓" :allowClear="true" :disabled="operateStatus?true:false" />
</a-form-item>
</td>
<td colspan="3">
<a-form-item name="lastName" :label="`英文名`">
<a-input v-model:value="formState.lastName" placeholder="请输入英文名" :allowClear="true" :disabled="operateStatus?true:false" />
</a-form-item>
</td>
</tr>
<tr>
<td colspan="3">
<a-form-item name="gender" :label="`性别`">
<a-select v-model:value="formState.gender" show-search placeholder="请选择性别" :options="defaultTypeAll.allGender" :filter-option="filterOption" :fieldNames="{value:'code',label:'name'}" :notFoundContent="'暂无数据'" :disabled="operateStatus?true:false"></a-select>
</a-form-item>
</td>
<td colspan="3">
<a-form-item name="dateBirth" :label="`出生日期`">
<a-date-picker v-model:value="formState.dateBirth" value-format="YYYY-MM-DD" :disabled="operateStatus?true:false" style="width: 100%;" :disabled-date="disabledDateMax" placeholder="请选择出生日期"/>
</a-form-item>
</td>
</tr>
<tr>
<td colspan="3">
<a-form-item name="visaType" :label="`签证种类`">
<a-select v-model:value="formState.visaType" show-search placeholder="请选择签证种类" :options="defaultTypeAll.allVisa" :filter-option="filterOption" :fieldNames="{value:'code',label:'name'}" :notFoundContent="'暂无数据'" :disabled="operateStatus?true:false"></a-select>
</a-form-item>
</td>
<td colspan="3">
<a-form-item name="periodStay" :label="`停留期至`">
<a-date-picker v-model:value="formState.periodStay" placeholder="请选择时间" value-format="YYYY-MM-DD" style="width: 100%;" :disabled="operateStatus?true:false" :disabled-date="disabledDateMin"/>
</a-form-item>
</td>
</tr>
<tr>
<td colspan="3">
<a-form-item name="reasonEntry" :label="`入境事由`">
<a-select v-model:value="formState.reasonEntry" show-search placeholder="请选择入境事由" :options="defaultTypeAll.allReasonEntry" :filter-option="filterOption" :fieldNames="{value:'code',label:'name'}" :notFoundContent="'暂无数据'" :disabled="operateStatus?true:false"></a-select>
</a-form-item>
</td>
<td colspan="3">
<a-form-item name="receptionUnit" :label="`接待单位`">
<a-input v-model:value="formState.receptionUnit" placeholder="请输入接待单位" :allowClear="true" :disabled="operateStatus?true:false" />
</a-form-item>
</td>
</tr>
<tr>
<td colspan="3">
<a-form-item name="emergencyContact" :label="`紧急情况联系人`">
<a-input v-model:value="formState.emergencyContact" placeholder="请输入紧急情况联系人" :allowClear="true" :disabled="operateStatus?true:false" />
</a-form-item>
</td>
<td colspan="3">
<a-form-item name="emergencyPhoneNumber" :label="`紧急情况联系电话`" :rules="[
{ message:'联系电话最多11位有效数字',max: 11,},
{ pattern:new RegExp('^[0-9]{1,}$','g'),message:'只允许包含数字'}]">
<a-input v-model:value="formState.emergencyPhoneNumber" placeholder="请输入紧急情况联系电话" :allowClear="true" :disabled="operateStatus?true:false" />
</a-form-item>
</td>
</tr>
<tr>
<td colspan="3">
<a-form-item name="phoneNumber" :label="`国内邀请人或本人联系电话`" :rules="[
{ required: true,message:'联系电话最多11位有效数字',max: 11,},
{ pattern:new RegExp('^[0-9]{1,}$','g'),message:'只允许包含数字'}]">
<a-input v-model:value="formState.phoneNumber" placeholder="请输入国内邀请人或本人联系电话" :allowClear="true" :disabled="operateStatus?true:false" />
</a-form-item>
</td>
<td colspan="3">
<a-form-item name="teamId" :label="`所属团队`">
<a-select v-model:value="formState.teamId" show-search placeholder="请选择所属团队" :options="defaultTypeAll.allTeam" :filter-option="filterOption" :fieldNames="{value:'id',label:'name'}" :notFoundContent="'暂无数据'" :disabled="operateStatus?true:false"></a-select>
</a-form-item>
</td>
</tr>
<tr>
<td colspan="3">
<a-form-item name="hotelAdress" :label="`旅馆地址`">
<a-input v-model:value="formState.hotelAddress" :allowClear="true" placeholder="请输入旅馆地址" :disabled="operateStatus?true:false" />
</a-form-item>
</td>
<td colspan="3">
<a-form-item name="remark" :label="`备注`">
<a-input v-model:value="formState.remark" :allowClear="true" placeholder="请输入备注" :disabled="operateStatus?true:false" />
</a-form-item>
</td>
</tr>
</table>
</a-form>
</div>
<div class="titleBox" v-if="visibleEdit">
<div style="margin: 0 auto">
<a-space :size="10">
<a-button type="primary" size="large" @click="edit" v-if="operateStatus">编辑</a-button>
<a-button type="primary" size="large" v-if="!operateStatus">扫描证件</a-button>
<a-button type="primary" size="large" v-if="!operateStatus">读取外国人永久居留证</a-button>
<a-button type="primary" size="large" @click="saveInfo" v-if="!operateStatus"><template #icon>
<file-protect-outlined />
</template>
保存</a-button>
<a-button size="large" @click="() => formRef.resetFields()" v-if="!operateStatus"><template #icon>
<reload-outlined />
</template>
清空</a-button>
<a-button size="large" @click="qx()" v-if="!operateStatus"><template #icon>
<reload-outlined />
</template>
取消</a-button>
</a-space>
</div>
</div>
</div>
</a-spin>
<template #footer>
</template>
</a-modal>
<Camera v-if="hotelFormVisible" :visible="hotelFormVisible" :title="`现场人像`" @handle-submit="onSubmit" @change-Cancel="changeCancel" />
<Cropper :imageSrc="imageSrc" v-if="hotelFormVisibles" :visible="hotelFormVisibles" :title="`截图`" @handle-submit="onSubmit_s" @change-Cancel="changeCancel_s" @handle-retake="handleRetake" />
</template>
<script setup>
import { EditFilled } from "@ant-design/icons-vue";
import { onMounted, reactive, watch } from "vue";
import { useStore } from '@/store/index.js'
import { forIn } from "lodash-es";
import Camera from "@/components/Camera.vue";
import { uploadImg } from '@/api/default.js';
import { message } from 'ant-design-vue';
import { file_img_src } from '@/utils/http_util.js';
import { updateForeignGuestCheckInList, queryForeignGuestDetail } from '@/api/foreignGuestCheckIn.js';
import default_img from '@/assets/img/default.png';
import dayjs from 'dayjs';
const userstore = useStore();
const props = defineProps({
visible: Boolean,
formData: {},
dictionaryAll: {},
flogStatus: Boolean,
visibleEdit: Boolean,//讲底下的编辑按钮隐藏 从离店页面进入是不显示按钮的
});
const formRef = ref();
const operateStatus = ref(true);
const loading = ref(false);
/**判断现场照片修改 */
const sitePhotos = ref(false);
/**判断证件照 */
const certificatePhotos = ref(false);
const emit = defineEmits(["changeCancel"]);
/**提交事件 */
const handleOk = async () => {
await emit("changeCancel");
};
const handleCancel = async () => {
await emit("changeCancel");
};
const rules = {
roomId: [
{
required: true,
message: '请输入房间号'
}
],
checkinTime: [
{
required: true,
message: '请选择入住时间'
}
],
nationalityCode: [
{
required: true,
message: '请选择国籍(地区)'
},
],
certificateNumber: [
{
required: true,
message: '请输入证件号码'
},
],
certificateType: [
{
required: true,
message: '请输入证件类型'
}
],
gender: [
{
required: true,
message: '请选择性别'
}
],
dateBirth: [
{
required: true,
message: '请选择出生日期'
},
],
visaType: [
{
required: true,
message: '请选择签证种类'
},
],
reasonEntry: [
{
required: true,
message: '请选择入境事由'
},
],
phoneNumber: [
{
required: true,
message: '请输入国内邀请人或本人联系电话'
}
],
teamId: [
{
required: true,
message: '请选择所属团队'
}
],
hotelAdress: [
{
required: true,
message: '请输入旅馆地址'
},
]
};
/**设置最小时间为今天 */
const disabledDateMin = current => {
// Can not select days before today and today
return current && current < dayjs().subtract(1, 'day').endOf('day');
};
/**设置最大时间为今天 */
const disabledDateMax = current => {
// Can not select days before today and today
return current && current > dayjs().endOf('day');
};
/**摄像头调用 */
const hotelFormVisible = ref(false);
const screenshot_url = ref("");
const onSubmit = (e) => {
hotelFormVisible.value = false;
imageSrc.value = e.value;
hotelFormVisibles.value = true;
};
const changeCancel = () => {
hotelFormVisible.value = false;
sitePhotos.value = false;
certificatePhotos.value = false;
};
/**开启摄像头 */
const OnCamera = () => {
hotelFormVisible.value = true;
};
/**截图 */
const hotelFormVisibles = ref(false);
const imageSrc = ref("");
const onSubmit_s = (e) => {
sitePhotos.value = true;
formState.sitePhoto = e.value;
formState.sitePhotoPath = e.value;
hotelFormVisibles.value = false;
};
const changeCancel_s = () => {
hotelFormVisibles.value = false;
};
const handleRetake = () => {
changeCancel_s();
OnCamera();
};
/**右侧切换截取图片 */
const checked_value1 = ref(true);
const checked_value2 = ref(false);
const checked_value3 = ref(false);
/**下拉框筛选 */
const filterOption = (input, option) => {
return option.name.toLowerCase().indexOf(input.toLowerCase()) >= 0;
};
const formState = reactive({});
const defaultTypeAll = reactive({});
const getData = (data) => {
forIn(data, (value, key) => (formState[key] = value))
}
const getData1 = (data) => {
forIn(props?.dictionaryAll, (value, key) => (defaultTypeAll[key] = value))
}
const edit = () => {
operateStatus.value = false;
}
/**选择头像 */
const handleChange = info => {
const isPNG = info.file.type === 'image/png' || info.file.type === 'image/jpg' || info.file.type === 'image/jpeg';
if (!isPNG) {
message.error(`${info.file.name} 不是图片格式,请上传PNG||JPG||JPEG`);
} else {
const reader = new FileReader();
reader.readAsDataURL(info.file);
reader.onload = () => {
formState.sitePhoto = reader.result;
formState.sitePhotoPath = reader.result;
sitePhotos.value = true;
};
}
};
/**不让文件直接上传 */
const beforeUpload = (file) => {
return false;
};
//上报信息
const saveInfo = () => {
/**批量操作上传图片 */
const arr_http = [];
if (sitePhotos.value) {/**现场照片 */
arr_http.push(file_img_src(formState.sitePhoto, userstore.hotelInfo.hotelId, 'FOREIGN_GUEST'));
} else {
arr_http.push('');
}
if (certificatePhotos.value) {/**身份证 */
arr_http.push(file_img_src(formState.certificatePhoto, userstore.hotelInfo.hotelId, 'FOREIGN_GUEST'));
} else {
arr_http.push('');
}
loading.value = true;
Promise.all(arr_http).then(([res1, res2]) => {
const arr = { ...formState };
if (sitePhotos.value) {
arr.sitePhoto = res1
}
if (certificatePhotos.value) {
arr.certificatePhoto = res2
}
updateForeignGuestCheckInList(arr)
.then((res) => {
if (res.code == 9000) {
message.success("已保存");
operateStatus.value = true;
sitePhotos.value = false;
certificatePhotos.value = false;
// reset();
}
loading.value = false;
})
.catch((res) => {
message.warning("保存失败");
loading.value = false;
});
});
}
const str_data = (str) => {
const str1 = str.substring(0, 4);
const str2 = str.substring(4, 6);
const str3 = str.substring(6, 8);
return str1 + "-" + str2 + "-" + str3;
};
onMounted(() => {
if (props?.visible) {
loading.value =true;
queryForeignGuestDetail({ id: props?.formData.id }).then(res => {
loading.value =false;
forIn(res.data, (value, key) => (formState[key] = value));
}).catch(error=>{
loading.value =false;
})
forIn(props?.dictionaryAll, (value, key) => (defaultTypeAll[key] = value));
operateStatus.value = props?.flogStatus;
// screenshot_url.value = props?.formData.sitePhotoPath;
};
});
const qx = () => {
queryForeignGuestDetail({ id: props?.formData.id }).then(res => {
forIn(res.data, (value, key) => (formState[key] = value));
})
operateStatus.value = true;
}
</script>
<style lang="less">
.visitorFrom {
width: 100%;
height: 100%;
padding: 0px;
margin: 0px;
.form {
.ant-form-item-with-help {
margin-bottom: 0px;
}
.ant-form-item-label {
flex: auto;
}
}
.form-tables {
width: 100%;
border-collapse: collapse;
tr {
width: 100%;
height: 60px;
td {
border: 1px solid #e7e7e7;
max-width: 222px;
.img-pub {
display: flex;
flex-direction: row;
justify-content: space-around;
flex-wrap: wrap;
margin: 10px;
.img-wp {
width: 140px;
height: 170px;
border: 1px solid #a5a5a5;
.img-div {
border-image-source: radial-gradient(
60% 60%,
transparent 0px,
transparent 100%,
#6691ef 100%
);
border-image-slice: 1;
border-width: 1px;
border-style: solid;
border-image-outset: 0px;
width: calc(100% - 50px);
height: calc(100% - 50px);
margin: 9px 25px 13px;
.img-span {
margin: 0px auto;
width: 14px;
line-height: 29px;
font-weight: 400;
font-size: 15px;
}
.img-span1 {
height: 100%;
display: flex;
flex-direction: row;
flex-wrap: nowrap;
justify-content: center;
align-items: center;
letter-spacing: 6px;
font-weight: 400;
font-size: 15px;
}
}
.check-div {
width: 100%;
text-align: center;
.ant-radio-wrapper {
margin-right: 0px;
}
}
}
}
}
}
}
.titleBox {
display: flex;
justify-content: space-between;
align-items: center;
background: #fafafa;
border-radius: 0px 0px 2px 2px;
border: 1px solid #e9e9e9;
padding: 10px;
margin: 25px 5px;
}
.sign {
display: inline-block;
font-size: 16px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: rgba(0, 0, 0, 0.85);
line-height: 16px;
&::before {
content: "";
display: inline-block;
width: 4px;
height: 12px;
background: #3162f5;
border-radius: 2px;
margin-right: 8px;
}
}
}
</style>
\ No newline at end of file
<template>
<div class="departure">
<a-spin :spinning="loading">
<div class="titleBox">
<div>
<span class="sign">离店列表</span>
</div>
</div>
<div style="margin: 0px 25px">
<a-form ref="formRef" name="advanced_search" class="ant-advanced-search-form form" :model="formState">
<a-row :gutter="24">
<a-col :span="3">
<a-form-item name="roomId" label="房间号">
<a-select show-search v-model:value="formState.roomId" :filter-option="filterOption" placeholder="请选择房间号" :options="options_room" :allowClear="true" optionLabelProp="name" :fieldNames="{ label: 'name', value: 'id' }">
</a-select>
</a-form-item>
</a-col>
<a-col :span="3">
<a-form-item name="name" label="姓名">
<a-input v-model:value="formState.name" placeholder="请输入姓名"></a-input>
</a-form-item>
</a-col>
<a-col :span="5">
<a-form-item name="name" label="证件号码">
<a-input v-model:value="formState.certificateNumber" placeholder="请输入证件号码"></a-input>
</a-form-item>
</a-col>
<a-col :span="7">
<a-form-item label="入住时间">
<a-range-picker show-time @change="(data, dateString) => handleChangeTime(data, dateString)" />
</a-form-item>
</a-col>
<a-col>
<a-space :size="10">
<a-button type="primary" @click="queryList()">查询</a-button>
<a-button type="primary" @click="departure()">批量离店</a-button>
<!-- <a-button type="primary">团队离店</a-button> -->
</a-space>
</a-col>
</a-row>
</a-form>
</div>
<div class="titleBox">
<div>
<span class="sign">内宾登记情况</span>
</div>
</div>
<a-spin :spinning="loading_inland">
<div style="margin: 0px 25px">
<a-table :row-selection="rowSelection_inland" :rowKey="item=>JSON.stringify(item.id)" :columns="columns_inland" :data-source="data_inland" :pagination="false"><template #bodyCell="{ column, record, index }">
<template v-if="column.dataIndex === 'cz'">
<a-space :size="0">
<a-button type="link" primary size="small" style="color: #52c41a" @click="eye_inland(record)">
<template #icon>
<eye-filled />
</template>
查看
</a-button>
<a-popconfirm v-if="record.state === 'ARRIVE'" title="是否离店" @confirm="setState_inland(record)">
<a-button type="link" primary size="small" style="color: #ff4d1f">
<template #icon>
<swap-outlined />
</template>
离店
</a-button>
</a-popconfirm>
</a-space>
</template>
</template>
</a-table>
<a-pagination v-model:current="page_inland" :rowKey="item=>item.id" :page-size-options="pageSizeOptions" v-model:page-size="pageSize_inland" show-quick-jumper show-size-changer :total="total_inland" v-show="data_inland.length > 0" size="small" :show-total="(total) => `总数共: ${total} 条`" @change="onChange_inland" style="margin: 20px 0px" />
</div>
</a-spin>
<div class="titleBox">
<div>
<span class="sign">外宾登记情况</span>
</div>
</div>
<a-spin :spinning="loading_abroad">
<div style="margin: 0px 25px">
<a-table :row-selection="rowSelection_abroad" :rowKey="item=>JSON.stringify(item.id)" :columns="columns_abroad" :data-source="data_abroad" :pagination="false"><template #bodyCell="{ column, record, index }">
<template v-if="column.dataIndex === 'cz'">
<a-space :size="0">
<a-button type="link" primary size="small" style="color: #52c41a" @click="eye_abroad(record)">
<template #icon>
<eye-filled />
</template>
查看
</a-button>
<a-popconfirm v-if="record.state === 'ARRIVE'" title="是否离店" @confirm="setState_abroad(record)">
<a-button type="link" primary size="small" style="color: #ff4d1f">
<template #icon>
<swap-outlined />
</template>
离店
</a-button>
</a-popconfirm>
</a-space>
</template>
</template>
</a-table>
<a-pagination v-model:current="page_abroad" :page-size-options="pageSizeOptions" v-model:page-size="pageSize_abroad" show-quick-jumper show-size-changer :total="total_abroad" v-show="data_abroad.length > 0" size="small" :show-total="(total) => `总数共: ${total} 条`" @change="onChange_abroad" style="margin: 20px 0px" />
</div>
</a-spin>
</a-spin>
<InlandEyes v-if="hotelFormVisible" :visible="hotelFormVisible" :visibleEdit="hotelFormVisible_edit" :id="info_id" :title="titles" @change-Cancel="changeCancel_inland"/>
<AbroadInfo v-if="abroadInfoVisible" :flogStatus="operateStatus" :visible="abroadInfoVisible" :dictionaryAll="dictionaryAllInfo" :formData="abroadInfo" @change-Cancel="changeCancel_adroad" :visibleEdit="hotelFormVisible_edit_s"/>
</div>
</template>
<script setup>
import { useStore } from "@/store/index.js";
import { inlandQuery, inlandCheckOut } from "@/api/domesticGuestCheckIn";
import { getForeignGuestCheckInList, departureForeignGuestCheckIn } from '@/api/foreignGuestCheckIn.js';
import { onMounted } from "vue";
import { message } from "ant-design-vue";
import InlandEyes from '@/views/inland/inlandEyes.vue';
import AbroadInfo from '@/views/abroad/abroadInfo.vue';
const userstore = useStore();
const formState = reactive({
name: "",
certificateNumber: "",
checkinTimeEnd: "",
checkinTimeStart: "",
state: "ARRIVE",
roomId: "",
hotelId: userstore.hotelInfo.hotelId, //旅馆id
current: 1,
pageSize: 4,
});
/**字典表查询---性别*/
const options_room = ref(userstore.roomAll); //房间字典
/**spinning*/
const loading = ref(false);
/**分页下拉框选项 */
const pageSizeOptions = ref(['4', '10', '20', '30', '40', '50']);
/**内宾表格----------------------- */
const columns_inland = [
{
title: "姓名",
dataIndex: "name",
},
{
title: "证件号码",
dataIndex: "certificateNumber",
},
{
title: "性别",
dataIndex: "genderName",
},
{
title: "民族",
dataIndex: "nationName",
},
{
title: "户籍地省市县区",
dataIndex: "provincialUrbanAreasName",
},
{
title: "房号",
dataIndex: "roomName",
},
{
title: "所属团队",
dataIndex: "teamName",
},
{
title: "旅客状态",
dataIndex: "state",
},
{
title: "入住时间",
dataIndex: "checkinTime",
},
{
title: "操作",
dataIndex: "cz",
fixed: "right",
width: 200,
},
];
const data_inland = ref([]);
const page_inland = ref(formState.current);/**当前第几页 */
const pageSize_inland = ref(formState.pageSize);/**当前每页的数据 */
const total_inland = ref(0);/**总数 */
const selectedRowKeys_inland = ref([]);/**当前选中集合 */
const loading_inland = ref(false);
const rowSelection_inland = {
onChange: (selectedRowKeys, selectedRows) => {
selectedRowKeys_inland.value = selectedRowKeys;
},
}
const onChange_inland = (page, pageSize) => {
page_inland.value = page;
pageSize_inland.value = pageSize;
queryInland_dd();
};
/**--------------------------- */
/**外宾表格----------------------- */
const columns_abroad = [
{
title: "姓名",
dataIndex: "chineseName",
},
{
title: "证件号码",
dataIndex: "certificateNumber",
},
{
title: "性别",
dataIndex: "genderName",
},
{
title: "出生日期",
dataIndex: 'dateBirth',
},
{
title: "国籍地区",
dataIndex: "nationalityCodeName",
},
{
title: "房号",
dataIndex: "roomName",
},
{
title: "所属团队",
dataIndex: "teamName",
},
{
title: "旅客状态",
dataIndex: "state",
},
{
title: "入住时间",
dataIndex: "checkinTime",
},
{
title: "操作",
dataIndex: "cz",
fixed: "right",
width: 200,
},
];
const data_abroad = ref([]);
const page_abroad = ref(formState.current);/**当前第几页 */
const pageSize_abroad = ref(formState.pageSize);/**当前每页的数据 */
const total_abroad = ref(0);/**总数 */
const selectedRowKeys_abroad = ref([]);/**当前选中集合 */
const loading_abroad = ref(false);
const rowSelection_abroad = {
onChange: (selectedRowKeys, selectedRows) => {
selectedRowKeys_abroad.value = selectedRowKeys;
},
}
const onChange_abroad = (page, pageSize) => {
page_abroad.value = page;
pageSize_abroad.value = pageSize;
queryAbroad_dd();
};
/**--------------------------- */
/**时间变化 */
const handleChangeTime = (data, dataArr,) => {
if (dataArr && dataArr.length > 0) {
formState.checkinTimeEnd = dataArr[1];
formState.checkinTimeStart = dataArr[0];
} else {
formState.checkinTimeEnd = "";
formState.checkinTimeStart = "";
}
};
/**下拉框筛选 */
const filterOption = (input, option) => {
return option.name.toLowerCase().indexOf(input.toLowerCase()) >= 0;
};
/**内宾查询 */
const queryInland = () => {
return new Promise((resolve) => {
inlandQuery(formState).then((res) => {
if (res?.code == 9000) {
resolve(res);
} else {
resolve("");
}
});
});
}
/**内宾单独查询 */
const queryInland_dd = () => {
const arr = { ...formState };
arr.current = page_inland.value;
arr.pageSize = pageSize_inland.value;
loading_inland.value = true;
inlandQuery(arr).then((res) => {
if (res?.code == 9000) {
data_inland.value = res.data.records;
total_inland.value = res.data.total;
}
loading_inland.value = false;
}).catch(error => {
loading_inland.value = false;
});
}
/**外宾查询 */
const queryAbroad = () => {
const arr = { ...formState };
return new Promise((resolve) => {
getForeignGuestCheckInList(arr).then((res) => {
if (res?.code == 9000) {
resolve(res);
} else {
resolve("");
}
});
});
}
/**外宾单独查询 */
const queryAbroad_dd = () => {
const arr = { ...formState };
arr.current = page_abroad.value;
arr.pageSize = pageSize_abroad.value;
loading_abroad.value = true;
getForeignGuestCheckInList(arr).then((res) => {
if (res?.code == 9000) {
data_abroad.value = res.data.records;
total_abroad.value = res.data.total;
}
loading_abroad.value = false;
}).catch(error => {
loading_abroad.value = false;
});
}
/**分页查询 */
const queryList = async () => {
loading.value = true;
page_inland.value = formState.current;
pageSize_inland.value = formState.pageSize;
page_abroad.value = formState.current;
pageSize_abroad.value = formState.pageSize;
Promise.all([queryInland(), queryAbroad()]).then(([res1, res2]) => {
loading.value = false;
data_inland.value = res1.data.records;
total_inland.value = res1.data.total;
data_abroad.value = res2.data.records;
total_abroad.value = res2.data.total;
}).catch(error => {
loading.value = false;
});
};
/**内宾单个离店 */
const setState_inland = (record) => {
loading.value = true;
inlandCheckOut([record.id])
.then((res) => {
loading.value = false;
if (res?.code == 9000) {
message.success("离店成功");
queryInland_dd();
}
})
.catch((res) => {
loading.value = false;
message.warning("离店失败");
});
}
/**内宾批量离店 */
const departure_inland = () => {
return new Promise((resolve) => {
inlandCheckOut(selectedRowKeys_inland.value).then((res) => {
if (res?.code == 9000) {
resolve(res);
} else {
resolve("");
}
});
});
}
/**外宾单个离店 */
const setState_abroad = (record) => {
loading.value = true;
departureForeignGuestCheckIn([record.id])
.then((res) => {
loading.value = false;
if (res?.code == 9000) {
message.success("离店成功");
queryAbroad_dd();
}
})
.catch((res) => {
loading.value = false;
message.warning("离店失败");
});
}
/**外宾批量离店 */
const departure_abroad = () => {
return new Promise((resolve) => {
departureForeignGuestCheckIn(selectedRowKeys_abroad.value).then((res) => {
if (res?.code == 9000) {
resolve(res);
} else {
resolve("");
}
});
});
}
/**批量离店 */
const departure = () => {
if (selectedRowKeys_inland.value.length > 0 || selectedRowKeys_abroad.value.length > 0) {
loading.value = true;
const arr_http = [];
if (selectedRowKeys_inland.value.length > 0) {
arr_http.push(departure_inland());
} else {
arr_http.push("");
}
if (selectedRowKeys_abroad.value.length > 0) {
arr_http.push(departure_abroad());
} else {
arr_http.push("");
}
Promise.all(arr_http).then(([res1, res2]) => {
loading.value = false;
message.success('离店成功')
queryList();
// if (selectedRowKeys_inland.value.length > 0) {
// if (res1?.code==9000){
// message.success('内宾离店成功')
// }
// }
// if (selectedRowKeys_abroad.value.length > 0) {
// if (res2?.code==9000){
// message.success('外宾离店成功')
// }
// }
}).catch(error => {
loading.value = false;
})
} else {
message.warning('请选择行')
}
}
/**内宾查看 */
const info_id = ref('');
const hotelFormVisible = ref(false);
const hotelFormVisible_edit = ref(false);
const titles = ref("查看内宾详情");
const changeCancel_inland = () => {
hotelFormVisible.value = false;
};
const eye_inland = ( e) => {
info_id.value = e.id;
hotelFormVisible.value = true;
hotelFormVisible_edit.value = false;
};
/**外宾查看 */
const abroadInfoVisible = ref(false);
const operateStatus = ref(false);
const dictionaryAllInfo = ref({});
const abroadInfo = ref('');
const hotelFormVisible_edit_s = ref(false);
const changeCancel_adroad = () => {
abroadInfoVisible.value = false;
};
const eye_abroad = ( e) => {
abroadInfo.value = e;
abroadInfoVisible.value = true;
operateStatus.value = true;
hotelFormVisible_edit_s.value = false;
};
onMounted(() => {
queryList();
})
</script>
<style lang="less">
.departure {
width: 100%;
height: 100%;
padding: 0px;
margin: 0px;
overflow-y: auto;
.form {
.ant-form-item {
margin-bottom: 0px;
}
}
.form-tables {
width: 100%;
border-collapse: collapse;
tr {
width: 100%;
height: 60px;
td {
border: 1px solid #e7e7e7;
max-width: 222px;
.img-wp {
width: 186.829px;
height: 230px;
border: 1px solid #a5a5a5;
.img-div {
border-image-source: radial-gradient(
60% 60%,
transparent 0px,
transparent 100%,
#6691ef 100%
);
border-image-slice: 1;
border-width: 1px;
border-style: solid;
border-image-outset: 0px;
width: calc(100% - 40px);
height: calc(100% - 40px);
margin: 20px;
.img-span {
margin: 23px auto;
width: 14px;
line-height: 35px;
font-weight: 400;
font-size: 15px;
}
}
}
}
}
}
.titleBox {
display: flex;
justify-content: space-between;
align-items: center;
background: #fafafa;
border-radius: 0px 0px 2px 2px;
border: 1px solid #e9e9e9;
padding: 10px;
margin: 25px 5px;
}
.sign {
display: inline-block;
font-size: 16px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: rgba(0, 0, 0, 0.85);
line-height: 16px;
&::before {
content: "";
display: inline-block;
width: 4px;
height: 12px;
background: #3162f5;
border-radius: 2px;
margin-right: 8px;
}
}
}
</style>
\ No newline at end of file
<template>
<a-modal :visible="visible" :title="title" width="60%" @cancel="handleCancel" @ok="handleCancel">
<div class="personnelAdd">
<div style="margin: 0px 5px">
<a-form class="form" ref="formRef" :model="formState" :labelCol="{ span: 8 }" :wrapper-col="{ span: 16 }" layout="inline" :rules="rules">
<table class="form-tables">
<tr>
<td colspan="1">
<a-form-item name="nickname" :label="`姓名`">
<a-input v-model:value="formState.nickname" placeholder="请输入姓名" :allowClear="true" :readonly="operateStatus==2?true:false" />
</a-form-item>
</td>
<td colspan="1" rowspan="5">
<div style="display: flex;flex-direction: row;justify-content: space-around;flex-wrap: wrap;">
<div class="img-wp">
<div class="img-div">
<div class="img-span" v-if="!formState.photo">
<span>照片</span>
</div>
<a-image :width="`100%`" :height="`100%`" :src="tmpImg" v-else />
</div>
<div class="check-div" style="text-align: center;margin-top: 10px;" v-if="operateStatus!=2">
<a-upload name="file" @change="handleChange" :showUploadList="false" :before-upload="beforeUpload">
<a-button>
上传照片
</a-button>
</a-upload>
</div>
</div>
</div>
</td>
</tr>
<tr>
<td colspan="1">
<a-form-item name="username" :label="`用户名`">
<a-input v-model:value="formState.username" placeholder="请输入用户名" :allowClear="true" :readonly="operateStatus==2?true:false" />
</a-form-item>
</td>
</tr>
<tr>
<td colspan="1">
<a-form-item name="password" :label="`密码`">
<a-input v-model:value="formState.password" placeholder="请输入密码" :allowClear="true" :readonly="operateStatus==2?true:false" />
</a-form-item>
</td>
</tr>
<tr>
<td colspan="1">
<a-form-item name="email" :label="`邮箱`">
<a-input v-model:value="formState.email" :allowClear="true" placeholder="请输入邮箱" :readonly="operateStatus==2?true:false" />
</a-form-item>
</td>
</tr>
<tr>
<td colspan="1">
<a-form-item name="phone" :label="`手机号`">
<a-input v-model:value="formState.phone" :allowClear="true" placeholder="请输入手机号" :readonly="operateStatus==2?true:false" />
</a-form-item>
</td>
</tr>
<tr>
<td colspan="1">
<a-form-item name="identityCard" :label="`身份证号`">
<a-input v-model:value="formState.identityCard" :allowClear="true" placeholder="请输入身份证号码" :readonly="operateStatus==2?true:false" />
</a-form-item>
</td>
<td colspan="1">
<a-form-item name="licensePlate" :label="`车牌号`">
<a-input-group compact>
<a-form-item style="width: 20%" name="plateProvince">
<a-select show-search v-model:value="formState.licensePlate" :filter-option="filterOption" :options="allProvince" placeholder="请选择省份" :allowClear="true" optionLabelProp="name" style="width: 100%" :fieldNames="{ label: 'name', value: 'name' }">
</a-select>
</a-form-item>
<a-input v-model:value="formState.plateNumber" style="width: 80%" />
</a-input-group>
</a-form-item>
</td>
</tr>
<tr>
<td colspan="1">
<a-form-item name="gender" :label="`性别`">
<a-select v-model:value="formState.gender" show-search placeholder="请选择性别" :options="allGender" :filter-option="filterOption" :fieldNames="{value:'code',label:'name'}" :notFoundContent="'暂无数据'" :disabled="operateStatus==2?true:false"></a-select>
</a-form-item>
</td>
<td colspan="1">
<a-form-item name="roles" :label="'权限'">
<a-select mode="multiple" v-model:value="formState.roles" show-search placeholder="请选择" :options="roles" :filter-option="filterOptionRoles" :fieldNames="{value:'id',label:'name'}" :notFoundContent="'暂无数据'" :disabled="operateStatus==2?true:false"></a-select>
</a-form-item>
</td>
</tr>
</table>
</a-form>
</div>
<div class="titleBox">
<div style="margin: 0 auto">
<a-space :size="10">
<a-button type="primary" size="large" v-if="operateStatus==2" @click="edit"><template #icon><file-protect-outlined /></template>编辑</a-button>
<a-button type="primary" size="large" @click="saveInfo" v-if="operateStatus==1||operateStatus==3"><template #icon><file-protect-outlined /></template>保存</a-button>
<a-button type="primary" size="large" @click="() => formRef.resetFields()" v-if="operateStatus==1"><template #icon>
<reload-outlined />
</template>
清空</a-button>
</a-space>
</div>
</div>
</div>
</a-modal>
</template>
<script setup>
import { useStore } from '@/store/index.js'
import { message } from 'ant-design-vue';
import { onMounted, reactive } from 'vue';
import { queryRole } from '@/api/role.js';
import { addPersonnel, updatePersonnel } from '@/api/user.js';
import { file_img_src } from '@/utils/http_util.js';
import { getImgByUrl } from '@/api/default.js';
import { forIn } from "lodash-es";
const props = defineProps({
visible: Boolean,
title: String,
formData: {},
flogStatus: Number
});
const emit = defineEmits(["changeCancel", "updateUserList"]);
const handleCancel = async () => {
await emit("changeCancel");
};
const userstore = useStore();
const formRef = ref();
const formState = reactive({
hotelId: userstore.hotelInfo.hotelId,
nickname: null,
username: null,
gender: null,
password: null,
email: null,
phone: null,
roles: [],
identityCard: null,
licensePlate: null,
plateNumber: null,
photo: null
});
const rules = {
roomId: [
{
required: true,
message: '请输入房间号'
}
],
residentName: [
{
required: true,
message: '请输入住客姓名'
}
],
certificateNumber: [
{
required: true,
message: '请选择访客证件号码'
},
],
nationalityCode: [
{
required: true,
message: '请选择访客国籍(地址)'
},
]
};
const roles = ref([]);
const allGender = ref(userstore.returnCode(5));
const allProvince = ref(userstore.returnCode(6)); //全省信息
const operateStatus = ref(1);
const loading = ref(false);
const tmpImg = ref('');
/**下拉框筛选 */
const filterOption = (input, option) => {
return option.name.toLowerCase().indexOf(input.toLowerCase()) >= 0;
};
const filterOptionRoles = (input, option) => {
return option.name.toLowerCase().indexOf(input.toLowerCase()) >= 0;
};
const handleMenuClick = (e) => {
console.log("click", e);
};
const saveInfo = () => {
formState.licensePlate = formState.licensePlate + formState.plateNumber;
if (operateStatus.value == 1) {
addPersonnel(formState).then(res => {
if (res.code == '9000') {
message.success('新增成功!');
formRef.value.resetFields();
formState.plateNumber = null;
formState.photo = null;
emit("updateUserList");
}
}).catch(error => {
message.error(error.message);
})
} else if (operateStatus.value == 3) {
updatePersonnel(formState).then(res => {
if (res.code == '9000') {
message.success('编辑成功!');
operateStatus.value = 2;
emit("updateUserList");
}
}).catch(error => {
message.error(error.message);
})
}
}
//选择头像
const handleChange = async info => {
const isPNG = info.file.type === 'image/png' || info.file.type === 'image/jpg' || info.file.type === 'image/jpeg';
if (!isPNG) {
message.error(`${info.file.name} 不是图片格式,请上传PNG||JPG||JPEG`);
} else {
const reader = new FileReader();
reader.readAsDataURL(info.file);
reader.onload = () => {
tmpImg.value = reader.result;
file_img_src(tmpImg.value, userstore.hotelInfo.hotelId, "PRACTICE_USER").then(res => {
formState.photo = res;
});
};
}
};
//不让文件直接上传
const beforeUpload = (file) => {
return false
};
//编辑
const edit = () => {
operateStatus.value = 3;
}
onMounted(() => {
//查询权限列表
queryRole().then(res => {
roles.value = res.data;
})
operateStatus.value = props?.flogStatus;
if (operateStatus.value == 2 || operateStatus.value == 3) {
forIn(props?.formData, (value, key) => (formState[key] = value));
let tmpRoles = formState.roles, tmpArr = [];
tmpRoles.forEach(item => {
tmpArr.push(item.id);
});
formState.roles = tmpArr;
let carNo = formState.licensePlate;
if (carNo?.length > 0) {
formState.licensePlate = carNo.slice(0, 1);
formState.plateNumber = carNo.slice(1, carNo.length - 1);
}
if (formState.photo) {
getImgByUrl({ bucket: 'PRACTICE_USER', filename: formState.photo, hotelId: formState.hotelId }).then(res => {
if (res.code == '9000') {
tmpImg.value = res.data;
}
}).catch(error => {
message.error(error.message);
})
}
}
})
</script>
<style lang="less">
.personnelAdd {
width: 100%;
height: 100%;
padding: 0px;
margin: 0px;
.form {
.ant-form-item-with-help {
margin-bottom: 0px;
}
.ant-form-item-label {
flex: auto;
}
}
.form-tables {
width: 100%;
border-collapse: collapse;
tr {
width: 100%;
height: 60px;
td {
border: 1px solid #e7e7e7;
max-width: 222px;
.img-wp {
width: 186.829px;
height: 230px;
border: 1px solid #a5a5a5;
.img-div {
border-image-source: radial-gradient(
60% 60%,
transparent 0px,
transparent 100%,
#6691ef 100%
);
border-image-slice: 1;
border-width: 1px;
border-style: solid;
border-image-outset: 0px;
width: calc(100% - 40px);
height: calc(100% - 80px);
margin: 20px;
.img-span {
margin: 23px auto;
width: 14px;
line-height: 35px;
font-weight: 400;
font-size: 15px;
}
}
}
}
}
}
.titleBox {
display: flex;
justify-content: space-between;
align-items: center;
background: #fafafa;
border-radius: 0px 0px 2px 2px;
border: 1px solid #e9e9e9;
padding: 10px;
margin: 25px 5px;
}
.sign {
display: inline-block;
font-size: 16px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: rgba(0, 0, 0, 0.85);
line-height: 16px;
&::before {
content: "";
display: inline-block;
width: 4px;
height: 12px;
background: #3162f5;
border-radius: 2px;
margin-right: 8px;
}
}
}
</style>
\ No newline at end of file
<template>
<a-modal :visible="visible" :title="title" width="60%" @cancel="handleCancel" @ok="handleCancel">
<div class="roleAdd">
<div style="margin: 0px 5px">
<a-form class="form" ref="formRef" :model="formState" :labelCol="{ span: 8 }" :wrapper-col="{ span: 16 }" layout="inline" :rules="rules">
<table class="form-tables">
<tr>
<td colspan="1">
<a-form-item name="name" :label="`角色名称`">
<a-input v-model:value="formState.name" :allowClear="true" placeholder="请输入角色名称" />
</a-form-item>
</td>
<td colspan="1">
<a-form-item name="description" :label="`角色描述`">
<a-input v-model:value="formState.description" :allowClear="true" placeholder="角色描述" />
</a-form-item>
</td>
</tr>
</table>
</a-form>
</div>
<div class="titleBox">
<div style="margin: 0 auto">
<a-space :size="10">
<a-button type="primary" size="large" @click="saveInfo">
<template #icon><file-protect-outlined /></template>保存
</a-button>
<a-button type="primary" size="large" @click="() => formRef.resetFields()" v-if="operateStatus==1">
<template #icon>
<reload-outlined />
</template>清空
</a-button>
</a-space>
</div>
</div>
</div>
</a-modal>
</template>
<script setup>
import { useStore } from '@/store/index.js'
import { message } from 'ant-design-vue';
import { onMounted, reactive } from 'vue';
import { addRoles, updateRoles } from '@/api/role.js';
import { forIn } from "lodash-es";
const props = defineProps({
visible: Boolean,
title: String,
formData: {},
flogStatus: Number
});
const emit = defineEmits(["changeCancel", "changeData"]);
const handleCancel = async () => {
await emit("changeCancel");
};
const userstore = useStore();
const formRef = ref();
const formState = reactive({
name: '',
description: ''
});
const rules = {
name: [
{
required: true,
message: '请输入角色名称'
}
],
description: [
{
required: true,
message: '请输入角色描述'
}
]
};
const roles = ref([]);
const operateStatus = ref(1);
const loading = ref(false);
const saveInfo = () => {
if (operateStatus.value == 1) {
addRoles(formState).then(res => {
if (res.code == '9000') {
message.success('新增成功!');
handleCancel();
emit("changeData");
}
}).catch(error => {
message.error(error.message);
});
} else if (operateStatus.value == 2) {
updateRoles(formState).then(res => {
if (res.code == '9000') {
message.success('编辑成功!');
handleCancel();
emit("changeData");
}
}).catch(error => {
message.error(error.message);
});
}
}
// let socket = null;
// // 提交按钮的点击事件处理函数
// const send = () => {
// // 向服务器发送消息
// socket.emit('send', '')
// }
onMounted(() => {
operateStatus.value = props?.flogStatus;
if (operateStatus.value == 2) {
forIn(props?.formData, (value, key) => (formState[key] = value));
}
// //实例websocket
// socket = io('ws://127.0.0.1:90/echo/');
// // 建立连接的事件
// socket.on('connect', () => console.log('connect: websocket 连接成功!'));
// // 关闭连接的事件
// socket.on('disconnect', () => console.log('disconnect: websocket 连接关闭!'));
// // 接收到消息的事件
// socket.on('message', msg => console.log(msg));
})
// onBeforeUnmount(() => {
// // 关闭连接
// socket.close()
// // 销毁 websocket 实例对象
// socket = null;
// })
</script>
<style lang="less">
.roleAdd {
width: 100%;
height: 100%;
padding: 0px;
margin: 0px;
.form {
.ant-form-item-with-help {
margin-bottom: 0px;
}
.ant-form-item-label {
flex: auto;
}
}
.form-tables {
width: 100%;
border-collapse: collapse;
tr {
width: 100%;
height: 60px;
td {
border: 1px solid #e7e7e7;
max-width: 222px;
.img-wp {
width: 186.829px;
height: 230px;
border: 1px solid #a5a5a5;
.img-div {
border-image-source: radial-gradient(
60% 60%,
transparent 0px,
transparent 100%,
#6691ef 100%
);
border-image-slice: 1;
border-width: 1px;
border-style: solid;
border-image-outset: 0px;
width: calc(100% - 40px);
height: calc(100% - 80px);
margin: 20px;
.img-span {
margin: 23px auto;
width: 14px;
line-height: 35px;
font-weight: 400;
font-size: 15px;
}
}
}
}
}
}
.titleBox {
display: flex;
justify-content: space-between;
align-items: center;
background: #fafafa;
border-radius: 0px 0px 2px 2px;
border: 1px solid #e9e9e9;
padding: 10px;
margin: 25px 5px;
}
.sign {
display: inline-block;
font-size: 16px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: rgba(0, 0, 0, 0.85);
line-height: 16px;
&::before {
content: "";
display: inline-block;
width: 4px;
height: 12px;
background: #3162f5;
border-radius: 2px;
margin-right: 8px;
}
}
}
</style>
\ No newline at end of file
<template>
<a-drawer v-model:visible="visible" class="custom-class" style="color: red" title="编辑权限" placement="right" @close="handleClose">
<a-tree mode="inline" v-model:checkedKeys="checkedKeys" checkable :tree-data="treeData" :fieldNames="{title:'label',key:'id'}" @check="changeChecked">
<template #label="{ label, id }">
<template>{{ label }}</template>
</template>
</a-tree>
<div style="margin-top:40px;margin-left:40px;">
<a-button type="primary" @click="confirm">
<template #icon>
<edit-filled />
</template>
确定
</a-button>
</div>
</a-drawer>
</template>
<script setup>
import { onMounted } from "vue";
import { forIn } from "lodash-es";
import { grantMenuRole } from '@/api/role.js';
import { message } from "ant-design-vue";
import { treeForeach } from '@/utils/http_util.js';
const props = defineProps({
visible: Boolean,
roleInfo: {},
treeData: []
});
const emit = defineEmits(["changeCancel"]);
const visible = ref(false);
const roleInformation = ref({});
const treeData = ref([]);
const checkedKeys = ref([]);
const showDrawer = () => {
visible.value = true;
};
const handleClose = () => {
emit("changeCancel");
}
const changeChecked = e => {
console.log(e);
}
//权限提交
const confirm = () => {
grantMenuRole(checkedKeys.value, roleInformation.value.id).then(res => {
if (res.code == '9000') {
message.success('权限添加成功!');
}
}).catch(error => {
message.error(error.message);
});
};
onMounted(() => {
visible.value = props.visible;
forIn(props?.roleInfo, (value, key) => { roleInformation.value[key] = value });
treeData.value = props?.treeData;
treeForeach(roleInformation.value.roles, node => {
checkedKeys.value.push(node.id);
})
});
</script>
\ No newline at end of file
<template>
<div class="personnelManagement">
<a-spin :spinning="loading">
<div class="titleBox">
<div>
<span class="sign">人员管理</span>
</div>
</div>
<div style="margin: 0px 25px">
<a-form ref="formRef" name="advanced_search" class="ant-advanced-search-form" :model="formState">
<a-row :gutter="24">
<a-col :span="3">
<a-form-item name="name" label="姓名">
<a-input v-model:value="formState.name" placeholder="请输入用户姓名"></a-input>
</a-form-item>
</a-col>
<a-col :span="3">
<a-form-item name="username" label="账号">
<a-input v-model:value="formState.username" placeholder="请输入用户账号"></a-input>
</a-form-item>
</a-col>
<a-col :span="3">
<a-form-item name="gender" label="性别">
<a-select v-model:value="formState.gender" show-search placeholder="请选择性别" :options="allGender" :filter-option="filterOption" :fieldNames="{value:'code',label:'name'}" :notFoundContent="'暂无数据'"></a-select>
</a-form-item>
</a-col>
<a-col style="text-align: right">
<a-button type="primary" @click="queryUser">
<template #icon>
<SearchOutlined />
</template>查询</a-button>&nbsp;
<a-button type="primary" @click="add">
<template #icon><plus-outlined /></template>新增</a-button>
</a-col>
</a-row>
</a-form>
</div>
<div style="margin: 0px 25px; height: calc(100% - 210px)">
<a-table :columns="columns" :data-source="data" :pagination="false" :scroll="{y:450}"><template #bodyCell="{ column, record }">
<template v-if="column.dataIndex === 'cz'">
<a-space :size="0">
<a-button type="link" primary size="small" style="color: #52c41a" @click="showInfo(record)">
<template #icon>
<eye-filled />
</template>
查看
</a-button>
<a-button type="link" primary size="small" style="color:#faad14" @click="edit(record)">
<template #icon>
<edit-filled />
</template>
修改
</a-button>
<a-button type="link" primary size="small" style="color: #52c41a" @click="reset(record)">
<template #icon>
<eye-filled />
</template>
重置密码
</a-button>
<a-popconfirm title="删除不可恢复,是否确认?" @confirm="deleteUser(record)">
<a-button type="link" primary size="small" style="color:#ff4d1f">
<template #icon>
<swap-outlined />
</template>
删除
</a-button>
</a-popconfirm>
</a-space>
</template>
</template>
</a-table>
</div>
</a-spin>
</div>
<PersonnelAdd v-if="personnelAddVisible" :flogStatus="operateStatus" :visible="personnelAddVisible" :formData="personnelInfo" @change-Cancel="changeCancelPersonnelAdd" :title="title" :updateUserList="queryUser" />
</template>
<script setup>
import { onMounted, reactive } from "vue";
import { getUserList, removePersonnel, resetPassword } from '@/api/user.js';
import { useStore } from '@/store/index.js';
import { message } from "ant-design-vue";
import PersonnelAdd from '@/views/employeeManagement/components/personnelAdd.vue';
const userstore = useStore();
const allGender = ref(userstore.returnCode(5));
const loading = ref(false);
const formState = reactive({
hotelId: userstore.hotelInfo.hotelId,
username: null,
name: null,
gender: null
});
/**下拉框筛选 */
const filterOption = (input, option) => {
return option.name.toLowerCase().indexOf(input.toLowerCase()) >= 0;
};
const personnelAddVisible = ref(false);
const operateStatus = ref(1);
const personnelInfo = ref({});
const title = ref('');
const changeCancelPersonnelAdd = () => {
personnelAddVisible.value = false;
}
const data = ref([]);
//查询用户
const queryUser = () => {
loading.value = true;
getUserList(formState).then(res => {
if (res.code == '9000') {
data.value = [];
res.data.forEach((item, index) => {
item['index'] = index + 1;
item['key'] = item.id;
data.value.push(item);
});
loading.value = false;
}
}).catch(error => {
message.error(error.message);
})
}
const columns = [
{
title: "序号",
dataIndex: "index",
},
{
title: "姓名",
dataIndex: "nickname",
},
{
title: "联系方式",
dataIndex: "phone",
},
{
title: "身份证号",
dataIndex: "identityCard",
},
{
title: "车牌号",
dataIndex: "licensePlate",
},
{
title: "操作",
dataIndex: "cz",
fixed: "right",
width: 350
}
];
//查看详情
const showInfo = (record) => {
personnelInfo.value = record;
operateStatus.value = 2;
personnelAddVisible.value = true;
title.value = '查看用户';
}
//新增
const add = () => {
personnelInfo.value = [];
operateStatus.value = 1;
personnelAddVisible.value = true;
title.value = '新增用户';
}
//编辑详情
const edit = (record) => {
personnelInfo.value = record;
operateStatus.value = 3;
personnelAddVisible.value = true;
title.value = '编辑用户';
}
//删除用户
const deleteUser = record => {
removePersonnel({ userId: record.id }).then(res => {
if (res.code == '9000') {
message.success('删除成功!');
queryUser();
}
}).catch(error => {
message.error(error.message);
});
}
const reset = record=> {
resetPassword({username: record.username, hotelId: userstore.hotelInfo.hotelId}).then(res => {
message.success('重置成功:' + res);
}).catch(error => {
message.error(error.message);
});
}
onMounted(() => {
queryUser();
})
</script>
<style lang="less">
.personnelManagement {
width: 100%;
height: 100%;
padding: 0%;
margin: 0px;
.titleBox {
display: flex;
justify-content: space-between;
align-items: center;
background: #fafafa;
border-radius: 0px 0px 2px 2px;
border: 1px solid #e9e9e9;
padding: 10px;
margin: 25px 5px;
}
.sign {
display: inline-block;
font-size: 16px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: rgba(0, 0, 0, 0.85);
line-height: 16px;
&::before {
content: "";
display: inline-block;
width: 4px;
height: 12px;
background: #3162f5;
border-radius: 2px;
margin-right: 8px;
}
}
}
</style>
<template>
<div class="rolesManagement">
<a-spin :spinning="loading">
<div class="titleBox">
<div>
<span class="sign">角色管理</span>
</div>
</div>
<div style="margin: 0px 25px 20px 25px">
<a-button type="primary" @click="queryRoleList">
<template #icon>
<SearchOutlined />
</template>查询</a-button>&nbsp;
<a-button type="primary" @click="addRoles">
<template #icon><plus-outlined /></template>新增</a-button>
</div>
<div style="margin: 0px 25px; height: calc(100% - 210px)">
<a-table :columns="columns" :data-source="data" :pagination="false" :scroll="{y:450}"><template #bodyCell="{ column, record }">
<template v-if="column.dataIndex === 'cz'">
<a-space :size="0">
<a-button type="link" primary size="small" style="color:#faad14" @click="edit(record)">
<template #icon>
<edit-filled />
</template>
修改
</a-button>
<a-popconfirm title="删除不可恢复,是否确认?" @confirm="deleteRole(record)">
<a-button type="link" primary size="small" style="color:#ff4d1f;">
<template #icon>
<swap-outlined />
</template>
删除
</a-button>
</a-popconfirm>
<a-button type="link" primary size="small" style="color: #52c41a;" @click="changeRole(record)">
<template #icon>
<edit-filled />
</template>
权限
</a-button>
</a-space>
</template>
</template>
</a-table>
</div>
</a-spin>
<RolePermissionDrawer v-if="drawerVisible" :visible="drawerVisible" :roleInfo="roleInfo" @change-Cancel="changeCancelRole" :treeData="treeData" />
<RoleAdd v-if="roleAddVisible" :flogStatus="operateStatus" :visible="roleAddVisible" :formData="roleData" @change-Cancel="changeCancelRoleAdd" :title="title" @changeData="queryRoleList" />
</div>
</template>
<script setup>
import { onMounted, reactive } from "vue";
import { queryRole, bulkRemoveRoles } from '@/api/role.js';
import { useStore } from '@/store/index.js';
import { getTree } from '@/api/menu.js';
import { message } from "ant-design-vue";
import RolePermissionDrawer from '@/views/employeeManagement/components/rolePermissionDrawer.vue';
import RoleAdd from '@/views/employeeManagement/components/roleAdd.vue';
const userstore = useStore();
const loading = ref(false);
const data = ref([]);
const roleAddVisible = ref(false);
const operateStatus = ref(1);//1为新增 2为编辑
const roleData = ref({});
const title = ref('角色新增');
//查询用户
const queryRoleList = () => {
loading.value = true;
queryRole().then(res => {
if (res.code == '9000') {
data.value = res.data;
loading.value = false;
}
}).catch(error => {
message.error(error.message);
loading.value = false;
})
}
const columns = [
{
title: "角色名称",
dataIndex: "name",
},
{
title: "创建时间",
dataIndex: "createTime",
},
{
title: "描述",
dataIndex: "description",
},
{
title: "操作",
dataIndex: "cz",
fixed: "right",
width: 300
},
];
const changeCancelRoleAdd = () => {
roleAddVisible.value = false;
}
//编辑详情
const edit = (record) => {
roleData.value = record;
operateStatus.value = 2;
title.value = '角色编辑!';
roleAddVisible.value = true;
}
//新增角色
const addRoles = () => {
operateStatus.value = 1;
title.value = '角色新增!';
roleAddVisible.value = true;
}
//删除
const deleteRole = record => {
bulkRemoveRoles([record.id]).then(res => {
if (res.code == '9000') {
message.success('删除成功!');
queryRoleList();
}
}).catch(error=>{
message.error(error.message);
});
}
//权限
const drawerVisible = ref(false);
const roleInfo = ref({});
const treeData = ref([]);
const changeRole = async record => {
getTree({ type: 'ROLE', value: record.id }).then(res => {
if (res.code == '9000') {
roleInfo.value = record;
roleInfo.value['roles'] = res.data;
drawerVisible.value = true;
}
});
}
const changeCancelRole = () => {
drawerVisible.value = false;
}
const defaultRoleMenu = (paramas, type) => {
}
onMounted(() => {
queryRoleList();
getTree({ type: 'USER', value: '1' }).then(res => {
if (res.code == '9000') {
treeData.value = res.data;
}
}).catch(error => {
console.log(error);
});
})
</script>
<style lang="less">
.rolesManagement {
width: 100%;
height: 100%;
padding: 0%;
margin: 0px;
.titleBox {
display: flex;
justify-content: space-between;
align-items: center;
background: #fafafa;
border-radius: 0px 0px 2px 2px;
border: 1px solid #e9e9e9;
padding: 10px;
margin: 25px 5px;
}
.sign {
display: inline-block;
font-size: 16px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: rgba(0, 0, 0, 0.85);
line-height: 16px;
&::before {
content: "";
display: inline-block;
width: 4px;
height: 12px;
background: #3162f5;
border-radius: 2px;
margin-right: 8px;
}
}
}
</style>
<template>
<a-modal class="handleForm" :visible="visible" :title="title" :width="600" :bodyStyle="{ padding: '16px 24px' }" @ok="handleOk" @cancel="handleCancel">
<a-form class="form" ref="formRef" :model="formState" :labelCol="{ span: 5 }" :wrapper-col="{ span: 19 }">
<a-form-item name="pass" :label="`旅馆代码`" :rules="{
required: true,
message: '请输入旅馆代码',
}">
<a-input v-model:value="formState.pass" placeholder="请输入" />
</a-form-item>
<a-form-item name="pass" :label="`旅馆名称`" :rules="{
required: true,
message: '请输入旅馆名称',
}">
<a-input v-model:value="formState.pass" placeholder="请输入" />
</a-form-item>
<a-form-item name="pass" :label="`旅馆招牌名称`" :rules="{
required: true,
message: '请输入旅馆招牌名称',
}">
<a-input v-model:value="formState.pass" placeholder="请输入" />
</a-form-item>
<a-form-item name="pass" :label="`旅馆负责人`" :rules="{
required: true,
message: '请输入旅馆负责人',
}">
<a-input v-model:value="formState.pass" placeholder="请输入" />
</a-form-item>
<a-form-item name="pass1" :label="`联系电话`" :rules="{
required: true,
}">
<a-input v-model:value="formState.pass1" placeholder="请输入" />
</a-form-item>
<a-form-item name="pass" :label="`地址`" :rules="{
required: true,
message: '请输入地址',
}">
<a-textarea v-model:value="formState.pass" placeholder="请输入" />
</a-form-item>
<a-form-item name="pass" :label="`相关证书`">
<a-upload v-model:file-list="fileList1" list-type="picture-card" @preview="handlePreview" :before-upload="beforeUpload" accept=".jpg, .jpeg, .png">
<div v-if="fileList1.length < 1">
<plus-outlined />
<div style="margin-top: 8px">Upload</div>
</div>
</a-upload>
</a-form-item>
<a-form-item name="pass" :label="`旅馆平面图`">
<a-upload v-model:file-list="fileList" list-type="picture-card" @preview="handlePreview" :before-upload="beforeUpload" :multiple="true" accept=".jpg, .jpeg, .png">
<div>
<plus-outlined />
<div style="margin-top: 8px">Upload</div>
</div>
</a-upload>
</a-form-item>
</a-form>
</a-modal>
</template>
<script setup>
import { reactive, ref, defineProps, onMounted } from "vue";
import { PlusOutlined } from "@ant-design/icons-vue";
const props = defineProps({
visible: Boolean,
title: String,
edits: Boolean,
});
const fileList = ref([]);
const fileList1 = ref([]);
const previewVisible = ref(false);
const previewImage = ref("");
const previewTitle = ref("");
const formState = reactive({
pass: "",
pass1: "",
});
const emit = defineEmits(["handleSubmit", "changeform", "previewImage"]);
const formRef = ref();
// 提交事件
const handleOk = async () => {
formRef.value?.validateFields().then(async (values) => {
await emit("handleSubmit", values);
});
};
function getBase64(file) {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = () => resolve(reader.result);
reader.onerror = (error) => reject(error);
});
}
const handlePreview = async (file) => {
if (!file.url && !file.preview) {
file.preview = await getBase64(file.originFileObj);
}
previewImage.value = file.url || file.preview;
previewVisible.value = true;
previewTitle.value =
file.name || file.url.substring(file.url.lastIndexOf("/") + 1);
await emit("previewImage", {
previewVisibles: previewVisible.value,
previewImages: previewImage.value,
previewTitles: previewTitle.value,
});
};
const beforeUpload = (file) => {
return false;
};
const checkePhonenumber = (rule, value) => {
if (value) {
const reg = /^1[3456789]\d{9}$/;
if (!reg.test(value)) {
return Promise.reject("请输入正确的手机号格式");
} else {
return Promise.resolve();
}
} else {
return Promise.reject("请输入联系电话");
}
};
// 关闭弹框事件
const handleCancel = async () => {
await emit("changeform", false);
};
onMounted(() => {
if (!props.edits) {
formState.pass = 1;
}
});
</script>
<style lang="less" scoped>
.handleForm {
:deep(.ant-modal-content .ant-modal-close-x) {
width: 49px;
height: 49px;
line-height: 49px;
}
:deep(.ant-modal-content .ant-modal-body) {
padding-block: 16px;
}
.form {
:deep(.ant-form-item-with-help) {
margin-bottom: -16px;
}
:deep(.ant-input-number, .ant-picker) {
width: 100%;
}
:deep(.ant-form-item) {
margin-right: 0;
margin-bottom: 10px;
}
}
.dropPoint {
display: flex;
justify-content: space-between;
align-items: center;
> .ant-input {
flex: 1;
margin-right: 10px;
}
}
}
</style>
\ No newline at end of file
<template>
<div class="hotelEdit">
<a-spin :spinning="loading">
<div style="margin: 0px 5px">
<a-form class="form" ref="formRef" :model="formState" :labelCol="{ span: 6 }" :wrapper-col="{ span: 18 }" layout="inline">
<table class="form-tables">
<tr>
<td colspan="3">
<a-form-item name="hotelCode" :label="`旅馆代码`" :rules="{
required: true,
message: '请输入旅馆代码',
}">
<a-input v-model:value="formState.hotelCode" :disabled="!is_edit" :allowClear="true" placeholder="请输入旅馆名称" />
</a-form-item>
</td>
<td colspan="3">
<a-form-item name="name" :label="`旅馆名称`" :rules="{
required: true,
message: '请输入旅馆名称',
}">
<a-input v-model:value="formState.name" :disabled="!is_edit" :allowClear="true" placeholder="请输入旅馆名称" />
</a-form-item>
</td>
<td colspan="3">
<a-form-item name="signboardName" :label="`旅馆招牌名称`" :rules="{
required: true,
message: '请输入旅馆招牌名称',
}">
<a-input v-model:value="formState.signboardName" :disabled="!is_edit" :allowClear="true" placeholder="请输入旅馆招牌名称" />
</a-form-item>
</td>
</tr>
<tr>
<td colspan="3">
<a-form-item name="hotelManager" :label="`旅馆负责人`" :rules="{
required: true,
message: '请输入旅馆负责人',
}">
<a-input v-model:value="formState.hotelManager" :disabled="!is_edit" :allowClear="true" placeholder="请输入旅馆负责人" />
</a-form-item>
</td>
<td colspan="6">
<a-form-item name="telephone" :label="`联系电话`" :wrapper-col="{ span: 21 }" :label-col="{ span: 3 }" :rules="[
{ required: true,message:'联系电话最多11位有效数字',max: 11,},
{ pattern:new RegExp('^[0-9]{1,}$','g'),message:'只允许包含数字'}]">
<a-input v-model:value="formState.telephone" :disabled="!is_edit" :allowClear="true" placeholder="联系电话" />
</a-form-item>
</td>
</tr>
<tr>
<td colspan="9">
<a-form-item name="address" :label="`地址`" :wrapper-col="{ span: 22 }" :label-col="{ span: 2 }" :rules="{
required: true,
message: '请输入地址',
}">
<a-input v-model:value="formState.address" :disabled="!is_edit" :allowClear="true" placeholder="请输入地址" />
</a-form-item>
</td>
</tr>
<tr>
<td colspan="9">
<a-form-item class="lgjc" :label="`旅馆检查二维码`" :wrapper-col="{ span: 22 }" :label-col="{ span: 2 }">
<a-image :width="200" :src="formState.inspectionQrCodePath" v-if="formState.inspectionQrCodePath!=''&&formState.inspectionQrCodePath!=null" />
<div style="width: 200px;height:200px;border:1px solid #a5a5a5" v-else>
</div>
<a-space :size="10" style="margin-left: 10px;">
<a-button size="large" v-if="is_edit&&formState.inspectionQrCodePath!=''&&formState.inspectionQrCodePath!=null" @click="delete_img(1)">
删除</a-button>
<a-upload name="file" @change="(file)=>handleChange(file,1)" :showUploadList="false" :before-upload="beforeUpload" v-if="is_edit">
<a-button type="primary" size="large">
选择二维码
</a-button>
</a-upload>
</a-space>
</a-form-item>
</td>
</tr>
</table>
</a-form>
</div>
<div class="titleBox">
<div>
<span class="sign">相关证书</span>
</div>
</div>
<div style="margin: 0px 25px" class="xgzs">
<div class="img-xgzs">
<div class="img-div">
<a-image :width="`100%`" :height="`100%`" :src="formState.businessLicensePath" v-if="formState.businessLicensePath!=''&&formState.businessLicensePath!=null" :fallback="default_img" />
<div style="width: 100%;height:200px;" v-else>
</div>
</div>
<div class="span-div">
<span>营业执照</span>
</div>
<div style="display: flex;justify-content: space-evenly;">
<a-button size="large" v-if="is_edit&&formState.businessLicensePath!=''&&formState.businessLicensePath!=null" @click="delete_img(2)">
删除</a-button>
<a-upload size="large" name="file" @change="(file)=>handleChange(file,2)" :showUploadList="false" :before-upload="beforeUpload" v-if="is_edit">
<a-button type="primary" size="large">
选择图片
</a-button>
</a-upload>
</div>
</div>
<div class="img-xgzs">
<div class="img-div">
<a-image :width="`100%`" :height="`100%`" :src="formState.specialIndustryLicensePath" v-if="formState.specialIndustryLicensePath!=''&&formState.specialIndustryLicensePath!=null" :fallback="default_img" />
<div style="width: 100%;height:200px;" v-else>
</div>
</div>
<div class="span-div">
<span>特种行业许可证</span>
</div>
<div style="display: flex;justify-content: space-evenly;">
<a-button size="large" v-if="is_edit&&formState.specialIndustryLicensePath!=''&&formState.specialIndustryLicensePath!=null" @click="delete_img(3)">
删除</a-button>
<a-upload size="large" name="file" @change="(file)=>handleChange(file,3)" :showUploadList="false" :before-upload="beforeUpload" v-if="is_edit">
<a-button type="primary" size="large">
选择图片
</a-button>
</a-upload>
</div>
</div>
<div class="img-xgzs">
<div class="img-div">
<a-image :width="`100%`" :height="`100%`" :src="formState.fireSafetyCertificationPath" v-if="formState.fireSafetyCertificationPath!=''&&formState.fireSafetyCertificationPath!=null" :fallback="default_img" />
<div style="width: 100%;height:200px;" v-else>
</div>
</div>
<div class="span-div">
<span>消防验收合格证明文件</span>
</div>
<div style="display: flex;justify-content: space-evenly;">
<a-button size="large" v-if="is_edit&&formState.fireSafetyCertificationPath!=''&&formState.fireSafetyCertificationPath!=null" @click="delete_img(4)">
删除</a-button>
<a-upload size="large" name="file" @change="(file)=>handleChange(file,4)" :showUploadList="false" :before-upload="beforeUpload" v-if="is_edit">
<a-button type="primary" size="large">
选择图片
</a-button>
</a-upload>
</div>
</div>
<div class="img-xgzs">
<div class="img-div">
<a-image :width="`100%`" :height="`100%`" :src="formState.systemUsageNotificationPath" v-if="formState.systemUsageNotificationPath!=''&&formState.systemUsageNotificationPath!=null" :fallback="default_img" />
<div style="width: 100%;height:200px;" v-else>
</div>
</div>
<div class="span-div">
<span>系统使用告知书</span>
</div>
<div style="display: flex;justify-content: space-evenly;">
<a-button size="large" v-if="is_edit&&formState.systemUsageNotificationPath!=''&&formState.systemUsageNotificationPath!=null" @click="delete_img(5)">
删除</a-button>
<a-upload size="large" name="file" @change="(file)=>handleChange(file,5)" :showUploadList="false" :before-upload="beforeUpload" v-if="is_edit">
<a-button type="primary" size="large">
选择图片
</a-button>
</a-upload>
</div>
</div>
</div>
<div class="titleBox">
<div>
<span class="sign">房屋平面图纸</span>
</div>
</div>
<div style="margin: 0px 25px">
<div style="display: flex;justify-content: space-evenly;">
<a-image-preview-group v-if="!is_edit">
<div v-if="formState?.planPhotoPath?.length>0" v-for="item in formState?.planPhotoPath">
<div style="width:200px;height:200px">
<a-image :width="`100%`" :height="`100%`" :src="item" />
</div>
</div>
</a-image-preview-group>
<a-upload v-model:file-list="fileList_plan_photo" list-type="picture-card" :max-count="5" :multiple="true" :before-upload="beforeUpload_arr" @preview="handlePreview" v-if="is_edit">
<div v-if="fileList_plan_photo.length < 5">
<plus-outlined />
<div style="margin-top: 8px">选择图片</div>
</div>
</a-upload>
</div>
</div>
<div class="titleBox">
<div>
<span class="sign">结构图</span>
</div>
</div>
<div style="margin: 0px 25px">
<div style="display: flex;justify-content: space-evenly;">
<a-image-preview-group v-if="!is_edit">
<div v-if="formState?.structuralPhotoPath?.length>0" v-for="item in formState?.structuralPhotoPath">
<div style="width:200px;height:200px">
<a-image :width="`100%`" :height="`100%`" :src="item" />
</div>
</div>
</a-image-preview-group>
<a-upload v-model:file-list="fileList_structural_photo" list-type="picture-card" :max-count="5" :multiple="true" :before-upload="beforeUpload_arr" @preview="handlePreview" v-if="is_edit">
<div v-if="fileList_structural_photo.length < 5">
<plus-outlined />
<div style="margin-top: 8px">选择图片</div>
</div>
</a-upload>
</div>
</div>
<div class="titleBox">
<div>
<span class="sign">内部实景图</span>
</div>
</div>
<div style="margin: 0px 25px">
<div style="display: flex;justify-content: space-evenly;">
<a-image-preview-group v-if="!is_edit">
<div v-if="formState?.internalPhotoPath?.length>0" v-for="item in formState?.internalPhotoPath">
<div style="width:200px;height:200px">
<a-image :width="`100%`" :height="`100%`" :src="item" />
</div>
</div>
</a-image-preview-group>
<a-upload v-model:file-list="fileList_internal_photo" list-type="picture-card" :max-count="5" :multiple="true" :before-upload="beforeUpload_arr" @preview="handlePreview" v-if="is_edit">
<div v-if="fileList_internal_photo.length < 5">
<plus-outlined />
<div style="margin-top: 8px">选择图片</div>
</div>
</a-upload>
</div>
</div>
<div class="titleBox">
<div>
<span class="sign">外观图</span>
</div>
</div>
<div style="margin: 0px 25px">
<div style="display: flex;justify-content: space-evenly;">
<a-image-preview-group v-if="!is_edit">
<div v-if="formState?.appearancePhotoPath?.length>0" v-for="item in formState?.appearancePhotoPath">
<div style="width:200px;height:200px">
<a-image :width="`100%`" :height="`100%`" :src="item" />
</div>
</div>
</a-image-preview-group>
<a-upload v-model:file-list="fileList_appearance_photo" list-type="picture-card" :max-count="5" :multiple="true" :before-upload="beforeUpload_arr" @preview="handlePreview" v-if="is_edit">
<div v-if="fileList_appearance_photo.length < 5">
<plus-outlined />
<div style="margin-top: 8px">选择图片</div>
</div>
</a-upload>
</div>
</div>
<a-modal :visible="previewVisible" :title="previewTitle" :footer="null" @cancel="handleCancel">
<img alt="example" style="width: 100%" :src="previewImage" />
</a-modal>
<a-affix :offset-bottom="0">
<div class="titleBox" style="margin: 0px;">
<div style="margin: 0 auto">
<a-space :size="10">
<a-button type="primary" size="large" @click="edit()" v-if="!is_edit"><template #icon>
</template>
编辑</a-button>
<a-button type="primary" size="large" @click="handleOk" v-if="is_edit"><template #icon>
</template>
保存</a-button>
<a-button size="large" v-if="is_edit" @click="qx()"><template #icon>
</template>
取消</a-button>
</a-space>
</div>
</div>
</a-affix>
</a-spin>
</div>
</template>
<script setup>
import { onMounted, ref, toRaw, watch } from "vue";
import requests from "@/utils/request_test";
import { file_img_src, dataURLtoFile, getImageFileFromUrl } from "@/utils/http_util.js";
import { message, Upload } from "ant-design-vue";
import { uploadImg } from "@/api/default.js";
import { useStore } from "@/store/index.js";
import { queryHotel, updateHotel, upLoadArrayImage, removeArrayImage } from '@/api/hotel.js'
import { forIn } from "lodash-es";
import default_img from '@/assets/img/default.png';
const props = defineProps({
visible: Boolean,
title: String,
datas: Object,
eyesEdit: Boolean,
});
const loading = ref(false);
const is_edit = ref(false);
const userstore = useStore();
const formRef = ref();
const formState = reactive({
hotelCode: '',
name: '',
signboardName: '',
hotelManager: '',
telephone: '',
address: '',
updater: '',
});
const reset = () => {
inspectionQrCode.value = false;
businessLicense.value = false;
specialIndustryLicense.value = false;
fireSafetyCertification.value = false;
systemUsageNotification.value = false;
};
const inspectionQrCode = ref(false);
const businessLicense = ref(false);
const specialIndustryLicense = ref(false);
const fireSafetyCertification = ref(false);
const systemUsageNotification = ref(false);
/**选择图片 */
const handleChange = (info, type) => {
const isPNG = info.file.type === 'image/png' || info.file.type === 'image/jpg' || info.file.type === 'image/jpeg';
if (!isPNG) {
message.error(`${info.file.name} 不是图片格式,请上传PNG||JPG||JPEG`);
} else {
const reader = new FileReader();
reader.readAsDataURL(info.file);
reader.onload = () => {
if (type == 1) {
// formState.inspectionQrCode = reader.result;
formState.inspectionQrCodePath = reader.result;
inspectionQrCode.value = true;
} else if (type == 2) {
// formState.businessLicense = reader.result;
formState.businessLicensePath = reader.result;
businessLicense.value = true;
} else if (type == 3) {
// formState.specialIndustryLicense = reader.result;
formState.specialIndustryLicensePath = reader.result;
specialIndustryLicense.value = true;
} else if (type == 4) {
// formState.fireSafetyCertification = reader.result;
formState.fireSafetyCertificationPath = reader.result;
fireSafetyCertification.value = true;
} else {
// formState.systemUsageNotification = reader.result;
formState.systemUsageNotificationPath = reader.result;
systemUsageNotification.value = true;
}
};
}
};
/**删除各类图片 */
const delete_img = (type) => {
if (type == 1) {
// formState.inspectionQrCode = '';
formState.inspectionQrCodePath = '';
inspectionQrCode.value = true;
} else if (type == 2) {
/**删除营业执照 */
// formState.businessLicense = '';
formState.businessLicensePath = '';
businessLicense.value = true;
} else if (type == 3) {
/**删除特种行业许可证 */
// formState.specialIndustryLicense = '';
formState.specialIndustryLicensePath = '';
specialIndustryLicense.value = true;
} else if (type == 4) {
/**删除消防验收合格证明文件 */
// formState.fireSafetyCertification = '';
formState.fireSafetyCertificationPath = '';
fireSafetyCertification.value = true;
} else {
/**删除系统使用告知书 */
// formState.systemUsageNotification = '';
formState.systemUsageNotificationPath = '';
systemUsageNotification.value = true;
}
}
/**多图片上传 */
const previewVisible = ref(false);
const previewImage = ref('');
const previewTitle = ref('');
const handleCancel = () => {
previewVisible.value = false;
previewTitle.value = '';
};
/**多图片的预览(未上传时的预览) */
const handlePreview = async file => {
if (!file.url && !file.preview) {
file.preview = await getBase64(file.originFileObj);
}
previewImage.value = file.url || file.preview;
previewVisible.value = true;
previewTitle.value = file.name || file.url.substring(file.url.lastIndexOf('/') + 1);
};
/**不让文件直接上传 */
const beforeUpload = (file) => {
return false;
};
/**多文件上传时选择文件,进行判断 */
const beforeUpload_arr = file => {
const isPNG = file.type === 'image/png' || file.type === 'image/jpg' || file.type === 'image/jpeg';
if (!isPNG) {
message.error(`${file.name} 不是图片格式,请上传PNG||JPG||JPEG`);
return Upload.LIST_IGNORE
}
return false;
};
/**开启编辑 */
const edit = () => {
is_edit.value = true;
}
/** 取消 */
const qx = () => {
queryJBXX();
is_edit.value = false;
}
/**提交事件 */
const handleOk = () => {
// plan_photo_64();
/**多图片上传 */
let fd = new FormData();
fd.append("hotelId", userstore.hotelInfo.hotelId);
toRaw(fileList_plan_photo.value).forEach(item => {//判断平面图是否修改
fd.append("plan_photo", item.url ? item : item.originFileObj);
})
toRaw(fileList_structural_photo.value).forEach(item => {//判断结构图是否修改
fd.append("structural_photo", item.url ? item : item.originFileObj);
})
toRaw(fileList_internal_photo.value).forEach(item => {//判断内部实景图是否修改
fd.append("internal_photo", item.url ? item : item.originFileObj);
})
toRaw(fileList_appearance_photo.value).forEach(item => {//判断外观图是否修改
fd.append("appearance_photo", item.url ? item : item.originFileObj);
})
formRef.value?.validateFields().then((values) => {
/**批量操作上传图片 */
const arr_http = [];
if (inspectionQrCode.value && formState.inspectionQrCodePath != '') {
arr_http.push(file_img_src(formState.inspectionQrCodePath, userstore.hotelInfo.hotelId, 'HOTEL'));
} else {
arr_http.push("");
}
if (businessLicense.value && formState.businessLicensePath != '') {
arr_http.push(file_img_src(formState.businessLicensePath, userstore.hotelInfo.hotelId, 'HOTEL'));
} else {
arr_http.push("");
}
if (specialIndustryLicense.value && formState.specialIndustryLicensePath != '') {
arr_http.push(file_img_src(formState.specialIndustryLicensePath, userstore.hotelInfo.hotelId, 'HOTEL'));
} else {
arr_http.push("");
}
if (fireSafetyCertification.value && formState.fireSafetyCertificationPath != '') {
arr_http.push(file_img_src(formState.fireSafetyCertificationPath, userstore.hotelInfo.hotelId, 'HOTEL'));
} else {
arr_http.push("");
}
if (systemUsageNotification.value && formState.systemUsageNotificationPath != '') {
arr_http.push(file_img_src(formState.systemUsageNotificationPath, userstore.hotelInfo.hotelId, 'HOTEL'));
} else {
arr_http.push("");
}
arr_http.push(upLoadArrayImage(fd));
/**单个删除相关证书和二维码 */
const arr_http_delete = [];
if (inspectionQrCode.value && formState.inspectionQrCode) {
arr_http_delete.push(formState.inspectionQrCode)
}
if (businessLicense.value && formState.businessLicense) {
arr_http_delete.push(formState.businessLicense)
}
if (specialIndustryLicense.value && formState.specialIndustryLicense) {
arr_http_delete.push(formState.specialIndustryLicense)
}
if (fireSafetyCertification.value && formState.fireSafetyCertification) {
arr_http_delete.push(formState.fireSafetyCertification)
}
if (systemUsageNotification.value && formState.systemUsageNotification) {
arr_http_delete.push(formState.systemUsageNotification)
}
// console.log(arr_http_delete)
// return
loading.value = true;
Promise.all(arr_http).then(([res1, res2, res3, res4, res5, res6]) => {
// let fds = new FormData();
// fds.append("bucket", 'HOTEL');
// fds.append("hotelId", userstore.hotelInfo.hotelId);
// fds.append("filenames", arr_http_delete);
removeArrayImage({ bucket: 'HOTEL', hotelId: userstore.hotelInfo.hotelId, filenames: arr_http_delete }).then(a => {
console.log('删除成功');
})
const arr = { ...formState };
if (inspectionQrCode.value) {
arr.inspectionQrCode = res1;
}
if (businessLicense.value) {
arr.businessLicense = res2;
}
if (specialIndustryLicense.value) {
arr.specialIndustryLicense = res3;
}
if (fireSafetyCertification.value) {
arr.fireSafetyCertification = res4;
}
if (systemUsageNotification.value) {
arr.systemUsageNotification = res5;
}
// arr.inspectionQrCodePath = '';
// arr.businessLicensePath = '';
// arr.specialIndustryLicensePath = '';
// arr.fireSafetyCertificationPath = '';
// arr.systemUsageNotificationPath = '';
delete arr.inspectionQrCodePath;
delete arr.businessLicensePath;
delete arr.specialIndustryLicensePath;
delete arr.fireSafetyCertificationPath;
delete arr.systemUsageNotificationPath;
updateHotel(arr).then(res => {
if (res?.code == 9000) {
message.success('修改成功');
queryJBXX();
reset();
is_edit.value = false;
}
loading.value = false;
}).catch(error => {
message.warning('修改失败')
loading.value = false;
})
});
});
};
const setValue = (values) => {
forIn(values, (value, key) => (formState[key] = value));
};
function getBase64(file) {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = () => resolve(reader.result);
reader.onerror = error => reject(error);
});
}
/**旅馆基本信息查询 */
const queryJBXX = async () => {
loading.value = true;
queryHotel({ hotelId: userstore.hotelInfo.hotelId }).then(res => {
if (res?.code == 9000) {
setValue(res.data);
fileList_plan_photo.value = [];
if (res.data.planPhotoPath.length > 0) {
res.data.planPhotoPath.forEach(item => {
getImageFileFromUrl(item, Date.parse(new Date()) + ".png").then(e => {
e.url = URL.createObjectURL(e);
fileList_plan_photo.value.push(e);
})
})
}
fileList_structural_photo.value = [];
if (res.data.structuralPhotoPath.length > 0) {
res.data.structuralPhotoPath.forEach(item => {
getImageFileFromUrl(item, Date.parse(new Date()) + ".png").then(e => {
e.url = URL.createObjectURL(e);
fileList_structural_photo.value.push(e);
})
})
}
fileList_internal_photo.value = [];
if (res.data.internalPhotoPath.length > 0) {
res.data.internalPhotoPath.forEach(item => {
getImageFileFromUrl(item, Date.parse(new Date()) + ".png").then(e => {
e.url = URL.createObjectURL(e);
fileList_internal_photo.value.push(e);
})
})
}
fileList_appearance_photo.value = [];
if (res.data.appearancePhotoPath.length > 0) {
res.data.appearancePhotoPath.forEach(item => {
getImageFileFromUrl(item, Date.parse(new Date()) + ".png").then(e => {
e.url = URL.createObjectURL(e);
fileList_appearance_photo.value.push(e);
})
})
}
// /**将当前5个单传图片转为file文件 */
// if (res.data.inspectionQrCode != '' || res.data.inspectionQrCode != null) {//二维码
// getImageFileFromUrl(res.data.inspectionQrCodePath, Date.parse(new Date()) + ".png").then(e => {//路径转为文件
// e.url = URL.createObjectURL(e);
// getBase64(e).then(es=>{//文件转为Base64
// inspectionQrCode_file.value = es;
// });
// })
// }
// if (res.data.businessLicensePath != '' || res.data.businessLicensePath != null) {//营业执照
// getImageFileFromUrl(res.data.businessLicensePath, Date.parse(new Date()) + ".png").then(e => {//路径转为文件
// e.url = URL.createObjectURL(e);
// getBase64(e).then(es=>{//文件转为Base64
// businessLicense_file.value = es;
// });
// })
// }
// if (res.data.specialIndustryLicensePath != '' || res.data.specialIndustryLicensePath != null) {//特种行业许可证
// getImageFileFromUrl(res.data.specialIndustryLicensePath, Date.parse(new Date()) + ".png").then(e => {//路径转为文件
// e.url = URL.createObjectURL(e);
// getBase64(e).then(es=>{//文件转为Base64
// specialIndustryLicense_file.value = es;
// });
// })
// }
// if (res.data.fireSafetyCertificationPath != '' || res.data.fireSafetyCertificationPath != null) {//消防验收合格证明文件
// getImageFileFromUrl(res.data.fireSafetyCertificationPath, Date.parse(new Date()) + ".png").then(e => {//路径转为文件
// e.url = URL.createObjectURL(e);
// getBase64(e).then(es=>{//文件转为Base64
// fireSafetyCertification_file.value = es;
// });
// })
// }
// if (res.data.systemUsageNotificationPath != '' || res.data.systemUsageNotificationPath != null) {//系统使用告知书
// getImageFileFromUrl(res.data.systemUsageNotificationPath, Date.parse(new Date()) + ".png").then(e => {//路径转为文件
// e.url = URL.createObjectURL(e);
// getBase64(e).then(es=>{//文件转为Base64
// systemUsageNotification_file.value = es;
// });
// })
// }
}
loading.value = false;
}).catch(error => {
loading.value = false;
})
}
/**5个单传图片 */
const inspectionQrCode_file = ref('');
const businessLicense_file = ref('');
const specialIndustryLicense_file = ref('');
const fireSafetyCertification_file = ref('');
const systemUsageNotification_file = ref('');
onMounted(() => {
queryJBXX();
});
/**判断plan_photo 平面图*/
const fileList_plan_photo = ref([]);//获取平面图的文件
const file_64_plan_photo = ref([]);//获取修改后的文件转为64位
// const plan_photo_64 = () => {
// file_64_plan_photo.value = [];
// fileList_plan_photo.value.map(item => {
// getBase64(toRaw(item).originFileObj).then(res => {
// file_64_plan_photo.value.push(dataURLtoFile(res, Date.parse(new Date()) + ".png"));
// });
// })
// // fileList_plan_photo.value.map(item => {
// // const reader = new FileReader();
// // reader.readAsDataURL(toRaw(item).originFileObj);
// // reader.onload = () => {
// // file_64_plan_photo.value.push(dataURLtoFile(reader.result, Date.parse(new Date()) + ".png"));
// // };
// // })
// }
/**判断structural_photo 结构图*/
const fileList_structural_photo = ref([]);//获取平面图的文件
const file_64_structural_photo = ref([]);//获取修改后的文件转为64位
// const structural_photo_64 = () => {
// file_64_structural_photo.value = [];
// fileList_structural_photo.value.map(item => {
// getBase64(toRaw(item).originFileObj).then(res => {
// file_64_structural_photo.value.push(dataURLtoFile(res, Date.parse(new Date()) + ".png"));
// });
// })
// }
/**判断internal_photo 内部实景图*/
const fileList_internal_photo = ref([]);//获取平面图的文件
const file_64_internal_photo = ref([]);//获取修改后的文件转为64位
// const internal_photo_64 = () => {
// file_64_internal_photo.value = [];
// fileList_internal_photo.value.map(item => {
// getBase64(toRaw(item).originFileObj).then(res => {
// file_64_internal_photo.value.push(dataURLtoFile(res, Date.parse(new Date()) + ".png"));
// });
// })
// }
/**判断appearance_photo 外观图*/
const fileList_appearance_photo = ref([]);//获取平面图的文件
const file_64_appearance_photo = ref([]);//获取修改后的文件转为64位
// const appearance_photo_64 = () => {
// file_64_appearance_photo.value = [];
// fileList_appearance_photo.value.map(item => {
// getBase64(toRaw(item).originFileObj).then(res => {
// file_64_appearance_photo.value.push(dataURLtoFile(res, Date.parse(new Date()) + ".png"));
// });
// })
// }
</script>
<style lang="less">
.hotelEdit {
width: 100%;
height: 100%;
padding: 0px;
margin: 0px;
overflow-y: auto;
.form {
.ant-form-item-with-help {
margin-bottom: 0px;
}
.ant-form-item-label {
flex: auto;
}
.lgjc {
.ant-form-item-label {
display: flex;
align-items: center;
justify-content: flex-end;
}
.ant-form-item-control {
margin: 20px 0px;
}
.ant-form-item-control-input-content {
display: flex;
}
}
}
.xgzs {
display: flex;
justify-content: space-evenly;
.img-xgzs {
.img-div {
// border-image-source: radial-gradient(
// 60% 60%,
// transparent 0px,
// transparent 100%,
// #6691ef 100%
// );
// border-image-slice: 1;
// border-width: 1px;
// border-style: solid;
// border-image-outset: 0px;
// width: calc(100% - 40px);
// height: calc(100% - 40px);
border: 1px solid #a5a5a5;
padding: 5px;
width: 200px;
height: 200px;
.img-span {
margin: 23px auto;
width: 14px;
line-height: 35px;
font-weight: 400;
font-size: 15px;
}
}
.span-div {
line-height: 50px;
text-align: center;
font-weight: 600;
letter-spacing: 2px;
}
}
}
.ant-upload-list {
display: flex;
justify-content: center;
}
.ant-image-img {
object-fit: contain;
}
.form-tables {
width: 100%;
border-collapse: collapse;
tr {
width: 100%;
height: 60px;
td {
border: 1px solid #e7e7e7;
max-width: 222px;
}
}
}
.titleBox {
display: flex;
justify-content: space-between;
align-items: center;
background: #fafafa;
border-radius: 0px 0px 2px 2px;
border: 1px solid #e9e9e9;
padding: 10px;
margin: 25px 5px;
}
.sign {
display: inline-block;
font-size: 16px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: rgba(0, 0, 0, 0.85);
line-height: 16px;
&::before {
content: "";
display: inline-block;
width: 4px;
height: 12px;
background: #3162f5;
border-radius: 2px;
margin-right: 8px;
}
}
}
</style>
\ No newline at end of file
<template>
<div class="main">
<a-spin :spinning="loading">
<div class="titleBox">
<div>
<span class="sign">旅馆基本信息</span>
</div>
</div>
<div style="margin: 0px 5px">
<a-descriptions title="" bordered size="small">
<a-descriptions-item label="旅馆代码:">{{ dataInfo?.hotelCode }}</a-descriptions-item>
<a-descriptions-item label="旅馆名称:">{{ dataInfo?.name }}</a-descriptions-item>
<a-descriptions-item label="旅馆招牌名称:">{{ dataInfo?.signboardName }}</a-descriptions-item>
<a-descriptions-item label="旅馆负责人:">{{ dataInfo?.hotelManager }}</a-descriptions-item>
<a-descriptions-item label="联系电话:" :span="2">{{ dataInfo?.telephone }}</a-descriptions-item>
<a-descriptions-item label="地址:" :span="3">{{ dataInfo?.address }}</a-descriptions-item>
<a-descriptions-item label="旅馆房间数:">{{ data_statistics?.hotelRooms }}</a-descriptions-item>
<a-descriptions-item label="入住房间数:">{{ data_statistics?.numberOfRoomsOccupied }}</a-descriptions-item>
<a-descriptions-item label="房屋入住率:">
<a-progress :stroke-color="{
'0%': '#108ee9',
'100%': '#87d068',
}" :percent="data_statistics?.occupancyRate?.toFixed(2)" />
</a-descriptions-item>
<a-descriptions-item label="入住旅客数:"> {{ data_statistics?.numberOfOccupants }}</a-descriptions-item>
<a-descriptions-item label="内宾数:">{{ data_statistics?.numberOfDomesticGuests }} </a-descriptions-item>
<a-descriptions-item label="外宾数:">{{ data_statistics?.numberOfForeignGuests }} </a-descriptions-item>
<a-descriptions-item label="旅馆检查二维码:">
<a-image :width="200" :src="dataInfo?.inspectionQrCodePath" v-if="dataInfo?.inspectionQrCodePath" />
</a-descriptions-item>
</a-descriptions>
</div>
<div class="titleBox">
<div>
<span class="sign">相关证书照片</span>
</div>
</div>
<div class="zp-class">
<a-image-preview-group>
<div class="xgzs">
<div class="img-xgzs">
<div class="img-div">
<a-image :width="`100%`" :height="`100%`" :src="dataInfo?.businessLicensePath" v-if="dataInfo?.businessLicensePath"/>
</div>
<div class="span-div">
<span>营业执照</span>
</div>
</div>
<div class="img-xgzs">
<div class="img-div">
<a-image :width="`100%`" :height="`100%`" :src="dataInfo?.specialIndustryLicensePath" v-if="dataInfo?.specialIndustryLicensePath"/>
</div>
<div class="span-div">
<span>特种行业许可证</span>
</div>
</div>
<div class="img-xgzs">
<div class="img-div">
<a-image :width="`100%`" :height="`100%`" :src="dataInfo?.fireSafetyCertificationPath" v-if="dataInfo?.fireSafetyCertificationPath"/>
</div>
<div class="span-div">
<span>消防验收合格证明文件</span>
</div>
</div>
<div class="img-xgzs">
<div class="img-div">
<a-image :width="`100%`" :height="`100%`" :src="dataInfo?.systemUsageNotificationPath" v-if="dataInfo?.systemUsageNotificationPath"/>
</div>
<div class="span-div">
<span>系统使用告知书</span>
</div>
</div>
</div>
</a-image-preview-group>
</div>
<div class="titleBox">
<div>
<span class="sign">平面图</span>
</div>
</div>
<div class="zp-class" style="margin-bottom: 20px;">
<a-image-preview-group>
<div v-if="dataInfo?.planPhotoPath?.length>0" v-for="item in dataInfo?.planPhotoPath">
<div style="width:200px;height:200px">
<a-image :width="`100%`" :height="`100%`" :src="item" />
</div>
</div>
</a-image-preview-group>
</div>
<div class="titleBox">
<div>
<span class="sign">结构图</span>
</div>
</div>
<div class="zp-class" style="margin-bottom: 20px;">
<a-image-preview-group>
<div v-if="dataInfo?.structuralPhotoPath?.length>0" v-for="item in dataInfo?.structuralPhotoPath">
<div style="width:200px;height:200px">
<a-image :width="`100%`" :height="`100%`" :src="item" />
</div>
</div>
</a-image-preview-group>
</div>
<div class="titleBox">
<div>
<span class="sign">内部实景图</span>
</div>
</div>
<div class="zp-class" style="margin-bottom: 20px;">
<a-image-preview-group>
<div v-if="dataInfo?.internalPhotoPath?.length>0" v-for="item in dataInfo?.internalPhotoPath">
<div style="width:200px;height:200px">
<a-image :width="`100%`" :height="`100%`" :src="item" />
</div>
</div>
</a-image-preview-group>
</div>
<div class="titleBox">
<div>
<span class="sign">外观图</span>
</div>
</div>
<div class="zp-class" style="margin-bottom: 20px;">
<a-image-preview-group>
<div v-if="dataInfo?.appearancePhotoPath?.length>0" v-for="item in dataInfo?.appearancePhotoPath">
<div style="width:200px;height:200px">
<a-image :width="`100%`" :height="`100%`" :src="item" />
</div>
</div>
</a-image-preview-group>
</div>
</a-spin>
</div>
</template>
<script setup>
import { onMounted } from "vue";
import { useStore } from "@/store/index.js";
import { queryHotel } from '@/api/hotel.js'
import { forIn } from "lodash-es";
import { queryRoomStatus } from '@/api/room.js';
const userstore = useStore();
const dataInfo = ref({});
const data_statistics = ref({});
const loading = ref(false);
/**旅馆基本信息查询 */
const queryHotels = () => {
return new Promise((resolve) => {
queryHotel({ hotelId: userstore.hotelInfo.hotelId }).then((res) => {
if (res.code == 9000) {
resolve(res.data);
} else {
resolve("");
}
});
});
}
/**旅馆统计列表 */
const hotelStatistics = () => {
return new Promise((resolve) => {
queryRoomStatus({ hotelId: userstore.hotelInfo.hotelId }).then((res) => {
if (res.code == 9000) {
resolve(res.data);
} else {
resolve("");
}
});
});
}
/**查询 */
const query = () => {
loading.value = true;
Promise.all([queryHotels(), hotelStatistics()]).then(([res1, res2]) => {
dataInfo.value = res1;
console.log(res1)
data_statistics.value = res2;
loading.value = false;
}).catch(error=>{
loading.value = false;
})
}
onMounted(() => {
query();
});
</script>
<style lang="less" scoped>
.main {
width: 100%;
height: 100%;
padding: 0px;
margin: 0px;
overflow-y: auto;
:deep(.ant-descriptions-bordered .ant-descriptions-item-label) {
text-align: right;
width: 140px;
color: #0e5de5;
font-weight: 600;
}
:deep(.ant-descriptions-bordered .ant-descriptions-item-content) {
font-weight: 600;
color: #434343;
width: 200px;
}
.titleBox {
display: flex;
justify-content: space-between;
align-items: center;
background: #fafafa;
border-radius: 0px 0px 2px 2px;
border: 1px solid #e9e9e9;
padding: 10px;
margin: 25px 5px;
}
.sign {
display: inline-block;
font-size: 16px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: rgba(0, 0, 0, 0.85);
line-height: 16px;
&::before {
content: "";
display: inline-block;
width: 4px;
height: 12px;
background: #3162f5;
border-radius: 2px;
margin-right: 8px;
}
}
.zp-class {
margin: 0px 5px;
display: flex;
flex-direction: row;
flex-wrap: wrap;
justify-content: space-evenly;
.xgzs {
display: flex;
justify-content: space-evenly;
width: 100%;
.img-xgzs {
.img-div {
border: 1px solid #a5a5a5;
padding: 5px;
width: 200px;
height: 200px;
.img-span {
margin: 23px auto;
width: 14px;
line-height: 35px;
font-weight: 400;
font-size: 15px;
}
}
.span-div {
line-height: 50px;
text-align: center;
font-weight: 600;
letter-spacing: 2px;
}
}
}
}
:deep(.ant-image-img) {
object-fit: contain;
}
}
</style>
\ No newline at end of file
<template>
<div class="inland">
<a-spin :spinning="loading">
<div class="titleBox">
<div>
<span class="sign">内宾登记信息列表</span>
</div>
</div>
<div style="margin: 0px 25px">
<a-form ref="formRef" name="advanced_search" class="ant-advanced-search-form" :model="formState">
<a-row :gutter="24">
<a-col :span="3">
<a-form-item name="isVerification" label="是否核验">
<a-select v-model:value="formState.isVerification" placeholder="请选择" :allowClear="true">
<a-select-option value="1"></a-select-option>
<a-select-option value="0"></a-select-option>
</a-select>
</a-form-item>
</a-col>
<a-col :span="3">
<a-form-item name="name" label="姓名">
<a-input v-model:value="formState.name" placeholder="请输入姓名" :allowClear="true"></a-input>
</a-form-item>
</a-col>
<a-col :span="3">
<a-form-item name="gender" label="性别">
<a-select v-model:value="formState.gender" placeholder="请选择性别" :allowClear="true" :options="options_gender" optionLabelProp="name" show-search :filter-option="filterOption" :fieldNames="{ label: 'name', value: 'code' }">
</a-select>
</a-form-item>
</a-col>
<a-col :span="3">
<a-form-item name="nation" label="民族">
<a-select show-search v-model:value="formState.nation" :filter-option="filterOption" placeholder="请选择民族" :allowClear="true" optionLabelProp="name" :options="options_nation" :fieldNames="{ label: 'name', value: 'code' }">
</a-select>
</a-form-item>
</a-col>
<a-col :span="5">
<a-form-item label="出生日期">
<a-range-picker v-model:value="csrq" @change="(data, dateString) => handleChangeTime(data, dateString, 1)" />
</a-form-item>
</a-col>
<a-col :span="7">
<a-form-item name="provincialUrbanAreas" label="户籍地省市县(区)">
<a-select show-search v-model:value="formState.provincialUrbanAreas" :filter-option="filterOption" placeholder="请选择户籍地" :allowClear="true" optionLabelProp="name" :options="options_provincialUrbanAreas" :fieldNames="{ label: 'name', value: 'code' }">
<template #option="{ name, code }">
{{ name }}&nbsp;&nbsp;{{ "[" + code + "]" }}
</template>
</a-select>
</a-form-item>
</a-col>
<a-col :span="7">
<a-form-item label="入住时间">
<a-range-picker v-model:value="rzsj" show-time @change="(data, dateString) => handleChangeTime(data, dateString, 2)" />
</a-form-item>
</a-col>
<a-col :span="7">
<a-form-item label="离店时间">
<a-range-picker v-model:value="ldsj" show-time @change="(data, dateString) => handleChangeTime(data, dateString, 3)" />
</a-form-item>
</a-col>
<a-col :span="3">
<a-form-item name="state" label="旅客状态">
<a-select show-search v-model:value="formState.state" :filter-option="filterOption" placeholder="请选择旅客状态" :allowClear="true" :options="options_state" optionLabelProp="name" :fieldNames="{ label: 'name', value: 'code' }">
</a-select>
</a-form-item>
</a-col>
<a-col :span="3">
<a-form-item name="roomId" label="房间号">
<a-select show-search v-model:value="formState.roomId" :filter-option="filterOption" placeholder="请选择房间号" :options="options_room" :allowClear="true" optionLabelProp="name" :fieldNames="{ label: 'name', value: 'id' }">
</a-select>
</a-form-item>
</a-col>
<a-col>
<a-button type="primary" @click="queryList()">查询</a-button>
<a-button style="margin: 0 8px" @click="qx()">清除</a-button>
</a-col>
</a-row>
</a-form>
</div>
<div style="margin: 0px 25px">
<a-table :row-selection="rowSelection_abroad" :rowKey="item=>JSON.stringify(item.id)" :columns="columns" :data-source="data" :pagination="false"><template #bodyCell="{ column, record, index }">
<template v-if="column.dataIndex === 'cz'">
<a-space :size="0">
<a-button type="link" primary size="small" style="color: #52c41a" @click="eyes(index, record)">
<template #icon>
<eye-filled />
</template>
查看
</a-button>
<a-button type="link" primary size="small" style="color: #faad14" @click="edits(index, record)">
<template #icon>
<edit-filled />
</template>
修改
</a-button>
<a-popconfirm v-if="record.state === 'ARRIVE'" title="是否离店" @confirm="setState(index, record)">
<a-button type="link" primary size="small" style="color: #ff4d1f">
<template #icon>
<swap-outlined />
</template>
离店
</a-button>
</a-popconfirm>
<a-button type="link" primary size="small" @click="visitorJump(record)">
<template #icon>
<contacts-filled />
</template>
访客登记
</a-button>
</a-space>
</template>
</template>
</a-table>
<a-pagination v-model:current="formState.current" show-quick-jumper show-size-changer :total="total" v-show="data.length > 0" size="small" :show-total="(total) => `总数共: ${total} 条`" @change="onChange" style="margin: 20px 0px" />
</div>
</a-spin>
<InlandEyes v-if="hotelFormVisible" :visible="hotelFormVisible" :id="info_id" :title="titles" @change-Cancel="changeCancel" @change-Edit="changeEdit" :visibleEdit="hotelFormVisible_edit_s" />
<InlandEdit v-if="hotelFormVisible_edit" :visible="hotelFormVisible_edit" :eyesEdit="hotelFormVisible_eyes_edit" :datas="data_edit" :title="title_edit" @change-Cancel="changeCancel_edit" @change-Data="changeData" />
</div>
</template>
<script setup>
import { onMounted, reactive, ref, watch, toRaw } from "vue";
import {
inlandQuery,
inlandGender,
inlandCheckOut,
} from "@/api/domesticGuestCheckIn";
import { useStore } from "@/store/index.js";
import InlandEdit from "@/views/inland/inlandEdit.vue";
import InlandEyes from "@/views/inland/inlandEyes.vue";
import { message } from "ant-design-vue";
import router from "../../router";
const userstore = useStore();
const loading = ref(false);
const formRef = ref();
const formState = reactive({
name: "",
gender: "",
nation: "",
dateBirthEnd: "",
dateBirthStart: "",
provincialUrbanAreas: "",
checkinTimeEnd: "",
checkinTimeStart: "",
departureTimeEnd: "",
departureTimeStart: "",
state: "",
roomId: "",
hotelId: userstore.hotelInfo.hotelId, //旅馆id
current: 1,
pageSize: 10,
isVerification: ''
});
const hotelFormVisible = ref(false);
/**下拉框筛选 */
const filterOption = (input, option) => {
return option.name.toLowerCase().indexOf(input.toLowerCase()) >= 0;
};
/**表格 */
const columns = [
{
title: "姓名",
dataIndex: "name",
},
{
title: "证件号码",
dataIndex: "certificateNumber",
},
{
title: "性别",
dataIndex: "genderName",
},
{
title: "民族",
dataIndex: "nationName",
},
{
title: "户籍地省市县区",
dataIndex: "provincialUrbanAreasName",
},
{
title: "房号",
dataIndex: "roomName",
},
{
title: "所属团队",
dataIndex: "teamName",
},
{
title: "入住时间",
dataIndex: "checkinTime",
},
{
title: "离店时间",
dataIndex: "departureTime",
},
{
title: "旅客状态",
dataIndex: "stateName",
},
{
title: "是否核验",
dataIndex: "isVerification",
},
{
title: "操作",
dataIndex: "cz",
fixed: "right",
width: 200,
},
];
const data = ref([]);
const selectedRowKeys_abroad = ref([]);/**当前选中集合 */
const rowSelection_abroad = {
onChange: (selectedRowKeys, selectedRows) => {
selectedRowKeys_abroad.value = selectedRowKeys;
},
}
/**时间变化 */
const handleChangeTime = (data, dataArr, type) => {
if (dataArr && dataArr.length > 0) {
if (type == 1) {
formState.dateBirthEnd = dataArr[1];
formState.dateBirthStart = dataArr[0];
} else if (type == 2) {
formState.checkinTimeEnd = dataArr[1];
formState.checkinTimeStart = dataArr[0];
} else {
formState.departureTimeEnd = dataArr[1];
formState.departureTimeStart = dataArr[0];
}
} else {
if (type == 1) {
formState.dateBirthEnd = "";
formState.dateBirthStart = "";
} else if (type == 2) {
formState.checkinTimeEnd = "";
formState.checkinTimeStart = "";
} else {
formState.departureTimeEnd = "";
formState.departureTimeStart = "";
}
}
};
/**分页 */
const total = ref(0);
/**分页切换 */
const onChange = (page, pageSize) => {
formState.current = page;
formState.pageSize = pageSize;
queryList();
};
/**查看 */
const info_id = ref({});
const titles = ref("查看内宾详情");
const changeCancel = () => {
hotelFormVisible.value = false;
};
const hotelFormVisible_edit_s = ref(false);
const indexs = ref(0);
const eyes = (index, e) => {
indexs.value = index;
info_id.value = e.id;
hotelFormVisible.value = true;
hotelFormVisible_edit_s.value = true;
};
const changeEdit = (e) => {
hotelFormVisible_eyes_edit.value = true;
hotelFormVisible.value = false;
hotelFormVisible_edit.value = true;
data_edit.value = e.value;
};
/**出生日期 */
const csrq = ref(undefined);
const rzsj = ref(undefined);
const ldsj = ref(undefined);
/**清除 */
const qx = () => {
formRef.value.resetFields();
csrq.value = undefined;
rzsj.value = undefined;
ldsj.value = undefined;
formState.dateBirthEnd = "";
formState.dateBirthStart = "";
formState.checkinTimeEnd = "";
formState.checkinTimeStart = "";
formState.departureTimeEnd = "";
formState.departureTimeStart = "";
}
/**修改内宾 */
const edits = (index, e) => {
indexs.value = index;
data_edit.value = e;
hotelFormVisible_eyes_edit.value = false;
hotelFormVisible_edit.value = true;
};
const hotelFormVisible_edit = ref(false);
const hotelFormVisible_eyes_edit = ref(false);
/**判断是从查看界面进入还是直接编辑 */
const data_edit = ref({});
const title_edit = ref("修改内宾");
const changeCancel_edit = (e) => {
if (toRaw(e)) {
hotelFormVisible.value = true;
}
hotelFormVisible_edit.value = false;
};
const changeData = (e) => {
queryList();
eyes(indexs.value, e);
};
/**离店 */
// const cancel_ld = (e) => {
// message.error("操作已取消!!!");
// };
const setState = async (index, record) => {
loading.value = true;
await inlandCheckOut([record.id])
.then((res) => {
loading.value = false;
if (res?.code == 9000) {
message.success("离店成功");
queryList();
}
})
.catch((res) => {
loading.value = false;
message.warning("离店失败");
});
};
/**分页查询 */
const queryList = async () => {
loading.value = true;
await inlandQuery(formState)
.then((res) => {
if (res?.code == 9000) {
data.value = res.data.records;
total.value = res.data.total;
}
loading.value = false;
})
.catch((res) => {
loading.value = false;
});
};
/**访客登记跳转 */
const visitorJump = (record) => {
// if(record.roomId==''||record.roomId==undefined){
// message.warning('该旅馆暂未入住')
// }
router.push({ path: '/visitor/visitorAdd', query: { roomId: record.roomId, name: record.name } });
}
/**字典表查询---性别*/
const options_room = ref(userstore.roomAll); //房间字典
const options_gender = ref(userstore.returnCode(5)); //性别
const options_nation = ref(userstore.returnCode(10)); //民族
const options_state = ref(userstore.returnCode(2)); //民族
const options_provincialUrbanAreas = ref(userstore.returnCode(11)); //省市县区
onMounted(() => {
// gender();
queryList();
});
</script>
<style lang="less">
.inland {
width: 100%;
height: 100%;
padding: 0%;
margin: 0px;
overflow-y: auto;
.titleBox {
display: flex;
justify-content: space-between;
align-items: center;
background: #fafafa;
border-radius: 0px 0px 2px 2px;
border: 1px solid #e9e9e9;
padding: 10px;
margin: 25px 5px;
}
.sign {
display: inline-block;
font-size: 16px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: rgba(0, 0, 0, 0.85);
line-height: 16px;
&::before {
content: "";
display: inline-block;
width: 4px;
height: 12px;
background: #3162f5;
border-radius: 2px;
margin-right: 8px;
}
}
}
</style>
\ No newline at end of file
<template>
<a-spin :spinning="loading">
<div class="inlandFrom">
<div class="titleBox">
<div>
<span class="sign">内宾登记表</span>
</div>
</div>
<div style="margin: 0px 5px">
<a-form class="form" ref="formRef" :model="formState" :labelCol="{ span: 6 }" :wrapper-col="{ span: 18 }" layout="inline">
<table class="form-tables">
<tr>
<td colspan="3">
<a-form-item name="roomId" :label="`房间号`" :rules="{
required: true,
message: '请选择房间号',
}">
<a-select show-search v-model:value="formState.roomId" :filter-option="filterOption" :options="options_room" placeholder="请选择房间号" :allowClear="true" optionLabelProp="name" :fieldNames="{ label: 'name', value: 'id' }">
</a-select>
</a-form-item>
</td>
<td colspan="3">
<a-form-item name="checkinTime" :label="`入住时间`">
<a-date-picker show-time placeholder="请选择时间" v-model:value="formState.checkinTime" style="width: 100%" value-format="YYYY-MM-DD HH:mm:ss" />
</a-form-item>
</td>
<td colspan="2" rowspan="9">
<div style="
display: flex;
flex-direction: row;
justify-content: space-around;
flex-wrap: wrap;
">
<div class="img-wp">
<div class="img-div">
<div class="img-span" v-if="formState.certificatePhoto == ''">
<span>证件人像</span>
</div>
<a-image :width="`100%`" :height="`100%`" :src="formState.certificatePhoto" v-else />
</div>
</div>
<div class="img-wp">
<div class="img-div">
<div class="img-span" v-if="formState.sitePhoto == ''">
<span>现场人像</span>
</div>
<a-image :width="`100%`" :height="`100%`" :src="formState.sitePhoto" v-else />
</div>
<div class="check-div" style="text-align: center;" @click="OnCamera()">
<a-button type="primary">获取头像</a-button>
</div>
<div class="check-div" style="text-align: center;margin-top: 10px;">
<a-upload name="file" @change="handleChange" :showUploadList="false" :before-upload="beforeUpload">
<a-button>
选择头像
</a-button>
</a-upload>
</div>
</div>
</div>
</td>
</tr>
<tr>
<td colspan="3">
<a-form-item name="certificateType" :label="`证件类型`" :rules="{
required: true,
message: '请选择证件类型',
}">
<a-select show-search v-model:value="formState.certificateType" :filter-option="filterOption" :options="options_certificateType" placeholder="请选择证件类型" :allowClear="true" optionLabelProp="name" :fieldNames="{ label: 'name', value: 'code' }">
</a-select>
</a-form-item>
</td>
<td colspan="3">
<a-form-item name="certificateNumber" :label="`证件号码`" :rules="[
{ required: true,message:'证件号码必须为18位数字加字母组合',len: 18,},
{ pattern:new RegExp(/^[1-9]\d{5}(19|20)\d{2}((0[1-9])|(1[0-2]))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$/,'g'),message:'请输入有效的证件号码'}]">
<a-input v-model:value="formState.certificateNumber" placeholder="请输入证件号码" :allowClear="true" />
</a-form-item>
</td>
</tr>
<tr>
<td colspan="3">
<a-form-item name="name" :label="`姓名`" :rules="{
required: true,
message: '请输入姓名',
}">
<a-input v-model:value="formState.name" placeholder="请输入姓名" :allowClear="true" />
</a-form-item>
</td>
<td colspan="3">
<a-form-item name="gender" :label="`性别`" :rules="{
required: true,
message: '请选择性别',
}">
<a-select show-search v-model:value="formState.gender" :filter-option="filterOption" :options="options_gender" placeholder="请选择性别" :allowClear="true" optionLabelProp="name" :fieldNames="{ label: 'name', value: 'code' }">
</a-select>
</a-form-item>
</td>
</tr>
<tr>
<td colspan="3">
<a-form-item name="dateBirth" :label="`出生日期`" :rules="{
required: true,
message: '请选择出生日期',
}">
<a-date-picker placeholder="请选择出生日期" :disabled-date="disabledDateMax" v-model:value="formState.dateBirth" value-format="YYYY-MM-DD" style="width: 100%" />
</a-form-item>
</td>
<td colspan="3">
<a-form-item name="nation" :label="`民族`" :rules="{
required: true,
message: '请选择民族',
}">
<a-select show-search v-model:value="formState.nation" :filter-option="filterOption" :options="options_nation" placeholder="请选择民族" :allowClear="true" optionLabelProp="name" :fieldNames="{ label: 'name', value: 'code' }">
</a-select>
</a-form-item>
</td>
</tr>
<tr>
<td colspan="6">
<a-form-item name="provincialUrbanAreas" :label="`省市县区`" :rules="{
required: true,
message: '请选择省市县区',
}" :wrapper-col="{ span: 21 }" :label-col="{ span: 3 }">
<a-select show-search v-model:value="formState.provincialUrbanAreas" :filter-option="filterOptions" :options="options_provincialUrbanAreas" placeholder="请选择省市县区" :allowClear="true" :fieldNames="{ label: 'name', value: 'code' }">
<template #option="{ name, code }">
{{ name }}&nbsp;&nbsp;{{ "[" + code + "]" }}
</template>
</a-select>
</a-form-item>
</td>
</tr>
<tr>
<td colspan="6">
<a-form-item name="address" :label="`住址`" :rules="{
required: true,
message: '请输入住址',
}" :wrapper-col="{ span: 21 }" :label-col="{ span: 3 }">
<a-input v-model:value="formState.address" placeholder="请输入" :allowClear="true" />
</a-form-item>
</td>
</tr>
<tr>
<td colspan="3">
<a-form-item name="phoneNumber" :label="`联系电话`" :rules="[
{ required: true,message:'联系电话最多11位有效数字',max: 11,},
{ pattern:new RegExp('^[0-9]{1,}$','g'),message:'只允许包含数字'}]">
<a-input v-model:value="formState.phoneNumber" placeholder="请输入" :allowClear="true" />
</a-form-item>
</td>
<td colspan="3">
<a-form-item name="plateNumber" :label="`车牌号`" :rules="[
{ pattern:new RegExp('([A-Z]{1}(([0-9]{5}[DF])|([DF]([A-HJ-NP-Z0-9])[0-9]{4})))|([A-Z]{1}[A-HJ-NP-Z0-9]{4}[A-HJ-NP-Z0-9挂学警港澳]{1})'),message:'输入有效车牌号'}]">
<a-input-group compact>
<a-form-item style="width: 20%" name="plateProvince">
<a-select show-search v-model:value="formState.plateProvince" :filter-option="filterOption" :options="options_plate_province" placeholder="请选择省份" :allowClear="true" optionLabelProp="name" style="width: 100%" :fieldNames="{ label: 'name', value: 'code' }">
</a-select>
</a-form-item>
<a-input v-model:value="formState.plateNumber" style="width: 80%" />
</a-input-group>
</a-form-item>
</td>
</tr>
<tr>
<td colspan="6">
<a-form-item name="teamId" :label="`所属团队`" :wrapper-col="{ span: 21 }" :label-col="{ span: 3 }">
<a-select show-search v-model:value="formState.teamId" :filter-option="filterOption" :options="options_team" placeholder="请选择所属团队" :allowClear="true" optionLabelProp="name">
</a-select>
</a-form-item>
</td>
</tr>
<tr>
<td colspan="6">
<a-form-item name="remark" :label="`备注`" :wrapper-col="{ span: 21 }" :label-col="{ span: 3 }">
<a-input v-model:value="formState.remark" :allowClear="true" placeholder="请输入备注" />
</a-form-item>
</td>
</tr>
</table>
</a-form>
</div>
<div class="titleBox">
<div style="margin: 0 auto">
<a-space :size="10">
<a-button type="primary" size="large" @click="handle_ID_reading()">读取证件</a-button>
<!-- <a-dropdown>
<template #overlay>
<a-menu @click="handleMenuClick">
<a-menu-item key="1">
<UserOutlined />
1st menu item
</a-menu-item>
<a-menu-item key="2">
<UserOutlined />
2nd menu item
</a-menu-item>
<a-menu-item key="3">
<UserOutlined />
3rd item
</a-menu-item>
</a-menu>
</template>
<a-button type="primary" size="large">
读取证件
<DownOutlined />
</a-button>
</a-dropdown> -->
<a-dropdown>
<template #overlay>
<a-menu @click="handleMenuClick">
<a-menu-item key="1">
<UserOutlined />
1st menu item
</a-menu-item>
<a-menu-item key="2">
<UserOutlined />
2nd menu item
</a-menu-item>
<a-menu-item key="3">
<UserOutlined />
3rd item
</a-menu-item>
</a-menu>
</template>
<a-button type="primary" size="large">
扫一扫
<DownOutlined />
</a-button>
</a-dropdown>
<!-- style="background-color: #faad14;color:white" -->
<a-button type="primary" size="large">扫描证件</a-button>
<a-button size="large">人证核验</a-button>
<a-button type="primary" size="large" @click="handleOk"><template #icon>
<file-protect-outlined />
</template>
保存</a-button>
<a-button size="large" @click="reset()"><template #icon>
<reload-outlined />
</template>
清空</a-button>
</a-space>
</div>
</div>
<Camera v-if="hotelFormVisible" :visible="hotelFormVisible" :title="`现场人像`" @handle-submit="onSubmit" @change-Cancel="changeCancel" />
<Cropper :imageSrc="imageSrc" v-if="hotelFormVisibles" :visible="hotelFormVisibles" :title="`截图`" @handle-submit="onSubmit_s" @change-Cancel="changeCancel_s" @handle-retake="handleRetake" />
</div>
</a-spin>
</template>
<script setup>
import Camera from "@/components/Camera.vue";
import Cropper from "@/components/Cropper.vue";
import { onMounted, ref, toRaw, watch } from "vue";
import requests from "@/utils/request_test";
import { inlandAdd } from "@/api/domesticGuestCheckIn";
// import { provincialUrbanAreas } from "@/utils/provincialUrbanAreas";
import { validateIdNo } from "@/utils/validates.js"
import { file_img_src } from "@/utils/http_util.js";
import { message } from "ant-design-vue";
import { uploadImg } from "@/api/default.js";
import { useStore } from "@/store/index.js";
import dayjs from 'dayjs';
const userstore = useStore();
const formRef = ref();
const formState = reactive({
hotelId: userstore.hotelInfo.hotelId, //旅馆id
roomId: "",
checkinTime: "",
certificateType: "",
certificateNumber: "",
name: "",
gender: "",
dateBirth: "",
nation: "",
provincialUrbanAreas: "",
address: "",
phoneNumber: "",
plateProvince: "",
plateNumber: "",
remark: "",
certificatePhoto: "", //证件照片
sitePhoto: "", //现场照片
state: "ARRIVE",
creator: userstore.userInfo.username,
});
const reset = () => {
formRef.value.resetFields();
formState.certificatePhoto = "";
formState.sitePhoto = "";
};
const loading = ref(false);
/**摄像头调用 */
const hotelFormVisible = ref(false);
const onSubmit = (e) => {
hotelFormVisible.value = false;
imageSrc.value = e.value;
hotelFormVisibles.value = true;
};
const changeCancel = () => {
hotelFormVisible.value = false;
};
/**开启摄像头 */
const OnCamera = () => {
hotelFormVisible.value = true;
};
/**截图 */
const hotelFormVisibles = ref(false);
const imageSrc = ref("");
const onSubmit_s = (e) => {
formState.sitePhoto = e.value;
hotelFormVisibles.value = false;
};
const changeCancel_s = () => {
hotelFormVisibles.value = false;
};
const handleRetake = () => {
changeCancel_s();
OnCamera();
};
/**选择头像 */
const handleChange = info => {
const isPNG = info.file.type === 'image/png' || info.file.type === 'image/jpg' || info.file.type === 'image/jpeg';
if (!isPNG) {
message.error(`${info.file.name} 不是图片格式,请上传PNG||JPG||JPEG`);
} else {
const reader = new FileReader();
reader.readAsDataURL(info.file);
reader.onload = () => {
formState.sitePhoto = reader.result;
};
}
};
/**不让文件直接上传 */
const beforeUpload = (file) => {
return false
};
/**设置最小时间为今天 */
const disabledDateMin = current => {
// Can not select days before today and today
return current && current < dayjs().subtract(1, 'day').endOf('day');
};
/**设置最大时间为今天 */
const disabledDateMax = current => {
// Can not select days before today and today
return current && current > dayjs().endOf('day');
};
/**提交事件 */
const handleOk = async () => {
formRef.value?.validateFields().then((values) => {
/**批量操作上传图片 */
const arr_http = [];
if (formState.sitePhoto != "") {
arr_http.push(file_img_src(formState.sitePhoto, userstore.hotelInfo.hotelId, 'DOMESTIC_GUEST'));
} else {
arr_http.push("");
}
if (formState.certificatePhoto != "") {
arr_http.push(file_img_src(formState.certificatePhoto, userstore.hotelInfo.hotelId, 'DOMESTIC_GUEST'));
} else {
arr_http.push("");
}
loading.value = true;
Promise.all(arr_http).then(([res1, res2]) => {
const arr = { ...formState };
if (formState.sitePhoto != "") {
arr.sitePhoto = res1;
}
if (formState.certificatePhoto != "") {
arr.certificatePhoto = res2;
}
inlandAdd(arr)
.then((res) => {
if (res.code == 9000) {
message.success("入住成功");
reset();
}
loading.value = false;
})
.catch((res) => {
message.warning("入住失败");
loading.value = false;
});
});
});
};
/**关闭弹框事件 */
const handleCancel = async () => {
// await emit("changeform", false);
};
/**下拉框筛选 */
const filterOption = (input, option) => {
return option.name.toLowerCase().indexOf(input.toLowerCase()) >= 0;
};
const filterOptions = (input, option) => {
return option.name.toLowerCase().indexOf(input.toLowerCase()) >= 0 || option.code.toLowerCase().indexOf(input.toLowerCase()) >= 0;
};
const handleMenuClick = (e) => {
console.log("click", e);
};
/**字典表查询 */
const options_room = ref(userstore.roomAll); //房间字典
const options_certificateType = ref(userstore.returnCode(3)); //证件类型
const options_gender = ref(userstore.returnCode(5)); //性别
const options_nation = ref(userstore.returnCode(10)); //民族
const options_provincialUrbanAreas = ref(userstore.returnCode(11)); //省市县区
const options_plate_province = ref(userstore.returnCode(6)); //全省信息
const options_team = ref([]); //旅游团队
onMounted(() => { });
const handle_ID_reading = () => {
loading.value = true;
requests({
url: "/dev",
method: "GET",
})
.then((res) => {
loading.value = false;
if (res.code == 9000) {
formState.certificateNumber = res.data.code;
formState.certificateType = userstore.returnCode(3).filter((item) => {
return item.name == "身份证";
})[0].code;
formState.name = res.data.name;
formState.gender = userstore.returnCode(5).filter((item) => {
return item.name == res.data.gender;
})[0].code;
formState.certificatePhoto =
"data:image/png;base64," + res.data.profilephoto;
formState.dateBirth = str_data(res.data.birthDay);
formState.address = res.data.address;
formState.nation = userstore.returnCode(10).filter((item) => {
return item.name == res.data.folk + "";
})[0].code;
}
})
.catch((res) => {
message.warning(res);
loading.value = false;
});
};
const str_data = (str) => {
const str1 = str.substring(0, 4);
const str2 = str.substring(4, 6);
const str3 = str.substring(6, 8);
return str1 + "-" + str2 + "-" + str3;
};
</script>
<style lang="less">
.inlandFrom {
width: 100%;
height: 100%;
padding: 0px;
margin: 0px;
overflow-y:auto;
.form {
.ant-form-item-with-help {
margin-bottom: 0px;
}
.ant-form-item-label {
flex: auto;
}
}
.form-tables {
width: 100%;
border-collapse: collapse;
tr {
width: 100%;
height: 60px;
td {
border: 1px solid #e7e7e7;
max-width: 222px;
.img-wp {
width: 186.829px;
height: 230px;
border: 1px solid #a5a5a5;
.img-div {
border-image-source: radial-gradient(
60% 60%,
transparent 0px,
transparent 100%,
#6691ef 100%
);
border-image-slice: 1;
border-width: 1px;
border-style: solid;
border-image-outset: 0px;
width: calc(100% - 40px);
height: calc(100% - 40px);
margin: 20px;
.img-span {
margin: 23px auto;
width: 14px;
line-height: 35px;
font-weight: 400;
font-size: 15px;
}
}
}
}
}
}
.titleBox {
display: flex;
justify-content: space-between;
align-items: center;
background: #fafafa;
border-radius: 0px 0px 2px 2px;
border: 1px solid #e9e9e9;
padding: 10px;
margin: 25px 5px;
}
.sign {
display: inline-block;
font-size: 16px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: rgba(0, 0, 0, 0.85);
line-height: 16px;
&::before {
content: "";
display: inline-block;
width: 4px;
height: 12px;
background: #3162f5;
border-radius: 2px;
margin-right: 8px;
}
}
}
</style>
\ No newline at end of file
<template>
<a-modal :visible="visible" :title="title" width="80%" @cancel="handleCancel">
<a-spin :spinning="loading">
<div class="inlandFrom">
<div style="margin: 0px 5px">
<a-form class="form" ref="formRef" :model="formState" :labelCol="{ span: 6 }" :wrapper-col="{ span: 18 }" layout="inline">
<table class="form-tables">
<tr>
<td colspan="3">
<a-form-item name="roomId" :label="`房间号`" :rules="{
required: true,
message: '请选择房间号',
}">
<a-select show-search v-model:value="formState.roomId" :filter-option="filterOption" :options="options_room" placeholder="请选择房间号" :allowClear="true" optionLabelProp="name" :fieldNames="{ label: 'name', value: 'id' }">
</a-select>
</a-form-item>
</td>
<td colspan="3">
<a-form-item name="checkinTime" :label="`入住时间`">
<a-date-picker show-time placeholder="请选择时间" v-model:value="formState.checkinTime" style="width: 100%" value-format="YYYY-MM-DD HH:mm:ss" />
</a-form-item>
</td>
<td colspan="2" rowspan="9">
<div style="
display: flex;
flex-direction: row;
justify-content: space-around;
flex-wrap: wrap;
">
<div class="img-wp">
<div class="img-div">
<div class="img-span" v-if="
formState.certificatePhotoPath == '' ||
formState.certificatePhotoPath == null
">
<span>证件人像</span>
</div>
<a-image :width="`100%`" :height="`100%`" :src="formState.certificatePhotoPath" v-else />
</div>
</div>
<div class="img-wp">
<div class="img-div">
<div class="img-span" v-if="
formState.sitePhotoPath == '' ||
formState.sitePhotoPath == null
">
<span>现场人像</span>
</div>
<a-image :width="`100%`" :height="`100%`" :src="formState.sitePhotoPath" v-else />
</div>
<div class="check-div" style="text-align: center" @click="OnCamera()">
<a-button type="primary">获取头像</a-button>
</div>
<div class="check-div" style="text-align: center;margin-top: 10px;">
<a-upload name="file" @change="handleChange" :showUploadList="false" :before-upload="beforeUpload">
<a-button>
选择头像
</a-button>
</a-upload>
</div>
</div>
</div>
</td>
</tr>
<tr>
<td colspan="3">
<a-form-item name="certificateType" :label="`证件类型`" :rules="{
required: true,
message: '请选择证件类型',
}">
<a-select show-search v-model:value="formState.certificateType" :filter-option="filterOption" :options="options_certificateType" placeholder="请选择证件类型" :allowClear="true" optionLabelProp="name" :fieldNames="{ label: 'name', value: 'code' }">
</a-select>
</a-form-item>
</td>
<td colspan="3">
<a-form-item name="certificateNumber" :label="`证件号码`" :rules="[
{ required: true,message:'证件号码必须为18位数字加字母组合',len: 18,},
{ pattern:new RegExp(/^[1-9]\d{5}(19|20)\d{2}((0[1-9])|(1[0-2]))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$/,'g'),message:'请输入有效的证件号码'}]">
<a-input v-model:value="formState.certificateNumber" placeholder="请输入证件号码" :allowClear="true" />
</a-form-item>
</td>
</tr>
<tr>
<td colspan="3">
<a-form-item name="name" :label="`姓名`" :rules="{
required: true,
message: '请输入姓名',
}">
<a-input v-model:value="formState.name" placeholder="请输入姓名" :allowClear="true" />
</a-form-item>
</td>
<td colspan="3">
<a-form-item name="gender" :label="`性别`" :rules="{
required: true,
message: '请选择性别',
}">
<a-select show-search v-model:value="formState.gender" :filter-option="filterOption" :options="options_gender" placeholder="请选择性别" :allowClear="true" optionLabelProp="name" :fieldNames="{ label: 'name', value: 'code' }">
</a-select>
</a-form-item>
</td>
</tr>
<tr>
<td colspan="3">
<a-form-item name="dateBirth" :label="`出生日期`" :rules="{
required: true,
message: '请选择出生日期',
}">
<a-date-picker placeholder="请选择出生日期" :disabled-date="disabledDateMax" v-model:value="formState.dateBirth" value-format="YYYY-MM-DD" style="width: 100%" />
</a-form-item>
</td>
<td colspan="3">
<a-form-item name="nation" :label="`民族`" :rules="{
required: true,
message: '请选择民族',
}">
<a-select show-search v-model:value="formState.nation" :filter-option="filterOption" :options="options_nation" placeholder="请选择民族" :allowClear="true" optionLabelProp="name" :fieldNames="{ label: 'name', value: 'code' }">
</a-select>
</a-form-item>
</td>
</tr>
<tr>
<td colspan="6">
<a-form-item name="provincialUrbanAreas" :label="`省市县区`" :rules="{
required: true,
message: '请选择省市县区',
}" :wrapper-col="{ span: 21 }" :label-col="{ span: 3 }">
<a-select show-search v-model:value="formState.provincialUrbanAreas" :filter-option="filterOptions" :options="options_provincialUrbanAreas" placeholder="请选择省市县区" :allowClear="true" :fieldNames="{ label: 'name', value: 'code' }">
<template #option="{ name, code }">
{{ name }}&nbsp;&nbsp;{{ "[" + code + "]" }}
</template>
</a-select>
</a-form-item>
</td>
</tr>
<tr>
<td colspan="6">
<a-form-item name="address" :label="`住址`" :rules="{
required: true,
message: '请输入住址',
}" :wrapper-col="{ span: 21 }" :label-col="{ span: 3 }">
<a-input v-model:value="formState.address" placeholder="请输入" :allowClear="true" />
</a-form-item>
</td>
</tr>
<tr>
<td colspan="3">
<a-form-item name="phoneNumber" :label="`联系电话`" :rules="[
{ required: true,message:'联系电话最多11位有效数字',max: 11,},
{ pattern:new RegExp('^[0-9]{1,}$','g'),message:'只允许包含数字'}]">
<a-input v-model:value="formState.phoneNumber" placeholder="请输入" :allowClear="true" />
</a-form-item>
</td>
<td colspan="3">
<a-form-item name="plateNumber" :label="`车牌号`" :rules="[
{ pattern:new RegExp('([A-Z]{1}(([0-9]{5}[DF])|([DF]([A-HJ-NP-Z0-9])[0-9]{4})))|([A-Z]{1}[A-HJ-NP-Z0-9]{4}[A-HJ-NP-Z0-9挂学警港澳]{1})'),message:'输入有效车牌号'}]">
<a-input-group compact>
<a-form-item style="width: 20%" name="plateProvince">
<a-select show-search v-model:value="formState.plateProvince" :filter-option="filterOption" :options="options_plate_province" placeholder="请选择省份" :allowClear="true" optionLabelProp="name" style="width: 100%" :fieldNames="{ label: 'name', value: 'code' }">
</a-select>
</a-form-item>
<a-input v-model:value="formState.plateNumber" style="width: 80%" />
</a-input-group>
</a-form-item>
</td>
</tr>
<tr>
<td colspan="6">
<a-form-item name="teamId" :label="`所属团队`" :wrapper-col="{ span: 21 }" :label-col="{ span: 3 }">
<a-select show-search v-model:value="formState.teamId" :filter-option="filterOption" :options="options_team" placeholder="请选择所属团队" :allowClear="true" optionLabelProp="name">
</a-select>
</a-form-item>
</td>
</tr>
<tr>
<td colspan="6">
<a-form-item name="remark" :label="`备注`" :wrapper-col="{ span: 21 }" :label-col="{ span: 3 }">
<a-input v-model:value="formState.remark" :allowClear="true" placeholder="请输入备注" />
</a-form-item>
</td>
</tr>
</table>
</a-form>
</div>
<div class="titleBox">
<div style="margin: 0 auto">
<a-space :size="10">
<a-button type="primary" size="large" @click="handle_ID_reading()">读取证件</a-button>
<!-- <a-dropdown>
<template #overlay>
<a-menu @click="handleMenuClick">
<a-menu-item key="1">
<UserOutlined />
1st menu item
</a-menu-item>
<a-menu-item key="2">
<UserOutlined />
2nd menu item
</a-menu-item>
<a-menu-item key="3">
<UserOutlined />
3rd item
</a-menu-item>
</a-menu>
</template>
<a-button type="primary" size="large">
读取证件
<DownOutlined />
</a-button>
</a-dropdown> -->
<a-dropdown>
<template #overlay>
<a-menu @click="handleMenuClick">
<a-menu-item key="1">
<UserOutlined />
1st menu item
</a-menu-item>
<a-menu-item key="2">
<UserOutlined />
2nd menu item
</a-menu-item>
<a-menu-item key="3">
<UserOutlined />
3rd item
</a-menu-item>
</a-menu>
</template>
<a-button type="primary" size="large">
扫一扫
<DownOutlined />
</a-button>
</a-dropdown>
<!-- style="background-color: #faad14;color:white" -->
<a-button type="primary" size="large">扫描证件</a-button>
<a-button size="large">人证核验</a-button>
<a-button type="primary" size="large" @click="handleOk"><template #icon>
<file-protect-outlined />
</template>
保存</a-button>
<a-button size="large" @click="handleCancel()"> 取消</a-button>
</a-space>
</div>
</div>
<Camera v-if="hotelFormVisible" :visible="hotelFormVisible" :title="`现场人像`" @handle-submit="onSubmit" @change-Cancel="changeCancel" />
<Cropper :imageSrc="imageSrc" v-if="hotelFormVisibles" :visible="hotelFormVisibles" :title="`截图`" @handle-submit="onSubmit_s" @change-Cancel="changeCancel_s" @handle-retake="handleRetake" />
</div>
</a-spin>
<template #footer> </template>
</a-modal>
</template>
<script setup>
import Camera from "@/components/Camera.vue";
import Cropper from "@/components/Cropper.vue";
import { onMounted, ref, toRaw, watch } from "vue";
import requests from "@/utils/request_test";
import { inlandEdit,inlandQueryOne } from "@/api/domesticGuestCheckIn";
// import { provincialUrbanAreas } from "@/utils/provincialUrbanAreas";
import { file_img_src } from "@/utils/http_util.js";
import { message } from "ant-design-vue";
import { uploadImg } from "@/api/default.js";
import { useStore } from "@/store/index.js";
import { forIn } from "lodash-es";
import dayjs from 'dayjs';
const props = defineProps({
visible: Boolean,
title: String,
datas: Object,
eyesEdit: Boolean,
});
const loading = ref(false);
const userstore = useStore();
const formRef = ref();
const formState = reactive({});
const reset = () => {
formRef.value.resetFields();
formState.certificatePhoto = "";
formState.sitePhoto = "";
};
/**摄像头调用 */
const hotelFormVisible = ref(false);
const onSubmit = (e) => {
hotelFormVisible.value = false;
imageSrc.value = e.value;
hotelFormVisibles.value = true;
};
const changeCancel = () => {
hotelFormVisible.value = false;
};
/**开启摄像头 */
const OnCamera = () => {
hotelFormVisible.value = true;
};
/**截图 */
const hotelFormVisibles = ref(false);
const imageSrc = ref("");
const onSubmit_s = (e) => {
sitePhotos.value = true;
formState.sitePhoto = e.value;
formState.sitePhotoPath = e.value;
hotelFormVisibles.value = false;
};
const changeCancel_s = () => {
hotelFormVisibles.value = false;
};
const handleRetake = () => {
changeCancel_s();
OnCamera();
};
/**选择头像 */
const handleChange = info => {
const isPNG = info.file.type === 'image/png'||info.file.type === 'image/jpg'||info.file.type === 'image/jpeg';
if (!isPNG) {
message.error(`${info.file.name} 不是图片格式,请上传PNG||JPG||JPEG`);
}else{
const reader = new FileReader();
reader.readAsDataURL(info.file);
reader.onload = () => {
formState.sitePhoto = reader.result;
formState.sitePhotoPath = reader.result;
sitePhotos.value = true;
};
}
};
/**设置最小时间为今天 */
const disabledDateMin = current => {
// Can not select days before today and today
return current && current < dayjs().subtract(1, 'day').endOf('day');
};
/**最大时间为今天 */
const disabledDateMax = current => {
// Can not select days before today and today
return current && current > dayjs().endOf('day');
};
/**不让文件直接上传 */
const beforeUpload = (file) => {
return false;
};
/**提交事件 */
const handleOk = async () => {
formRef.value?.validateFields().then((values) => {
/**批量操作上传图片 */
const arr_http = [];
if (sitePhotos.value) {
arr_http.push(file_img_src(formState.sitePhoto, userstore.hotelInfo.hotelId, 'DOMESTIC_GUEST'));
} else {
arr_http.push("");
}
if (certificatePhotos.value) {
arr_http.push(file_img_src(formState.certificatePhoto, userstore.hotelInfo.hotelId, 'DOMESTIC_GUEST'));
} else {
arr_http.push("");
}
loading.value = true;
Promise.all(arr_http).then(([res1, res2]) => {
const arr = { ...formState };
if (sitePhotos.value) {
arr.sitePhoto = res1;
}
if (certificatePhotos.value) {
arr.certificatePhoto = res2;
}
arr.updater = userstore.userInfo.username;
inlandEdit(arr)
.then((res) => {
if (res.code == 9000) {
message.success("已保存");
emit("changeData", formState);
handleCancel();
}
loading.value = false;
})
.catch((res) => {
message.warning("保存失败");
loading.value = false;
});
});
});
};
const emit = defineEmits(["changeCancel", "changeData"]);
/**关闭弹框事件 */
const handleCancel = async () => {
sitePhotos.value = false;
certificatePhotos.value = false;
await emit("changeCancel", props.eyesEdit);
};
/**下拉框筛选 */
const filterOption = (input, option) => {
return option.name.toLowerCase().indexOf(input.toLowerCase()) >= 0;
};
const filterOptions = (input, option) => {
return option.name.toLowerCase().indexOf(input.toLowerCase()) >= 0||option.code.toLowerCase().indexOf(input.toLowerCase()) >= 0;
};
const handleMenuClick = (e) => {
console.log("click", e);
};
/**字典表查询 */
const options_room = ref(userstore.roomAll); //房间字典
const options_certificateType = ref(userstore.returnCode(3)); //证件类型
const options_gender = ref(userstore.returnCode(5)); //性别
const options_nation = ref(userstore.returnCode(10)); //民族
const options_provincialUrbanAreas = ref(userstore.returnCode(11)); //省市县区
const options_plate_province = ref(userstore.returnCode(6)); //全省信息
const options_team = ref([]); //旅游团队
const setValue = (values) => {
forIn(values, (value, key) => (formState[key] = value));
};
onMounted(() => {
setValue(props?.datas);
queryList({ id: props?.datas.id });
});
const queryList = async (params) => {
loading.value = true;
await inlandQueryOne(params)
.then((res) => {
if (res?.code == 9000) {
setValue(res.data);
}
loading.value = false;
})
.catch((res) => {
loading.value = false;
});
};
const handle_ID_reading = () => {
requests({
url: "/dev",
method: "GET",
})
.then((res) => {
if (res.code == 9000) {
formState.certificateNumber = res.data.code;
formState.certificateType = userstore.returnCode(3).filter((item) => {
return item.name == "身份证";
})[0].code;
formState.name = res.data.name;
formState.gender = userstore.returnCode(5).filter((item) => {
return item.name == res.data.gender;
})[0].code;
formState.certificatePhoto =
"data:image/png;base64," + res.data.profilephoto;
formState.dateBirth = str_data(res.data.birthDay);
formState.address = res.data.address;
formState.nation = userstore.returnCode(10).filter((item) => {
return item.name == res.data.folk + "";
})[0].code;
formState.certificatePhotoPath =
"data:image/png;base64," + res.data.profilephoto;
certificatePhotos.value = true;
}
})
.catch((res) => {
message.warning(res);
});
};
const str_data = (str) => {
const str1 = str.substring(0, 4);
const str2 = str.substring(4, 6);
const str3 = str.substring(6, 8);
return str1 + "-" + str2 + "-" + str3;
};
/**判断现场照片修改 */
const sitePhotos = ref(false);
/**判断证件照 */
const certificatePhotos = ref(false);
</script>
<style lang="less">
.inlandFrom {
width: 100%;
height: 100%;
padding: 0px;
margin: 0px;
.form {
.ant-form-item-with-help {
margin-bottom: 0px;
}
.ant-form-item-label {
flex: auto;
}
}
.form-tables {
width: 100%;
border-collapse: collapse;
tr {
width: 100%;
height: 60px;
td {
border: 1px solid #e7e7e7;
max-width: 222px;
.img-wp {
width: 186.829px;
height: 230px;
border: 1px solid #a5a5a5;
.img-div {
border-image-source: radial-gradient(
60% 60%,
transparent 0px,
transparent 100%,
#6691ef 100%
);
border-image-slice: 1;
border-width: 1px;
border-style: solid;
border-image-outset: 0px;
width: calc(100% - 40px);
height: calc(100% - 40px);
margin: 20px;
.img-span {
margin: 23px auto;
width: 14px;
line-height: 35px;
font-weight: 400;
font-size: 15px;
}
}
}
}
}
}
.titleBox {
display: flex;
justify-content: space-between;
align-items: center;
background: #fafafa;
border-radius: 0px 0px 2px 2px;
border: 1px solid #e9e9e9;
padding: 10px;
margin: 25px 5px;
}
.sign {
display: inline-block;
font-size: 16px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: rgba(0, 0, 0, 0.85);
line-height: 16px;
&::before {
content: "";
display: inline-block;
width: 4px;
height: 12px;
background: #3162f5;
border-radius: 2px;
margin-right: 8px;
}
}
}
</style>
\ No newline at end of file
<template>
<a-modal :visible="visible" :title="title" width="80%" @cancel="handleCancel">
<a-spin :spinning="loading">
<div class="inlandEyes">
<div style="margin: 0px 5px">
<a-form class="form" ref="formRef" :model="formState" :labelCol="{ span: 10 }" :wrapper-col="{ span: 14 }" layout="inline">
<table class="form-tables">
<tr>
<td colspan="2" class="td1">
<span>证件类型:</span>
</td>
<td colspan="2" class="td2">
<span>{{ data?.certificateTypeName }}</span>
</td>
<td colspan="2" class="td1">证件号码:</td>
<td colspan="2" class="td2">
<span>{{ data?.certificateNumber }}</span>
</td>
<td colspan="3" rowspan="11">
<div style="
display: flex;
flex-direction: row;
justify-content: space-around;
flex-wrap: wrap;
">
<div class="img-wp">
<div class="img-div">
<a-image width="100%" height="100%" :src="
data?.certificatePhotoPath == null
? ''
: data?.certificatePhotoPath
" :fallback="default_img" />
</div>
<div class="img-span">
<span>证件人像</span>
</div>
</div>
</div>
</td>
</tr>
<tr>
<td colspan="2" class="td1">
<span>姓名:</span>
</td>
<td colspan="2" class="td2">
<span>{{ data?.name }}</span>
</td>
<td colspan="2" class="td1"><span>性别: </span></td>
<td colspan="2" class="td2">
<span>{{ data?.genderName }}</span>
</td>
</tr>
<tr>
<td colspan="2" class="td1">
<span>民族:</span>
</td>
<td colspan="2" class="td2">
<span>{{ data?.nationName }}</span>
</td>
<td colspan="2" class="td1"><span>出生日期: </span></td>
<td colspan="2" class="td2">
<span>{{ data?.dateBirth }}</span>
</td>
</tr>
<tr>
<td colspan="2" class="td1">
<span>户籍地省市县区:</span>
</td>
<td colspan="2" class="td2">
<span>{{ data?.provincialUrbanAreasName }}</span>
</td>
<td colspan="2" class="td1"><span>住址: </span></td>
<td colspan="2" class="td2">
<span>{{ data?.address }}</span>
</td>
</tr>
<tr>
<td colspan="2" class="td1">
<span>联系电话:</span>
</td>
<td colspan="2" class="td2">
<span>{{ data?.phoneNumber }}</span>
</td>
<td colspan="2" class="td1"><span>车牌号: </span></td>
<td colspan="2" class="td2">
<span>{{
data?.plateProvinceName != null && data?.plateNumber != null
? data?.plateProvinceName + "-" + data?.plateNumber
: ""
}}</span>
</td>
</tr>
<tr>
<td colspan="2" class="td1">
<span>所属团队:</span>
</td>
<td colspan="6" class="td2">
<span>{{ data?.teamName }}</span>
</td>
</tr>
<tr>
<td colspan="2" class="td1">
<span>房间号:</span>
</td>
<td colspan="2" class="td2">
<span>{{ data?.roomName }}</span>
</td>
<!-- <td colspan="4" v-show="update">
<a-form-item
name="roomId"
:label="`房间号`"
:rules="{
required: true,
message: '请选择房间号',
}"
>
<a-select
show-search
v-model:value="formState.roomId"
:filter-option="filterOption"
:options="options_room"
placeholder="请选择房间号"
:allowClear="true"
optionLabelProp="name"
:fieldNames="{ label: 'name', value: 'id' }"
>
</a-select>
</a-form-item>
</td> -->
<td colspan="2" class="td1"><span>旅客状态: </span></td>
<td colspan="2" class="td2">
<span>{{ data?.stateName }}</span>
</td>
</tr>
<tr>
<td colspan="2" class="td1">
<span>入住时间:</span>
</td>
<td colspan="2" class="td2">
<span>{{ data?.checkinTime }}</span>
</td>
<td colspan="2" class="td1"><span>离店时间: </span></td>
<td colspan="2" class="td2">
<span>{{ data?.departureTime }}</span>
</td>
</tr>
<tr>
<td colspan="2" class="td1">
<span>登记时间:</span>
</td>
<td colspan="2" class="td2">
<span>{{ data?.createTime }}</span>
</td>
<td colspan="2" class="td1"><span>修改时间: </span></td>
<td colspan="2" class="td2">
<span>{{ data?.updateTime }}</span>
</td>
</tr>
<tr>
<td colspan="2" class="td1">
<span>登记人:</span>
</td>
<td colspan="2" class="td2">
<span>{{ data?.creatorName }}</span>
</td>
<td colspan="2" class="td1"><span>修改人:</span></td>
<td colspan="2" class="td2">
<span>{{ data?.updaterName }}</span>
</td>
</tr>
<tr>
<td colspan="2" class="td1">
<span>是否未成年人:</span>
</td>
<td colspan="2" class="td2">
<span :style="{ color: data?.minority == 0 ? '' : 'red' }">{{
data?.minority == 0 ? "成年" : "未成年"
}}</span>
</td>
<td colspan="2" class="td1"><span>备注:</span></td>
<td colspan="2" class="td2">
<span>{{ data?.remark }}</span>
</td>
</tr>
</table>
</a-form>
</div>
<div class="titleBox" v-if="visibleEdit">
<div style="margin: 0 auto">
<a-space :size="10">
<a-button size="large" type="primary" @click="edit()"><template #icon> <edit-filled /> </template>编辑</a-button>
<a-button size="large" type="primary">人证核验</a-button>
<a-button size="large">打印登记单</a-button>
</a-space>
</div>
</div>
</div>
</a-spin>
<template #footer> </template>
</a-modal>
</template>
<script setup>
import { EditFilled } from "@ant-design/icons-vue";
import { onMounted, watch } from "vue";
import { useStore } from "@/store/index.js";
import { forIn } from "lodash-es";
import { inlandQueryOne } from "@/api/domesticGuestCheckIn";
import default_img from '@/assets/img/default.png';
const userstore = useStore();
const props = defineProps({
visible: Boolean,
id: {},
title: String,
visibleEdit: Boolean,
});
const formRef = ref();
const formState = reactive({
hotelId: userstore.hotelInfo.hotelId, //旅馆id
roomId: "",
checkinTime: "",
certificateType: "",
certificateNumber: "",
name: "",
gender: "",
dateBirth: "",
nation: "",
provincialUrbanAreas: "",
address: "",
phoneNumber: "",
plateProvince: "",
plateNumber: "",
teamId: "",
remark: "",
});
const emit = defineEmits(["changeCancel", "changeEdit"]);
const handleCancel = async () => {
await emit("changeCancel");
};
const data = ref({});
onMounted(() => {
queryList({ id: props?.id });
});
const loading = ref(false);
const queryList = async (params) => {
loading.value = true;
await inlandQueryOne(params)
.then((res) => {
if (res?.code == 9000) {
data.value = res.data;
}
loading.value = false;
})
.catch((res) => {
loading.value = false;
});
};
const edit = async () => {
await emit("changeEdit", data);
};
</script>
<style lang="less">
.inlandEyes {
width: 100%;
height: 100%;
padding: 0px;
margin: 0px;
.form {
.ant-form-item-with-help {
margin-bottom: 0px;
}
.ant-form-item-label {
flex: auto;
}
}
.form-tables {
width: 100%;
border-collapse: collapse;
tr {
width: 100%;
height: 40px;
td {
border: 1px solid #e7e7e7;
max-width: 222px;
width: 110px;
.img-wp {
width: 186.829px;
height: 230px;
// border: 1px solid #a5a5a5;
.img-div {
border-image-source: radial-gradient(
60% 60%,
transparent 0px,
transparent 100%,
#6691ef 100%
);
border-image-slice: 1;
border-width: 1px;
border-style: solid;
border-image-outset: 0px;
width: calc(100% - 40px);
height: calc(100% - 40px);
margin: 20px;
}
.img-span {
text-align: center;
color: orange;
font-weight: 400;
font-size: 15px;
}
}
}
.td1 {
font-weight: 600;
font-size: 13px;
text-align: right;
padding: 0px 20px;
color: #007cef;
letter-spacing: 2px;
}
.td2 {
text-align: left;
padding: 0px 20px;
}
}
}
.titleBox {
display: flex;
justify-content: space-between;
align-items: center;
background: #fafafa;
border-radius: 0px 0px 2px 2px;
border: 1px solid #e9e9e9;
padding: 10px;
margin: 25px 5px;
}
.sign {
display: inline-block;
font-size: 16px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: rgba(0, 0, 0, 0.85);
line-height: 16px;
&::before {
content: "";
display: inline-block;
width: 4px;
height: 12px;
background: #3162f5;
border-radius: 2px;
margin-right: 8px;
}
}
}
</style>
\ No newline at end of file
<template> <template>
<div class="login"> <div class="login">
<div class="login-content"> <div class="login-main">
<div class="left-content"> </div> <div class="login-footer"></div>
<div class="right-content"> <div class="login-content">
<div class="login-form"> <div class="login-content-title">数据分析系统</div>
<div class="login-img"> <div class="login-content-form">
<img :src="logoImg" alt=""> <a-form :model="formState" @finish="handleFinish" @finishFailed="handleFinishFailed">
</div> <a-form-item>
<h2>旅馆业治安管理信息系统</h2> <a-input v-model:value="formState.user" placeholder="Username">
<p>系统的实施对于促进旅游业的发展,维护公众安全、保障人民群众生命财产安全具有重要作用。</p>
<a-form ref="formRef" :model="formState" :rules="rules">
<a-form-item name="department">
<a-tree-select v-model:value="formState.department" size="large" v-model:searchValue="searchValue" show-search style="width: 100%" :dropdown-style="{ maxHeight: '400px', overflow: 'auto' }" placeholder="请选择派出所" allow-clear tree-default-expand-all :tree-data="treeData" tree-node-filter-prop="label">
<template #title="{ value: val, label }">
<b v-if="val === 'parent 1-1'" style="color: #08c">sss</b>
<template v-else>
<template v-for="(fragment, i) in label.toString().split(new RegExp(`(?<=${searchValue})|(?=${searchValue})`, 'i'))">
<span v-if="fragment.toLowerCase() === searchValue.toLowerCase()" :key="i" style="color: #08c">
{{ fragment }}
</span>
<template v-else>{{ fragment }}</template>
</template>
</template>
</template>
</a-tree-select>
</a-form-item>
<a-form-item name="hotel">
<a-spin :spinning="loading">
<a-select v-model:value="formState.hotel" show-search placeholder="请选择旅馆" :options="hotelList" size="large" :filter-option="filterOption" @change="handleChange" :fieldNames="{value:'id',label:'name'}" :notFoundContent="'暂无数据'"></a-select>
</a-spin>
</a-form-item>
<a-form-item ref="username" name="username">
<a-input v-model:value="formState.username" placeholder="请输入您的用户名" size="large">
<template #prefix> <template #prefix>
<UserOutlined /> <UserOutlined style="color: rgba(0, 0, 0, 0.25)" />
</template> </template>
</a-input> </a-input>
</a-form-item> </a-form-item>
<a-form-item ref="password" name="password"> <a-form-item>
<a-input-password v-model:value="formState.password" placeholder="请输入您的密码" size="large"> <a-input v-model:value="formState.password" type="password" placeholder="Password">
<template #prefix>
<LockOutlined />
</template>
</a-input-password>
</a-form-item>
<a-form-item ref="code" name="code">
<a-input v-model:value="formState.code" placeholder="验证码" style="width:200px;" size="large">
<template #prefix> <template #prefix>
<KeyOutlined /> <LockOutlined style="color: rgba(0, 0, 0, 0.25)" />
</template> </template>
</a-input> </a-input>
<img :src="formState.imgCode" alt="" style="width:120px;height:40px;margin-left:2px;margin-top: -2px;margin-right: 10px;">
<a-button type="primary" class="login-button" @click="getVerifyCodeFn" style="position:relative;top:0px;" size="large">
<template #icon>
<ReloadOutlined />
</template>
</a-button>
</a-form-item> </a-form-item>
<a-form-item> <a-form-item>
<a-button class="login-button" type="primary" block @click="onSubmit" size="large">登录</a-button> <a-button type="primary" html-type="submit" :loading="loading"
:disabled="formState.user === '' || formState.password === ''">
登录
</a-button>
</a-form-item> </a-form-item>
<!-- <a-form-item>
<a-button class="login-button" type="primary" block @click="onRegister">单位注册</a-button>
</a-form-item> -->
</a-form> </a-form>
</div> </div>
</div> </div>
</div> </div>
<registerModal ref="register" />
</div> </div>
</template> </template>
<script setup> <script setup>
import router from '../../router/index.js'; import { UserOutlined, LockOutlined } from '@ant-design/icons-vue';
import registerModal from '../login/register.vue'; import { reactive, ref } from 'vue';
import { getVerifyCode, getUserList, login, } from '../../api/user'; import router from '@/router/index.js';
import { getDeptTree } from '../../api/dept'; // import { login } from '../../api/login/login';
import { queryHotelByDept } from '../../api/hotel';
import { onMounted } from 'vue';
import { message } from 'ant-design-vue'; import { message } from 'ant-design-vue';
import { useStore } from '@/store/index.js'
import logoImg from '@/assets/img/login/logo.png';
const userStore = useStore();
const formRef = ref();
const treeData = ref([]);
const searchValue = ref('');
const loading = ref(false); const loading = ref(false);
const register = ref();
const hotelAdress = ref('');
const formState = reactive({ const formState = reactive({
department: undefined, user:'',
hotel: undefined, password:''
username: '',
password: '',
imgCode: ''
}); });
const checkKey1 = ref(); const handleFinish = async (values) => {
const rules = { loading.value = true;
username: [ // try {
{ // const response = await login() || [];
required: true, // if (response.data) {
message: '请输入您的真实用户信息', // message.success('登录成功!');
trigger: 'blur', // router.push({
}, // name: 'home'
{ // });
min: 2, // }
max: 10, // } catch (error) {
message: '用户名长度为 2 到 10', // loading.value = false;
trigger: 'blur', // }
},
],
password: [
{
required: true,
message: '请输入正确的密码',
trigger: 'blur',
}
],
department: [
{
required: true,
message: '请选择派出所',
trigger: 'change',
},
],
hotel: [
{
required: true,
message: '请选择旅馆',
trigger: 'change',
},
],
};
const hotelList = ref([]);
const onSubmit = () => {
const param = {
// "hotelId": "1",
"hotelId": formState.hotel,
"passwordBase64": btoa(formState.password),
"username": formState.username,
"verifyCode": formState.code,
"checkKey": checkKey1.value,
"address": hotelAdress.value
};
userStore.getUserInfo(param);
getVerifyCodeFn();
//表单验证 ---- 暂时封闭
// formRef.value
// .validate()
// .then(() => {
// console.log('values', formState, toRaw(formState));
// })
// .catch(error => {
// console.log('error', error);
// });
};
const onRegister = () => {
register.value.showModal();
};
const resetForm = () => {
formRef.value.resetFields();
};
//获取验证码
const getVerifyCodeFn = () => {
checkKey1.value = new Date().getTime();
getVerifyCode({ checkKey: checkKey1.value }).then(res => {
let blob = new Blob([res], { type: "image/png" });
let imageUrl = (window.URL || window.webkitURL).createObjectURL(blob)
formState.imgCode = imageUrl || '';
});
}
//获取派出所组织机构树
const getDeptTreeFn = () => {
getDeptTree().then(res => {
treeData.value = res.data;
}).catch(err => {
message.error(err.message);
});
}
loading.value = false;
//监听派出所部门变化 console.log(values);
watch(() => formState.department, (newVal, oldVal) => {
formState.hotel = undefined;
loading.value = true;
queryHotelByDept({ 'deptid': formState.department }).then(res => {
hotelList.value = res.data;
loading.value = false;
}).catch(res => {
loading.value = false;
});
});
const handleChange = (value, options) => {
hotelAdress.value = options.address;
}; };
const filterOption = (input, option) => { const handleFinishFailed = errors => {
return option.name.toLowerCase().indexOf(input.toLowerCase()) >= 0; console.log(errors);
}; };
//获取验证码
onMounted(() => {
//获取派出所组织机构树
getDeptTreeFn();
//首次获取验证码
getVerifyCodeFn();
})
</script> </script>
<style lang="less">
<style lang="less" scoped>
.login { .login {
width: 100%; width: 100%;
height: 100%; height: 100%;
// display: flex; position: absolute;
// align-items: center; background: url("@/assets/img/login/login_bg.png");
// justify-content: center; background-size: 100% 100%;
// background-color: rgb(41, 23, 91); margin: 0;
.login-content { padding: 0;
width: 100%;
.login-main {
width: 800px;
height: 100%; height: 100%;
display: flex; position: relative;
// margin-top: 13%; margin: auto;
.left-content {
width: calc(100% - 768px);
height: 100%;
background: url("@/assets/img/login/bg.png"); .login-footer {
width: 450px;
height: 450px;
top: calc(13% + 350px);
margin-left: calc(50% - 225px);
position: absolute;
background: url("@/assets/img/login/01-1.png");
background-size: 100% 100%;
} }
.right-content {
width: 768px; .login-content {
height: 100%; width: 500px;
padding-top: 6%; height: 500px;
display: flex; position: absolute;
justify-content: center; background: url("@/assets/img/login/02.png");
.login-form { background-size: 100% 100%;
width: 60%; left: calc(50% - 250px);
height: 100%; top: 10%;
.login-img {
text-align: center; .login-content-title {
} color: #ffffff;
h2 { position: absolute;
margin-top: 40px; top: 22%;
text-align: center; font-size: 30px;
font-size: 37px; font-weight: 500;
font-weight: 600; left: 34%;
letter-spacing: 4px; background-color: #12698640;
} }
p {
color: #b8b5b5; .login-content-form {
width: 340px;
height: 225px;
padding: 40px 50px 50px 50px;
position: absolute;
background: url("@/assets/img/login/03.png");
background-size: 100% 100%;
left: 17.5%;
top: 31%;
text-align: center;
.anticon-user,
.anticon-lock {
color: #1d2d46 !important;
} }
// .login-button {
// // background-color: rgb(41, 23, 91);
// // border: 1px solid white;
// // box-shadow: 0px 0px 1px 1px #ddddddb3;
// &:hover,
// &:focus,
// &:visited {
// background-color: #26184b;
// border: 1px solid #26184b;
// }
// }
} }
} }
} }
} }
</style> </style>
\ No newline at end of file
\ No newline at end of file
<template>
<div class="login">
<div class="login-content">
<h2>旅馆业治安管理信息系统</h2>
<a-form ref="formRef" :model="formState" :rules="rules">
<a-form-item name="department">
<a-tree-select v-model:value="formState.department" v-model:searchValue="searchValue" show-search style="width: 100%" :dropdown-style="{ maxHeight: '400px', overflow: 'auto' }" placeholder="请选择派出所" allow-clear tree-default-expand-all :tree-data="treeData" tree-node-filter-prop="label">
<template #title="{ value: val, label }">
<b v-if="val === 'parent 1-1'" style="color: #08c">sss</b>
<template v-else>
<template v-for="(fragment, i) in label.toString().split(new RegExp(`(?<=${searchValue})|(?=${searchValue})`, 'i'))">
<span v-if="fragment.toLowerCase() === searchValue.toLowerCase()" :key="i" style="color: #08c">
{{ fragment }}
</span>
<template v-else>{{ fragment }}</template>
</template>
</template>
</template>
</a-tree-select>
</a-form-item>
<a-form-item name="hotel">
<a-spin :spinning="loading">
<a-select v-model:value="formState.hotel" show-search placeholder="请选择旅馆" :options="hotelList" :filter-option="filterOption" @change="handleChange" :fieldNames="{value:'id',label:'name'}" :notFoundContent="'暂无数据'"></a-select>
</a-spin>
</a-form-item>
<a-form-item ref="username" name="username">
<a-input v-model:value="formState.username" placeholder="请输入您的用户名">
<template #prefix>
<UserOutlined />
</template>
</a-input>
</a-form-item>
<a-form-item ref="password" name="password">
<a-input-password v-model:value="formState.password" placeholder="请输入您的密码">
<template #prefix>
<LockOutlined />
</template>
</a-input-password>
</a-form-item>
<a-form-item ref="code" name="code">
<a-input v-model:value="formState.code" placeholder="验证码" style="width:200px;">
<template #prefix>
<KeyOutlined />
</template>
</a-input>
<img :src="formState.imgCode" alt="" style="width:100px;height:30px;margin-left:2px;margin-top: -2px;margin-right: 10px;">
<a-button type="primary" class="login-button" @click="getVerifyCodeFn" style="position:relative;top:0px;">
<template #icon>
<ReloadOutlined />
</template>
</a-button>
</a-form-item>
<a-form-item>
<a-button class="login-button" type="primary" block @click="onSubmit">登录</a-button>
</a-form-item>
<a-form-item>
<a-button class="login-button" type="primary" block @click="onRegister">单位注册</a-button>
</a-form-item>
</a-form>
</div>
<registerModal ref="register" />
</div>
</template>
<script setup>
import router from '../../router/index.js';
import registerModal from '../login/register.vue';
import { getVerifyCode, getUserList, login, } from '../../api/user';
import { getDeptTree } from '../../api/dept';
import { queryHotelByDept } from '../../api/hotel';
import { onMounted } from 'vue';
import { message } from 'ant-design-vue';
import { useStore } from '@/store/index.js'
const userStore = useStore();
const formRef = ref();
const treeData = ref([]);
const searchValue = ref('');
const loading = ref(false);
const register = ref();
const hotelAdress = ref('');
const formState = reactive({
department: undefined,
hotel: undefined,
username: '',
password: '',
imgCode: ''
});
const checkKey1 = ref();
const rules = {
username: [
{
required: true,
message: '请输入您的真实用户信息',
trigger: 'blur',
},
{
min: 2,
max: 10,
message: '用户名长度为 2 到 10',
trigger: 'blur',
},
],
password: [
{
required: true,
message: '请输入正确的密码',
trigger: 'blur',
}
],
department: [
{
required: true,
message: '请选择派出所',
trigger: 'change',
},
],
hotel: [
{
required: true,
message: '请选择旅馆',
trigger: 'change',
},
],
};
const hotelList = ref([]);
const onSubmit = () => {
const param = {
// "hotelId": "1",
"hotelId": formState.hotel,
"passwordBase64": btoa(formState.password),
"username": formState.username,
"verifyCode": formState.code,
"checkKey": checkKey1.value,
"address": hotelAdress.value
};
userStore.getUserInfo(param);
getVerifyCodeFn();
//表单验证 ---- 暂时封闭
// formRef.value
// .validate()
// .then(() => {
// console.log('values', formState, toRaw(formState));
// })
// .catch(error => {
// console.log('error', error);
// });
};
const onRegister = () => {
register.value.showModal();
};
const resetForm = () => {
formRef.value.resetFields();
};
//获取验证码
const getVerifyCodeFn = () => {
checkKey1.value = new Date().getTime();
getVerifyCode({ checkKey: checkKey1.value }).then(res => {
let blob = new Blob([res], { type: "image/png" });
let imageUrl = (window.URL || window.webkitURL).createObjectURL(blob)
formState.imgCode = imageUrl || '';
});
}
//获取派出所组织机构树
const getDeptTreeFn = () => {
getDeptTree().then(res => {
treeData.value = res.data;
}).catch(err => {
message.error(err.message);
});
}
//监听派出所部门变化
watch(() => formState.department, (newVal, oldVal) => {
formState.hotel = undefined;
loading.value = true;
queryHotelByDept({ 'deptid': formState.department }).then(res => {
hotelList.value = res.data;
loading.value = false;
}).catch(res => {
loading.value = false;
});
});
const handleChange = (value, options) => {
hotelAdress.value = options.address;
};
const filterOption = (input, option) => {
return option.name.toLowerCase().indexOf(input.toLowerCase()) >= 0;
};
//获取验证码
onMounted(() => {
//获取派出所组织机构树
getDeptTreeFn();
//首次获取验证码
getVerifyCodeFn();
})
</script>
<style lang="less" scoped>
.login {
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
background-color: rgb(41, 23, 91);
.login-content {
width: 500px;
height: 600px;
margin-top: 13%;
h2 {
padding: 20px 0px;
text-align: center;
color: white;
}
.login-button {
background-color: rgb(41, 23, 91);
border: 1px solid white;
box-shadow: 0px 0px 1px 1px #ddddddb3;
&:hover,
&:focus,
&:visited {
background-color: #26184b;
border: 1px solid #26184b;
}
}
}
}
</style>
\ No newline at end of file
<template>
<div>
<a-modal v-model:visible="visible" title="用户注册" :footer="null">
<a-form ref="formRef" :model="formState" :rules="rules" :label-col="labelCol" :wrapper-col="wrapperCol">
<a-form-item name="department" label="派出所">
<a-select v-model:value="formState.department" placeholder="请选择派出所" size="large">
<a-select-option value="shanghai">Zone one</a-select-option>
<a-select-option value="beijing">Zone two</a-select-option>
</a-select>
</a-form-item>
<a-form-item name="hotel" label="旅馆">
<a-select v-model:value="formState.hotel" placeholder="请选择旅馆" size="large">
<a-select-option value="shanghai">Zone one</a-select-option>
<a-select-option value="beijing">Zone two</a-select-option>
</a-select>
</a-form-item>
<a-form-item name="role" label="角色">
<a-select v-model:value="formState.role" placeholder="请选择角色" size="large">
<a-select-option value="shanghai">Zone one</a-select-option>
<a-select-option value="beijing">Zone two</a-select-option>
</a-select>
</a-form-item>
<a-form-item ref="iphone" name="iphone" label="手机号">
<a-input v-model:value="formState.iphone" placeholder="请输入您的手机号" size="large">
<template #prefix>
<PhoneOutlined />
</template>
</a-input>
</a-form-item>
<a-form-item ref="email" name="email" label="邮箱">
<a-input v-model:value="formState.email" placeholder="请输入您的邮箱" size="large">
<template #prefix>
<MailOutlined />
</template>
</a-input>
</a-form-item>
<a-form-item ref="nickname" name="nickname" label="昵称">
<a-input v-model:value="formState.nickname" placeholder="请输入您的昵称" size="large">
<template #prefix>
<SolutionOutlined />
</template>
</a-input>
</a-form-item>
<a-form-item ref="username" name="username" label="用户名">
<a-input v-model:value="formState.username" placeholder="请输入您的用户名" size="large">
<template #prefix>
<UserOutlined />
</template>
</a-input>
</a-form-item>
<a-form-item ref="password" name="password" label="密码">
<a-input v-model:value="formState.password" placeholder="请输入您的密码" size="large">
<template #prefix>
<LockOutlined />
</template>
</a-input>
</a-form-item>
<a-form-item :wrapper-col="{ span: 14, offset: 8 }">
<a-button class="login-button" size="large" type="primary" @click="onRegister">注册</a-button>
<a-button class="login-button" size="large" type="primary" style="margin-left:10px;" @click="onCancle">取消</a-button>
</a-form-item>
</a-form>
</a-modal>
</div>
</template>
<script setup>
import { onMounted } from 'vue';
import { register } from '../../api/user'
import { queryRole } from '../../api/role'
const formRef = ref();
const formState = reactive({
department: undefined,
hotel: undefined,
role: undefined,
username: '',
password: '',
iphone: '',
email: '',
nickname: ''
});
const labelCol = {
span: 4,
};
const wrapperCol = {
span: 18,
};
const rules = {
username: [
{
required: true,
message: '请输入您的真实用户信息',
trigger: 'blur',
},
{
min: 3,
max: 5,
message: 'Length should be 3 to 5',
trigger: 'blur',
},
],
password: [
{
required: true,
message: '请输入正确的密码',
trigger: 'blur',
}
],
department: [
{
required: true,
message: '请选择派出所',
trigger: 'change',
},
],
hotel: [
{
required: true,
message: '请选择旅馆',
trigger: 'change',
},
],
};
const visible = ref(false);
const showModal = () => {
visible.value = true;
};
const onRegister = e => {
console.log(e);
// visible.value = false;
register({
"email": formState.email,
"hotel_id": "test",
"nickname": formState.nickname,
"password": formState.password,
"phone": formState.iphone,
"roles": [
0
],
"username": formState.username,
}).then(res => {
// debugger
})
};
const onCancle = () => {
visible.value = false;
}
onMounted(() => {
queryRole({ user_id: 1 }).then(res => {
// debugger
})
})
defineExpose({
showModal
})
</script>
\ No newline at end of file
<template>
<div class="restoreCheckIn">
<a-spin :spinning="loading">
<div class="titleBox">
<div>
<span class="sign" style="color: red;">离店列表(只能恢复近8小时)</span>
</div>
</div>
<div style="margin: 0px 25px">
<a-form ref="formRef" name="advanced_search" class="ant-advanced-search-form form" :model="formState">
<a-row :gutter="24">
<a-col :span="3">
<a-form-item name="roomId" label="房间号">
<a-select show-search v-model:value="formState.roomId" :filter-option="filterOption" placeholder="请选择房间号" :options="options_room" :allowClear="true" optionLabelProp="name" :fieldNames="{ label: 'name', value: 'id' }">
</a-select>
</a-form-item>
</a-col>
<a-col :span="3">
<a-form-item name="name" label="姓名">
<a-input v-model:value="formState.name" placeholder="请输入姓名"></a-input>
</a-form-item>
</a-col>
<a-col :span="5">
<a-form-item name="name" label="证件号码">
<a-input v-model:value="formState.certificateNumber" placeholder="请输入证件号码"></a-input>
</a-form-item>
</a-col>
<a-col :span="7">
<a-form-item label="入住时间">
<a-range-picker show-time @change="(data, dateString) => handleChangeTime(data, dateString)" />
</a-form-item>
</a-col>
<a-col>
<a-space :size="10">
<a-button type="primary" @click="queryList()">查询</a-button>
<a-button type="primary" @click="restore()">批量恢复</a-button>
</a-space>
</a-col>
</a-row>
</a-form>
</div>
<div class="titleBox">
<div>
<span class="sign">内宾离店情况</span>
</div>
</div>
<a-spin :spinning="loading_inland">
<div style="margin: 0px 25px">
<a-table :row-selection="rowSelection_inland" :rowKey="item=>JSON.stringify(item.id)" :columns="columns_inland" :data-source="data_inland" :pagination="false"><template #bodyCell="{ column, record, index }">
<template v-if="column.dataIndex === 'cz'">
<a-space :size="0">
<a-button type="link" primary size="small" style="color: #52c41a" @click="eye_inland(record)">
<template #icon>
<eye-filled />
</template>
查看
</a-button>
<a-popconfirm v-if="record.state === 'DEPART'" title="是否恢复" @confirm="setState_inland(record)">
<a-button type="link" primary size="small" style="color: #ff4d1f">
<template #icon>
<undo-outlined />
</template>
恢复
</a-button>
</a-popconfirm>
</a-space>
</template>
</template>
</a-table>
<a-pagination v-model:current="page_inland" :rowKey="item=>item.id" :page-size-options="pageSizeOptions" v-model:page-size="pageSize_inland" show-quick-jumper show-size-changer :total="total_inland" v-show="data_inland.length > 0" size="small" :show-total="(total) => `总数共: ${total} 条`" @change="onChange_inland" style="margin: 20px 0px" />
</div>
</a-spin>
<div class="titleBox">
<div>
<span class="sign">外宾离店情况</span>
</div>
</div>
<a-spin :spinning="loading_abroad">
<div style="margin: 0px 25px">
<a-table :row-selection="rowSelection_abroad" :rowKey="item=>JSON.stringify(item.id)" :columns="columns_abroad" :data-source="data_abroad" :pagination="false"><template #bodyCell="{ column, record, index }">
<template v-if="column.dataIndex === 'cz'">
<a-space :size="0">
<a-button type="link" primary size="small" style="color: #52c41a" @click="eye_abroad(record)">
<template #icon>
<eye-filled />
</template>
查看
</a-button>
<a-popconfirm v-if="record.state === 'DEPART'" title="是否恢复" @confirm="setState_abroad(record)">
<a-button type="link" primary size="small" style="color: #ff4d1f">
<template #icon>
<undo-outlined />
</template>
恢复
</a-button>
</a-popconfirm>
</a-space>
</template>
</template>
</a-table>
<a-pagination v-model:current="page_abroad" :page-size-options="pageSizeOptions" v-model:page-size="pageSize_abroad" show-quick-jumper show-size-changer :total="total_abroad" v-show="data_abroad.length > 0" size="small" :show-total="(total) => `总数共: ${total} 条`" @change="onChange_abroad" style="margin: 20px 0px" />
</div>
</a-spin>
</a-spin>
<InlandEyes v-if="hotelFormVisible" :visible="hotelFormVisible" :visibleEdit="hotelFormVisible_edit" :id="info_id" :title="titles" @change-Cancel="changeCancel_inland" />
<AbroadInfo v-if="abroadInfoVisible" :flogStatus="operateStatus" :visible="abroadInfoVisible" :dictionaryAll="dictionaryAllInfo" :formData="abroadInfo" @change-Cancel="changeCancel_adroad" :visibleEdit="hotelFormVisible_edit_s" />
</div>
</template>
<script setup>
import { useStore } from "@/store/index.js";
import { inlandQuery } from "@/api/domesticGuestCheckIn";
import { getForeignGuestCheckInList } from '@/api/foreignGuestCheckIn.js';
import { onMounted } from "vue";
import { message } from "ant-design-vue";
import InlandEyes from '@/views/inland/inlandEyes.vue';
import AbroadInfo from '@/views/abroad/abroadInfo.vue';
import { ChangeDateType } from '@/utils/http_util.js';
import { restoreForeignGuestsToStay, restoreDomesticGuestsToStay } from '@/api/restoreCheckIn.js';
const userstore = useStore();
const formState = reactive({
name: "",
certificateNumber: "",
checkinTimeEnd: "",
checkinTimeStart: "",
state: "DEPART",
roomId: "",
hotelId: userstore.hotelInfo.hotelId, //旅馆id
current: 1,
pageSize: 4,
departureTimeStart: '',
departureTimeEnd: '',
});
/**字典表查询---性别*/
const options_room = ref(userstore.roomAll); //房间字典
/**spinning*/
const loading = ref(false);
/**分页下拉框选项 */
const pageSizeOptions = ref(['4', '10', '20', '30', '40', '50']);
/**内宾表格----------------------- */
const columns_inland = [
{
title: "姓名",
dataIndex: "name",
},
{
title: "证件号码",
dataIndex: "certificateNumber",
},
{
title: "性别",
dataIndex: "genderName",
},
{
title: "民族",
dataIndex: "nationName",
},
{
title: "户籍地省市县区",
dataIndex: "provincialUrbanAreasName",
},
{
title: "房号",
dataIndex: "roomName",
},
{
title: "所属团队",
dataIndex: "teamName",
},
{
title: "旅客状态",
dataIndex: "state",
},
{
title: "入住时间",
dataIndex: "checkinTime",
},
{
title: "离开时间",
dataIndex: "departureTime",
},
{
title: "操作",
dataIndex: "cz",
fixed: "right",
width: 200,
},
];
const data_inland = ref([]);
const page_inland = ref(formState.current);/**当前第几页 */
const pageSize_inland = ref(formState.pageSize);/**当前每页的数据 */
const total_inland = ref(0);/**总数 */
const selectedRowKeys_inland = ref([]);/**当前选中集合 */
const loading_inland = ref(false);
const rowSelection_inland = {
onChange: (selectedRowKeys, selectedRows) => {
selectedRowKeys_inland.value = selectedRowKeys;
},
}
const onChange_inland = (page, pageSize) => {
page_inland.value = page;
pageSize_inland.value = pageSize;
queryInland_dd();
};
/**--------------------------- */
/**外宾表格----------------------- */
const columns_abroad = [
{
title: "姓名",
dataIndex: "chineseName",
},
{
title: "证件号码",
dataIndex: "certificateNumber",
},
{
title: "性别",
dataIndex: "genderName",
},
{
title: "出生日期",
dataIndex: 'dateBirth',
},
{
title: "国籍地区",
dataIndex: "nationalityCodeName",
},
{
title: "房号",
dataIndex: "roomName",
},
{
title: "所属团队",
dataIndex: "teamName",
},
{
title: "旅客状态",
dataIndex: "state",
},
{
title: "入住时间",
dataIndex: "checkinTime",
},
{
title: "离店时间",
dataIndex: "departureTime",
},
{
title: "操作",
dataIndex: "cz",
fixed: "right",
width: 200,
},
];
const data_abroad = ref([]);
const page_abroad = ref(formState.current);/**当前第几页 */
const pageSize_abroad = ref(formState.pageSize);/**当前每页的数据 */
const total_abroad = ref(0);/**总数 */
const selectedRowKeys_abroad = ref([]);/**当前选中集合 */
const loading_abroad = ref(false);
const rowSelection_abroad = {
onChange: (selectedRowKeys, selectedRows) => {
selectedRowKeys_abroad.value = selectedRowKeys;
},
}
const onChange_abroad = (page, pageSize) => {
page_abroad.value = page;
pageSize_abroad.value = pageSize;
queryAbroad_dd();
};
/**--------------------------- */
/**时间变化 */
const handleChangeTime = (data, dataArr,) => {
if (dataArr && dataArr.length > 0) {
formState.checkinTimeEnd = dataArr[1];
formState.checkinTimeStart = dataArr[0];
} else {
formState.checkinTimeEnd = "";
formState.checkinTimeStart = "";
}
};
/**下拉框筛选 */
const filterOption = (input, option) => {
return option.name.toLowerCase().indexOf(input.toLowerCase()) >= 0;
};
/**内宾查询 */
const queryInland = () => {
formState.departureTimeStart = ChangeDateType(new Date(new Date().getTime() - 8 * 60 * 60 * 1000), 'yyyy-MM-dd hh:mm:ss');
formState.departureTimeEnd = ChangeDateType(new Date(), 'yyyy-MM-dd hh:mm:ss');
return new Promise((resolve) => {
inlandQuery(formState).then((res) => {
if (res?.code == 9000) {
resolve(res);
} else {
resolve("");
}
});
});
}
/**内宾单独查询 */
const queryInland_dd = () => {
const arr = { ...formState };
arr.current = page_inland.value;
arr.pageSize = pageSize_inland.value;
loading_inland.value = true;
arr.departureTimeStart = ChangeDateType(new Date(new Date().getTime() - 8 * 60 * 60 * 1000), 'yyyy-MM-dd hh:mm:ss');
arr.departureTimeEnd = ChangeDateType(new Date(), 'yyyy-MM-dd hh:mm:ss');
inlandQuery(arr).then((res) => {
if (res?.code == 9000) {
data_inland.value = res.data.records;
total_inland.value = res.data.total;
}
loading_inland.value = false;
}).catch(error => {
loading_inland.value = false;
});
}
/**外宾查询 */
const queryAbroad = () => {
const arr = { ...formState };
arr.departureTimeStart = ChangeDateType(new Date(new Date().getTime() - 8 * 60 * 60 * 1000), 'yyyy-MM-dd hh:mm:ss');
arr.departureTimeEnd = ChangeDateType(new Date(), 'yyyy-MM-dd hh:mm:ss');
return new Promise((resolve) => {
getForeignGuestCheckInList(arr).then((res) => {
if (res?.code == 9000) {
resolve(res);
} else {
resolve("");
}
});
});
}
/**外宾单独查询 */
const queryAbroad_dd = () => {
const arr = { ...formState };
arr.current = page_abroad.value;
arr.pageSize = pageSize_abroad.value;
loading_abroad.value = true;
arr.departureTimeStart = ChangeDateType(new Date(new Date().getTime() - 8 * 60 * 60 * 1000), 'yyyy-MM-dd hh:mm:ss');
arr.departureTimeEnd = ChangeDateType(new Date(), 'yyyy-MM-dd hh:mm:ss');
getForeignGuestCheckInList(arr).then((res) => {
if (res?.code == 9000) {
data_abroad.value = res.data.records;
total_abroad.value = res.data.total;
}
loading_abroad.value = false;
}).catch(error => {
loading_abroad.value = false;
});
}
/**分页查询 */
const queryList = async () => {
loading.value = true;
page_inland.value = formState.current;
pageSize_inland.value = formState.pageSize;
page_abroad.value = formState.current;
pageSize_abroad.value = formState.pageSize;
Promise.all([queryInland(), queryAbroad()]).then(([res1, res2]) => {
loading.value = false;
data_inland.value = res1.data.records;
total_inland.value = res1.data.total;
data_abroad.value = res2.data.records;
total_abroad.value = res2.data.total;
}).catch(error => {
loading.value = false;
});
};
/**内宾单个恢复 */
const setState_inland = (record) => {
loading.value = true;
restoreDomesticGuestsToStay([record.id])
.then((res) => {
loading.value = false;
if (res?.code == 9000) {
message.success("恢复成功");
queryInland_dd();
}
})
.catch((res) => {
loading.value = false;
message.warning("恢复失败");
});
}
/**内宾批量恢复 */
const departure_inland = () => {
return new Promise((resolve) => {
restoreDomesticGuestsToStay(selectedRowKeys_inland.value).then((res) => {
if (res?.code == 9000) {
resolve(res);
} else {
resolve("");
}
});
});
}
/**外宾单个恢复 */
const setState_abroad = (record) => {
loading.value = true;
restoreForeignGuestsToStay([record.id])
.then((res) => {
loading.value = false;
if (res?.code == 9000) {
message.success("恢复成功");
queryAbroad_dd();
}
})
.catch((res) => {
loading.value = false;
message.warning("恢复失败");
});
}
/**外宾批量恢复 */
const departure_abroad = () => {
return new Promise((resolve) => {
restoreForeignGuestsToStay(selectedRowKeys_abroad.value).then((res) => {
if (res?.code == 9000) {
resolve(res);
} else {
resolve("");
}
});
});
}
/**批量恢复 */
const restore = () => {
if (selectedRowKeys_inland.value.length > 0 || selectedRowKeys_abroad.value.length > 0) {
loading.value = true;
const arr_http = [];
if (selectedRowKeys_inland.value.length > 0) {
arr_http.push(departure_inland());
} else {
arr_http.push("");
}
if (selectedRowKeys_abroad.value.length > 0) {
arr_http.push(departure_abroad());
} else {
arr_http.push("");
}
Promise.all(arr_http).then(([res1, res2]) => {
loading.value = false;
message.success('恢复成功')
queryList();
}).catch(error => {
loading.value = false;
})
} else {
message.warning('请选择行')
}
}
/**内宾查看 */
const info_id = ref('');
const hotelFormVisible = ref(false);
const hotelFormVisible_edit = ref(false);
const titles = ref("查看内宾详情");
const changeCancel_inland = () => {
hotelFormVisible.value = false;
};
const eye_inland = (e) => {
info_id.value = e.id;
hotelFormVisible.value = true;
hotelFormVisible_edit.value = false;
};
/**外宾查看 */
const abroadInfoVisible = ref(false);
const operateStatus = ref(false);
const dictionaryAllInfo = ref({});
const abroadInfo = ref('');
const hotelFormVisible_edit_s = ref(false);
const changeCancel_adroad = () => {
abroadInfoVisible.value = false;
};
const eye_abroad = (e) => {
abroadInfo.value = e;
abroadInfoVisible.value = true;
operateStatus.value = true;
hotelFormVisible_edit_s.value = false;
};
onMounted(() => {
queryList();
})
</script>
<style lang="less">
.restoreCheckIn {
width: 100%;
height: 100%;
padding: 0px;
margin: 0px;
overflow-y: auto;
.form {
.ant-form-item {
margin-bottom: 0px;
}
}
.form-tables {
width: 100%;
border-collapse: collapse;
tr {
width: 100%;
height: 60px;
td {
border: 1px solid #e7e7e7;
max-width: 222px;
.img-wp {
width: 186.829px;
height: 230px;
border: 1px solid #a5a5a5;
.img-div {
border-image-source: radial-gradient(
60% 60%,
transparent 0px,
transparent 100%,
#6691ef 100%
);
border-image-slice: 1;
border-width: 1px;
border-style: solid;
border-image-outset: 0px;
width: calc(100% - 40px);
height: calc(100% - 40px);
margin: 20px;
.img-span {
margin: 23px auto;
width: 14px;
line-height: 35px;
font-weight: 400;
font-size: 15px;
}
}
}
}
}
}
.titleBox {
display: flex;
justify-content: space-between;
align-items: center;
background: #fafafa;
border-radius: 0px 0px 2px 2px;
border: 1px solid #e9e9e9;
padding: 10px;
margin: 25px 5px;
}
.sign {
display: inline-block;
font-size: 16px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: rgba(0, 0, 0, 0.85);
line-height: 16px;
&::before {
content: "";
display: inline-block;
width: 4px;
height: 12px;
background: #3162f5;
border-radius: 2px;
margin-right: 8px;
}
}
}
</style>
\ No newline at end of file
<template>
<div class="room">
<a-spin :spinning="loading">
<div class="titleBox">
<div>
<span class="sign">房号列表</span>
</div>
</div>
<div style="margin: 0px 25px">
<a-form ref="formRef" name="advanced_search" class="ant-advanced-search-form" :model="formState">
<a-row :gutter="24">
<a-col :span="3">
<a-form-item name="name" label="房号">
<a-input v-model:value="formState.name" placeholder="请输入房号"></a-input>
</a-form-item>
</a-col>
<!-- <a-col :span="3">
<a-form-item name="field1" label="房间类型">
<a-input v-model:value="formState.field1" placeholder="请输入房间类型"></a-input>
</a-form-item>
</a-col> -->
<a-col :span="3">
<a-form-item name="floor" label="楼层">
<a-input v-model:value="formState.floor" placeholder="请输入楼层"></a-input>
</a-form-item>
</a-col>
<a-col :span="3">
<a-form-item name="roomPhone" label="房间电话">
<a-input v-model:value="formState.roomPhone" placeholder="请输入房间电话"></a-input>
</a-form-item>
</a-col>
<a-col :span="5">
<a-form-item name="room_num1" label="床位数">
<a-form-item style="width: calc(40% - 11px);float: left;" name="room_num">
<a-input-number style="width: 100%;" v-model:value="formState.minBed" @change="" placeholder="床位数" :min="0" :max="formState.maxBed"></a-input-number>
</a-form-item><span>&nbsp;&nbsp;</span>
<a-input-number style="width: calc(40% - 11px)" v-model:value="formState.maxBed" placeholder="床位数" :min="formState.minBed"></a-input-number>
</a-form-item>
</a-col>
<a-col style="text-align: right">
<a-button type="primary" @click="queryRoomsByParamsButton">
<template #icon>
<SearchOutlined />
</template>查询</a-button>&nbsp;
<a-button type="primary" @click="addSingleRoom">
<template #icon><plus-outlined /></template>新增</a-button>&nbsp;
<a-button type="primary" @click="addBatchRoom">
<template #icon><appstore-add-outlined /></template>批量新增</a-button>&nbsp;
<a-button type="primary" :disabled="state.selectedRowKeys.length>0?false:true" @click="bulkDeleteRooms">
<template #icon><delete-outlined /></template>批量删除</a-button>&nbsp;
<!-- <a-button style="margin: 0 8px" @click="() => formRef.resetFields()">清除</a-button>&nbsp; -->
<a-button type="primary" html-type="submit" @click="eye_info">查看房态</a-button>
</a-col>
</a-row>
</a-form>
</div>
<div style="margin: 0px 25px; height: calc(100% - 210px)">
<a-table :row-selection="{selectedRowKeys: state.selectedRowKeys,onChange: onSelectChange}" :columns="columns" :data-source="data" :pagination="false" :scroll="{y:450}"><template #bodyCell="{ column, record }">
<template v-if="column.dataIndex === 'cz'">
<a-space :size="0">
<a-button type="link" primary size="small" style="color: #52c41a" @click="eyes(record)">
<template #icon>
<eye-filled />
</template>
查看
</a-button>
<a-button type="link" primary size="small" style="color:#faad14" @click="edit(record)">
<template #icon>
<edit-filled />
</template>
修改
</a-button>
<a-popconfirm title="删除不可恢复,是否确认?" @confirm="deleteRooms(record)">
<a-button type="link" primary size="small" style="color:#ff4d1f">
<template #icon>
<swap-outlined />
</template>
删除
</a-button>
</a-popconfirm>
</a-space>
</template>
</template>
</a-table>
<a-pagination v-model:current="formState.current" :page-size="10" show-quick-jumper :total="formState.total" size="small" :show-total="(total) => `总数共: ${total} 条`" @change="onChangePagination" style="margin: 20px 0px" />
</div>
<RoomDynamics v-if="hotelFormVisible" :visible="hotelFormVisible" :title="title" @change-Cancel="changeCancel" />
<RoomEyes v-if="hotelFormVisibles" :visible="hotelFormVisibles" :flogStatus="operateStatus" :title="titles" :records='currentData' @change-Cancel="changeCancelEye" @refresh-Table="queryRoomsByParams" />
<RoomSingleAdd v-if="roomSingleAddVisible" :visible="roomSingleAddVisible" :title="roomSingleAddTitle" @change-Cancel="changeCancelSingleAdd" />
<RoomBatchAdd v-if="roomBatchAddVisible" :visible="roomBatchAddVisible" :title="roomBatchAddTitle" @change-Cancel="changeCancelBatchAdd" />
</a-spin>
</div>
</template>
<script setup>
import { onMounted, reactive, ref } from "vue";
import RoomDynamics from "@/views/room/roomDynamics.vue";
import RoomEyes from "@/views/room/roomEyes.vue";
import RoomSingleAdd from '@/views/room/roomSingleAdd.vue';
import RoomBatchAdd from '@/views/room/roomBatchAdd.vue';
import { EyeFilled } from "@ant-design/icons-vue";
import { getRooms, bulkRemoveRooms } from "@/api/room.js";
import { useStore } from '@/store/index.js'
import { message } from "ant-design-vue";
const usestore = useStore();
const formRef = ref();
const formState = reactive({
hotelId: usestore.hotelInfo.hotelId,
current: 1,
floor: 1,
minBed: 1,
maxBed: 5,
name: '',
pageSize: 10,
roomPhone: '',
state: '',
type: '',
total: 0
});
const loading = ref(false);
const roomIds = ref([]);
const hotelFormVisible = ref(false);
const title = ref('房间动态');
const changeCancel = () => {
hotelFormVisible.value = false;
};
const eye_info = () => {
hotelFormVisible.value = true;
}
const hotelFormVisibles = ref(false);
const titles = ref('房间详情');
const changeCancelEye = () => {
hotelFormVisibles.value = false;
};
/**查看 */
const currentData = ref({});
const operateStatus = ref(false);
const eyes = (e) => {
currentData.value = e;
operateStatus.value = true;
hotelFormVisibles.value = true;
};
//编辑
const edit = e => {
currentData.value = e;
operateStatus.value = false;
hotelFormVisibles.value = true;
}
//删除
const deleteDefault = data => {
bulkRemoveRooms(data).then(res => {
if (res.code == '9000') {
queryRoomsByParams();
message.success('删除成功!');
} else {
message.error('删除失败');
}
}).catch(error => {
message.error(error.message);
})
};
const deleteRooms = e => {
deleteDefault([e.id]);
}
//批量删除
const bulkDeleteRooms = () => {
deleteDefault(state.selectedRowKeys);
}
/**下拉框筛选 */
const filterOption = (input, option) => {
return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0;
};
/**表格 */
const columns = [
{
title: "序号",
dataIndex: "index",
},
{
title: "房间号",
dataIndex: "name",
},
{
title: "楼层",
dataIndex: "floor",
},
{
title: "房间电话",
dataIndex: "roomPhone",
},
{
title: "床位数",
dataIndex: "bed",
},
{
title: "操作",
dataIndex: "cz",
fixed: "right",
width: 300
},
];
const data = ref([]);
const state = reactive({
selectedRowKeys: [],
// Check here to configure the default column
loading: false,
});
const onSelectChange = (selectedRowKeys) => {
console.log("selectedRowKeys changed: ", selectedRowKeys);
state.selectedRowKeys = selectedRowKeys;
};
/**分页 */
const onChangePagination = (pageNumber) => {
loading.value = true;
formState.current = pageNumber;
queryRoomsByParams();
// console.log("Page: ", pageNumber);
};
//单个房间新增
const roomSingleAddVisible = ref(false);
const roomSingleAddTitle = ref('单个房间新增');
const changeCancelSingleAdd = () => {
roomSingleAddVisible.value = false;
}
const addSingleRoom = () => {
roomSingleAddVisible.value = true;
}
//批量房间新增
const roomBatchAddVisible = ref(false);
const roomBatchAddTitle = ref('房间批量新增');
const changeCancelBatchAdd = () => {
roomBatchAddVisible.value = false;
}
const addBatchRoom = () => {
roomBatchAddVisible.value = true;
}
//按钮查询
const queryRoomsByParamsButton = () => {
formState.current = 1;
queryRoomsByParams();
}
//分页查询房间
const queryRoomsByParams = () => {
loading.value = true;
getRooms(formState).then(res => {
if (res.code == '9000') {
data.value = [];
formState.pageSize = 10;
formState.total = res.data.total;
res.data.records.forEach((item, index) => {
item['index'] = (formState.current - 1) * 10 + index + 1;
item['key'] = item.id;
data.value.push(item);
});
loading.value = false;
}
}).catch(error => {
message.error(error.message);
loading.value = false;
});
}
//刷新主页面表格
onMounted(() => {
loading.value = true;
//默认查询
queryRoomsByParams();
})
</script>
<style lang="less">
.room {
width: 100%;
height: 100%;
padding: 0%;
margin: 0px;
.titleBox {
display: flex;
justify-content: space-between;
align-items: center;
background: #fafafa;
border-radius: 0px 0px 2px 2px;
border: 1px solid #e9e9e9;
padding: 10px;
margin: 25px 5px;
}
.sign {
display: inline-block;
font-size: 16px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: rgba(0, 0, 0, 0.85);
line-height: 16px;
&::before {
content: "";
display: inline-block;
width: 4px;
height: 12px;
background: #3162f5;
border-radius: 2px;
margin-right: 8px;
}
}
}
</style>
\ No newline at end of file
<template>
<a-modal :visible="visible" :title="title" width="60%" @cancel="handleCancel" @ok="handleCancel">
<div class="roomBatchAdd">
<div style="margin: 0px 5px">
<a-form class="form" ref="formRef" :model="formState" :labelCol="{ span: 6 }" :wrapper-col="{ span: 18 }" layout="inline">
<table class="form-tables">
<tr>
<td colspan="3">
<a-form-item name="'minFloorNo'" :label="'楼层'">
<a-input-number v-model:value="formState.minFloorNo" placeholder="开始楼层" :allowClear="true" />
&nbsp;&nbsp;
<a-form-item-rest>
<a-input-number v-model:value="formState.maxFloorNo" placeholder="结束楼层" :allowClear="true" />
</a-form-item-rest>
</a-form-item>
</td>
<td colspan="3">
<a-form-item name="floorDigit" :label="'楼层位数'">
<a-input-number v-model:value="formState.floorDigit" placeholder="请输入楼层位数" :allowClear="true" />
</a-form-item>
</td>
</tr>
<tr>
<td colspan="3">
<a-form-item name="minRoomNo" :label="'房间号'">
<a-input-number v-model:value="formState.minRoomNo" placeholder="开始房号" :allowClear="true" />
&nbsp;&nbsp;
<a-form-item-rest>
<a-input-number v-model:value="formState.maxRoomNo" placeholder="结束房号" :allowClear="true" />
</a-form-item-rest>
</a-form-item>
</td>
<td colspan="3">
<a-form-item name="roomDigit" :label="'房号位数'">
<a-input-number v-model:value="formState.roomDigit" placeholder="请输入房号位数" :allowClear="true" />
</a-form-item>
</td>
</tr>
<tr>
<td colspan="3">
<a-form-item name="buildingNo" :label="'房号模板'">
<a-input-group compact>
<a-input v-model:value="formState.buildingNo" style="width: 20%" />
<a-form-item-rest>
<a-input value="【楼层】【房间号】" style="width: 40%" />
</a-form-item-rest>
</a-input-group>
</a-form-item>
</td>
<td colspan="3">
<a-form-item name="phoneTemplate" :label="'电话号码模板'">
<a-input-group compact>
<a-input v-model:value="formState.phoneTemplate" style="width: 20%" />
<a-form-item-rest>
<a-input value="【楼层】【房间号】" style="width: 40%" />
</a-form-item-rest>
</a-input-group>
</a-form-item>
</td>
</tr>
<tr>
<td colspan="3">
<a-form-item name="bed" :label="'床位数'">
<a-input-number v-model:value="formState.bed" placeholder="请输入床位数" :allowClear="true" />
</a-form-item>
</td>
</tr>
<tr>
<td colspan="3">
<a-form-item name="avoidFloorNum" :label="'楼层规避数字'">
<a-input v-model:value="formState.avoidFloorNum" placeholder="请输入楼层规避数字,多个数字以@隔开,例如3@4" />
</a-form-item>
</td>
<td colspan="3">
<a-form-item v-for="(domain, index) in floorRules.domains" :key="domain.key" formItemLayout :label="`楼层数字转换${index+1}`" :name="`domains${index}`" style="margin-top:10px;">
<a-form-item-rest>
<a-input v-model:value="domain.no" placeholder="原始楼层顺序号" :allowClear="true" style="width:40%;" />
</a-form-item-rest>
=>
<a-form-item-rest>
<a-input v-model:value="domain.value" placeholder="新的楼层顺序号" :allowClear="true" style="width:40%;" />
</a-form-item-rest>&nbsp;
<MinusCircleOutlined v-if="floorRules.domains.length > 0" class="dynamic-delete-button" :disabled="floorRules.domains.length === 0" @click="removeDomainFloor(domain)" />
</a-form-item>
<a-form-item style="margin-top:10px;margin-bottom:10px;">
<a-button type="dashed" style="width: 60%;margin-left:100px;" @click="addDomainFloor">
<PlusOutlined />
新增转换楼层
</a-button>
</a-form-item>
</td>
</tr>
<tr>
<td colspan="3">
<a-form-item name="avoidRoomNum" :label="'房号规避数字'">
<a-input v-model:value="formState.avoidRoomNum" placeholder="请输入房号规避数字,多个数字以@隔开,例如3@4" />
</a-form-item>
</td>
<td colspan="3">
<a-form-item v-for="(domain, index) in roomRules.domains" :key="domain.key" formItemLayout :label="`房号数字转换${index+1}`" :name="`domains${index}`" style="margin-top:10px;">
<a-form-item-rest>
<a-input v-model:value="domain.no" placeholder="原始房间顺序号" :allowClear="true" style="width:40%;" />
</a-form-item-rest>
=>
<a-form-item-rest>
<a-input v-model:value="domain.value" placeholder="新的房间顺序号" :allowClear="true" style="width:40%;" />
</a-form-item-rest>&nbsp;
<MinusCircleOutlined v-if="roomRules.domains.length > 0" class="dynamic-delete-button" :disabled="roomRules.domains.length === 0" @click="removeDomainRoom(domain)" />
</a-form-item>
<a-form-item style="margin-top:10px;margin-bottom:10px;">
<a-button type="dashed" style="width: 60%;margin-left:100px;" @click="addDomainRoom">
<PlusOutlined />
新增转换房号
</a-button>
</a-form-item>
</td>
</tr>
<tr>
<td colspan="6">
<a-form-item name="roomNumPreview" :label="'房号预览'">
<a-input v-model:value="formState.roomNumPreview" readonly style="color:red;font-weight:600;" />
</a-form-item>
</td>
</tr>
<tr>
<td colspan="6">
<a-form-item name="phoneNumPreview" :label="'电话号码预览'">
<a-input v-model:value="formState.phoneNumPreview" readonly style="color:red;font-weight:600;" />
</a-form-item>
</td>
</tr>
</table>
</a-form>
</div>
<div class="titleBox">
<div style="margin: 0 auto">
<a-space :size="10">
<a-button type="primary" size="large" @click="preview">预览</a-button>
<a-button type="primary" size="large" @click="saveRoom" :disabled="previewData.length>0?false:true">保存</a-button>
<a-button type="primary" size="large" @click="() => formRef.resetFields()"><template #icon>
<reload-outlined />
</template>
清空</a-button>
</a-space>
</div>
</div>
</div>
<template #footer>
</template>
</a-modal>
</template>
<script setup>
import { reactive } from "vue";
import { useStore } from '@/store/index.js';
import { previewRooms, addRooms } from '@/api/room.js';
import { message } from "ant-design-vue";
const usestore = useStore();
const props = defineProps({
visible: Boolean,
title: String,
});
const formRef = ref();
const formState = reactive({
hotelId: usestore.hotelInfo.hotelId,
creator: usestore.userInfo.username,
bed: null,
buildingNo: null,
floorDigit: null,
minRoomNo: null,
maxRoomNo: null,
roomRule: [],
roomDigit: null,
minFloorNo: null,
maxFloorNo: null,
avoidFloorNum: null,
floorRule: [],
phoneTemplate: '',
avoidRoomNum: null,
roomNumPreview: '',
phoneNumPreview: ''
})
const defalutDictionaryAll = reactive({
allRoomType: usestore.returnCode(1),
allRoomBedNum: [{ id: 1, code: 1, name: '一张床' }, { id: 2, code: 2, name: '两张床' }, { id: 1, code: 1, name: '三张床' }, { id: 1, code: 1, name: '四张床' }, { id: 5, code: 5, name: '五张床' }],
allRoomState: [{ id: 1, code: 1, name: '正常' }, { id: 1, code: 1, name: '维修' }, { id: 1, code: 1, name: '关闭' }]
});
const rules = {
name: [
{
required: true,
message: '请输入房间号'
}
],
type: [
{
required: true,
message: '请选择房间类型'
}
],
floor: [
{
required: true,
message: '请输入楼层'
},
],
room_phone: [
{
required: true,
message: '请输入房间电话'
},
],
bed: [
{
required: true,
message: '请选择床数量'
}
],
state: [
{
required: true,
message: '请选择房间状态'
}
]
};
//预览的数据
const previewData = ref([]);
const emit = defineEmits(["changeCancel"]);
const handleCancel = async () => {
await emit("changeCancel");
};
const handleOk = async () => {
formRef.value?.validateFields().then(async (values) => {
// await emit("handleSubmit", values);
});
};
/**下拉框筛选 */
const filterOption = (input, option) => {
return option.name.toLowerCase().indexOf(input.toLowerCase()) >= 0;
};
const preview = () => {
//楼层号
if (formState.avoidFloorNum) {
if (formState.avoidFloorNum.indexOf('@') > -1) {
const avoidList = formState.avoidFloorNum.split('@');
avoidList.forEach(item => {
const obj = {};
obj['no'] = item;
obj['value'] = null;
formState.floorRule.push(obj);
});
} else {
formState.floorRule.push({ no: formState.avoidFloorNum, value: null });
}
}
floorRules.domains.forEach(item => {
if (item.no) {
formState.floorRule.push(item);
}
})
// formState.floorRule = formState.floorRule.concat(floorRules.domains);
//房间号
if (formState.avoidRoomNum) {
if (formState.avoidRoomNum.indexOf('@') > -1) {
const avoidList = formState.avoidRoomNum.split('@');
avoidList.forEach(item => {
const obj = {};
obj['no'] = item;
obj['value'] = null;
formState.roomRule.push(obj);
});
} else {
formState.roomRule.push({ no: formState.avoidRoomNum, value: null });
}
}
roomRules.domains.forEach(item => {
if (item.no) {
formState.roomRule.push(item);
}
});
// formState.roomRule = formState.roomRule.concat(roomRules.domains);
previewRooms(formState).then(res => {
if (res.code == '9000') {
// message.success('规则创建成功!');
previewData.value = res.data;
// floorRules.domains = [];
// roomRules.domains = [];
// formState.floorRule = [];
// formState.roomRule = [];
// formRef.value.resetFields();
formState.roomNumPreview = `第一个房号:${res.data[0].name},最后一个房号是:${res.data[res.data.length - 1].name}。`;
}
}).catch(error => {
message.error(error.message);
})
}
//保存房号
const saveRoom = () => {
if (previewData.value.length > 0) {
addRooms(previewData.value).then(res => {
if (res.code == '9000') {
message.success('新增成功:'+res.data.success+',新增失败:'+res.data.failure+',失败原因:'+res.data.message.join(''),10);
floorRules.domains = [];
roomRules.domains = [];
formRef.value.resetFields();
}
});
} else {
message.warning('暂无数据新增!');
}
}
//楼层规则
const floorRules = reactive({
domains: [],
});
const addDomainFloor = () => {
floorRules.domains.push({
no: null,
value: null,
key: Date.now()
});
};
const removeDomainFloor = item => {
let index = floorRules.domains.indexOf(item);
if (index !== -1) {
floorRules.domains.splice(index, 1);
}
};
//房间规则
const roomRules = reactive({
domains: [],
});
const addDomainRoom = () => {
roomRules.domains.push({
value: '',
key: '',
});
};
const removeDomainRoom = item => {
let index = roomRules.domains.indexOf(item);
if (index !== -1) {
roomRules.domains.splice(index, 1);
}
};
const formItemLayout = {
labelCol: {
span: 10,
},
wrapperCol: {
span: 14
}
};
</script>
<style lang="less">
.roomBatchAdd {
width: 100%;
height: 100%;
padding: 0px;
margin: 0px;
.form {
.ant-form-item-with-help {
margin-bottom: 0px;
}
.ant-form-item-label {
flex: auto;
}
}
.form-tables {
width: 100%;
border-collapse: collapse;
tr {
width: 100%;
height: 60px;
td {
border: 1px solid #e7e7e7;
max-width: 222px;
}
}
}
.titleBox {
display: flex;
justify-content: space-between;
align-items: center;
background: #fafafa;
border-radius: 0px 0px 2px 2px;
border: 1px solid #e9e9e9;
padding: 10px;
margin: 25px 5px;
}
}
</style>
\ No newline at end of file
<template>
<a-modal :visible="visible" :title="title" width="80%" @cancel="handleCancel" @ok="handleCancel">
<div class="roomDynamics">
<div style="margin: 0px 5px">
<a-form class="form" ref="formRef" :model="formState" :labelCol="{ span: 4 }" :wrapper-col="{ span: 20 }" layout="inline">
<table class="form-tables">
<tr>
<td colspan="2" class="td1">
<span>旅馆房间数:</span>
</td>
<td colspan="2" class="td2">
<span v-text="formState.hotelRooms"></span>
</td>
<td colspan="2" class="td1">入住房间数:</td>
<td colspan="2" class="td2">
<span v-text="formState.numberOfRoomsOccupied"></span>
</td>
<td colspan="2" class="td1">
<span>房间入住率:</span>
</td>
<td colspan="2" class="td2">
<a-progress :stroke-color="{'0%': '#108ee9','100%': '#87d068'}" :percent="parseFloat(formState.occupancyRate).toFixed(2)" />
</td>
</tr>
<tr>
<td colspan="2" class="td1">
<span>入住旅客数:</span>
</td>
<td colspan="2" class="td2">
<span v-text="formState.numberOfOccupants"></span>
</td>
<td colspan="2" class="td1">
<span>内宾数:</span>
</td>
<td colspan="2" class="td2">
<span v-text="formState.numberOfDomesticGuests"></span>
</td>
<td colspan="2" class="td1">
<span>外宾数:</span>
</td>
<td colspan="2" class="td2">
<span v-text="formState.numberOfForeignGuests"></span>
</td>
</tr>
</table>
</a-form>
</div>
<div style="margin: 0px 5px">
<div style="width: 100%; float: left; margin: 20px 10px; font-weight: 400">
<div style="float: left">
<span style="font-weight: 900">说明: </span>
<span>右上角&nbsp;</span>
</div>
<div style=" width: 20px; height: 20px; background: #13c2c2; float: left; text-align: center; color: white ">
<span>[1]</span>
</div>
<div style="float: left">
<span>&nbsp;表示房间床位数;&nbsp;</span>
</div>
<div style="width: 20px;height: 20px;background: #2db7f5;float: left;text-align: center; color: white;">
<span></span>
</div>
<div style="float: left">
<span>&nbsp;表示房间入住总人数;&nbsp;</span>
</div>
<div style="width: 20px;height: 20px;background: #87d068;float: left;text-align: center;color: white;">
<span></span>
</div>
<div style="float: left">
<span>&nbsp;表示入住内宾数;&nbsp;</span>
</div>
<div style="width: 20px;height: 20px;background: #f1ce03;float: left;text-align: center;color: white;">
<span></span>
</div>
<div style="float: left">
<span>&nbsp;表示入住外宾数; 灰色背景房间无人入住</span>
</div>
</div>
<a-list :grid="{ gutter: 16, column: 8 }" :data-source="formStateArr" class="list-div">
<template #renderItem="{ item }">
<a-list-item>
<a-badge-ribbon :text="'[' + item.bed + ']'" color="cyan">
<a-card :style="{background:item.totalCheckIn > 0? '#d1ffbe' : '#ebebeb'}">
<div style="line-height: 50px; text-align: center">
<span style="color: #ff4d1f;font-size: 17px;letter-spacing: 2px;font-weight: 600;">{{ item.roomNo }}</span>
</div>
<div style="height: 20px;width: 100%;display: flex;flex-direction: row;flex-wrap: nowrap;justify-content: space-evenly;">
<div style="padding: 0px 6px;background: #2db7f5;width: fit-content;color: white; " v-show="item.total != 0">
<span>{{"总(" + (item.totalCheckIn) + ")"}}</span>
</div>
<div style="padding: 0px 6px;background: #87d068;width: fit-content;color: white;" v-show="item.domesticGuestCheckIn != 0">
<span>{{ "内(" + item.domesticGuestCheckIn + ")" }}</span>
</div>
<div style="padding: 0px 6px;background: #f1ce03;width: fit-content;color: white;" v-show="item.foreignGuestCheckIn != 0">
<span>{{ "外(" + item.foreignGuestCheckIn + ")" }}</span>
</div>
</div>
</a-card>
</a-badge-ribbon>
</a-list-item>
</template>
</a-list>
</div>
</div>
<template #footer> </template>
</a-modal>
</template>
<script setup>
import { queryRoomStatus, queryStatisticsRoomStatus } from '@/api/room.js';
import { useStore } from '@/store/index.js';
import { message } from 'ant-design-vue';
import { onMounted } from 'vue';
const usestore = useStore();
const props = defineProps({
visible: Boolean,
title: String,
});
const formRef = ref();
const formState = ref({});
const formStateArr = ref([]);
const emit = defineEmits(["changeCancel"]);
const handleCancel = async () => {
await emit("changeCancel");
}
onMounted(() => {
//上半部分
queryRoomStatus({ hotelId: usestore.hotelInfo.hotelId }).then(res => {
if (res.code == '9000') {
formState.value = res.data;
}
}).catch(error => {
message.error(error.message);
})
//下半部分
queryStatisticsRoomStatus({ hotelId: usestore.hotelInfo.hotelId }).then(res => {
if (res.code == '9000') {
formStateArr.value = res.data;
}
}).catch(error => {
message.error(error.message);
})
})
</script>
<style lang="less">
.roomDynamics {
width: 100%;
height: 100%;
padding: 0px;
margin: 0px;
.form {
.ant-form-item-with-help {
margin-bottom: 0px;
}
.ant-form-item-label {
flex: auto;
}
}
.form-tables {
width: 100%;
border-collapse: collapse;
tr {
width: 100%;
height: 60px;
td {
border: 1px solid #e7e7e7;
max-width: 222px;
width: 110px;
.img-wp {
width: 175px;
height: 230px;
// border: 1px solid #a5a5a5;
.img-div {
border-image-source: radial-gradient(
60% 60%,
transparent 0px,
transparent 100%,
#6691ef 100%
);
border-image-slice: 1;
border-width: 1px;
border-style: solid;
border-image-outset: 0px;
width: calc(100% - 40px);
height: calc(100% - 40px);
margin: 20px;
}
.img-span {
text-align: center;
color: orange;
font-weight: 400;
font-size: 15px;
}
}
}
.td1 {
font-weight: 600;
font-size: 13px;
text-align: right;
padding: 0px 20px;
color: #007cef;
letter-spacing: 2px;
}
.td2 {
text-align: left;
padding: 0px 20px;
color: #ff4d1f;
font-weight: 600;
.ant-progress-text {
color: #ff4d1f;
}
}
}
}
.list-div {
.ant-card-body {
padding: 10px;
}
}
.titleBox {
display: flex;
justify-content: space-between;
align-items: center;
background: #fafafa;
border-radius: 0px 0px 2px 2px;
border: 1px solid #e9e9e9;
padding: 10px;
margin: 25px 5px;
}
.sign {
display: inline-block;
font-size: 16px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: rgba(0, 0, 0, 0.85);
line-height: 16px;
&::before {
content: "";
display: inline-block;
width: 4px;
height: 12px;
background: #3162f5;
border-radius: 2px;
margin-right: 8px;
}
}
}
</style>
\ No newline at end of file
<template>
<a-modal :visible="visible" :title="title" width="60%" @cancel="handleCancel" @ok="handleCancel">
<div class="roomEyesFrom">
<div style="margin: 0px 5px">
<a-form class="form" ref="formRef" :model="formState" :labelCol="{ span: 4 }" :wrapper-col="{ span: 20 }" layout="inline">
<table class="form-tables">
<tr>
<td colspan="2" class="td1">
<span>房号:</span>
</td>
<td colspan="2" class="td2">
<a-input v-model:value="formState.name" placeholder="请输入房号" :readonly="operateStatus?true:false"></a-input>
<!-- <span v-text="formState.name"></span> -->
</td>
<td colspan="2" class="td1">房间类型:</td>
<td colspan="2" class="td2">
<!-- <a-input v-model:value="formState.type" placeholder="请输入房间类型" :readonly="operateStatus?true:false"></a-input> -->
<a-select style="width:100%;" show-search v-model:value="formState.type" :filter-option="filterOption" placeholder="请选择房间类型" :allowClear="true" :options="roomType" optionLabelProp="name"
:fieldNames="{ label: 'name', value: 'code' }" :disabled="operateStatus?true:false">
</a-select>
<!-- <span v-text="formState.type"></span> -->
</td>
</tr>
<tr>
<td colspan="2" class="td1">
<span>楼层:</span>
</td>
<td colspan="6" class="td2">
<!-- <span v-text="formState.floor"></span> -->
<a-input v-model:value="formState.floor" placeholder="请输入楼层" :readonly="operateStatus?true:false"></a-input>
</td>
</tr>
<tr>
<td colspan="2" class="td1">
<span>床位数:</span>
</td>
<td colspan="2" class="td2">
<a-input v-model:value="formState.bed" placeholder="请输入床位数" :readonly="operateStatus?true:false"></a-input>
<!-- <span v-text="formState.bed"></span> -->
</td>
<td colspan="2" class="td1"><span>房间电话: </span></td>
<td colspan="2" class="td2">
<a-input v-model:value="formState.roomPhone" placeholder="请输入房间电话" :readonly="operateStatus?true:false"></a-input>
<!-- <span v-text="formState.roomPhone"></span> -->
</td>
</tr>
<tr>
<td colspan="2" class="td1">
<span>创建人:</span>
</td>
<td colspan="2" class="td2">
<a-input v-model:value="formState.creator" readonly></a-input>
</td>
<td colspan="2" class="td1"><span>创建时间: </span></td>
<td colspan="2" class="td2">
<a-input v-model:value="formState.createTime" readonly></a-input>
</td>
</tr>
<tr>
<td colspan="2" class="td1">
<span>修改人:</span>
</td>
<td colspan="2" class="td2">
<a-input v-model:value="formState.updater" readonly></a-input>
</td>
<td colspan="2" class="td1"><span>修改时间: </span></td>
<td colspan="2" class="td2">
<a-input v-model:value="formState.updateTime" readonly></a-input>
</td>
</tr>
<tr>
<td colspan="2" class="td1">
<span>备注:</span>
</td>
<td colspan="6" class="td2">
<a-input v-model:value="formState.remark" placeholder="请输入备注" :readonly="operateStatus?true:false"></a-input>
<!-- <span v-text="formState.remark"></span> -->
</td>
</tr>
</table>
</a-form>
</div>
<div class="titleBox">
<div style="margin: 0 auto">
<a-space :size="10">
<a-button type="primary" size="large" @click="edit">编辑</a-button>
<a-button type="primary" size="large" @click="saveInfo"><template #icon><file-protect-outlined /></template>保存</a-button>
<a-button type="primary" size="large" @click="() => formRef.resetFields()"><template #icon>
<reload-outlined />
</template>
清空</a-button>
</a-space>
</div>
</div>
</div>
<template #footer> </template>
</a-modal>
</template>
<script setup>
import { onMounted } from "vue";
import { forIn } from "lodash-es";
import { updateRoomsInfo } from '@/api/room.js';
import { message } from "ant-design-vue";
import { useStore } from "@/store/index.js";
const userstore = useStore();
const props = defineProps({
visible: Boolean,
title: String,
records: {},
flogStatus: Boolean
});
const roomType = ref(ref(userstore.returnCode(1)));
const formRef = ref();
const formState = reactive({});
const operateStatus = ref(true);
const emit = defineEmits(["changeCancel","refreshTable"]);
const handleCancel = async () => {
await emit("changeCancel");
};
/**提交事件 */
const handleOk = async () => {
formRef.value?.validateFields().then(async (values) => {
// await emit("handleSubmit", values);
});
};
/**下拉框筛选 */
const filterOption = (input, option) => {
return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0;
};
const onChange = (value, dateString) => {
formState.pass = dateString;
console.log("Selected Time: ", value);
console.log("Formatted Selected Time: ", dateString);
};
const onOk = (value, dateString) => {
formState.pass = dateString;
console.log("onOk: ", value);
};
const handleMenuClick = (e) => {
console.log("click", e);
};
//编辑
const edit = () => {
operateStatus.value = false;
}
//保存
const saveInfo = () => {
updateRoomsInfo(formState).then(res => {
if (res.code == '9000') {
emit('refreshTable');
message.success('保存成功!');
}
}).catch(error => {
message.error(error.message);
})
}
onMounted(() => {
forIn(props?.records, (value, key) => (formState[key] = value));
operateStatus.value = props?.flogStatus;
})
</script>
<style lang="less">
.roomEyesFrom {
width: 100%;
height: 100%;
padding: 0px;
margin: 0px;
.form {
.ant-form-item-with-help {
margin-bottom: 0px;
}
.ant-form-item-label {
flex: auto;
}
}
.form-tables {
width: 100%;
border-collapse: collapse;
tr {
width: 100%;
height: 60px;
td {
border: 1px solid #e7e7e7;
max-width: 222px;
width: 110px;
.img-wp {
width: 175px;
height: 230px;
// border: 1px solid #a5a5a5;
.img-div {
border-image-source: radial-gradient(
60% 60%,
transparent 0px,
transparent 100%,
#6691ef 100%
);
border-image-slice: 1;
border-width: 1px;
border-style: solid;
border-image-outset: 0px;
width: calc(100% - 40px);
height: calc(100% - 40px);
margin: 20px;
}
.img-span {
text-align: center;
color: orange;
font-weight: 400;
font-size: 15px;
}
}
}
.td1 {
font-weight: 600;
font-size: 13px;
text-align: right;
padding: 0px 20px;
color: #007cef;
letter-spacing: 2px;
}
.td2 {
text-align: left;
padding: 0px 20px;
}
}
}
.titleBox {
display: flex;
justify-content: space-between;
align-items: center;
background: #fafafa;
border-radius: 0px 0px 2px 2px;
border: 1px solid #e9e9e9;
padding: 10px;
margin: 25px 5px;
}
.sign {
display: inline-block;
font-size: 16px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: rgba(0, 0, 0, 0.85);
line-height: 16px;
&::before {
content: "";
display: inline-block;
width: 4px;
height: 12px;
background: #3162f5;
border-radius: 2px;
margin-right: 8px;
}
}
}
</style>
\ No newline at end of file
<template>
<a-modal :visible="visible" :title="title" width="60%" @cancel="handleCancel" @ok="handleCancel">
<div class="roomSingleAdd">
<div style="margin: 0px 5px">
<a-form class="form" ref="formRef" :model="formState" :labelCol="{ span: 6 }" :wrapper-col="{ span: 18 }" layout="inline" :rules="rules">
<table class="form-tables">
<tr>
<td colspan="3">
<a-form-item name="floor" :label="'楼层'">
<a-input v-model:value="formState.floor" placeholder="请输入楼层" :allowClear="true" />
</a-form-item>
</td>
<td colspan="3">
<a-form-item name="name" :label="'房间号'">
<a-input v-model:value="formState.name" placeholder="请输入房间号" :allowClear="true" />
</a-form-item>
</td>
</tr>
<tr>
<td colspan="3">
<a-form-item name="type" :label="'房间类型'">
<a-select v-model:value="formState.type" show-search placeholder="请选择房间类型" :options="defalutDictionaryAll.allRoomType" :filter-option="filterOption" :fieldNames="{value:'code',label:'name'}" :notFoundContent="'暂无数据'"></a-select>
</a-form-item>
</td>
<td colspan="3">
<a-form-item name="bed" :label="'床数量'">
<a-select v-model:value="formState.bed" show-search placeholder="请选择床数量" :options="defalutDictionaryAll.allRoomBedNum" :filter-option="filterOption" :fieldNames="{value:'code',label:'name'}" :notFoundContent="'暂无数据'"></a-select>
</a-form-item>
</td>
</tr>
<tr>
<td colspan="3">
<a-form-item name="roomPhone" :label="'房间电话'">
<a-input v-model:value="formState.roomPhone" placeholder="请输入房间电话" :allowClear="true" />
</a-form-item>
</td>
<td colspan="3">
<a-form-item name="state" :label="'房间状态'">
<a-select v-model:value="formState.state" show-search placeholder="请选择房间状态" :options="defalutDictionaryAll.allRoomState" :filter-option="filterOption" :fieldNames="{value:'code',label:'name'}" :notFoundContent="'暂无数据'"></a-select>
</a-form-item>
</td>
</tr>
<tr>
<td colspan="6">
<a-form-item name="reamrk" :label="'备注'" :label-col="{ span: 3 }" :wrapper-col="{ span: 21 }">
<a-input v-model:value="formState.reamrk" placeholder="请输入备注" :allowClear="true" />
</a-form-item>
</td>
</tr>
</table>
</a-form>
</div>
<div class="titleBox">
<div style="margin: 0 auto">
<a-space :size="10">
<a-button type="primary" size="large" @click="saveRoom">保存</a-button>
<a-button type="primary" size="large" @click="() => formRef.resetFields()"><template #icon>
<reload-outlined />
</template>
清空</a-button>
</a-space>
</div>
</div>
</div>
<template #footer>
</template>
</a-modal>
</template>
<script setup>
import { reactive } from "vue";
import { useStore } from '@/store/index.js';
import { addRooms } from '@/api/room.js';
import { message } from "ant-design-vue";
const usestore = useStore();
const props = defineProps({
visible: Boolean,
title: String,
});
const formRef = ref();
const formState = reactive({
hotelId: usestore.hotelInfo.hotelId,
creator: usestore.userInfo.username,
name: '',
type: '',
floor: '',
roomPhone: '',
bed: '',
state: '',
remark: ''
})
const defalutDictionaryAll = reactive({
allRoomType: usestore.returnCode(1),
allRoomBedNum: [{ id: 1, code: 1, name: '一张床' }, { id: 2, code: 2, name: '两张床' }, { id: 3, code: 3, name: '三张床' }, { id: 4, code: 4, name: '四张床' }, { id: 5, code: 5, name: '五张床' }],
allRoomState: [{ id: 1, code: 1, name: '正常' }, { id: 2, code: 2, name: '维修' }, { id: 3, code: 3, name: '关闭' }]
});
const rules = {
name: [
{
required: true,
message: '请输入房间号'
}
],
type: [
{
required: true,
message: '请选择房间类型'
}
],
floor: [
{
required: true,
message: '请输入楼层'
},
],
room_phone: [
{
required: true,
message: '请输入房间电话'
},
],
bed: [
{
required: true,
message: '请选择床数量'
}
],
state: [
{
required: true,
message: '请选择房间状态'
}
]
};
const emit = defineEmits(["changeCancel"]);
const handleCancel = async () => {
await emit("changeCancel");
};
const handleOk = async () => {
formRef.value?.validateFields().then(async (values) => {
// await emit("handleSubmit", values);
});
};
/**下拉框筛选 */
const filterOption = (input, option) => {
return option.name.toLowerCase().indexOf(input.toLowerCase()) >= 0;
};
//保存房号
const saveRoom = () => {
addRooms([formState]).then(res => {
if (res.code == '9000') {
message.success('房号新增成功!');
formRef.value.resetFields();
}
}).catch(error => {
message.error(error.message);
});
}
</script>
<style lang="less">
.roomSingleAdd {
width: 100%;
height: 100%;
padding: 0px;
margin: 0px;
.form {
.ant-form-item-with-help {
margin-bottom: 0px;
}
.ant-form-item-label {
flex: auto;
}
}
.form-tables {
width: 100%;
border-collapse: collapse;
tr {
width: 100%;
height: 60px;
td {
border: 1px solid #e7e7e7;
max-width: 222px;
}
}
}
.titleBox {
display: flex;
justify-content: space-between;
align-items: center;
background: #fafafa;
border-radius: 0px 0px 2px 2px;
border: 1px solid #e9e9e9;
padding: 10px;
margin: 25px 5px;
}
}
</style>
\ No newline at end of file
<template>
<div class="visitor">
<a-spin :spinning="loading">
<div class="titleBox">
<div>
<span class="sign">访客登记信息列表</span>
</div>
</div>
<div style="margin: 0px 25px">
<a-form ref="formRef" name="advanced_search" class="ant-advanced-search-form" :model="formState">
<a-row :gutter="24">
<a-col :span="4">
<a-form-item name="roomId" label="房号">
<a-select v-model:value="formState.roomId" :allowClear="true" show-search placeholder="请选择房号" :options="dictionaryAll.allRoom" :filter-option="filterOption" :fieldNames="{value:'id',label:'name'}" :notFoundContent="'暂无数据'" optionLabelProp="name"></a-select>
</a-form-item>
</a-col>
<a-col :span="6">
<a-form-item name="name" label="访客中文姓名">
<a-input v-model:value="formState.name" :allowClear="true" placeholder="请输入中文姓名"></a-input>
</a-form-item>
</a-col>
<a-col :span="8">
<a-form-item name="certificateNumber" label="访客证件号码">
<a-input v-model:value="formState.certificateNumber" :allowClear="true" placeholder="请输入证件号码"></a-input>
</a-form-item>
</a-col>
<a-col :span="6">
<a-form-item name="residentName" label="住客姓名">
<a-input v-model:value="formState.residentName" :allowClear="true" placeholder="请输入住客姓名"></a-input>
</a-form-item>
</a-col>
<a-col :span="7">
<a-form-item name="nationalityCode" label="访客国籍(地区)">
<a-select v-model:value="formState.nationalityCode" :allowClear="true" show-search placeholder="请选择国家及地区" :options="dictionaryAll.allCountry" :filter-option="filterOption" :fieldNames="{value:'code',label:'name'}" :notFoundContent="'暂无数据'" optionLabelProp="name"></a-select>
</a-form-item>
</a-col>
<a-col :span="6">
<a-form-item name="visitTime" label="来访时间">
<a-range-picker :allowClear="true" show-time @change="onChangeRangeDate" />
</a-form-item>
</a-col>
<a-col :span="4">
<a-form-item name="state" label="访客状态">
<a-select v-model:value="formState.state" :allowClear="true" show-search placeholder="请选择访客状态" :options="dictionaryAll.allCheckInState" :filter-option="filterOption" :fieldNames="{value:'code',label:'name'}" :notFoundContent="'暂无数据'" optionLabelProp="name"></a-select>
</a-form-item>
</a-col>
<a-col style="text-align: right">
<a-button type="primary" html-type="submit" @click="searchVisitor">搜索</a-button>
<a-button style="margin: 0 8px" @click="() => formRef.resetFields()">清除</a-button>
</a-col>
</a-row>
</a-form>
</div>
<div style="margin: 0px 25px; height: calc(100% - 210px)">
<a-table :row-selection="{selectedRowKeys: state.selectedRowKeys,onChange: onSelectChange,}" :columns="columns" :data-source="data" :pagination="false" :scroll="{y:450}">
<template #bodyCell="{ column, record }">
<template v-if="column.dataIndex === 'cz'">
<a-space :size="0">
<a-button type="link" primary size="small" style="color:#52c41a" @click="eyes(record)">
<template #icon>
<eye-filled />
</template>
查看
</a-button>
<a-button type="link" primary size="small" style="color:#faad14" @click="edit(record)">
<template #icon>
<edit-filled />
</template>
修改
</a-button>
<a-popconfirm title="是否离店?" @confirm="checkOut(record)" v-if="record.state=='DEPART'?false:true">
<a-button type="link" primary size="small" style="color:#ff4d1f">
<template #icon>
<swap-outlined />
</template>
离店
</a-button>
</a-popconfirm>
</a-space>
</template>
</template>
</a-table>
<a-pagination v-model:current="formState.current" show-quick-jumper show-size-changer :total="total" v-show="data.length > 0" size="small" :show-total="(total) => `总数共: ${total} 条`" @change="onChangePagination" style="margin: 20px 0px" />
</div>
</a-spin>
<VisitorInfo v-if="visitorInfoVisible" :flogStatus="operateStatus" :visible="visitorInfoVisible" :dictionaryAll="dictionaryAllInfo" :formData="visitorInfo" @change-Cancel="changeCancel" />
</div>
</template>
<script setup>
import { onMounted, reactive, ref } from "vue";
import { getVisitorList, departureVisitorRegist } from '@/api/visitorRegist.js'
import { useStore } from '@/store/index.js';
import { message } from "ant-design-vue";
import VisitorInfo from "@/views/visitor/visitorInfo.vue";
const loading = ref(false);
const userstore = useStore();
const formRef = ref();
const formState = reactive({
hotelId: userstore.hotelInfo.hotelId,
roomId: '',
name: '',
certificateNumber: '',
residentName: '',
nationalityCode: '',
visitingTimeStart: '',
visitingTimeEnd: '',
state: '',
current: 1,
pageSize: 10,
});
//获取a-range-date时间
const onChangeRangeDate = (value, dataArr) => {
if (dataArr && dataArr.length > 0) {
formState.visitingTimeEnd = dataArr[1];
formState.visitingTimeStart = dataArr[0];
}
}
const dictionaryAll = reactive({
allRoom: userstore.roomAll,
allCountry: userstore.returnCode(9),
allCheckInState: userstore.returnCode(2)
});
/**下拉框筛选 */
const filterOption = (input, option) => {
return option.name.toLowerCase().indexOf(input.toLowerCase()) >= 0;
};
/**表格 */
const columns = [
// {
// title: "序号",
// dataIndex: 'key',
// },
{
title: "房号",
dataIndex: "roomName",
},
{
title: "访客中文姓名",
dataIndex: "name",
},
{
title: "访客英文姓名",
dataIndex: "foreignName",
},
{
title: "证件号码",
dataIndex: "certificateNumber",
},
{
title: "联系电话",
dataIndex: 'phoneNumber',
},
{
title: "访客状态",
dataIndex: "stateName",
},
{
title: "住客姓名",
dataIndex: "residentName",
},
{
title: "来访时间",
dataIndex: "visitingTime",
},
{
title: "离开时间",
dataIndex: "departureTime",
},
{
title: "操作",
dataIndex: "cz",
fixed: "right",
width: 230,
}
];
const state = reactive({
selectedRowKeys: [],
// Check here to configure the default column
loading: false,
});
const onSelectChange = (selectedRowKeys) => {
console.log("selectedRowKeys changed: ", selectedRowKeys);
state.selectedRowKeys = selectedRowKeys;
};
/**分页 */
const onChangePagination = (page, pageSize) => {
formState.current = page;
formState.pageSize = pageSize;
searchVisitor();
};
/**查看 */
const visitorInfo = ref({});
const dictionaryAllInfo = ref({});
const visitorInfoVisible = ref(false);
const operateStatus = ref(false);
const changeCancel = () => {
visitorInfoVisible.value = false;
}
const eyes = (e) => {
visitorInfo.value = e;
visitorInfoVisible.value = true;
dictionaryAllInfo.value = dictionaryAll;
operateStatus.value = true;
}
//编辑
const edit = (e) => {
visitorInfo.value = e;
visitorInfoVisible.value = true;
dictionaryAllInfo.value = dictionaryAll;
operateStatus.value = false;
}
//离店
const checkOut = record => {
loading.value = true;
departureVisitorRegist([record.id]).then(res => {
if (res.code == '9000') {
message.success('离店成功')
searchVisitor();
}
loading.value = false;
}).catch(error => {
message.warning('离店失败');
loading.value = false;
})
}
//搜索
const data = ref([]);
const total = ref(0);
const searchVisitor = () => {
loading.value = true;
getVisitorList(formState).then(res => {
loading.value = false;
if (res?.code == 9000) {
data.value = res.data.records;
total.value = res.data.total;
}
}).catch(err => {
loading.value = false;
})
}
onMounted(() => {
searchVisitor();
});
</script>
<style lang="less">
.visitor {
width: 100%;
height: 100%;
padding: 0%;
margin: 0px;
.titleBox {
display: flex;
justify-content: space-between;
align-items: center;
background: #fafafa;
border-radius: 0px 0px 2px 2px;
border: 1px solid #e9e9e9;
padding: 10px;
margin: 25px 5px;
}
.sign {
display: inline-block;
font-size: 16px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: rgba(0, 0, 0, 0.85);
line-height: 16px;
&::before {
content: "";
display: inline-block;
width: 4px;
height: 12px;
background: #3162f5;
border-radius: 2px;
margin-right: 8px;
}
}
}
</style>
\ No newline at end of file
<template>
<a-spin :spinning="loading">
<div class="hotelFrom">
<div class="titleBox">
<div>
<span class="sign">访客登记信息列表</span>
</div>
<div v-if="id_disabled">
<a-space :size="10">
<a-button type="primary" size="large" @click="returnToPreviousPage()">返回</a-button>
</a-space>
</div>
</div>
<div style="margin: 0px 5px">
<a-form class="form" ref="formRef" :model="formState" :labelCol="{ span: 8 }" :wrapper-col="{ span: 16 }" layout="inline" :rules="rules">
<table class="form-tables">
<tr>
<td colspan="1">
<a-form-item name="roomId" :label="`房间号`">
<a-select v-model:value="formState.roomId" :disabled="id_disabled" show-search placeholder="请选择旅馆" :options="dictionaryAll.allRoom" :filter-option="filterOption" optionLabelProp="name" :fieldNames="{value:'id',label:'name'}" :notFoundContent="'暂无数据'"></a-select>
</a-form-item>
</td>
<td colspan="1" rowspan="5">
<div class="img-pub">
<div class="img-wp">
<div class="img-div" style="width: calc(100% - 32px);height: calc(100% - 20px);margin: 10px 16px 10px;">
<!-- <div class="img-span">
<span>证件人像</span>
</div> -->
<div class="img-span" style="line-height: 36px;" v-if="formState.certificatePhoto == ''">
<span>证件人像</span>
</div>
<a-image :width="`100%`" :height="`100%`" :src="formState.certificatePhoto" v-else />
</div>
<!-- <div class="check-div">
<a-radio v-model:checked="checked_value1" @click="dx_click(1)">截取人像照片</a-radio>
</div> -->
</div>
<div class="img-wp">
<div class="img-div">
<div class="img-span" v-if="formState.sitePhoto == ''">
<span>现场人像</span>
</div>
<a-image :width="`100%`" :height="`100%`" :src="formState.sitePhoto" v-else />
</div>
<!-- <div class="check-div">
<a-radio v-model:checked="checked_value2" @click="dx_click(2)">截取现场照片</a-radio>
</div> -->
<div class="check-div" style="text-align: center" @click="OnCamera()">
<a-button type="primary" size="small">截取现场照片</a-button>
</div>
<div class="check-div" style="text-align: center;margin-top: 10px;">
<a-upload name="file" @change="handleChange" :showUploadList="false" :before-upload="beforeUpload">
<a-button>
选择头像
</a-button>
</a-upload>
</div>
</div>
</div>
</td>
</tr>
<tr>
<td colspan="1">
<a-form-item name="residentName" :label="`住客姓名`">
<a-input v-model:value="formState.residentName" :disabled="id_disabled" placeholder="请输入" />
</a-form-item>
</td>
</tr>
<tr>
<td colspan="1">
<a-form-item name="certificateNumber" :label="`访客证件号码`" :rules="[
{ required: true,message:'证件号码必须为18位数字加字母组合',len: 18,},
{ pattern:new RegExp(/^[1-9]\d{5}(19|20)\d{2}((0[1-9])|(1[0-2]))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$/,'g'),message:'请输入有效的证件号码'}]">
<a-input v-model:value="formState.certificateNumber" placeholder="请输入" :allowClear="true" />
</a-form-item>
</td>
</tr>
<tr>
<td colspan="1">
<a-form-item name="nationalityCode" :label="`访客国籍(地区)`">
<a-select v-model:value="formState.nationalityCode" show-search placeholder="请选择访客国籍" :options="dictionaryAll.allCountry" :filter-option="filterOption" optionLabelProp="name" :fieldNames="{value:'code',label:'name'}" :notFoundContent="'暂无数据'"></a-select>
</a-form-item>
</td>
</tr>
<tr>
<td colspan="1">
<a-form-item name="name" :label="`访客中文姓名`">
<a-input v-model:value="formState.name" :allowClear="true" placeholder="请输入中文姓名" />
</a-form-item>
</td>
</tr>
<tr>
<td colspan="1">
<a-form-item name="foreignName" :label="`访客英文姓名`">
<a-input v-model:value="formState.foreignName" :allowClear="true" placeholder="请输入英文姓名" />
</a-form-item>
</td>
<td colspan="1">
<a-form-item name="phoneNumber" :label="`访客联系电话`" :rules="[
{ pattern:new RegExp('^[0-9]{1,}$','g'),message:'只允许包含数字'}]">
<a-input v-model:value="formState.phoneNumber" :allowClear="true" placeholder="请输入联系电话" />
</a-form-item>
</td>
</tr>
<tr>
<td colspan="2">
<a-form-item name="remark" :label="`备注`" :wrapper-col="{ span: 20 }" :label-col="{ span: 4 }">
<a-input v-model:value="formState.remark" :allowClear="true" placeholder="请输入备注" />
</a-form-item>
</td>
</tr>
</table>
</a-form>
</div>
<div class="titleBox">
<div style="margin: 0 auto">
<a-space :size="10">
<a-button type="primary" size="large" @click="handle_ID_reading()">读取证件</a-button>
<a-button type="primary" size="large">扫描证件</a-button>
<a-button type="primary" size="large" @click="saveInfo"><template #icon><file-protect-outlined /></template>保存</a-button>
<a-button size="large" @click="qk()"><template #icon>
<reload-outlined />
</template>
清空</a-button>
</a-space>
</div>
</div>
<Camera v-if="hotelFormVisible" :visible="hotelFormVisible" :title="`现场人像`" @handle-submit="onSubmit" @change-Cancel="changeCancel" />
<Cropper :imageSrc="imageSrc" v-if="hotelFormVisibles" :visible="hotelFormVisibles" :title="`截图`" @handle-submit="onSubmit_s" @change-Cancel="changeCancel_s" @handle-retake="handleRetake" />
</div>
</a-spin>
</template>
<script setup>
import { useStore } from '@/store/index.js'
import { file_img_src, ChangeDateType } from '@/utils/http_util.js';
import { addVisitorRegist } from '@/api/visitorRegist.js';
import { uploadImg } from '@/api/default.js';
import { message } from 'ant-design-vue';
import { onMounted, toRaw } from 'vue';
import requests from "@/utils/request_test";
import { useRoute } from 'vue-router';
import { forIn } from "lodash-es";
import router from "../../router";
const route = useRoute();
const userstore = useStore();
const formRef = ref();
const formState = reactive({
hotelId: userstore.hotelInfo.hotelId,
roomId: "",
residentName: "",
certificateNumber: "",//证件号码
certificatePhoto: "",//证件照片
nationalityCode: "",
name: "",
foreignName: "",
phoneNumber: "",
remark: "",
sitePhoto: "",
visitingTime: undefined,
state: "ARRIVE",
verificationState: "",
creator: userstore.userInfo.username,
departureTime: "",
updater: ""
});
const rules = {
roomId: [
{
required: true,
message: '请输入房间号'
}
],
residentName: [
{
required: true,
message: '请输入住客姓名'
}
],
certificateNumber: [
{
required: true,
message: '请选择访客证件号码'
},
],
nationalityCode: [
{
required: true,
message: '请选择访客国籍(地址)'
},
]
};
/**摄像头调用 */
const hotelFormVisible = ref(false);
// const screenshot_url = ref("");
const onSubmit = (e) => {
// formState.sitePhoto = e.value;
hotelFormVisible.value = false;
imageSrc.value = e.value;
hotelFormVisibles.value = true;
};
const changeCancel = () => {
hotelFormVisible.value = false;
};
/**开启摄像头 */
const OnCamera = () => {
hotelFormVisible.value = true;
};
/**截图 */
const hotelFormVisibles = ref(false);
const imageSrc = ref("");
const onSubmit_s = (e) => {
formState.sitePhoto = e.value;
hotelFormVisibles.value = false;
};
const changeCancel_s = () => {
hotelFormVisibles.value = false;
};
const handleRetake = () => {
changeCancel_s();
OnCamera();
};
/**清空 */
const qk = ()=>{
formRef.value.resetFields();
formState.sitePhoto = '';
}
const dictionaryAll = reactive({
allRoom: userstore.roomAll,
allCountry: userstore.returnCode(9)
});
const checked_value1 = ref(false);
const checked_value2 = ref(false);
/**提交事件 */
const handleOk = async () => {
formRef.value?.validateFields().then(async (values) => {
// await emit("handleSubmit", values);
});
};
/**关闭弹框事件 */
const handleCancel = async () => {
// await emit("changeform", false);
};
const dx_click = (e) => {
if (e == 1) {
checked_value1.value = true;
checked_value2.value = false;
} else {
checked_value1.value = false;
checked_value2.value = true;
}
};
const loading = ref(false);
/**下拉框筛选 */
const filterOption = (input, option) => {
return option.name.toLowerCase().indexOf(input.toLowerCase()) >= 0;
};
const onChange = (value, dateString) => {
formState.pass = dateString;
console.log("Selected Time: ", value);
console.log("Formatted Selected Time: ", dateString);
};
const onOk = (value, dateString) => {
formState.pass = dateString;
console.log("onOk: ", value);
};
const handleMenuClick = (e) => {
console.log("click", e);
};
const reset = () => {
formRef.value.resetFields();
formState.certificatePhoto = "";
formState.sitePhoto = "";
};
/**选择头像 */
const handleChange = info => {
const isPNG = info.file.type === 'image/png'||info.file.type === 'image/jpg'||info.file.type === 'image/jpeg';
if (!isPNG) {
message.error(`${info.file.name} 不是图片格式,请上传PNG||JPG||JPEG`);
}else{
const reader = new FileReader();
reader.readAsDataURL(info.file);
reader.onload = () => {
formState.sitePhoto = reader.result;
};
}
};
/**不让文件直接上传 */
const beforeUpload = (file) => {
return false;
};
/**返回 */
const returnToPreviousPage = ()=>{
router.go(-1);
}
const saveInfo = () => {
formRef.value?.validateFields().then((values) => {
/**批量操作上传图片 */
const arr_http = [];
if (formState.sitePhoto != "") {/**现场照片 */
arr_http.push(file_img_src(formState.sitePhoto, userstore.hotelInfo.hotelId, 'VISITOR'));
} else {
arr_http.push('');
}
if (formState.certificatePhoto != "") {/**身份证 */
arr_http.push(file_img_src(formState.certificatePhoto, userstore.hotelInfo.hotelId, 'VISITOR'));
} else {
arr_http.push('');
}
loading.value = true;
Promise.all(arr_http).then(([res1, res2]) => {
const arr = { ...formState };
if (formState.sitePhoto != "") {
arr.sitePhoto = res1
}
if (formState.certificatePhoto != "") {
arr.certificatePhoto = res2
}
arr.visitingTime = ChangeDateType(new Date(), 'yyyy-MM-dd hh:mm:ss');
addVisitorRegist(arr).then((res) => {
if (res.code == 9000) {
message.success("已保存");
reset();
returnToPreviousPage();
}
loading.value = false;
}).catch((res) => {
message.warning("保存失败");
});
loading.value = false;
});
})
}
const str_data = (str) => {
const str1 = str.substring(0, 4);
const str2 = str.substring(4, 6);
const str3 = str.substring(6, 8);
return str1 + "-" + str2 + "-" + str3;
};
const id_disabled = ref(false);
onMounted(() => {
if(route.query.roomId){//判断是否传过来
// console.log(typeof())
formState.roomId = parseInt(route.query.roomId);
formState.residentName = route.query.name;
id_disabled.value = true;
}
})
const handle_ID_reading = () => {
loading.value = true;
requests({ url: "/dev", method: "GET", }).then((res) => {
loading.value = false;
if (res.code == 9000) {
formState.certificateNumber = res.data.code;
formState.certificateType = userstore.returnCode(3).filter((item) => {
return item.name == "身份证";
})[0].code;
formState.name = res.data.name;
formState.gender = userstore.returnCode(5).filter((item) => {
return item.name == res.data.gender;
})[0].code;
formState.certificatePhoto =
"data:image/png;base64," + res.data.profilephoto;
formState.dateBirth = str_data(res.data.birthDay);
formState.address = res.data.address;
formState.nation = userstore.returnCode(10).filter((item) => {
return item.name == res.data.folk + "";
})[0].code;
}
})
.catch((res) => {
message.warning(res);
loading.value = false;
});
};
</script>
<style lang="less">
.hotelFrom {
width: 100%;
height: 100%;
padding: 0px;
margin: 0px;
overflow-y:auto;
.form {
.ant-form-item-with-help {
margin-bottom: 0px;
}
.ant-form-item-label {
flex: auto;
}
}
.form-tables {
width: 100%;
border-collapse: collapse;
tr {
width: 100%;
height: 60px;
td {
border: 1px solid #e7e7e7;
max-width: 222px;
.img-pub {
display: flex;
flex-direction: row;
justify-content: space-around;
flex-wrap: wrap;
margin: 10px;
.img-wp {
width: 140px;
height: 170px;
border: 1px solid #a5a5a5;
.img-div {
border-image-source: radial-gradient(
60% 60%,
transparent 0px,
transparent 100%,
#6691ef 100%
);
border-image-slice: 1;
border-width: 1px;
border-style: solid;
border-image-outset: 0px;
width: calc(100% - 50px);
height: calc(100% - 50px);
margin: 9px 25px 13px;
.img-span {
margin: 0px auto;
width: 14px;
line-height: 29px;
font-weight: 400;
font-size: 15px;
}
.img-span1 {
height: 100%;
display: flex;
flex-direction: row;
flex-wrap: nowrap;
justify-content: center;
align-items: center;
letter-spacing: 6px;
font-weight: 400;
font-size: 15px;
}
}
.check-div {
width: 100%;
text-align: center;
.ant-radio-wrapper {
margin-right: 0px;
}
}
}
}
}
}
}
.titleBox {
display: flex;
justify-content: space-between;
align-items: center;
background: #fafafa;
border-radius: 0px 0px 2px 2px;
border: 1px solid #e9e9e9;
padding: 10px;
margin: 25px 5px;
}
.sign {
display: inline-block;
font-size: 16px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: rgba(0, 0, 0, 0.85);
line-height: 16px;
&::before {
content: "";
display: inline-block;
width: 4px;
height: 12px;
background: #3162f5;
border-radius: 2px;
margin-right: 8px;
}
}
}
</style>
\ No newline at end of file
<template>
<a-modal :visible="visible" title="查看详情" width="80%" @cancel="handleCancel">
<a-spin :spinning="loading">
<div class="hotelFrom">
<div style="margin: 0px 5px">
<a-form class="form" ref="formRef" :model="formState" :labelCol="{ span: 8 }" :wrapper-col="{ span: 16 }" layout="inline" :rules="rules">
<table class="form-tables">
<tr>
<td colspan="1">
<a-form-item name="roomId" :label="`房间号`">
<a-select v-model:value="formState.roomId" show-search placeholder="请选择旅馆" :options="dictionaryAll.allRoom" :filter-option="filterOption" :fieldNames="{value:'id',label:'name'}" :notFoundContent="'暂无数据'" :disabled="operateStatus?true:false"></a-select>
</a-form-item>
</td>
<td colspan="1" rowspan="5">
<div class="img-pub">
<div class="img-wp">
<div class="img-div" style="width: calc(100% - 32px);height: calc(100% - 20px);margin: 10px 16px 10px;">
<!-- <div class="img-span">
<span>证件人像</span>
</div> -->
<div class="img-span" style="line-height: 36px;" v-if="formState.certificatePhotoPath == ''||formState.certificatePhotoPath==null">
<span>证件人像</span>
</div>
<a-image :width="`100%`" :height="`100%`" :src="formState.certificatePhotoPath" v-else />
</div>
<!-- <div class="check-div">
<a-radio v-model:checked="checked_value1" @click="dx_click(1)">截取人像照片</a-radio>
</div> -->
</div>
<div class="img-wp">
<div class="img-div">
<div class="img-span" v-if="formState.sitePhotoPath == ''||formState.sitePhotoPath==null">
<span>现场人像</span>
</div>
<a-image :width="`100%`" :height="`100%`" :src="formState.sitePhotoPath" :fallback="default_img" v-else />
</div>
<!-- <div class="check-div">
<a-radio v-model:checked="checked_value2" @click="dx_click(2)">截取现场照片</a-radio>
</div> -->
<div class="check-div" style="text-align: center" @click="OnCamera()">
<a-button type="primary" size="small" :disabled="operateStatus?true:false">截取现场照片</a-button>
</div>
<div class="check-div" style="text-align: center;margin-top: 10px;" v-if="!operateStatus">
<a-upload name="file" @change="handleChange" :showUploadList="false" :before-upload="beforeUpload">
<a-button>
选择头像
</a-button>
</a-upload>
</div>
</div>
</div>
</td>
</tr>
<tr>
<td colspan="1">
<a-form-item name="residentName" :label="`住客姓名`">
<a-input v-model:value="formState.residentName" placeholder="请输入" :allowClear="true" :disabled="operateStatus?true:false" />
</a-form-item>
</td>
</tr>
<tr>
<td colspan="1">
<a-form-item name="certificateNumber" :label="`访客证件号码`" :rules="[
{ required: true,message:'证件号码必须为18位数字加字母组合',len: 18,},
{ pattern:new RegExp(/^[1-9]\d{5}(19|20)\d{2}((0[1-9])|(1[0-2]))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$/,'g'),message:'请输入有效的证件号码'}]">
<a-input v-model:value="formState.certificateNumber" placeholder="请输入" :allowClear="true" :disabled="operateStatus?true:false" />
</a-form-item>
</td>
</tr>
<tr>
<td colspan="1">
<a-form-item name="nationalityCode" :label="`访客国籍(地区)`">
<a-select v-model:value="formState.nationalityCode" show-search placeholder="请选择访客国籍" :options="dictionaryAll.allCountry" :filter-option="filterOption" :fieldNames="{value:'code',label:'name'}" :notFoundContent="'暂无数据'" :disabled="operateStatus?true:false"></a-select>
</a-form-item>
</td>
</tr>
<tr>
<td colspan="1">
<a-form-item name="name" :label="`访客中文姓名`">
<a-input v-model:value="formState.name" :allowClear="true" placeholder="请输入中文姓名" :disabled="operateStatus?true:false" />
</a-form-item>
</td>
</tr>
<tr>
<td colspan="1">
<a-form-item name="foreignName" :label="`访客英文姓名`">
<a-input v-model:value="formState.foreignName" :allowClear="true" placeholder="请输入英文姓名" :disabled="operateStatus?true:false" />
</a-form-item>
</td>
<td colspan="1">
<a-form-item name="phoneNumber" :label="`访客联系电话`" :rules="[
{ pattern:new RegExp('^[0-9]{1,}$','g'),message:'只允许包含数字'}]">
<a-input v-model:value="formState.phoneNumber" :allowClear="true" placeholder="请输入联系电话" :disabled="operateStatus?true:false" />
</a-form-item>
</td>
</tr>
<tr>
<td colspan="2">
<a-form-item name="remark" :label="`备注`" :wrapper-col="{ span: 20 }" :label-col="{ span: 4 }">
<a-input v-model:value="formState.remark" :allowClear="true" placeholder="请输入备注" :disabled="operateStatus?true:false" />
</a-form-item>
</td>
</tr>
</table>
</a-form>
</div>
<div class="titleBox">
<div style="margin: 0 auto">
<a-space :size="10">
<a-button type="primary" size="large" @click="edit" v-if="operateStatus">编辑</a-button>
<a-button type="primary" size="large" @click="handle_ID_reading()" v-if="!operateStatus">读取证件</a-button>
<a-button type="primary" size="large" v-if="!operateStatus">扫描证件</a-button>
<a-button type="primary" size="large" v-if="!operateStatus" @click="saveInfo"><template #icon><file-protect-outlined /></template>保存</a-button>
<a-button size="large" @click="() => formRef.resetFields()" v-if="!operateStatus"><template #icon>
<reload-outlined />
</template>
清空</a-button>
<a-button size="large" @click="handleCancel()" v-if="!operateStatus">取消</a-button>
</a-space>
</div>
</div>
<Camera v-if="hotelFormVisible" :visible="hotelFormVisible" :title="`现场人像`" @handle-submit="onSubmit" @change-Cancel="changeCancel" />
<Cropper :imageSrc="imageSrc" v-if="hotelFormVisibles" :visible="hotelFormVisibles" :title="`截图`" @handle-submit="onSubmit_s" @change-Cancel="changeCancel_s" @handle-retake="handleRetake" />
</div>
</a-spin>
<template #footer> </template>
</a-modal>
</template>
<script setup>
import { useStore } from '@/store/index.js'
import { file_img_src } from '@/utils/http_util.js';
import { updateVisitorRegist, queryVisitorRegistDetail } from '@/api/visitorRegist.js';
import { uploadImg } from '@/api/default.js';
import { message } from 'ant-design-vue';
import { onMounted } from 'vue';
import { forIn } from "lodash-es";
import requests from "@/utils/request_test";
import default_img from '@/assets/img/default.png';
const userstore = useStore();
const formRef = ref();
const formState = reactive({});
const operateStatus = ref(true);
const loading = ref(false);
const props = defineProps({
visible: Boolean,
formData: {},
dictionaryAll: {},
flogStatus: Boolean
});
const emit = defineEmits(["changeCancel"]);
const rules = {
roomId: [
{
required: true,
message: '请输入房间号'
}
],
residentName: [
{
required: true,
message: '请输入住客姓名'
}
],
certificateNumber: [
{
required: true,
message: '请选择访客证件号码'
},
],
nationalityCode: [
{
required: true,
message: '请选择访客国籍(地址)'
},
]
};
/**摄像头调用 */
const hotelFormVisible = ref(false);
// const screenshot_url = ref("");
const onSubmit = (e) => {
// screenshot_url.value = e.value;
hotelFormVisible.value = false;
imageSrc.value = e.value;
hotelFormVisibles.value = true;
};
const changeCancel = () => {
hotelFormVisible.value = false;
sitePhotos.value = false;
certificatePhotos.value = false;
};
/**开启摄像头 */
const OnCamera = () => {
hotelFormVisible.value = true;
};
/**截图 */
const hotelFormVisibles = ref(false);
const imageSrc = ref("");
const onSubmit_s = (e) => {
sitePhotos.value = true;
formState.sitePhoto = e.value;
formState.sitePhotoPath = e.value;
hotelFormVisibles.value = false;
};
const changeCancel_s = () => {
hotelFormVisibles.value = false;
};
const handleRetake = () => {
changeCancel_s();
OnCamera();
};
const dictionaryAll = reactive({
});
const checked_value1 = ref(false);
const checked_value2 = ref(false);
/**提交事件 */
const handleOk = async () => {
formRef.value?.validateFields().then(async (values) => {
// await emit("handleSubmit", values);
});
};
/**关闭弹框事件 */
const handleCancel = async () => {
await emit("changeCancel");
};
const dx_click = (e) => {
if (e == 1) {
checked_value1.value = true;
checked_value2.value = false;
} else {
checked_value1.value = false;
checked_value2.value = true;
}
};
/**下拉框筛选 */
const filterOption = (input, option) => {
return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0;
};
const onChange = (value, dateString) => {
formState.pass = dateString;
console.log("Selected Time: ", value);
console.log("Formatted Selected Time: ", dateString);
};
const onOk = (value, dateString) => {
formState.pass = dateString;
console.log("onOk: ", value);
};
const handleMenuClick = (e) => {
console.log("click", e);
};
/**选择头像 */
const handleChange = info => {
const isPNG = info.file.type === 'image/png'||info.file.type === 'image/jpg'||info.file.type === 'image/jpeg';
if (!isPNG) {
message.error(`${info.file.name} 不是图片格式,请上传PNG||JPG||JPEG`);
}else{
const reader = new FileReader();
reader.readAsDataURL(info.file);
reader.onload = () => {
formState.sitePhoto = reader.result;
formState.sitePhotoPath = reader.result;
sitePhotos.value = true;
};
}
};
/**不让文件直接上传 */
const beforeUpload = (file) => {
return false;
};
const reset = () => {
// formRef.value.resetFields();
formState.certificatePhoto = "";
formState.sitePhoto = "";
sitePhotos.value = false;
certificatePhotos.value = false;
};
const saveInfo = () => {
/**批量操作上传图片 */
formRef.value?.validateFields().then((values) => {
const arr_http = [];
if (sitePhotos.value) {/**现场照片 */
arr_http.push(file_img_src(formState.sitePhoto, userstore.hotelInfo.hotelId, 'VISITOR'));
} else {
arr_http.push('');
}
if (certificatePhotos.value) {/**身份证 */
arr_http.push(file_img_src(formState.certificatePhoto, userstore.hotelInfo.hotelId, 'VISITOR'));
} else {
arr_http.push('');
}
loading.value = true;
Promise.all(arr_http).then(([res1, res2]) => {
const arr = { ...formState };
if (sitePhotos.value) {
arr.sitePhoto = res1
}
if (certificatePhotos.value) {
arr.certificatePhoto = res2
}
updateVisitorRegist(arr)
.then((res) => {
if (res.code == 9000) {
message.success("已保存");
operateStatus.value = true;
// reset();
sitePhotos.value = false;
certificatePhotos.value = false;
}
loading.value = false;
})
.catch((res) => {
message.warning("保存失败");
loading.value = false;
});
});
})
}
const str_data = (str) => {
const str1 = str.substring(0, 4);
const str2 = str.substring(4, 6);
const str3 = str.substring(6, 8);
return str1 + "-" + str2 + "-" + str3;
};
const handle_ID_reading = () => {
requests({
url: "/dev",
method: "GET",
})
.then((res) => {
if (res.code == 9000) {
formState.certificateNumber = res.data.code;
formState.certificateType = userstore.returnCode(3).filter((item) => {
return item.name == "身份证";
})[0].code;
formState.name = res.data.name;
formState.gender = userstore.returnCode(5).filter((item) => {
return item.name == res.data.gender;
})[0].code;
formState.certificatePhoto =
"data:image/png;base64," + res.data.profilephoto;
formState.dateBirth = str_data(res.data.birthDay);
formState.address = res.data.address;
formState.nation = userstore.returnCode(10).filter((item) => {
return item.name == res.data.folk + "";
})[0].code;
formState.certificatePhotoPath =
"data:image/png;base64," + res.data.profilephoto;
certificatePhotos.value = true
}
})
.catch((res) => {
message.warning(res);
});
};
const edit = () => {
operateStatus.value = false;
}
onMounted(() => {
if (props?.visible) {
loading.value = true;
queryVisitorRegistDetail({ id: props?.formData.id }).then(res => {
forIn(res.data, (value, key) => (formState[key] = value));
loading.value = false;
}).catch(error => {
loading.value = true;
});
forIn(props?.dictionaryAll, (value, key) => (dictionaryAll[key] = value));
operateStatus.value = props?.flogStatus;
};
})
/**判断现场照片修改 */
const sitePhotos = ref(false);
/**判断证件照 */
const certificatePhotos = ref(false);
</script>
<style lang="less">
.hotelFrom {
width: 100%;
height: 100%;
padding: 0px;
margin: 0px;
.form {
.ant-form-item-with-help {
margin-bottom: 0px;
}
.ant-form-item-label {
flex: auto;
}
}
.form-tables {
width: 100%;
border-collapse: collapse;
tr {
width: 100%;
height: 60px;
td {
border: 1px solid #e7e7e7;
max-width: 222px;
.img-pub {
display: flex;
flex-direction: row;
justify-content: space-around;
flex-wrap: wrap;
margin: 10px;
.img-wp {
width: 140px;
height: 170px;
border: 1px solid #a5a5a5;
.img-div {
border-image-source: radial-gradient(
60% 60%,
transparent 0px,
transparent 100%,
#6691ef 100%
);
border-image-slice: 1;
border-width: 1px;
border-style: solid;
border-image-outset: 0px;
width: calc(100% - 50px);
height: calc(100% - 50px);
margin: 9px 25px 13px;
.img-span {
margin: 0px auto;
width: 14px;
line-height: 29px;
font-weight: 400;
font-size: 15px;
}
.img-span1 {
height: 100%;
display: flex;
flex-direction: row;
flex-wrap: nowrap;
justify-content: center;
align-items: center;
letter-spacing: 6px;
font-weight: 400;
font-size: 15px;
}
}
.check-div {
width: 100%;
text-align: center;
.ant-radio-wrapper {
margin-right: 0px;
}
}
}
}
}
}
}
.titleBox {
display: flex;
justify-content: space-between;
align-items: center;
background: #fafafa;
border-radius: 0px 0px 2px 2px;
border: 1px solid #e9e9e9;
padding: 10px;
margin: 25px 5px;
}
.sign {
display: inline-block;
font-size: 16px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: rgba(0, 0, 0, 0.85);
line-height: 16px;
&::before {
content: "";
display: inline-block;
width: 4px;
height: 12px;
background: #3162f5;
border-radius: 2px;
margin-right: 8px;
}
}
}
</style>
\ No newline at end of file
...@@ -47,7 +47,7 @@ export default defineConfig({ ...@@ -47,7 +47,7 @@ export default defineConfig({
proxy: { proxy: {
//拦截请求地址包含/api,匹配到的是生产环境 //拦截请求地址包含/api,匹配到的是生产环境
"/api": { "/api": {
target: "http://172.16.60.201:8081", //后台服务地址 target: "http://192.168.168.107:8081", //后台服务地址
changeOrigin: true, changeOrigin: true,
//重写,/api开头的替换成空字符串,即去掉接口中去掉这个字符串 //重写,/api开头的替换成空字符串,即去掉接口中去掉这个字符串
rewrite: (path) => path.replace(/^\/api/, "") rewrite: (path) => path.replace(/^\/api/, "")
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment