Browse Source

用户管理-人脸

master
xuhuajiao 2 days ago
parent
commit
6b69a0aab4
  1. 1
      public/index.html
  2. 29
      src/api/system/user.js
  3. 519
      src/views/system/user/index.vue

1
public/index.html

@ -8,7 +8,6 @@
<link rel="icon" href="<%= BASE_URL %>favicon.svg" type="image/svg+xml">
<script src="/static/adapter.min.js"></script>
<script src="/static/webrtcstreamer.js"></script>
<script type="text/javascript" src="/static/gs_label_c_sdk_2.0.0.js"></script>
<title><%= webpackConfig.name %></title>
<script type="text/javascript" src="/static/config.js"></script>
</head>

29
src/api/system/user.js

@ -107,5 +107,32 @@ export function FetchEditUserState(data) {
})
}
export default { FetchSyncUser, FetchUserDetailsById, add, edit, del, resetpassword, FetchEditUserState, FetchInitUserList }
// 批量同步人员人脸
export function FetchSyncUserFace(data) {
return request({
url: 'api/user/syncUserFace',
method: 'post',
data
})
}
// 解绑人员人脸
export function FetchUnbindUserFace(data) {
return request({
url: 'api/user/unbindUserFace',
method: 'post',
data
})
}
// 根据人员信息查看相关人脸信息
export function FetchFaceTByNameAndFondsNo(params) {
return request({
url: 'api/user/getFaceTByNameAndFondsNo',
method: 'get',
params
})
}
export default { FetchSyncUser, FetchUserDetailsById, add, edit, del, resetpassword, FetchEditUserState, FetchInitUserList, FetchSyncUserFace, FetchUnbindUserFace, FetchFaceTByNameAndFondsNo }

519
src/views/system/user/index.vue

@ -21,9 +21,6 @@
>
<template slot-scope="{ data }">
<span class="tree-text">{{ data.deptName }}</span>
<!-- <el-tooltip :content="data.deptName" placement="left">
<span class="tree-text">{{ data.deptName }}</span>
</el-tooltip> -->
</template>
</el-tree>
</el-scrollbar>
@ -60,6 +57,10 @@
<i class="iconfont icon-zidonggengxin" />
同步
</el-button>
<el-button :loading="syncFaceLoading" size="mini" style="background-color: #0348f3; color: #fff;" @click="toSyncFace()">
<i class="iconfont icon-yonghuguanli" />
自动人脸绑定
</el-button>
</template>
</crudOperation>
</div>
@ -113,7 +114,7 @@
</el-radio-group>
</el-form-item>
<el-form-item label="状态" prop="platformStatus">
<!-- :disabled="form.id === user.id" -->
<!-- :disabled="(crud.status.edit === 1 && form.addtype === 1) || form.id === user.id" -->
<el-radio-group v-model="form.platformStatus" :disabled="crud.status.edit === 1 && form.addtype === 1">
<el-radio :label="1">激活</el-radio>
<el-radio :label="2">禁用</el-radio>
@ -126,17 +127,19 @@
</el-form-item>
</el-form>
<div class="right-user-img">
<!-- <img src="http://172.17.162.10:15000/api/minio/getImg?bucket=4&fileName=b89ea010-56fd-492c-a6d7-f4cb317116cb" alt="人员照片"> -->
<img :src="imageUrl || require('@/assets/images/user.jpg')" alt="人员照片">
<div style="display: flex; flex-direction: column; align-items: center; ">
<!-- 还需判断是否绑定过 -->
<!-- <el-button v-if="crud.status.add !== 1" size="small" type="primary" style="background-color: #ed4a41; border-color: #ed4a41; color: #fff;"><i class="iconfont icon-jiebang" />清除绑定</el-button>
<el-button size="small" type="primary" :loading="autoGetLoading" style="margin: 10px 0 0 0 !important;" @click="autoGetFaceUsers"><i class="iconfont icon-zidonggengxin" style="font-size: 14px !important;" />自动获取</el-button> -->
<div style="display: flex; flex-direction: column; align-items: center; ">
<el-button v-if="!hasBindFaceDb" size="small" type="primary" :loading="autoGetLoading" style="margin: 10px 0 !important;" @click="autoGetFaceUsers">
<i class="iconfont icon-zidonggengxin" style="font-size: 14px !important;" />
{{ crud.status.edit === 1 && form.facetBarcode !== null ? '重新获取' : '手动获取' }}
</el-button>
<!-- 新增清除按钮 -->
<el-button v-if="form.facetBarcode" size="small" style="margin: 0 !important; background-color: rgb(246, 81, 99); border-color: rgb(246, 81, 99); color: rgb(255, 255, 255);" @click="clearFaceInfo">
<i class="iconfont icon-shanchu" style="font-size:14px" />
{{ hasBindFaceDb ? '解绑人脸' : '清除人脸' }}
</el-button>
</div>
<!-- <div class="upload-btn" style="margin: 0 0 10px 0;">
<input id="upFile" type="file" name="upFile" accept="image/*" @change="changeFile($event)">
<el-button size="small" type="primary"><i class="iconfont icon-shangchuan" />选择上传照片</el-button>
</div> -->
<!-- <el-button type="primary" @click="showCamera"><i class="iconfont icon-yulan" />摄像头拍摄</el-button> -->
</div>
</div>
<div slot="footer" class="dialog-footer">
@ -146,24 +149,41 @@
</div>
</el-dialog>
<!-- 人脸选择弹窗 -->
<el-dialog
:visible.sync="faceUserdialogVisible"
title="人脸用户列表"
width="500px"
title="选择人脸用户"
width="776px"
class="face-select-dialog"
append-to-body
:close-on-click-modal="false"
:modal-append-to-body="false"
:visible.sync="faceSelectDialogVisible"
>
<el-table ref="faceUserTable" :data="faceUserTable" style="width: 100%" height="300px" max-height="300px" @selection-change="handleFaceUserSelectionChange">
<el-table-column type="selection" align="center" width="55" />
<el-table-column prop="lastname" label="账号" />
<el-table-column prop="lastname" label="用户名" />
<el-table-column prop="sex" label="性别" width="60" />
<el-table-column prop="departmentname" label="所属部门" />
</el-table>
<div v-if="showGuessTip" class="guess-tip">
未查询到匹配人脸用户猜测你是想从下面列表选择
</div>
<div class="face-card-wrap">
<div
v-for="item in autoFaceUserOptions"
:key="item.guid"
class="face-card-item"
:class="{active: tempSelectFace?.guid === item.guid}"
@click="tempSelectFace = item"
>
<img
:src="baseApi + '/api/minio/getImg?bucket=2&fileName=' + item.guid"
alt="人脸照片"
class="face-img"
>
<div class="face-info">
<div class="face-name">{{ item.name }}</div>
<div class="face-barcode">{{ item.barcode }}</div>
</div>
</div>
</div>
<div slot="footer" class="dialog-footer">
<el-button @click="faceUserdialogVisible = false">取消</el-button>
<el-button type="primary" @click="confirmFaceUserSelection">确定</el-button>
<el-button @click="faceSelectDialogVisible = false">取消</el-button>
<el-button type="primary" @click="confirmSelectFace">确定</el-button>
</div>
</el-dialog>
@ -182,8 +202,7 @@
</el-dialog>
<!--表格渲染-->
<el-table ref="table" v-loading="crud.loading" :data="crud.data" style="width: 100%;" height="calc(100vh - 330px)" @row-click="clickRowHandler" @selection-change="crud.selectionChangeHandler">
<!-- :selectable="checkboxT" -->
<el-table-column type="selection" align="center" width="55" />
<el-table-column type="selection" :selectable="checkboxT" align="center" width="55" />
<el-table-column prop="loginid" label="账号" />
<el-table-column prop="lastname" label="用户名" />
<el-table-column prop="sex" label="性别" width="60" />
@ -194,15 +213,15 @@
<el-tag v-if="scope.row.addtype === 1" type="success">同步用户</el-tag>
</template>
</el-table-column>
<el-table-column prop="isFace" label="人脸绑定">
<el-table-column prop="facetBarcode" label="人脸绑定">
<template slot-scope="scope">
<el-tag v-if="scope.row.isFace === 1" type="success">已绑定</el-tag>
<el-tag v-if="scope.row.isFace === 0" type="info">未绑定</el-tag>
<el-tag v-if="scope.row.facetBarcode !== null" type="success">已绑定</el-tag>
<el-tag v-else type="info">未绑定</el-tag>
</template>
</el-table-column>
<el-table-column prop="platformStatus" label="状态" align="center" width="60">
<template slot-scope="scope">
<!-- :disabled="user.id === scope.row.userId" -->
<!-- :disabled="user.id === scope.row.id" -->
<el-switch v-if="scope.row.addtype===2" v-model="scope.row.platformStatus" active-color="#409EFF" inactive-color="#F56C6C" :active-value="1" :inactive-value="2" @change="changeEnabled(scope.row, scope.row.platformStatus)" />
</template>
</el-table-column>
@ -223,23 +242,18 @@
<script>
import { getToken } from '@/utils/auth'
import crudUser, { resetpassword, FetchSyncUser } from '@/api/system/user'
// FetchSonDepts , getDepts,
import crudUser, { resetpassword, FetchSyncUser, FetchSyncUserFace, FetchUnbindUserFace, FetchFaceTByNameAndFondsNo } from '@/api/system/user'
import { getInitDeptTree } from '@/api/system/dept'
import { getAll } from '@/api/system/role'
import CRUD, { presenter, header, form, crud } from '@crud/crud'
import crudOperation from '@crud/CRUD.operation'
import pagination from '@crud/Pagination'
// import Treeselect from '@riophae/vue-treeselect'
import { mapGetters } from 'vuex'
import '@riophae/vue-treeselect/dist/vue-treeselect.css'
// import { LOAD_CHILDREN_OPTIONS } from '@riophae/vue-treeselect'
// import Vue from 'vue'
import { exportFile } from '@/utils/index'
import qs from 'qs'
let userRoles = []
// dept: { id: null }, isAdmin: false fonds: { id: null },
const defaultForm = { id: null, lastname: null, loginid: null, sex: '男', email: null, platformStatus: 1, roleIds: [], departmentid: null, mobile: null }
const defaultForm = { id: null, lastname: null, loginid: null, sex: '男', email: null, platformStatus: 1, roleIds: [], departmentid: null, mobile: null, facetBarcode: null, facePhoto: null }
export default {
name: 'User',
components: { crudOperation, pagination },
@ -282,10 +296,6 @@ export default {
defaultProps: { children: 'children', label: 'deptName' },
levelNumber: 0,
permission: { add: [], edit: [], del: [] },
enabledTypeOptions: [
{ key: '1', display_name: '激活' },
{ key: '0', display_name: '锁定' }
],
userTypeOptions: [
{ value: 1, label: '同步用户' },
{ value: 2, label: '自建用户' }
@ -311,14 +321,18 @@ export default {
{ trigger: 'blur', validator: validateRole }
]
},
imageUrl: null,
faceUserdialogVisible: false,
faceUserTable: [],
autoGetLoading: false,
selectedFaceUser: null,
deptGroupOptions: [],
syncLoading: false,
selectedDeptInfo: null
selectedDeptInfo: null,
autoFaceUserValue: null,
autoFaceUserOptions: [],
syncFaceLoading: false,
hasBindFaceDb: false, //
imageUrl: null,
showGuessTip: false, //
faceSelectDialogVisible: false, //
tempSelectFace: null, //
autoGetLoading: false
}
},
computed: {
@ -344,7 +358,7 @@ export default {
this.syncLoading = true
FetchSyncUser().then((res) => {
console.log('res', res)
if (res) {
if (res.code !== null) {
this.$message({ message: '同步用户数据成功', type: 'success', offset: 8 })
this.crud.toQuery()
} else {
@ -357,6 +371,23 @@ export default {
this.syncLoading = false
})
},
toSyncFace() {
this.syncFaceLoading = true
FetchSyncUserFace().then((res) => {
console.log('res', res)
if (res) {
this.$message({ message: res.message, type: 'success', offset: 8 })
this.crud.toQuery()
} else {
this.$message({ message: '自动绑定人脸数据失败', type: 'error', offset: 8 })
}
this.syncFaceLoading = false
}).catch(err => {
console.log('自动绑定人脸数据失败', err)
this.$message({ message: '自动绑定人脸数据失败', type: 'error', offset: 8 })
this.syncFaceLoading = false
})
},
// internalId
getDeptByInternalId(internalId) {
if (!internalId) return null
@ -368,6 +399,7 @@ export default {
},
//
handleDeptChange(val) {
console.log('val', val)
this.selectedDeptInfo = val
this.form.departmentid = val ? val.deptsId : null
},
@ -413,17 +445,26 @@ export default {
delete this.crud.params.size
}
},
[CRUD.HOOK.beforeAddCancel]() {
this.autoFaceUserOptions = []
this.imageUrl = null
this.tempSelectFace = null
this.faceSelectDialogVisible = false
this.showGuessTip = false
},
[CRUD.HOOK.beforeEditCancel]() {
this.autoFaceUserOptions = []
this.imageUrl = null
this.tempSelectFace = null
this.faceSelectDialogVisible = false
this.showGuessTip = false
},
//
[CRUD.HOOK.afterToCU](crud, form) {
this.getRoles()
//
if (form.departmentid) {
this.selectedDeptInfo = this.getDeptByInternalId(form.departmentid)
// if (form.internalId) {
// this.selectedDeptInfo = this.getDeptByInternalId(form.departmentid)
// } else {
// this.selectedDeptInfo = this.findDeptObjById(form.departmentid)
// }
} else {
const deptObj = this.findDeptObjById(this.query.deptId)
this.selectedDeptInfo = deptObj
@ -433,39 +474,10 @@ export default {
//
[CRUD.HOOK.beforeToAdd](crud, form) {
//
this.hasBindFaceDb = false
this.roleDatas = []
this.selectedDeptInfo = null
},
//
// [CRUD.HOOK.beforeToEdit](crud, form) {
// form.roleIds = []
// this.leftDeptsId = crud.form.departmentid
// if (form.roleIds.includes(',')) {
// const arr = form.roleIds.split(',')
// this.roles.map((role) => {
// arr.forEach(item => {
// if (item === String(role.name)) {
// return form.roleIds.push(role)
// }
// })
// })
// } else {
// this.roles.map((role) => {
// if (form.roleIds === String(role.name)) {
// return form.roles.push(role)
// }
// })
// }
// this.roleDatas = []
// userRoles = []
// const _this = this
// form.roleIds.forEach(function(role, index) {
// _this.roleDatas.push(role.id)
// const rol = { id: role.id }
// userRoles.push(rol)
// })
// crud.form.id = crud.form.userId
// },
[CRUD.HOOK.beforeToEdit](crud, form) {
//
this.roleDatas = []
@ -473,6 +485,15 @@ export default {
if (form.id) {
const params = { userId: form.id }
this.hasBindFaceDb = !!form.facePhoto && !!form.facetBarcode
if (form.facePhoto) {
const linkSrc = window.g.ApiUrl
this.imageUrl = linkSrc + '/api/minio/getImg?bucket=4&fileName=' + form.facePhoto + '.bmp'
} else {
this.imageUrl = null
}
crudUser.FetchUserDetailsById(params).then(res => {
console.log('获取用户详情成功', res)
@ -523,6 +544,10 @@ export default {
return true
},
clickRowHandler(row) {
//
// if (row.id === this.user.id) {
// return
// }
this.$refs.table.clearSelection()
this.$refs.table.toggleRowSelection(row)
},
@ -557,18 +582,7 @@ export default {
},
changeRole(value) {
userRoles = [...value]
// value.forEach(function(data, index) {
// const role = { id: data }
// userRoles.push(role)
// })
},
// deleteTag(value) {
// userRoles.forEach(function(data, index) {
// if (data.id === value) {
// userRoles.splice(index, value)
// }
// })
// },
},
deleteTag(value) {
const index = userRoles.findIndex(item => item === value)
if (index > -1) {
@ -633,7 +647,6 @@ export default {
}
groupMap[key].children.push(item)
})
//
Object.values(groupMap).forEach(group => {
groupSelectOptions.push({
@ -642,7 +655,9 @@ export default {
deptsId: child.deptsId,
deptName: child.deptName,
internalId: child.internalId,
departmentCode: child.departmentCode || null
departmentCode: child.departmentCode || null,
fondsNo: child.fondsNo,
group: { label: group.deptName }
}))
})
})
@ -655,7 +670,9 @@ export default {
deptsId: item.deptsId,
deptName: item.deptName,
internalId: item.internalId,
departmentCode: item.departmentCode || null
departmentCode: item.departmentCode || null,
fondsNo: item.fondsNo,
group: { label: '其他部门' }
}))
})
}
@ -679,83 +696,12 @@ export default {
this.handleNodeClick(rootNode)
}
})
// console.log('this.fondsDatas', this.fondsDatas)
// this.$nextTick(() => {
// if (root.children.length) {
// let first = null
// if (root.children[0].children) {
// first = root.children[0].children[0]
// } else {
// first = root.children[0]
// }
// if (first) {
// this.$refs.tree.setCurrentKey(first.id)
// this.handleNodeClick(first)
// }
// }
// })
})
},
filterNode(value, data) {
if (!value) return true
return data.deptName?.includes(value)
},
// changeFondsValue(value) {
// this.depts = []
// console.log(this.lastValue)
// if (this.lastValue) {
// if (value !== this.lastValue) {
// this.form.dept.id = null
// }
// }
// var obj = {}
// obj = this.fondsOptions.find(function(item) {
// return item.id === value
// })
// const params = {
// 'fondsId': obj.id,
// 'fondsName': obj.fondsName,
// 'status': 1
// }
// this.getDepts(params)
// },
// getDepts(params) {
// getDepts(params).then(res => {
// this.depts = res.content.map(function(obj) {
// if (obj.sonNum !== 0) {
// obj.hasChildren = true
// } else {
// obj.hasChildren = false
// }
// if (obj.hasChildren) {
// obj.children = null
// }
// return obj
// })
// })
// },
//
// loadDepts({ action, parentNode, callback }) {
// if (action === LOAD_CHILDREN_OPTIONS) {
// FetchSonDepts({ deptsId: parentNode.deptsId }).then(res => {
// parentNode.children = res.map(function(obj) {
// if (obj.sonNum !== 0) {
// obj.hasChildren = true
// } else {
// obj.hasChildren = false
// }
// if (obj.hasChildren) {
// obj.children = null
// }
// return obj
// })
// setTimeout(() => {
// callback()
// }, 100)
// })
// }
// },
//
toDelete(datas) {
this.deleteData = datas
@ -829,67 +775,123 @@ export default {
})
},
checkboxT(row, rowIndex) {
return row.userId !== this.user.id
},
// fondsNormalizer(node) {
// if (node.children && !node.children.length) {
// delete node.children
// }
// return {
// id: node.id,
// label: node.fondsName,
// children: node.children
// }
// },
// normalizer(node) {
// if (node.children && !node.children.length) {
// delete node.children
// }
// return {
// id: node.deptsId,
// label: node.deptsName,
// children: node.children
// }
// },
//
autoGetFaceUsers() {
return row.id !== this.user.id
},
async autoGetFaceUsers() {
this.autoFaceUserOptions = []
this.tempSelectFace = null
this.showGuessTip = false
//
if (!this.selectedDeptInfo) {
this.$message({ message: '请先选择所属部门', type: 'warning', offset: 8 })
return
}
this.autoGetLoading = true
//
setTimeout(() => {
//
this.faceUserTable = [
{ userId: 1, loginid: 'user1', lastname: '用户1', sex: '男', deptsName: '技术部' },
{ userId: 2, loginid: 'user2', lastname: '用户2', sex: '女', deptsName: '市场部' },
{ userId: 3, loginid: 'user3', lastname: '用户3', sex: '男', deptsName: '财务部' }
]
try {
//
const paramsFirst = {
fondsNo: this.selectedDeptInfo.fondsNo,
name: this.form.lastname || ''
}
console.log('第一次查询人脸参数(带名称):', paramsFirst)
let resList = await FetchFaceTByNameAndFondsNo(paramsFirst)
// [
// {
// 'barcode': 'S00101_1',
// 'guid': 'd98f0098-10b7-4132-a177-f1c8c508e44a',
// 'name': '',
// 'opTime': '2026-05-19T06:29:03.260+00:00',
// 'groupindex': 0,
// 'isupdate': 1,
// 'libcode': 'S00101',
// 'score': 0,
// 'remarks': null
// }
// ]
// && name
if ((!resList || resList.length === 0) && this.form.lastname) {
const paramsSecond = {
fondsNo: this.selectedDeptInfo.fondsNo,
name: ''
}
console.log('未匹配到数据,执行第二次查询(清空用户名)', paramsSecond)
resList = await FetchFaceTByNameAndFondsNo(paramsSecond)
//
this.showGuessTip = true
}
this.autoGetLoading = false
if (!resList || resList.length === 0) {
this.$message({ message: '未查询到该市州下的人脸数据', type: 'info', offset: 8 })
return
}
this.autoFaceUserOptions = resList
//
this.faceSelectDialogVisible = true
} catch (err) {
console.error('获取人脸异常:', err)
this.autoGetLoading = false
this.faceUserdialogVisible = true
}, 1500)
},
//
handleFaceUserSelectionChange(selection) {
//
if (selection.length > 1) {
this.$refs.faceUserTable.clearSelection()
this.$refs.faceUserTable.toggleRowSelection(selection[selection.length - 1])
this.selectedFaceUser = selection[selection.length - 1]
} else if (selection.length === 1) {
this.selectedFaceUser = selection[0]
this.$message({ message: '查询人脸失败', type: 'error', offset: 8 })
}
},
//
confirmSelectFace() {
if (!this.tempSelectFace) {
this.$message({ message: '请选择一条人脸信息', type: 'warning', offset: 8 })
return
}
//
this.fillUserData(this.tempSelectFace)
this.faceSelectDialogVisible = false
},
//
handleSelectFaceUser(userInfo) {
if (!userInfo) return
this.fillUserData(userInfo)
},
//
fillUserData(userInfo) {
this.form.facetBarcode = userInfo.barcode
this.form.facePhoto = userInfo.guid
if (!this.form.lastname) {
this.form.lastname = userInfo.name
}
// const linkSrc = process.env.NODE_ENV === 'production' ? window.g.ApiUrl : process.env.VUE_APP_BASE_API
const linkSrc = window.g.ApiUrl
if (userInfo.guid) {
this.imageUrl = linkSrc + '/api/minio/getImg?bucket=4&fileName=' + userInfo.guid + '.bmp'
// this.imageUrl = 'http://172.17.162.10:15000/api/minio/getImg?bucket=4&fileName=b89ea010-56fd-492c-a6d7-f4cb317116cb.bmp'
} else {
this.selectedFaceUser = null
this.imageUrl = null
}
},
//
confirmFaceUserSelection() {
if (this.selectedFaceUser) {
// form
this.form.lastname = this.selectedFaceUser.lastname
this.form.nickName = this.selectedFaceUser.nickName
this.form.sex = this.selectedFaceUser.sex
//
this.faceUserdialogVisible = false
//
clearFaceInfo() {
//
if (this.hasBindFaceDb) {
FetchUnbindUserFace({
id: this.form.id
}).then(res => {
console.log('res', res)
if (res === '解绑成功') {
this.$message({ message: res, type: 'success', offset: 8 })
this.form.facetBarcode = null
this.form.facePhoto = null
this.imageUrl = null
this.hasBindFaceDb = false
this.crud.refresh()
} else {
this.$message({ message: res.msg || '解绑失败', type: 'error', offset: 8 })
}
})
} else {
this.$message({ message: '请选择一个用户', type: 'warning', offset: 8 })
//
this.form.facetBarcode = null
this.form.facePhoto = null
this.imageUrl = null
}
}
}
@ -937,7 +939,7 @@ export default {
display: block;
width: 150px;
height: 200px;
margin: 0 0 20px 0;
// margin: 0 0 20px 0;
}
}
.upload-btn{
@ -959,6 +961,7 @@ export default {
}
.el-table{
::v-deep .el-tag{
margin: 0 !important;
&.el-tag--small{
color: #0348f3 !important;
background-color: #eef5fe !important;
@ -976,4 +979,66 @@ export default {
}
}
}
.face-select-dialog{
::v-deep .el-dialog{
.el-dialog__body{
padding: 10px 0 0 0;
}
.el-dialog__footer{
padding: 10px 0 20px 0;
}
}
}
.face-card-wrap {
max-height: 425px;
overflow-y: auto;
display: flex;
flex-wrap: wrap;
gap: 16px;
padding: 10px 0;
}
.face-card-item {
width: 130px;
border: 1px solid #e4e7ed;
border-radius: 6px;
padding: 10px;
cursor: pointer;
transition: 0.2s;
&:hover {
border-color: #409EFF;
}
&.active {
border-color: #409EFF;
background-color: #ecf5ff;
}
.face-img {
display: block;
width: 110px;
height: 145px;
object-fit: cover;
border-radius: 4px;
}
.face-info {
margin-top: 8px;
text-align: center;
}
.face-name {
font-size: 14px;
color: #333;
}
.face-barcode {
font-size: 12px;
color: #909399;
margin-top: 4px;
word-break: break-all;
}
}
.guess-tip{
padding: 8px 12px;
background: #fff7e6;
color: #fa8c16;
border-radius: 4px;
margin-bottom: 12px;
font-size:14px;
}
</style>
Loading…
Cancel
Save