Browse Source

白名单需求

master
xuhuajiao 3 weeks ago
parent
commit
946de743fe
  1. 4
      .env.development
  2. 22
      src/api/asset/index.js
  3. 590
      src/views/assetManage/assetWhitelist/index.vue
  4. 48
      src/views/assetManage/inventory/index.vue

4
.env.development

@ -3,8 +3,8 @@ ENV = 'development'
# 接口地址
# 许镇-本地服地址
# VUE_APP_BASE_API = 'http://192.168.99.63:15000'
VUE_APP_BASE_API = 'http://192.168.99.101:15000'
VUE_APP_BASE_API = 'http://192.168.99.63:15000'
# VUE_APP_BASE_API = 'http://192.168.99.101:15000'
VUE_APP_WEBRTCSTREAMER_API = '127.0.0.1:8000'
# 是否启用 babel-plugin-dynamic-import-node插件

22
src/api/asset/index.js

@ -97,6 +97,24 @@ export function FetchInitInOutBill(params) {
})
}
// 添加白名单
export function FetchAddAssetWhiteList(data) {
return request({
url: 'api/asset/addAssetWhiteList',
method: 'post',
data
})
}
// 删除资产白名单
export function FetchDeleteAssetWhiteList(data) {
return request({
url: 'api/asset/deleteAssetWhiteList',
method: 'post',
data
})
}
export default {
FetchInitAssetInfo,
add,
@ -108,5 +126,7 @@ export default {
FetchDeleteAssetInfoPhotoById,
FetchInOutDetailsByBillNo,
FetchInitStockTakeBill,
FetchInitInOutBill
FetchInitInOutBill,
FetchAddAssetWhiteList,
FetchDeleteAssetWhiteList
}

590
src/views/assetManage/assetWhitelist/index.vue

@ -0,0 +1,590 @@
<template>
<div class="app-container row-container">
<!--工具栏-->
<div class="head-container">
<div v-if="crud.props.searchToggle" class="head-search">
<!-- 搜索 -->
<el-input v-model="query.search" size="small" clearable placeholder="输入资产名称/编码搜索" prefix-icon="el-icon-search" style="width: 220px;" class="filter-item" @keyup.enter.native="crud.toQuery" />
<rrOperation />
</div>
<crudOperation :permission="permission">
<template v-slot:left>
<el-button size="mini" @click="toAdd()">
<i class="iconfont icon-xinzeng" />
新增
</el-button>
<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>
</crudOperation>
</div>
<div class="container-wrap">
<span class="right-top-line" />
<span class="left-bottom-line" />
<el-table ref="table" v-loading="crud.loading" highlight-current-row style="width: 100%;" height="calc(100vh - 330px)" :data="crud.data" @row-dblclick="handleRowDblClick" @selection-change="crud.selectionChangeHandler">
<el-table-column type="selection" width="55" />
<el-table-column prop="mark" label="资产编号" min-width="180px" :show-overflow-tooltip="true" />
<el-table-column prop="name" label="资产名称" min-width="180px" :show-overflow-tooltip="true" />
<el-table-column prop="capitaltyepname" label="资产类型" width="80px" :show-overflow-tooltip="true" />
<el-table-column prop="startprice" label="价值" width="80px" align="right" :show-overflow-tooltip="true" :formatter="(row) => formatMoney(row.startprice)" />
<el-table-column prop="unitname" label="计量单位" width="80px" align="center" :show-overflow-tooltip="true" />
<el-table-column prop="departmentname" label="使用部门" :show-overflow-tooltip="true" />
<el-table-column prop="resourcename" label="使用人" :show-overflow-tooltip="true" />
<el-table-column prop="blongdepartmentname" label="所属部门" min-width="140px" :show-overflow-tooltip="true" />
<el-table-column prop="glrname" label="管理人" :show-overflow-tooltip="true" />
<el-table-column prop="cfdname" label="存放地" min-width="140px" :show-overflow-tooltip="true" />
<el-table-column prop="whiteCreateTime" label="加入时间" width="180px">
<template slot-scope="scope">
<div>{{ scope.row.whiteCreateTime | parseTime }}</div>
</template>
</el-table-column>
<el-table-column prop="whiteLastname" label="操作人" />
<el-table-column prop="whiteRemark" label="备注" :show-overflow-tooltip="true" />
</el-table>
<!--分页组件-->
<pagination v-if="crud.data.length!==0" />
</div>
<!-- 资产详情弹窗 -->
<el-dialog class="detailBook" append-to-body :close-on-click-modal="false" :modal-append-to-body="false" :before-close="handleCloseDialog" :visible="detailDialogVisible" title="资产详情">
<span class="dialog-right-top" />
<span class="dialog-left-bottom" />
<div class="setting-dialog">
<div class="detail-tab tab-content">
<div class="detail-check">
<ul class="book-detail">
<li><span>资产编号</span>{{ selectedAsset && selectedAsset.mark }}</li>
<li><span>资产名称</span>{{ selectedAsset && selectedAsset.name }}</li>
<li><span>资产类型</span>{{ selectedAsset && selectedAsset.capitaltyepname || '——' }}</li>
<li><span>规格型号</span>{{ selectedAsset && selectedAsset.capitalspec || '——' }}</li>
<li><span>设备用途</span>{{ selectedAsset && selectedAsset.sbyt || '——' }}</li>
<li><span>价值类型</span>{{ selectedAsset && selectedAsset.jzlx || '——' }}</li>
<li><span>价值</span>{{ selectedAsset ? formatMoney(selectedAsset?.startprice) : '——' }}</li>
<li><span>数量</span>{{ selectedAsset && selectedAsset.capitalnum }}</li>
<li><span>实际数量</span>{{ selectedAsset && selectedAsset.sjsl }}</li>
<li><span>计量单位</span>{{ selectedAsset && selectedAsset.unitname }}</li>
<li><span>使用部门</span>{{ selectedAsset && selectedAsset.departmentname }}</li>
<li><span>使用人</span>{{ selectedAsset && selectedAsset.resourcename }}</li>
<li><span>所属部门</span>{{ selectedAsset && selectedAsset.blongdepartmentname }}</li>
<li><span>管理人</span>{{ selectedAsset && selectedAsset.glrname }}</li>
<li><span>存放地</span>{{ selectedAsset && selectedAsset.cfdname }}</li>
<li><span>供应商</span>{{ selectedAsset && selectedAsset.gys }}</li>
<li><span>项目名称</span>{{ selectedAsset && selectedAsset.xmmc }}</li>
<li><span>无线电设备用途</span>{{ selectedAsset && selectedAsset.wxdsbyt }}</li>
<li><span>领用日期</span>{{ selectedAsset && selectedAsset.deprestartdate | parseTime }}</li>
<li><span>投入使用日期</span>{{ selectedAsset && selectedAsset.trsyrq | parseTime }}</li>
<li><span>入账日期</span>{{ selectedAsset && selectedAsset.rzrq | parseTime }}</li>
<li><span>保修截至日期</span>{{ selectedAsset && selectedAsset.bxjzrq | parseTime }}</li>
</ul>
<!-- 资产图片列表竖向滚动 + 删除按钮 -->
<div class="asset-image-wrapper">
<div v-if="assetImageList.length > 0" class="asset-image-scroll">
<div v-for="(item, index) in assetImageList" :key="item.id || index" class="image-item">
<el-image
class="preview-img"
:src="item.imgUrl"
fit="contain"
:preview-src-list="assetImageList.map(img => img.imgUrl)"
:preview-initial-index="index"
/>
</div>
</div>
<div v-else class="default-img">
<img :src="require('@/assets/images/system/default-img2.png')" alt="默认图片">
</div>
</div>
</div>
</div>
</div>
</el-dialog>
<el-dialog
title="新增资产白名单"
:visible.sync="addDialogVisible"
width="1000px"
append-to-body
:close-on-click-modal="false"
@close="resetAddDialog"
>
<div style="display: flex; justify-content: space-between; align-items: center; padding-bottom: 20px;">
<div>
<el-input v-model="addSearch" size="small" clearable placeholder="输入资产名称/编码搜索" prefix-icon="el-icon-search" style="width: 220px;" class="filter-item" @keyup.enter.native="toQuery" @clear="toQuery" />
<el-button class="filter-item filter-search" size="mini" type="success" icon="el-icon-search" @click="toQuery">搜索</el-button>
</div>
<div style="color:#606266;">
已选择资产<span style="color:#409EFF">{{ selectedMarkSet.size }}</span>
</div>
</div>
<div v-loading="addDialogLoading">
<el-table ref="addTable" :row-key="row => row.mark" :data="initAssetList" height="446px" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" :reserve-selection="true" />
<el-table-column prop="mark" label="资产编号" min-width="200px" :show-overflow-tooltip="true" />
<el-table-column prop="name" label="资产名称" min-width="200px" :show-overflow-tooltip="true" />
<el-table-column prop="capitaltyepname" label="资产类型" width="80px" :show-overflow-tooltip="true" />
<el-table-column prop="startprice" label="价值" width="80px" align="right" :show-overflow-tooltip="true" :formatter="(row) => formatMoney(row.startprice)" />
<el-table-column prop="unitname" label="计量单位" width="80px" align="center" :show-overflow-tooltip="true" />
<el-table-column prop="departmentname" label="使用部门" :show-overflow-tooltip="true" />
<el-table-column prop="resourcename" label="使用人" :show-overflow-tooltip="true" />
<el-table-column prop="blongdepartmentname" label="所属部门" min-width="140px" :show-overflow-tooltip="true" />
<el-table-column prop="glrname" label="管理人" :show-overflow-tooltip="true" />
<el-table-column prop="cfdname" label="存放地" min-width="140px" :show-overflow-tooltip="true" />
<el-table-column prop="is_whitelist" label="是否白名单" width="90px" align="center" fixed="right">
<template slot-scope="scope">
<el-tag v-if="scope.row.is_whitelist" type="success">白名单</el-tag>
<span v-else>-</span>
</template>
</el-table-column>
</el-table>
<!-- 弹窗内分页 -->
<el-pagination
:current-page="addPage.pageNo"
:page-sizes="[10, 20, 50, 100]"
:page-size="addPage.pageSize"
layout="total, sizes, prev, pager, next"
:total="addPage.total"
style="margin: 20px 0 !important;"
@size-change="onAddSizeChange"
@current-change="onAddPageChange"
/>
<div style="padding: 20px 20px 0 20px;">
<el-form ref="form" inline :model="addForm" size="small" label-width="40px">
<el-form-item label="备注" prop="remark" style="margin-bottom: 0 !important;">
<el-input v-model="addForm.remark" type="textarea" rows="3" placeholder="请输入备注" style="width: 880px;" />
</el-form-item>
</el-form>
</div>
</div>
<span slot="footer" class="dialog-footer">
<el-button @click="addDialogVisible = false">取消</el-button>
<el-button type="primary" :loading="submitLoading" @click="submitAdd">确定</el-button>
</span>
</el-dialog>
</div>
</template>
<script>
import crudAsset, { FetchAssetInfoDetailsByMark, FetchInitAssetInfo, FetchAddAssetWhiteList, FetchDeleteAssetWhiteList } from '@/api/asset/index'
import CRUD, { presenter, header, crud } from '@crud/crud'
import rrOperation from '@crud/RR.operation'
import crudOperation from '@crud/CRUD.operation'
import pagination from '@crud/Pagination'
import { mapGetters } from 'vuex'
// import { addAssetWhitelist } from '@/api/asset/index' //
export default {
name: 'AssetWhitelist',
components: { pagination, crudOperation, rrOperation },
cruds() {
return CRUD({ title: '资产白名单', idField: 'mark', url: 'api/asset/initAssetInfo', crudMethod: { ...crudAsset }, optShow: {
add: false,
edit: false,
del: false,
reset: true,
download: false,
group: false
}})
},
mixins: [presenter(), header(), crud()],
data() {
return {
permission: { add: [], edit: [], del: [] },
selectedFile: null,
detailDialogVisible: false,
selectedAsset: null,
assetImageList: [],
addDialogVisible: false,
addDialogLoading: false,
submitLoading: false,
initAssetList: [], //
selectedMarkSet: new Map(), // mark -> row reserve-selection
addForm: {
remark: ''
},
//
addPage: {
pageNo: 1,
pageSize: 10,
total: 0
},
addSearch: ''
}
},
computed: {
...mapGetters([
'baseApi',
'user'
])
},
created() {
},
mounted() {
},
methods: {
[CRUD.HOOK.beforeRefresh]() {
this.crud.params.isWhite = true
//
this.originalPage = this.crud.page.page
this.originalSize = this.crud.page.size
// pageNopageSize
this.crud.params.pageNo = this.crud.page.page
this.crud.params.pageSize = this.crud.page.size
// pagesize
this.crud.params.page = undefined
this.crud.params.size = undefined
},
[CRUD.HOOK.afterRefresh](crud) {
//
if (this.originalPage !== undefined) {
this.crud.page.page = this.originalPage
this.crud.page.size = this.originalSize
// pageNopageSize
delete this.crud.params.pageNo
delete this.crud.params.pageSize
delete this.crud.params.page
delete this.crud.params.size
}
console.log(crud.data)
},
//
[CRUD.HOOK.beforeToAdd](crud, form) {
},
//
[CRUD.HOOK.beforeToEdit](crud, form) {
},
//
[CRUD.HOOK.afterValidateCU](crud) {
return true
},
formatMoney(money) {
if (!money && money !== 0) return '——'
return Number(money).toLocaleString('en-US')
},
//
handleRowDblClick(row) {
this.detailDialogVisible = true
this.selectedAsset = {}
this.assetImageList = []
const params = { mark: row.mark }
FetchAssetInfoDetailsByMark(params).then(res => {
this.selectedAsset = res || row
const photoList = res.assetInfoPhoto || []
this.assetImageList = photoList.map(item => ({
id: item.id,
photoUrl: item.photoUrl,
imgUrl: this.baseApi + '/api/minio/getImg?bucket=2&fileName=' + item.photoUrl
}))
})
},
handleCloseDialog() {
this.detailDialogVisible = false
this.selectedAsset = null
this.assetImageList = []
},
toAdd() {
this.addDialogVisible = true
this.addPage.pageNo = 1
this.addPage.pageSize = 10
this.addPage.total = 0
this.selectedMarkSet.clear()
//
this.$nextTick(() => {
this.$refs.addTable && this.$refs.addTable.clearSelection()
})
this.addForm.remark = ''
this.loadInitAssetList()
},
toQuery() {
this.addPage.pageNo = 1
this.addPage.pageSize = 10
this.addPage.total = 0
this.loadInitAssetList()
},
//
async loadInitAssetList() {
this.addDialogLoading = true
try {
const res = await FetchInitAssetInfo({
search: this.addSearch,
pageNo: this.addPage.pageNo,
pageSize: this.addPage.pageSize
})
this.initAssetList = res.records || []
this.addPage.total = res.total || 0
// reserve-selection
} catch (e) {
this.$message.error('加载失败')
} finally {
this.addDialogLoading = false
}
},
handleSelectionChange(rows) {
// rows
this.selectedMarkSet = new Map(rows.map(row => [row.mark, row]))
console.log('当前全部选中mark集合:', Array.from(this.selectedMarkSet.keys()))
},
//
onAddPageChange(val) {
this.addPage.pageNo = val
this.loadInitAssetList()
},
onAddSizeChange(val) {
this.addPage.pageSize = val
this.addPage.pageNo = 1
this.loadInitAssetList()
},
//
async submitAdd() {
const selectedRows = Array.from(this.selectedMarkSet.values())
console.log('最终选中的全部行:', selectedRows)
if (selectedRows.length === 0) {
return this.$message.warning('请至少选择一条资产')
}
this.submitLoading = true
try {
const params = {
assetInfos: selectedRows.map(row => ({ mark: row.mark, epc: row.epc })),
createBy: this.user.id,
remark: this.addForm.remark
}
console.log('params', params)
await FetchAddAssetWhiteList(params).then(res => {
console.log('FetchAddAssetWhiteList', res)
if (res.code !== null) {
this.$message.success(res || '加入白名单成功')
this.addDialogVisible = false
this.crud.refresh()
} else {
this.$message.error(res.message || '加入白名单失败')
}
}).catch(err => {
this.$message.error(err.message || '加入白名单失败')
})
} catch (err) {
this.$message.error(err.message || '加入白名单失败')
} finally {
this.submitLoading = false
}
},
//
resetAddDialog() {
this.initAssetList = []
this.selectedMarkSet.clear()
this.addForm.remark = ''
this.addPage.pageNo = 1
this.addPage.total = 0
this.addSearch = ''
this.$nextTick(() => {
this.$refs.addTable && this.$refs.addTable.clearSelection()
})
},
toDelete(datas) {
console.log('toDelete', datas)
this.$confirm('此操作将删除当前所选' + this.crud.title + '<span>你是否还要继续?</span>', '提示', {
confirmButtonText: '继续',
cancelButtonText: '取消',
type: 'warning',
dangerouslyUseHTMLString: true
}).then(() => {
this.crud.delAllLoading = true
const marks = datas.map(val => val.mark)
console.log('marks', marks)
FetchDeleteAssetWhiteList(marks).then(res => {
console.log('FetchDeleteAssetWhiteList', res)
if (res.code !== null) {
this.$message({ message: res, type: 'success', offset: 8 })
this.crud.delAllLoading = false
this.crud.refresh()
} else {
this.$message.error(res.message || '删除失败')
}
}).catch(err => {
this.crud.delAllLoading = false
console.log(err)
})
}).catch(() => {
})
}
}
}
</script>
<style lang="scss" scoped>
.sync-loading {
display: flex;
justify-content: center;
align-items: center;
min-height: 200px;
}
.sync-loading-content {
text-align: center;
}
.sync-loading-icon {
font-size: 48px;
color: #409EFF;
}
.sync-status {
margin-top: 15px;
text-align: center;
color: #606266;
font-size: 14px;
}
.file-tip {
margin-left: 10px;
font-size: 12px;
color: #606266;
}
.sync-result{
display: flex;
justify-content: center;
align-items: center;
margin-top: 40px;
font-size: 22px;
text-align: center;
.sync-text{
margin-left: 10px;
p{
display: inline-block;
span{
display: inline-block;
padding: 0 4px;
}
}
}
}
::v-deep .el-dialog__footer{
padding: 0 0 20px 0 !important;
}
.asset-detail-content {
display: flex;
gap: 20px;
}
.asset-info {
flex: 1;
}
//
.asset-image-wrapper {
width: 400px;
height: 660px; /* 固定高度 */
overflow: hidden;
}
.asset-image-scroll {
width: 100%;
height: 100%;
overflow-y: auto; /* 竖向滚动条 */
padding-right: 5px;
display: flex;
flex-direction: column;
gap: 10px;
}
.image-item {
position: relative;
width: 100%;
height: 150px;
background: #f5f7fa;
border-radius: 4px;
overflow: hidden;
flex-shrink: 0;
}
.preview-img {
width: 100%;
height: 100%;
object-fit: contain;
background: #fff;
}
//
.delete-btn {
position: absolute;
top: 5px;
right: 5px;
width: 22px;
height: 22px;
background: rgba(0, 0, 0, 0.6);
color: #fff;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
z-index: 10;
transition: 0.2s;
&:hover {
background: #f56c6c;
}
i {
font-size: 14px;
}
}
//
.default-img {
width: 100%;
height: 200px;
display: flex;
align-items: center;
justify-content: center;
background-color: #f5f7fa;
border: 2px solid #dcdfe6;
border-radius: 4px;
img {
width: 180px;
height: 180px;
object-fit: cover;
}
}
.detailBook {
::v-deep .el-dialog {
width: 1000px !important;
.el-dialog__body{
padding: 0 0 30px 0;
}
}
.detail-check{
display: flex;
justify-content: space-between;
align-items: flex-start;
padding: 20px 30px;
background-color: #F6F8FC;
}
.book-detail{
display: flex;
flex-direction: column;
justify-content: flex-start;
li{
line-height: 30px;
span{
display: inline-block;
width: 120px;
text-align: right;
margin-right: 10px;
color: #0C0E1E;
}
i{
font-style: normal;
padding: 0 8px;
}
&.row-li{
width: 100%
}
}
}
::v-deep .dialog-footer{
margin-top: 30px;
}
}
.dialog-footer{
margin: 20px auto 0 auto;
}
::v-deep .el-table__fixed-right{
background-color: #fff !important;
}
</style>

48
src/views/assetManage/inventory/index.vue

@ -32,10 +32,16 @@
<el-table-column prop="blongdepartmentname" label="所属部门" min-width="140px" :show-overflow-tooltip="true" />
<el-table-column prop="glrname" label="管理人" :show-overflow-tooltip="true" />
<el-table-column prop="cfdname" label="存放地" min-width="140px" :show-overflow-tooltip="true" />
<el-table-column prop="rzrq" label="更新时间" width="180px">
<!-- <el-table-column prop="rzrq" label="更新时间" width="180px">
<template slot-scope="scope">
<div>{{ scope.row.rzrq | parseTime }}</div>
</template>
</el-table-column> -->
<el-table-column prop="is_whitelist" label="是否白名单" align="center">
<template slot-scope="scope">
<el-tag v-if="scope.row.is_whitelist" type="success">白名单</el-tag>
<span v-else>-</span>
</template>
</el-table-column>
</el-table>
<!--分页组件-->
@ -623,24 +629,24 @@ export default {
}
}
.preview-dialog{
::v-deep .el-dialog {
width: 1300px !important;
.el-dialog__body{
padding: 10px 0 30px 0 !important;
}
// .preview-content{
// height: calc(100vh - 330px) !important;
// overflow: hidden !important;
// overflow-y: auto !important;
// border: none !important;
// .el-form-item__label{
// color: #0C0E1E !important;
// }
// }
// .dialog-footer{
// margin-top: 10px !important;
// }
}
}
// .el-table{
// ::v-deep .el-tag{
// margin: 0 !important;
// &.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;
// }
// }
// }
</style>
Loading…
Cancel
Save