8 changed files with 725 additions and 130 deletions
-
11src/api/faceRecognition/index.js
-
BINsrc/assets/images/user.jpg
-
BINsrc/assets/images/user2.jpg
-
168src/views/faceRecognition/faceRecLog.vue
-
157src/views/faceRecognition/module/faceSearch.vue
-
44src/views/faceRecognition/module/selfRegister.vue
-
37src/views/faceRecognition/personInfoManage.vue
-
438src/views/faceRecognition/personRegister.vue
|
Before Width: 110 | Height: 160 | Size: 2.9 KiB After Width: 240 | Height: 340 | Size: 6.2 KiB |
|
After Width: 110 | Height: 160 | Size: 2.9 KiB |
@ -0,0 +1,438 @@ |
|||
<template> |
|||
<div class="app-container row-container"> |
|||
<div class="head-container"> |
|||
<div class="head-search" style="align-items: center; "> |
|||
<el-select v-model="query.personType" clearable size="small" placeholder="用户类型" class="filter-item" style="width: 140px;" @change="crud.toQuery"> |
|||
<i slot="prefix" class="iconfont icon-zhuangtai" /> |
|||
<el-option v-for="item in userTypeOptions" :key="item.value" :label="item.label" :value="item.value" /> |
|||
</el-select> |
|||
<el-input v-model="query.search" size="small" clearable placeholder="输入证号、姓名、身份证号搜索" prefix-icon="el-icon-search" class="filter-item" style="width: 260px;" @keyup.enter.native="crud.toQuery" /> |
|||
<rrOperation /> |
|||
</div> |
|||
<crudOperation :permission="permission"> |
|||
<template v-slot:middle> |
|||
<el-button slot="reference" size="mini" :loading="crud.delAllLoading" :disabled="crud.selections.length === 0" @click="toDelete(crud.selections)"> |
|||
<i class="iconfont icon-shanchu" /> |
|||
删除 |
|||
</el-button> |
|||
</template> |
|||
<template v-slot:right> |
|||
<el-button size="mini" @click="handleBatchImport"> |
|||
<i class="iconfont icon-piliangchengjian" /> |
|||
批量导入 |
|||
</el-button> |
|||
</template> |
|||
</crudOperation> |
|||
</div> |
|||
<div class="container-wrap"> |
|||
<span class="right-top-line" /> |
|||
<span class="left-bottom-line" /> |
|||
<el-dialog :close-on-click-modal="false" :modal-append-to-body="false" append-to-body :before-close="crud.cancelCU" :visible.sync="crud.status.cu > 0" :title="crud.status.title"> |
|||
<span class="dialog-right-top" /> |
|||
<span class="dialog-left-bottom" /> |
|||
<div class="setting-dialog"> |
|||
<div style="display: flex; justify-content: flex-start;"> |
|||
<el-form ref="form" :model="form" :rules="rules" size="small" label-width="110px"> |
|||
<el-form-item label="馆代码" prop="libcode"> |
|||
<el-input v-model="form.libcode" disabled placeholder="系统自动输入" /> |
|||
</el-form-item> |
|||
<el-form-item label="读者证号" prop="barcode"> |
|||
<el-input v-model="form.barcode" placeholder="请输入" /> |
|||
</el-form-item> |
|||
<el-form-item label="姓名" prop="personName"> |
|||
<el-input v-model="form.personName" placeholder="请输入" /> |
|||
</el-form-item> |
|||
<el-form-item label="身份证号" prop="idCard"> |
|||
<el-input v-model="form.idCard" placeholder="请输入" /> |
|||
</el-form-item> |
|||
<el-form-item label="联系方式" prop="phone"> |
|||
<el-input v-model="form.phone" placeholder="请输入" /> |
|||
</el-form-item> |
|||
<el-form-item label="性别" prop="personSex"> |
|||
<el-radio-group v-model="form.personSex"> |
|||
<el-radio :label="1">男</el-radio> |
|||
<el-radio :label="0">女</el-radio> |
|||
</el-radio-group> |
|||
</el-form-item> |
|||
<el-form-item label="用户类型" prop="personType"> |
|||
<el-select v-model="form.personType" placeholder="请选择"> |
|||
<el-option |
|||
v-for="(item,index) in userTypeOptions" |
|||
:key="index" |
|||
:label="item.label" |
|||
:value="item.value" |
|||
/> |
|||
</el-select> |
|||
</el-form-item> |
|||
</el-form> |
|||
<div class="right-user-img"> |
|||
<img :src="imageUrl || require('@/assets/images/user.jpg')" alt="人员照片"> |
|||
<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"><i class="iconfont icon-yulan" />摄像头拍摄</el-button> |
|||
</div> |
|||
</div> |
|||
<div slot="footer" class="dialog-footer"> |
|||
<el-button type="text" @click="crud.cancelCU">取消</el-button> |
|||
<el-button :loading="crud.status.cu === 2" type="primary" @click="crud.submitCU">确定</el-button> |
|||
</div> |
|||
</div> |
|||
</el-dialog> |
|||
<el-table ref="table" v-loading="crud.loading" highlight-current-row style="width: 100%;" height="calc(100vh - 330px)" :data="crud.data" @selection-change="crud.selectionChangeHandler" @row-click="clickRowHandler"> |
|||
<el-table-column type="selection" align="center" width="55" /> |
|||
<el-table-column type="index" label="序号" width="55" /> |
|||
<el-table-column prop="personName" label="姓名" /> |
|||
<el-table-column prop="personSex" label="性别" width="60"> |
|||
<template slot-scope="scope"> |
|||
<span>{{ scope.row.personSex === 1 ? '男' : '女' }}</span> |
|||
</template> |
|||
</el-table-column> |
|||
<el-table-column prop="barcode" label="读者证号" /> |
|||
<el-table-column prop="idCard" label="身份证号" /> |
|||
<el-table-column prop="libcode" label="馆代码" width="100" /> |
|||
<el-table-column prop="personPhotoUrl" label="已存照片" align="center"> |
|||
<template slot-scope="scope"> |
|||
<!-- <img v-if="scope.row.personPhotoUrl === '' || scope.row.personPhotoUrl === null" src="~@/assets/images/cover-bg.png" alt="" style="display:block; height: 60px;"> |
|||
<img v-else :src="baseApi + '/api/fileRelevant/getImg?imgType=3&imgId=' + scope.row.personPhotoUrl" alt="" style="display:block; height: 60px;"> --> |
|||
<span v-if="scope.row.personPhotoUrl === '' || scope.row.personPhotoUrl === null">否</span> |
|||
<span v-else>是</span> |
|||
</template> |
|||
</el-table-column> |
|||
<el-table-column prop="personType" label="用户类型" align="center"> |
|||
<template slot-scope="scope"> |
|||
<el-tag v-if="scope.row.personType === 0">普通用户</el-tag> |
|||
<el-tag v-if="scope.row.personType === 1" type="success">VIP用户</el-tag> |
|||
<el-tag v-if="scope.row.personType === 2" type="info">黑名单用户</el-tag> |
|||
</template> |
|||
</el-table-column> |
|||
<el-table-column label="操作" align="center" prop="columnStatus" width="240"> |
|||
<template slot-scope="scope"> |
|||
<el-button :class="scope.row.personType === 2 ? 'remove-black-btn' : ''" size="mini" style="padding: 5px;" @click="addBlackOrVipUser(scope.row,0)"> |
|||
<i class="iconfont icon-heimingdan" /> |
|||
{{ scope.row.personType === 2 ? '移出黑名单' : '加入黑名单' }} |
|||
</el-button> |
|||
<el-button :class="scope.row.personType === 1 ? 'remove-vip-btn' : ''" size="mini" style="padding: 5px;" @click="addBlackOrVipUser(scope.row,1)"> |
|||
<i class="iconfont icon-yooxi" /> |
|||
{{ scope.row.personType === 1 ? '移出VIP' : '加入VIP' }} |
|||
</el-button> |
|||
</template> |
|||
</el-table-column> |
|||
</el-table> |
|||
<pagination v-if="crud.data.length !== 0" /> |
|||
</div> |
|||
|
|||
<el-dialog :close-on-click-modal="false" :modal-append-to-body="false" append-to-body title="人脸查询" :visible.sync="faceSearchVisible" :before-close="handleClose"> |
|||
<FaceSearch ref="faceSearchRefs" :is-diaglog-face-search="true" /> |
|||
</el-dialog> |
|||
|
|||
<BatchImport ref="batchImportRefs" @refresh="updatePerson" /> |
|||
|
|||
<el-dialog :close-on-click-modal="false" :modal-append-to-body="false" append-to-body title="自助注册" :visible.sync="selfRegisterVisible"> |
|||
<SelfRegister ref="selfRegisterRefs" :is-dialog-face-regsiter="true" /> |
|||
</el-dialog> |
|||
|
|||
</div> |
|||
</template> |
|||
|
|||
<script> |
|||
import crudFace, { FetchPersonInfoById, FetchChangePersonInfo } from '@/api/faceRecognition/index' |
|||
import CRUD, { presenter, header, form, crud } from '@crud/crud' |
|||
import rrOperation from '@crud/RR.operation' |
|||
import crudOperation from '@crud/CRUD.operation' |
|||
import pagination from '@crud/Pagination' |
|||
import FaceSearch from './module/faceSearch' |
|||
import SelfRegister from './module/selfRegister' |
|||
import BatchImport from './module/batchImport' |
|||
// import { exportFile } from '@/utils/index' |
|||
// import qs from 'qs' |
|||
import { mapGetters } from 'vuex' |
|||
import { upload } from '@/utils/upload' |
|||
|
|||
const defaultForm = { personId: null, libcode: null, barcode: null, personName: null, personPhotoUrl: null, idCard: null, phone: null, personSex: 1, personType: 0, personPhotoBase64: null } |
|||
export default { |
|||
name: 'PersonInfoManage', |
|||
components: { pagination, crudOperation, rrOperation, FaceSearch, SelfRegister, BatchImport }, |
|||
cruds() { |
|||
return CRUD({ title: '人员信息', idField: 'personId', url: 'api/person/initPersonInfo', crudMethod: { ...crudFace }, optShow: { |
|||
add: true, |
|||
edit: true, |
|||
del: false, |
|||
reset: true, |
|||
download: false, |
|||
group: false |
|||
}}) |
|||
}, |
|||
mixins: [presenter(), header(), form(defaultForm), crud()], |
|||
data() { |
|||
return { |
|||
permission: { |
|||
add: ['admin', 'face:add'], |
|||
edit: ['admin', 'face:edit'], |
|||
del: ['admin', 'face:del'] |
|||
}, |
|||
userTypeOptions: [ |
|||
{ value: 0, label: '普通用户' }, |
|||
{ value: 1, label: 'VIP用户' }, |
|||
{ value: 2, label: '黑名单用户' } |
|||
], |
|||
rules: { |
|||
libcode: [ |
|||
{ required: true, message: '馆代码不可为空', trigger: 'blur' } |
|||
], |
|||
barcode: [ |
|||
{ required: true, message: '读者证号不可为空', trigger: 'blur' } |
|||
], |
|||
personName: [ |
|||
{ required: true, message: '姓名不可为空', trigger: 'blur' } |
|||
], |
|||
personType: [ |
|||
{ required: true, message: '请选择用户类型', trigger: 'change' } |
|||
] |
|||
}, |
|||
file: null, |
|||
fileNames: '', |
|||
filePath: '', |
|||
imageUrl: null, |
|||
selfRegisterVisible: false, |
|||
faceSearchVisible: false |
|||
} |
|||
}, |
|||
computed: { |
|||
...mapGetters([ |
|||
'baseApi', |
|||
'user' |
|||
]) |
|||
}, |
|||
created() { |
|||
}, |
|||
mounted() { |
|||
}, |
|||
methods: { |
|||
updatePerson() { |
|||
this.crud.refresh() |
|||
}, |
|||
[CRUD.HOOK.beforeRefresh]() { |
|||
this.crud.query.libcode = this.user.fonds.fondsNo |
|||
}, |
|||
[CRUD.HOOK.afterRefresh]() { |
|||
}, |
|||
// 新增与编辑前做的操作 |
|||
[CRUD.HOOK.afterToCU](crud, form) { |
|||
form.libcode = this.user.fonds.fondsNo |
|||
}, |
|||
// 新增前 |
|||
[CRUD.HOOK.beforeToAdd](crud, form) { |
|||
}, |
|||
// 编辑前 |
|||
[CRUD.HOOK.beforeToEdit](crud, form) { |
|||
this.imageUrl = null |
|||
const params = { |
|||
'id': form.personId |
|||
} |
|||
FetchPersonInfoById(params).then(res => { |
|||
if (res) { |
|||
// crud.form = { ...crud.form, ...res } |
|||
|
|||
Object.keys(crud.form).forEach(key => { |
|||
this.$set(crud.form, key, null) |
|||
}) |
|||
|
|||
Object.keys(res).forEach(key => { |
|||
this.$set(crud.form, key, res[key]) |
|||
}) |
|||
if (this.form.personPhotoUrl) { |
|||
this.imageUrl = this.baseApi + '/api/fileRelevant/getImg?imgType=3&imgId=' + this.form.personPhotoUrl |
|||
} else { |
|||
this.imageUrl = require('@/assets/images/user.jpg') |
|||
} |
|||
} else { |
|||
this.$message({ message: '获取数据失败', type: 'error', offset: 8 }) |
|||
} |
|||
}).catch((err) => { |
|||
this.$message({ message: '获取数据失败', type: 'error', offset: 8 }) |
|||
console.error(err) |
|||
}) |
|||
}, |
|||
// 提交前做的操作 |
|||
[CRUD.HOOK.afterValidateCU](crud) { |
|||
if (crud.form.personPhotoUrl === '' || crud.form.personPhotoUrl === null) { |
|||
this.$message({ message: '请选择上传照片', type: 'error', offset: 8 }) |
|||
return false |
|||
} |
|||
console.log(crud.form) |
|||
return true |
|||
}, |
|||
async changeFile(e) { |
|||
const file = e.target.files[0] |
|||
|
|||
if (file && file.type.startsWith('image/')) { |
|||
this.file = e.target.files[0] |
|||
this.fileNames = this.file.name |
|||
|
|||
const fileBase64 = await this.getBase64(this.file) |
|||
this.imageUrl = fileBase64 |
|||
upload(this.baseApi + '/api/fileRelevant/uploadFaceImg', this.file).then(res => { |
|||
console.log(res) |
|||
if (res.data.code === 200) { |
|||
this.form.personPhotoUrl = res.data.data |
|||
} |
|||
}) |
|||
} else { |
|||
this.$message({ message: '只可上传图片', type: 'error', offset: 8 }) |
|||
this.imageUrl = null |
|||
} |
|||
}, |
|||
handleFaceSearch() { |
|||
this.faceSearchVisible = true |
|||
// this.$nextTick(() => { |
|||
// this.$refs.faceSearchRefs |
|||
// }) |
|||
}, |
|||
handleSelfRegister() { |
|||
this.selfRegisterVisible = true |
|||
this.$nextTick(() => { |
|||
this.$refs.selfRegisterRefs.generateQrcode() |
|||
}) |
|||
}, |
|||
handleBatchImport() { |
|||
this.$refs.batchImportRefs.batchImportVisible = true |
|||
}, |
|||
toDelete(datas) { |
|||
this.$confirm('此操作将删除当前所选' + this.crud.title + '<span>你是否还要继续?</span>', '提示', { |
|||
confirmButtonText: '继续', |
|||
cancelButtonText: '取消', |
|||
type: 'warning', |
|||
dangerouslyUseHTMLString: true |
|||
}).then(() => { |
|||
this.crud.delAllLoading = true |
|||
const ids = [] |
|||
datas.forEach(val => { |
|||
ids.push(val.personId) |
|||
}) |
|||
crudFace.del(ids).then(() => { |
|||
this.$message({ message: '删除成功', type: 'success', offset: 8 }) |
|||
this.crud.delAllLoading = false |
|||
this.crud.refresh() |
|||
}).catch(err => { |
|||
this.crud.delAllLoading = false |
|||
console.log(err) |
|||
}) |
|||
}).catch(() => { |
|||
}) |
|||
}, |
|||
addBlackOrVipUser(data, type) { |
|||
const message = type === 1 ? 'VIP' : '黑名单' |
|||
this.$confirm('此操作将所选用户加入 / 移出 ' + message + '<span>你是否还要继续?</span>', '提示', { |
|||
confirmButtonText: '继续', |
|||
cancelButtonText: '取消', |
|||
type: 'warning', |
|||
dangerouslyUseHTMLString: true |
|||
}).then(() => { |
|||
if (data.personType === 0 && type === 1) { |
|||
data.personType = 1 |
|||
} else if (data.personType === 0 && type === 0) { |
|||
data.personType = 2 |
|||
} else if (data.personType === 1 && type === 1) { |
|||
data.personType = 0 |
|||
} else if (data.personType === 1 && type === 0) { |
|||
data.personType = 2 |
|||
} else if (data.personType === 2 && type === 1) { |
|||
data.personType = 1 |
|||
} else if (data.personType === 2 && type === 0) { |
|||
data.personType = 0 |
|||
} |
|||
FetchChangePersonInfo(data).then(res => { |
|||
this.$message({ message: '修改成功', type: 'success', offset: 8 }) |
|||
}).catch(() => { |
|||
this.$message({ message: '修改失败', type: 'error', offset: 8 }) |
|||
}) |
|||
}).catch(() => { |
|||
this.$message({ message: '已取消修改', offset: 8 }) |
|||
}) |
|||
}, |
|||
getBase64(file) { |
|||
const reader = new FileReader() |
|||
reader.readAsDataURL(file) |
|||
return new Promise((resolve) => { |
|||
reader.onload = () => { |
|||
resolve(reader.result) |
|||
} |
|||
}) |
|||
}, |
|||
// 获取图片的分辨率 |
|||
getImgPx(img) { |
|||
const image = new Image() |
|||
image.src = img |
|||
return new Promise((resolve) => { |
|||
image.onload = () => { |
|||
const width = image.width |
|||
const height = image.height |
|||
resolve({ width, height }) |
|||
} |
|||
}) |
|||
}, |
|||
clickRowHandler(row) { |
|||
this.$refs.table.clearSelection() |
|||
this.$refs.table.toggleRowSelection(row) |
|||
}, |
|||
handleClose() { |
|||
this.faceSearchVisible = false |
|||
if (this.$refs.faceSearchRefs) { |
|||
this.$refs.faceSearchRefs.imageUrl = null |
|||
this.$refs.faceSearchRefs.searchPerson = {} |
|||
this.$refs.faceSearchRefs.btnLoading = false |
|||
} |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.face-search.el-button:hover, |
|||
.face-search.el-button:focus, |
|||
.face-search.el-button--info.is-plain:hover, |
|||
.face-search.el-button--info.is-plain:focus{ |
|||
background: #E8F2FF !important; |
|||
} |
|||
|
|||
.right-user-img{ |
|||
flex: 1; |
|||
display: flex; |
|||
flex-direction: column; |
|||
align-items: center; |
|||
margin-left: 30px; |
|||
border-left: 1px solid #E8E8E8; |
|||
img{ |
|||
display: block; |
|||
width: 150px; |
|||
height: 200px; |
|||
margin: 20px 0; |
|||
} |
|||
} |
|||
|
|||
::v-deep .el-tag{ |
|||
&.el-tag--small{ |
|||
color: #0348f3 !important; |
|||
background-color: #eef5fe !important; |
|||
border-color: #eef5fe !important; |
|||
} |
|||
&.el-tag--success { |
|||
background-color: #e7faf0 !important; |
|||
border-color: #d0f5e0!important; |
|||
color: #13ce66!important; |
|||
} |
|||
&.el-tag--info { |
|||
background-color: #f4f4f5 !important; |
|||
border-color: #f4f4f5!important; |
|||
color: #909399!important; |
|||
} |
|||
} |
|||
|
|||
.remove-black-btn, |
|||
.remove-vip-btn{ |
|||
border-color: #909399; |
|||
color: #909399; |
|||
} |
|||
</style> |
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue