资产清单对接,费用类型对接
This commit is contained in:
parent
7e8237190a
commit
50a376b14b
5
package.json
Normal file
5
package.json
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"qrcode.vue": "^3.6.0"
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
NODE_ENV = 'development'
|
||||
|
||||
# 开发环境API地址
|
||||
VUE_APP_BASE_API = http://192.168.137.3:8080/api
|
||||
VUE_APP_BASE_API = http://192.168.137.3:8080/api
|
@ -1,26 +1,26 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
// 查询资产清单列表
|
||||
export function listAsset(query) {
|
||||
// 获取资产列表
|
||||
export function listAssets(query) {
|
||||
return request({
|
||||
url: '/asset/inventory/list',
|
||||
url: '/asset/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
// 查询资产详细
|
||||
export function getAsset(id) {
|
||||
// 获取资产详情
|
||||
export function getAsset(assetCode) {
|
||||
return request({
|
||||
url: '/asset/inventory/' + id,
|
||||
method: 'get'
|
||||
url: `/asset/${assetCode}`,
|
||||
method: 'get',
|
||||
})
|
||||
}
|
||||
|
||||
// 新增资产
|
||||
export function addAsset(data) {
|
||||
return request({
|
||||
url: '/asset/inventory',
|
||||
url: '/asset/create',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
@ -29,71 +29,50 @@ export function addAsset(data) {
|
||||
// 修改资产
|
||||
export function updateAsset(data) {
|
||||
return request({
|
||||
url: '/asset/inventory',
|
||||
url: `/asset/${data.assetCode}`,
|
||||
method: 'put',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 删除资产
|
||||
export function delAsset(id) {
|
||||
export function deleteAsset(assetCode) {
|
||||
return request({
|
||||
url: '/asset/inventory/' + id,
|
||||
method: 'delete'
|
||||
url: '/asset/delete',
|
||||
method: 'delete',
|
||||
params: { assetCode }
|
||||
})
|
||||
}
|
||||
|
||||
// 批量删除资产
|
||||
export function delAssetBatch(ids) {
|
||||
export function deleteAssets(assetCodes) {
|
||||
return request({
|
||||
url: '/asset/inventory/batch',
|
||||
url: '/asset/batch/delete',
|
||||
method: 'delete',
|
||||
data: { ids }
|
||||
data: { assetCodes }
|
||||
})
|
||||
}
|
||||
|
||||
// 导出资产清单
|
||||
// 导出资产
|
||||
export function exportAsset(query) {
|
||||
return request({
|
||||
url: '/asset/inventory/export',
|
||||
url: '/asset/export',
|
||||
method: 'get',
|
||||
params: query,
|
||||
responseType: 'blob'
|
||||
})
|
||||
}
|
||||
|
||||
// 下载导入模板
|
||||
// 下载资产导入模板
|
||||
export function downloadTemplate() {
|
||||
return request({
|
||||
url: '/asset/inventory/template',
|
||||
url: '/asset/template/download',
|
||||
method: 'get',
|
||||
responseType: 'blob'
|
||||
})
|
||||
}
|
||||
|
||||
// 导入资产数据
|
||||
export function importAsset(file) {
|
||||
const formData = new FormData()
|
||||
formData.append('file', file)
|
||||
return request({
|
||||
url: '/asset/inventory/import',
|
||||
method: 'post',
|
||||
data: formData,
|
||||
headers: {
|
||||
'Content-Type': 'multipart/form-data'
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 获取资产分类树形列表
|
||||
export function listAssetClassTree() {
|
||||
return request({
|
||||
url: '/asset/class/tree',
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
// 获取资产位置树形列表
|
||||
// 获取资产位置树
|
||||
export function listAssetLocationTree() {
|
||||
return request({
|
||||
url: '/asset/location/tree',
|
||||
@ -109,7 +88,7 @@ export function listCompanies() {
|
||||
})
|
||||
}
|
||||
|
||||
// 获取用户列表(用于选择管理员)
|
||||
// 获取用户列表
|
||||
export function listUsers(query) {
|
||||
return request({
|
||||
url: '/system/user/list',
|
||||
@ -118,33 +97,41 @@ export function listUsers(query) {
|
||||
})
|
||||
}
|
||||
|
||||
// 打印资产标签
|
||||
export function printAssetLabel(ids) {
|
||||
// 上传资产图片
|
||||
export function uploadAssetImage(data) {
|
||||
return request({
|
||||
url: '/asset/inventory/print',
|
||||
url: '/asset/upload/image',
|
||||
method: 'post',
|
||||
data: { ids }
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 获取资产状态列表
|
||||
export function getAssetStatusOptions() {
|
||||
/**
|
||||
* 批量打印资产标签
|
||||
* @param {Array} assetCodes 资产编码数组
|
||||
* @returns {Object} 请求结果
|
||||
*/
|
||||
export function printAssetLabels(assetCodes) {
|
||||
return request({
|
||||
url: '/asset/inventory/status/options',
|
||||
url: '/asset/print',
|
||||
method: 'post',
|
||||
data: assetCodes
|
||||
})
|
||||
}
|
||||
|
||||
// 检查资产编码是否存在
|
||||
export function checkAssetCode(code) {
|
||||
return request({
|
||||
url: '/asset/check/code',
|
||||
method: 'get',
|
||||
params: { code }
|
||||
})
|
||||
}
|
||||
|
||||
// 获取标签配置
|
||||
export function getLabelConfig() {
|
||||
return request({
|
||||
url: '/asset/label',
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
// 上传资产照片
|
||||
export function uploadAssetImage(file) {
|
||||
const formData = new FormData()
|
||||
formData.append('file', file)
|
||||
return request({
|
||||
url: '/common/upload',
|
||||
method: 'post',
|
||||
data: formData,
|
||||
headers: {
|
||||
'Content-Type': 'multipart/form-data'
|
||||
}
|
||||
})
|
||||
}
|
93
pc/src/api/finance.js
Normal file
93
pc/src/api/finance.js
Normal file
@ -0,0 +1,93 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
// 费用分类管理接口
|
||||
export function getFeeCategories(query) {
|
||||
return request({
|
||||
url: '/finance/category/page',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
export function getAllFeeCategories() {
|
||||
return request({
|
||||
url: '/finance/category/list',
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
export function getFeeCategory(id) {
|
||||
return request({
|
||||
url: `/finance/category/${id}`,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
export function addFeeCategory(data) {
|
||||
return request({
|
||||
url: '/finance/category',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function updateFeeCategory(id, data) {
|
||||
return request({
|
||||
url: `/finance/category/${id}`,
|
||||
method: 'put',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function deleteFeeCategory(id) {
|
||||
return request({
|
||||
url: `/finance/category/${id}`,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
// 费用类型管理接口
|
||||
export function getFeeTypes(query) {
|
||||
return request({
|
||||
url: '/finance/type/page',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
export function getFeeTypesByCategory(categoryId) {
|
||||
return request({
|
||||
url: `/finance/type/list/${categoryId}`,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
export function getFeeType(id) {
|
||||
return request({
|
||||
url: `/finance/type/${id}`,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
export function addFeeType(data) {
|
||||
return request({
|
||||
url: '/finance/type',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function updateFeeType(id, data) {
|
||||
return request({
|
||||
url: `/finance/type/${id}`,
|
||||
method: 'put',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function deleteFeeType(id) {
|
||||
return request({
|
||||
url: `/finance/type/${id}`,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
29
pc/src/api/inventory.js
Normal file
29
pc/src/api/inventory.js
Normal file
@ -0,0 +1,29 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
/**
|
||||
* 导入库存
|
||||
* @param {Object} data 文件数据
|
||||
* @returns {Object} 请求结果
|
||||
*/
|
||||
export function importInventory(data) {
|
||||
return request({
|
||||
url: '/inventory/import',
|
||||
method: 'post',
|
||||
data: data,
|
||||
headers: {
|
||||
'Content-Type': 'multipart/form-data'
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载库存导入模板
|
||||
* @returns {Object} 请求结果
|
||||
*/
|
||||
export function downloadInventoryTemplate() {
|
||||
return request({
|
||||
url: '/inventory/template/download',
|
||||
method: 'get',
|
||||
responseType: 'blob'
|
||||
})
|
||||
}
|
@ -11,8 +11,8 @@
|
||||
>
|
||||
<template v-for="route in routes">
|
||||
<el-submenu
|
||||
v-if="route.children && route.children.length > 1"
|
||||
:key="route.path"
|
||||
v-if="route.children && route.children.length > 0"
|
||||
:key="route.path + '-submenu'"
|
||||
:index="route.path"
|
||||
>
|
||||
<template slot="title">
|
||||
@ -30,7 +30,7 @@
|
||||
</el-submenu>
|
||||
<el-menu-item
|
||||
v-else-if="!route.hidden"
|
||||
:key="route.path"
|
||||
:key="route.path + '-item'"
|
||||
:index="route.path"
|
||||
>
|
||||
<i :class="route.meta && route.meta.icon"></i>
|
||||
|
@ -3,6 +3,7 @@ import VueRouter from 'vue-router'
|
||||
import Layout from '@/layout/index'
|
||||
import systemRoutes from './modules/system'
|
||||
import projectRoutes from './modules/project'
|
||||
import financeRoutes from './modules/finance'
|
||||
|
||||
Vue.use(VueRouter)
|
||||
|
||||
@ -28,6 +29,7 @@ const routes = [
|
||||
},
|
||||
systemRoutes,
|
||||
projectRoutes,
|
||||
financeRoutes,
|
||||
{
|
||||
path: '/asset',
|
||||
component: Layout,
|
||||
|
17
pc/src/router/modules/finance.js
Normal file
17
pc/src/router/modules/finance.js
Normal file
@ -0,0 +1,17 @@
|
||||
import Layout from '@/layout/index'
|
||||
|
||||
export default {
|
||||
path: '/finance',
|
||||
component: Layout,
|
||||
name: 'Finance',
|
||||
meta: { title: '业务财务', icon: 'el-icon-money' },
|
||||
redirect: '/finance/feeType',
|
||||
children: [
|
||||
{
|
||||
path: 'feeType',
|
||||
component: () => import('@/views/finance/feeType/index.vue'),
|
||||
name: 'FeeType',
|
||||
meta: { title: '费用类型', icon: 'el-icon-tickets' }
|
||||
}
|
||||
]
|
||||
}
|
@ -33,11 +33,11 @@ service.interceptors.response.use(
|
||||
// 如果返回的状态码不是000000,则判断为错误
|
||||
if (res.code !== '000000') {
|
||||
Message({
|
||||
message: res.msg || '系统错误',
|
||||
message: res.msg || res.message || '系统错误',
|
||||
type: 'error',
|
||||
duration: 5 * 1000
|
||||
})
|
||||
return Promise.reject(new Error(res.msg || '系统错误'))
|
||||
return Promise.reject(new Error(res.msg || res.message || '系统错误'))
|
||||
} else {
|
||||
return res
|
||||
}
|
||||
|
@ -3,27 +3,27 @@
|
||||
<el-tabs v-model="activeTab">
|
||||
<el-tab-pane label="基础信息" name="basic">
|
||||
<el-descriptions class="margin-top" title="资产基础信息" :column="3" border>
|
||||
<el-descriptions-item label="资产编码">{{ assetDetail.code }}</el-descriptions-item>
|
||||
<el-descriptions-item label="资产分类">{{ assetDetail.classificationName }}</el-descriptions-item>
|
||||
<el-descriptions-item label="资产名称">{{ assetDetail.name }}</el-descriptions-item>
|
||||
<el-descriptions-item label="资产编码">{{ assetDetail.assetCode || assetDetail.code }}</el-descriptions-item>
|
||||
<el-descriptions-item label="资产分类">{{ getClassificationName(assetDetail.classificationId) }}</el-descriptions-item>
|
||||
<el-descriptions-item label="资产名称">{{ assetDetail.assetName || assetDetail.name }}</el-descriptions-item>
|
||||
<el-descriptions-item label="资产状态">
|
||||
<el-tag :type="getStatusType(assetDetail.status)">{{ getStatusText(assetDetail.status) }}</el-tag>
|
||||
<el-tag :type="getStatusType(assetDetail.assetStatus || assetDetail.status)">{{ getStatusText(assetDetail.assetStatus || assetDetail.status) }}</el-tag>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="品牌">{{ assetDetail.brand }}</el-descriptions-item>
|
||||
<el-descriptions-item label="型号">{{ assetDetail.model }}</el-descriptions-item>
|
||||
<el-descriptions-item label="设备序列号">{{ assetDetail.serialNumber }}</el-descriptions-item>
|
||||
<el-descriptions-item label="管理员">{{ assetDetail.administratorName }}</el-descriptions-item>
|
||||
<el-descriptions-item label="所属公司">{{ assetDetail.companyName }}</el-descriptions-item>
|
||||
<el-descriptions-item label="所在位置">{{ assetDetail.locationName }}</el-descriptions-item>
|
||||
<el-descriptions-item label="所在位置">{{ getLocationName(assetDetail.locationId) }}</el-descriptions-item>
|
||||
<el-descriptions-item label="购置方式">
|
||||
{{ assetDetail.purchaseType === '1' ? '采购' : assetDetail.purchaseType === '2' ? '租赁' : '-' }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="购置金额(含税)">{{ assetDetail.purchaseAmount }}</el-descriptions-item>
|
||||
<el-descriptions-item label="购置时间">{{ assetDetail.purchaseTime }}</el-descriptions-item>
|
||||
<el-descriptions-item label="入库时间">{{ assetDetail.storageTime }}</el-descriptions-item>
|
||||
<el-descriptions-item label="预计使用期限(月)">{{ assetDetail.expectedUsePeriod }}</el-descriptions-item>
|
||||
<el-descriptions-item label="购置时间">{{ assetDetail.purchaseDate || assetDetail.purchaseTime }}</el-descriptions-item>
|
||||
<el-descriptions-item label="入库时间">{{ assetDetail.storageDate || assetDetail.storageTime }}</el-descriptions-item>
|
||||
<el-descriptions-item label="预计使用期限(月)">{{ assetDetail.expectedUsePeriod || assetDetail.expectedDepreciationPeriod }}</el-descriptions-item>
|
||||
<el-descriptions-item label="预计折旧期限(月)">{{ assetDetail.expectedDepreciationPeriod }}</el-descriptions-item>
|
||||
<el-descriptions-item label="保养到期时间">{{ assetDetail.maintenanceTime }}</el-descriptions-item>
|
||||
<el-descriptions-item label="保养到期时间">{{ assetDetail.maintenanceDueDate || assetDetail.maintenanceTime }}</el-descriptions-item>
|
||||
<el-descriptions-item label="保养说明" :span="3">{{ assetDetail.maintenanceDescription }}</el-descriptions-item>
|
||||
<el-descriptions-item label="备注" :span="3">{{ assetDetail.remark }}</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
@ -46,6 +46,8 @@
|
||||
|
||||
<script>
|
||||
import { getAsset } from '@/api/asset/inventory'
|
||||
import { getClassificationTree } from '@/api/asset/classification'
|
||||
import { getLocationTree } from '@/api/asset/location'
|
||||
|
||||
export default {
|
||||
name: 'AssetDetail',
|
||||
@ -59,7 +61,11 @@ export default {
|
||||
return {
|
||||
loading: false,
|
||||
activeTab: 'basic',
|
||||
assetDetail: {}
|
||||
assetDetail: {},
|
||||
// 资产分类选项
|
||||
classificationOptions: [],
|
||||
// 资产位置选项
|
||||
locationOptions: []
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
@ -72,6 +78,10 @@ export default {
|
||||
immediate: true
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.getClassificationOptions()
|
||||
this.getLocationOptions()
|
||||
},
|
||||
methods: {
|
||||
/** 获取资产详情 */
|
||||
getAssetDetail() {
|
||||
@ -81,6 +91,7 @@ export default {
|
||||
getAsset(this.assetId).then(response => {
|
||||
if (response.code === '000000') {
|
||||
this.assetDetail = response.data || {}
|
||||
console.log('资产详情数据:', this.assetDetail)
|
||||
} else {
|
||||
this.$message.error(response.msg || '获取资产详情失败')
|
||||
}
|
||||
@ -93,14 +104,14 @@ export default {
|
||||
/** 获取资产状态显示文本 */
|
||||
getStatusText(status) {
|
||||
const statusMap = {
|
||||
'0': '空闲',
|
||||
'1': '在用',
|
||||
'2': '借用',
|
||||
'3': '派发中',
|
||||
'4': '退库中',
|
||||
'5': '借出中',
|
||||
'6': '归还中',
|
||||
'7': '维修中'
|
||||
'空闲': '空闲',
|
||||
'在用': '在用',
|
||||
'借用': '借用',
|
||||
'派发中': '派发中',
|
||||
'退库中': '退库中',
|
||||
'借出中': '借出中',
|
||||
'归还中': '归还中',
|
||||
'维修中': '维修中'
|
||||
}
|
||||
return statusMap[status] || '未知'
|
||||
},
|
||||
@ -108,16 +119,125 @@ export default {
|
||||
/** 获取资产状态显示类型 */
|
||||
getStatusType(status) {
|
||||
const typeMap = {
|
||||
'0': 'success',
|
||||
'1': 'primary',
|
||||
'2': 'info',
|
||||
'3': 'warning',
|
||||
'4': 'warning',
|
||||
'5': 'warning',
|
||||
'6': 'warning',
|
||||
'7': 'danger'
|
||||
'空闲': 'success',
|
||||
'在用': 'primary',
|
||||
'借用': 'info',
|
||||
'派发中': 'warning',
|
||||
'退库中': 'warning',
|
||||
'借出中': 'warning',
|
||||
'归还中': 'warning',
|
||||
'维修中': 'danger'
|
||||
}
|
||||
return typeMap[status] || 'info'
|
||||
},
|
||||
|
||||
/** 获取资产分类树形选项 */
|
||||
getClassificationOptions() {
|
||||
getClassificationTree({ status: '1' }).then(response => {
|
||||
if (response.code === '000000') {
|
||||
this.classificationOptions = this.processClassificationTree(response.data || [])
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
/** 处理分类树形数据 */
|
||||
processClassificationTree(data) {
|
||||
if (!data || !Array.isArray(data)) return []
|
||||
|
||||
const processNode = (node) => {
|
||||
const processedNode = {
|
||||
id: node.id,
|
||||
name: `${node.classificationCode || node.code || ''}-${node.classificationName || node.label || ''}`,
|
||||
children: []
|
||||
}
|
||||
|
||||
if (node.children && Array.isArray(node.children) && node.children.length > 0) {
|
||||
processedNode.children = node.children.map(child => processNode(child))
|
||||
}
|
||||
|
||||
return processedNode
|
||||
}
|
||||
|
||||
return data.map(item => processNode(item))
|
||||
},
|
||||
|
||||
/** 获取位置树选项 */
|
||||
getLocationOptions() {
|
||||
getLocationTree().then(response => {
|
||||
if (response.code === '000000') {
|
||||
this.locationOptions = this.processLocationTree(response.data || [])
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
processLocationTree(data) {
|
||||
if (!data || !Array.isArray(data)) return []
|
||||
|
||||
const processNode = (node) => {
|
||||
const processedNode = {
|
||||
id: node.id,
|
||||
name: `${node.code || ''}-${node.locationName || node.label || ''}`,
|
||||
children: []
|
||||
}
|
||||
|
||||
if (node.children && Array.isArray(node.children) && node.children.length > 0) {
|
||||
processedNode.children = node.children.map(child => processNode(child))
|
||||
}
|
||||
|
||||
return processedNode
|
||||
}
|
||||
|
||||
return data.map(item => processNode(item))
|
||||
},
|
||||
|
||||
/** 获取分类名称 */
|
||||
getClassificationName(classificationId) {
|
||||
if (!classificationId) return '未知分类'
|
||||
|
||||
// 如果已有名称,直接返回
|
||||
if (this.assetDetail.classificationName) return this.assetDetail.classificationName
|
||||
|
||||
// 递归查找分类
|
||||
const findClassification = (items) => {
|
||||
for (const item of items) {
|
||||
if (item.id === classificationId) {
|
||||
return item.name
|
||||
}
|
||||
if (item.children && item.children.length > 0) {
|
||||
const found = findClassification(item.children)
|
||||
if (found) return found
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
const name = findClassification(this.classificationOptions)
|
||||
return name || '未知分类'
|
||||
},
|
||||
|
||||
/** 获取位置名称 */
|
||||
getLocationName(locationId) {
|
||||
if (!locationId) return '未知位置'
|
||||
|
||||
// 如果已有名称,直接返回
|
||||
if (this.assetDetail.locationName) return this.assetDetail.locationName
|
||||
|
||||
// 递归查找位置
|
||||
const findLocation = (items) => {
|
||||
for (const item of items) {
|
||||
if (item.id === locationId) {
|
||||
return item.name
|
||||
}
|
||||
if (item.children && item.children.length > 0) {
|
||||
const found = findLocation(item.children)
|
||||
if (found) return found
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
const name = findLocation(this.locationOptions)
|
||||
return name || '未知位置'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -10,17 +10,25 @@
|
||||
<el-cascader
|
||||
v-model="form.classificationId"
|
||||
:options="classificationOptions"
|
||||
:props="{ checkStrictly: true, value: 'id', label: 'name', emitPath: false }"
|
||||
:props="{
|
||||
checkStrictly: true,
|
||||
emitPath: false,
|
||||
expandTrigger: 'hover',
|
||||
value: 'id',
|
||||
label: 'name',
|
||||
leaf: 'leaf'
|
||||
}"
|
||||
placeholder="请选择资产分类"
|
||||
clearable
|
||||
filterable
|
||||
style="width: 100%"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="管理员" prop="administratorId">
|
||||
<el-form-item label="管理员" prop="adminUserId">
|
||||
<el-select
|
||||
v-model="form.administratorId"
|
||||
v-model="form.adminUserId"
|
||||
placeholder="请选择管理员"
|
||||
filterable
|
||||
remote
|
||||
@ -57,9 +65,17 @@
|
||||
<el-cascader
|
||||
v-model="form.locationId"
|
||||
:options="locationOptions"
|
||||
:props="{ checkStrictly: true, value: 'id', label: 'name', emitPath: false }"
|
||||
:props="{
|
||||
checkStrictly: true,
|
||||
emitPath: false,
|
||||
expandTrigger: 'hover',
|
||||
value: 'id',
|
||||
label: 'name',
|
||||
leaf: 'leaf'
|
||||
}"
|
||||
placeholder="请选择所在位置"
|
||||
clearable
|
||||
filterable
|
||||
style="width: 100%"
|
||||
/>
|
||||
</el-form-item>
|
||||
@ -73,16 +89,16 @@
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="资产名称" prop="name">
|
||||
<el-input v-model="form.name" placeholder="请输入资产名称" />
|
||||
<el-form-item label="资产名称" prop="assetName">
|
||||
<el-input v-model="form.assetName" placeholder="请输入资产名称" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="8">
|
||||
<el-form-item label="资产编码" prop="code">
|
||||
<el-input v-model="form.code" placeholder="请输入资产编码" :disabled="isEdit" />
|
||||
<el-form-item label="资产编码" prop="assetCode">
|
||||
<el-input v-model="form.assetCode" placeholder="请输入资产编码" :disabled="isEdit" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
@ -109,17 +125,17 @@
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="预计使用期限(月)" prop="expectedUsePeriod">
|
||||
<el-input-number v-model="form.expectedUsePeriod" :min="0" :step="1" style="width: 100%" />
|
||||
<el-form-item label="预计使用期限(月)" prop="expectedDepreciationPeriod">
|
||||
<el-input-number v-model="form.expectedDepreciationPeriod" :min="0" :step="1" style="width: 100%" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="8">
|
||||
<el-form-item label="购置时间" prop="purchaseTime">
|
||||
<el-form-item label="购置时间" prop="purchaseDate">
|
||||
<el-date-picker
|
||||
v-model="form.purchaseTime"
|
||||
v-model="form.purchaseDate"
|
||||
type="date"
|
||||
placeholder="请选择购置时间"
|
||||
style="width: 100%"
|
||||
@ -128,9 +144,9 @@
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="入库时间" prop="storageTime">
|
||||
<el-form-item label="入库时间" prop="storageDate">
|
||||
<el-date-picker
|
||||
v-model="form.storageTime"
|
||||
v-model="form.storageDate"
|
||||
type="date"
|
||||
placeholder="请选择入库时间"
|
||||
style="width: 100%"
|
||||
@ -139,9 +155,9 @@
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="保养到期时间" prop="maintenanceTime">
|
||||
<el-form-item label="保养到期时间" prop="maintenanceDueDate">
|
||||
<el-date-picker
|
||||
v-model="form.maintenanceTime"
|
||||
v-model="form.maintenanceDueDate"
|
||||
type="date"
|
||||
placeholder="请选择保养到期时间"
|
||||
style="width: 100%"
|
||||
@ -207,7 +223,10 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getAsset, addAsset, updateAsset, listAssetClassTree, listAssetLocationTree, listCompanies, listUsers, uploadAssetImage } from '@/api/asset/inventory'
|
||||
import { getAsset, addAsset, updateAsset, listCompanies, listUsers, uploadAssetImage, checkAssetCode } from '@/api/asset/inventory'
|
||||
import { getClassificationTree } from '@/api/asset/classification'
|
||||
import { getLocationTree } from '@/api/asset/location'
|
||||
|
||||
|
||||
export default {
|
||||
name: 'AssetForm',
|
||||
@ -243,22 +262,22 @@ export default {
|
||||
form: {
|
||||
id: undefined,
|
||||
classificationId: undefined,
|
||||
administratorId: undefined,
|
||||
adminUserId: undefined,
|
||||
companyId: undefined,
|
||||
locationId: undefined,
|
||||
purchaseType: '1',
|
||||
name: '',
|
||||
code: '',
|
||||
assetName: '',
|
||||
assetCode: '',
|
||||
brand: '',
|
||||
model: '',
|
||||
serialNumber: '',
|
||||
purchaseAmount: undefined,
|
||||
expectedUsePeriod: undefined,
|
||||
expectedDepreciationPeriod: undefined,
|
||||
remark: '',
|
||||
purchaseTime: '',
|
||||
storageTime: '',
|
||||
purchaseDate: '',
|
||||
storageDate: '',
|
||||
imageUrl: '',
|
||||
maintenanceTime: '',
|
||||
maintenanceDueDate: '',
|
||||
maintenanceDescription: '',
|
||||
expectedDepreciationPeriod: undefined
|
||||
},
|
||||
@ -267,7 +286,7 @@ export default {
|
||||
classificationId: [
|
||||
{ required: true, message: '请选择资产分类', trigger: 'change' }
|
||||
],
|
||||
administratorId: [
|
||||
adminUserId: [
|
||||
{ required: true, message: '请选择管理员', trigger: 'change' }
|
||||
],
|
||||
companyId: [
|
||||
@ -279,7 +298,7 @@ export default {
|
||||
purchaseType: [
|
||||
{ required: true, message: '请选择购置方式', trigger: 'change' }
|
||||
],
|
||||
code: [
|
||||
assetCode: [
|
||||
{ required: true, message: '请输入资产编码', trigger: 'blur' }
|
||||
],
|
||||
brand: [
|
||||
@ -294,11 +313,39 @@ export default {
|
||||
this.getCompanyOptions()
|
||||
this.remoteSearchAdmin('')
|
||||
|
||||
// 添加模拟数据,确保表单可以完成
|
||||
this.addMockData()
|
||||
|
||||
if (this.isEdit && this.assetId) {
|
||||
this.getAssetDetail()
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
/** 添加模拟数据 */
|
||||
addMockData() {
|
||||
// 模拟管理员数据
|
||||
if (this.adminOptions.length === 0) {
|
||||
this.adminOptions = [
|
||||
{ id: '1', name: '张三' },
|
||||
{ id: '2', name: '李四' },
|
||||
{ id: '3', name: '王五' },
|
||||
{ id: '4', name: '赵六' },
|
||||
{ id: '5', name: '钱七' }
|
||||
]
|
||||
}
|
||||
|
||||
// 模拟公司数据
|
||||
if (this.companyOptions.length === 0) {
|
||||
this.companyOptions = [
|
||||
{ id: '1', name: '总公司' },
|
||||
{ id: '2', name: '北京分公司' },
|
||||
{ id: '3', name: '上海分公司' },
|
||||
{ id: '4', name: '广州分公司' },
|
||||
{ id: '5', name: '深圳分公司' }
|
||||
]
|
||||
}
|
||||
},
|
||||
|
||||
/** 获取资产详情 */
|
||||
getAssetDetail() {
|
||||
this.loading = true
|
||||
@ -307,9 +354,9 @@ export default {
|
||||
this.form = response.data || {}
|
||||
|
||||
// 如果有管理员,添加到选项中
|
||||
if (this.form.administratorId && this.form.administratorName) {
|
||||
if (this.form.adminUserId && this.form.administratorName) {
|
||||
this.adminOptions = [
|
||||
{ id: this.form.administratorId, name: this.form.administratorName }
|
||||
{ id: this.form.adminUserId, name: this.form.administratorName }
|
||||
]
|
||||
}
|
||||
} else {
|
||||
@ -323,28 +370,78 @@ export default {
|
||||
|
||||
/** 获取资产分类树形选项 */
|
||||
getClassificationOptions() {
|
||||
listAssetClassTree().then(response => {
|
||||
getClassificationTree({ status: '1' }).then(response => {
|
||||
if (response.code === '000000') {
|
||||
this.classificationOptions = response.data || []
|
||||
this.classificationOptions = this.processClassificationTree(response.data || [])
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
/** 获取资产位置树形选项 */
|
||||
/** 处理分类树形数据 */
|
||||
processClassificationTree(data) {
|
||||
if (!data || !Array.isArray(data)) return []
|
||||
|
||||
const processNode = (node) => {
|
||||
const processedNode = {
|
||||
id: node.id,
|
||||
name: `${node.classificationCode || node.code || ''}-${node.classificationName || node.label || ''}`,
|
||||
children: []
|
||||
}
|
||||
|
||||
if (node.children && Array.isArray(node.children) && node.children.length > 0) {
|
||||
processedNode.children = node.children.map(child => processNode(child))
|
||||
processedNode.leaf = false
|
||||
} else {
|
||||
processedNode.leaf = true
|
||||
}
|
||||
|
||||
return processedNode
|
||||
}
|
||||
|
||||
return data.map(item => processNode(item))
|
||||
},
|
||||
|
||||
/** 获取位置树选项 */
|
||||
getLocationOptions() {
|
||||
listAssetLocationTree().then(response => {
|
||||
getLocationTree().then(response => {
|
||||
if (response.code === '000000') {
|
||||
this.locationOptions = response.data || []
|
||||
this.locationOptions = this.processLocationTree(response.data || [])
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
processLocationTree(data) {
|
||||
if (!data || !Array.isArray(data)) return []
|
||||
|
||||
const processNode = (node) => {
|
||||
const processedNode = {
|
||||
id: node.id,
|
||||
name: `${node.code || ''}-${node.locationName || node.label || ''}`,
|
||||
children: []
|
||||
}
|
||||
|
||||
if (node.children && Array.isArray(node.children) && node.children.length > 0) {
|
||||
processedNode.children = node.children.map(child => processNode(child))
|
||||
processedNode.leaf = false
|
||||
} else {
|
||||
processedNode.leaf = true
|
||||
}
|
||||
|
||||
return processedNode
|
||||
}
|
||||
|
||||
return data.map(item => processNode(item))
|
||||
},
|
||||
|
||||
/** 获取公司选项 */
|
||||
getCompanyOptions() {
|
||||
listCompanies().then(response => {
|
||||
if (response.code === '000000') {
|
||||
this.companyOptions = response.data || []
|
||||
}
|
||||
}).catch(() => {
|
||||
// 如果API调用失败,使用模拟数据
|
||||
this.addMockData()
|
||||
})
|
||||
},
|
||||
|
||||
@ -358,6 +455,8 @@ export default {
|
||||
}
|
||||
}).catch(() => {
|
||||
this.adminLoading = false
|
||||
// 如果API调用失败,使用模拟数据
|
||||
this.addMockData()
|
||||
})
|
||||
},
|
||||
|
||||
@ -369,23 +468,47 @@ export default {
|
||||
|
||||
const formData = { ...this.form }
|
||||
|
||||
const method = this.isEdit ? updateAsset : addAsset
|
||||
method(formData).then(response => {
|
||||
if (response.code === '000000') {
|
||||
this.$message.success(this.isEdit ? '修改成功' : '新增成功')
|
||||
this.$emit('refresh')
|
||||
this.$emit('close')
|
||||
} else {
|
||||
this.$message.error(response.msg || (this.isEdit ? '修改失败' : '新增失败'))
|
||||
}
|
||||
this.loading = false
|
||||
}).catch(() => {
|
||||
this.loading = false
|
||||
})
|
||||
// 检查资产编码是否已存在
|
||||
if (!this.isEdit) {
|
||||
checkAssetCode(this.form.code).then(response => {
|
||||
if (response.code === '000000') {
|
||||
if (!response.data) {
|
||||
this.$message.error('资产编码已存在,请更换其他编码')
|
||||
this.loading = false
|
||||
return
|
||||
}
|
||||
this.saveAsset(formData)
|
||||
} else {
|
||||
this.$message.error(response.msg || '检查资产编码失败')
|
||||
this.loading = false
|
||||
}
|
||||
}).catch(() => {
|
||||
this.loading = false
|
||||
})
|
||||
} else {
|
||||
this.saveAsset(formData)
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
/** 保存资产信息 */
|
||||
saveAsset(formData) {
|
||||
const method = this.isEdit ? updateAsset : addAsset
|
||||
method(formData).then(response => {
|
||||
if (response.code === '000000') {
|
||||
this.$message.success(this.isEdit ? '修改成功' : '新增成功')
|
||||
this.$emit('refresh')
|
||||
this.$emit('close')
|
||||
} else {
|
||||
this.$message.error(response.msg || (this.isEdit ? '修改失败' : '新增失败'))
|
||||
}
|
||||
this.loading = false
|
||||
}).catch(() => {
|
||||
this.loading = false
|
||||
})
|
||||
},
|
||||
|
||||
/** 取消按钮 */
|
||||
cancel() {
|
||||
this.$emit('close')
|
||||
@ -410,7 +533,7 @@ export default {
|
||||
if (response.code === '000000') {
|
||||
this.form.imageUrl = response.data.url
|
||||
} else {
|
||||
this.$message.error('上传图片失败')
|
||||
this.$message.error(response.msg || '上传图片失败')
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -1,57 +1,26 @@
|
||||
<template>
|
||||
<div class="asset-print-container" v-loading="loading">
|
||||
<div class="print-options">
|
||||
<div class="option-item">
|
||||
<span class="option-label">标签模板:</span>
|
||||
<el-select v-model="printParams.templateId" placeholder="请选择标签模板" style="width: 200px">
|
||||
<el-option
|
||||
v-for="item in templateOptions"
|
||||
:key="item.id"
|
||||
:label="item.name"
|
||||
:value="item.id"
|
||||
/>
|
||||
</el-select>
|
||||
</div>
|
||||
<div class="option-item">
|
||||
<span class="option-label">纸张类型:</span>
|
||||
<el-select v-model="printParams.paperType" placeholder="请选择纸张类型" style="width: 200px">
|
||||
<el-option label="A4" value="A4" />
|
||||
<el-option label="A5" value="A5" />
|
||||
<el-option label="标签纸" value="LABEL" />
|
||||
</el-select>
|
||||
</div>
|
||||
<div class="option-item">
|
||||
<span class="option-label">显示内容:</span>
|
||||
<el-checkbox-group v-model="printParams.showFields">
|
||||
<el-checkbox label="code">资产编码</el-checkbox>
|
||||
<el-checkbox label="name">资产名称</el-checkbox>
|
||||
<el-checkbox label="qrCode">二维码</el-checkbox>
|
||||
<el-checkbox label="barCode">条形码</el-checkbox>
|
||||
</el-checkbox-group>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="preview-container">
|
||||
<div class="preview-title">打印预览</div>
|
||||
<div class="preview-content" ref="previewContent">
|
||||
<div v-for="(asset, index) in assetsToPrint" :key="index" class="label-item">
|
||||
<div class="label-header">资产标签</div>
|
||||
<div class="label-content">
|
||||
<div v-if="printParams.showFields.includes('code')" class="label-field">
|
||||
<span class="field-label">资产编码:</span>
|
||||
<span class="field-value">{{ asset.code }}</span>
|
||||
</div>
|
||||
<div v-if="printParams.showFields.includes('name')" class="label-field">
|
||||
<span class="field-label">资产名称:</span>
|
||||
<span class="field-value">{{ asset.name }}</span>
|
||||
</div>
|
||||
<!-- 模拟二维码 -->
|
||||
<div v-if="printParams.showFields.includes('qrCode')" class="label-qrcode">
|
||||
<div class="mock-qrcode"></div>
|
||||
</div>
|
||||
<!-- 模拟条形码 -->
|
||||
<div v-if="printParams.showFields.includes('barCode')" class="label-barcode">
|
||||
<div class="mock-barcode"></div>
|
||||
<div ref="printSection" class="print-page">
|
||||
<div class="print-content">
|
||||
<div class="print-header">{{ currentDate }} {{ title }}</div>
|
||||
<div class="label-grid">
|
||||
<div v-for="(asset, index) in selectedAssets" :key="index" class="label-item">
|
||||
<div class="label-content">
|
||||
<div class="qrcode-section">
|
||||
<div class="asset-icon">
|
||||
<!-- <i class="el-icon-s-goods"></i> 资产 -->
|
||||
</div>
|
||||
<div class="qrcode">
|
||||
<qrcode-vue :value="asset.id || asset.assetId" :size="80" level="H"></qrcode-vue>
|
||||
</div>
|
||||
<!-- <div class="asset-code">资产编码: {{ asset.assetCode || asset.code }}</div> -->
|
||||
</div>
|
||||
|
||||
<div class="info-section">
|
||||
<div v-for="(field, fieldIndex) in displayFields" :key="fieldIndex" class="info-item">
|
||||
<span v-if="asset[field.key]">{{ field.label }}: {{ asset[field.key] }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -66,49 +35,84 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { printAssetLabel } from '@/api/asset/inventory'
|
||||
import { getLabelConfig } from '@/api/asset/inventory'
|
||||
import QrcodeVue from 'qrcode.vue'
|
||||
|
||||
export default {
|
||||
name: 'AssetLabelPrint',
|
||||
components: {
|
||||
QrcodeVue
|
||||
},
|
||||
props: {
|
||||
ids: {
|
||||
type: Array,
|
||||
required: true
|
||||
},
|
||||
selectedAssets: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
loading: false,
|
||||
assetsToPrint: [],
|
||||
templateOptions: [
|
||||
{ id: '1', name: '默认标签模板' },
|
||||
{ id: '2', name: '简洁标签模板' },
|
||||
{ id: '3', name: '详细标签模板' }
|
||||
],
|
||||
printParams: {
|
||||
templateId: '1',
|
||||
paperType: 'A4',
|
||||
showFields: ['code', 'name', 'qrCode']
|
||||
}
|
||||
title: '资产标签',
|
||||
currentDate: '',
|
||||
labelConfig: null,
|
||||
displayFields: [
|
||||
{ key: 'assetName', label: '资产名称' },
|
||||
{ key: 'classificationName', label: '资产分类' },
|
||||
{ key: 'locationName', label: '所在位置' },
|
||||
{ key: 'brand', label: '品牌' },
|
||||
{ key: 'model', label: '型号' },
|
||||
{ key: 'serialNumber', label: '设备序列号' },
|
||||
{ key: 'administratorName', label: '管理员' }
|
||||
]
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.getPrintData()
|
||||
// 设置当前日期
|
||||
this.setCurrentDate()
|
||||
|
||||
// 打印完整的资产对象,便于调试
|
||||
console.log('Selected assets:', JSON.stringify(this.selectedAssets))
|
||||
|
||||
// 获取标签配置
|
||||
this.getLabelConfig()
|
||||
},
|
||||
methods: {
|
||||
/** 获取打印数据 */
|
||||
getPrintData() {
|
||||
if (!this.ids || this.ids.length === 0) {
|
||||
this.$message.warning('未选择要打印的资产')
|
||||
return
|
||||
}
|
||||
|
||||
/** 设置当前日期 */
|
||||
setCurrentDate() {
|
||||
const now = new Date()
|
||||
this.currentDate = now.getFullYear() + '/' +
|
||||
String(now.getMonth() + 1).padStart(2, '0') + '/' +
|
||||
String(now.getDate()).padStart(2, '0')
|
||||
},
|
||||
|
||||
/** 获取标签配置 */
|
||||
getLabelConfig() {
|
||||
this.loading = true
|
||||
printAssetLabel(this.ids).then(response => {
|
||||
getLabelConfig().then(response => {
|
||||
if (response.code === '000000') {
|
||||
this.assetsToPrint = response.data || []
|
||||
} else {
|
||||
this.$message.error(response.msg || '获取打印数据失败')
|
||||
this.labelConfig = response.data
|
||||
|
||||
// 如果API返回了需要显示的字段,则使用API返回的字段
|
||||
if (this.labelConfig && this.labelConfig.labelItems) {
|
||||
// 解析labelItems字段
|
||||
// 如果是字符串(逗号分隔的ID列表),则转换为ID数组
|
||||
let labelItemArray = []
|
||||
if (typeof this.labelConfig.labelItems === 'string') {
|
||||
const itemIds = this.labelConfig.labelItems.split(',').filter(item => item.trim() !== '')
|
||||
labelItemArray = itemIds.map(id => ({ id: parseInt(id.trim()) }))
|
||||
} else if (Array.isArray(this.labelConfig.labelItems)) {
|
||||
labelItemArray = this.labelConfig.labelItems
|
||||
}
|
||||
|
||||
// 如果有标签项,则映射到对应的字段
|
||||
if (labelItemArray.length > 0) {
|
||||
this.displayFields = this.mapLabelItemsToFields(labelItemArray)
|
||||
}
|
||||
}
|
||||
}
|
||||
this.loading = false
|
||||
}).catch(() => {
|
||||
@ -116,134 +120,264 @@ export default {
|
||||
})
|
||||
},
|
||||
|
||||
/** 将标签项映射到对应的字段 */
|
||||
mapLabelItemsToFields(labelItems) {
|
||||
// 定义字段ID与资产数据属性的映射关系
|
||||
const fieldMappings = {
|
||||
1: { key: 'assetName', label: '资产名称', possibleKeys: ['assetName', 'name'] },
|
||||
2: { key: 'classificationName', label: '资产分类', possibleKeys: ['classificationName', 'className'] },
|
||||
3: { key: 'assetCode', label: '资产编码', possibleKeys: ['assetCode', 'code'] },
|
||||
4: { key: 'locationName', label: '资产位置', possibleKeys: ['locationName', 'location'] },
|
||||
5: { key: 'brand', label: '品牌', possibleKeys: ['brand'] },
|
||||
6: { key: 'model', label: '型号', possibleKeys: ['model'] },
|
||||
7: { key: 'serialNumber', label: '设备序列号', possibleKeys: ['serialNumber', 'sn'] },
|
||||
8: { key: 'administratorName', label: '管理员', possibleKeys: ['administratorName', 'admin', 'adminName'] },
|
||||
9: { key: 'maintenanceDueDate', label: '保养到期时间', possibleKeys: ['maintenanceDueDate', 'maintenanceTime', 'maintDueDate', 'maintainEndDate'] },
|
||||
10: { key: 'maintenanceDescription', label: '保养说明', possibleKeys: ['maintenanceDescription', 'maintInstructions', 'maintenanceDesc', 'maintDesc', 'maintenanceInfo'] },
|
||||
11: { key: 'departmentName', label: '使用部门', possibleKeys: ['departmentName', 'deptName', 'department'] }
|
||||
}
|
||||
|
||||
// 打印调试信息
|
||||
console.log('labelItems:', labelItems)
|
||||
|
||||
// 根据labelItems筛选出需要显示的字段
|
||||
return labelItems.map(item => {
|
||||
// 支持多种可能的ID属性名
|
||||
const id = item.id || item.fieldId
|
||||
const mapping = fieldMappings[id]
|
||||
|
||||
console.log('Processing item:', item, 'mapping:', mapping)
|
||||
|
||||
if (mapping) {
|
||||
return {
|
||||
key: mapping.key,
|
||||
label: item.name || item.fieldName || mapping.label,
|
||||
possibleKeys: mapping.possibleKeys
|
||||
}
|
||||
}
|
||||
return null
|
||||
}).filter(item => item !== null)
|
||||
},
|
||||
|
||||
/** 获取打印内容 */
|
||||
getPrintContent() {
|
||||
this.handlePrint()
|
||||
return true
|
||||
},
|
||||
|
||||
/** 执行打印 */
|
||||
handlePrint() {
|
||||
// 创建打印窗口
|
||||
// 创建打印窗口并生成内容
|
||||
const printWindow = window.open('', '_blank')
|
||||
|
||||
if (!printWindow) {
|
||||
this.$message.error('打印窗口被阻止,请允许弹出窗口后重试')
|
||||
this.$message.error('打印窗口被浏览器阻止,请允许弹出窗口')
|
||||
return
|
||||
}
|
||||
|
||||
// 构建打印内容
|
||||
let printContent = `
|
||||
<html>
|
||||
<head>
|
||||
<title>资产标签打印</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
margin: 0;
|
||||
padding: 20px;
|
||||
}
|
||||
.print-page {
|
||||
page-break-after: always;
|
||||
}
|
||||
.label-item {
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 5px;
|
||||
padding: 10px;
|
||||
margin-bottom: 15px;
|
||||
width: 300px;
|
||||
}
|
||||
.label-header {
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
margin-bottom: 10px;
|
||||
padding-bottom: 5px;
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
.label-content {
|
||||
padding: 5px;
|
||||
}
|
||||
.label-field {
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
.field-label {
|
||||
font-weight: bold;
|
||||
display: inline-block;
|
||||
width: 80px;
|
||||
}
|
||||
.field-value {
|
||||
display: inline-block;
|
||||
}
|
||||
.label-qrcode, .label-barcode {
|
||||
text-align: center;
|
||||
margin-top: 10px;
|
||||
}
|
||||
.mock-qrcode {
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
background: repeating-conic-gradient(#000 0% 25%, #fff 0% 50%) 50% / 10px 10px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
.mock-barcode {
|
||||
width: 150px;
|
||||
height: 40px;
|
||||
background: repeating-linear-gradient(to right, #000, #000 2px, #fff 2px, #fff 4px);
|
||||
margin: 0 auto;
|
||||
}
|
||||
@media print {
|
||||
body {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
// 获取资产列表
|
||||
const assetsToUse = this.selectedAssets
|
||||
|
||||
// 创建样式内容
|
||||
const styleContent = `
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
margin: 0;
|
||||
padding: 20px;
|
||||
}
|
||||
.print-header {
|
||||
text-align: right;
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.label-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
gap: 20px;
|
||||
}
|
||||
.label-item {
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 5px;
|
||||
padding: 10px;
|
||||
background-color: #fff;
|
||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
||||
page-break-inside: avoid;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.label-content {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
}
|
||||
.qrcode-section {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
width: 120px;
|
||||
border-right: 1px dashed #ddd;
|
||||
padding-right: 10px;
|
||||
}
|
||||
.asset-icon {
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
.qrcode img {
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
}
|
||||
.asset-code {
|
||||
font-size: 12px;
|
||||
text-align: center;
|
||||
word-break: break-all;
|
||||
color: #666;
|
||||
}
|
||||
.info-section {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
}
|
||||
.info-item {
|
||||
font-size: 12px;
|
||||
margin-bottom: 5px;
|
||||
color: #333;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
@media print {
|
||||
body {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
@page {
|
||||
size: A4;
|
||||
margin: 1cm;
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
// 生成HTML内容
|
||||
printWindow.document.write('<html><head><title>资产标签打印</title>')
|
||||
printWindow.document.write('<style>' + styleContent + '</style>')
|
||||
printWindow.document.write('<script src="https://cdn.jsdelivr.net/npm/qrcode-generator@1.4.4/qrcode.min.js"><\/script>')
|
||||
printWindow.document.write('</head><body>')
|
||||
|
||||
// 添加标题
|
||||
printWindow.document.write('<div class="print-header">' + this.currentDate + ' ' + this.title + '</div>')
|
||||
printWindow.document.write('<div class="label-grid">')
|
||||
|
||||
// 添加每个资产的标签
|
||||
assetsToUse.forEach(asset => {
|
||||
const assetId = asset.id || asset.assetId
|
||||
|
||||
printWindow.document.write('<div class="label-item">')
|
||||
printWindow.document.write('<div class="label-content">')
|
||||
printWindow.document.write('<div class="qrcode-section">')
|
||||
// printWindow.document.write('<div class="asset-icon">资产</div>')
|
||||
printWindow.document.write('<div class="qrcode" id="qrcode-' + assetId + '"></div>')
|
||||
// printWindow.document.write('<div class="asset-code">资产编码: ' + (asset.assetCode || asset.code) + '</div>')
|
||||
printWindow.document.write('</div>')
|
||||
|
||||
printWindow.document.write('<div class="info-section">')
|
||||
|
||||
// 添加显示字段
|
||||
this.displayFields.forEach(field => {
|
||||
// 添加调试输出
|
||||
console.log('Checking field:', field.key, 'in asset:', asset)
|
||||
|
||||
// 尝试从资产对象中获取字段值
|
||||
let value = asset[field.key];
|
||||
|
||||
// 如果没有找到值,尝试使用可能的键名列表
|
||||
if (!value && field.possibleKeys) {
|
||||
for (const possibleKey of field.possibleKeys) {
|
||||
if (asset[possibleKey] !== undefined && asset[possibleKey] !== null) {
|
||||
value = asset[possibleKey];
|
||||
console.log('Found value with alternative key:', possibleKey, value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
`
|
||||
|
||||
this.assetsToPrint.forEach((asset, index) => {
|
||||
printContent += `
|
||||
<div class="label-item">
|
||||
<div class="label-header">资产标签</div>
|
||||
<div class="label-content">
|
||||
${this.printParams.showFields.includes('code') ? `
|
||||
<div class="label-field">
|
||||
<span class="field-label">资产编码:</span>
|
||||
<span class="field-value">${asset.code}</span>
|
||||
</div>
|
||||
` : ''}
|
||||
${this.printParams.showFields.includes('name') ? `
|
||||
<div class="label-field">
|
||||
<span class="field-label">资产名称:</span>
|
||||
<span class="field-value">${asset.name}</span>
|
||||
</div>
|
||||
` : ''}
|
||||
${this.printParams.showFields.includes('qrCode') ? `
|
||||
<div class="label-qrcode">
|
||||
<div class="mock-qrcode"></div>
|
||||
</div>
|
||||
` : ''}
|
||||
${this.printParams.showFields.includes('barCode') ? `
|
||||
<div class="label-barcode">
|
||||
<div class="mock-barcode"></div>
|
||||
</div>
|
||||
` : ''}
|
||||
</div>
|
||||
</div>
|
||||
${(index + 1) % 6 === 0 ? '<div class="print-page"></div>' : ''}
|
||||
`
|
||||
}
|
||||
|
||||
console.log('Final value:', value);
|
||||
|
||||
// 即使数据为空也显示字段名称
|
||||
printWindow.document.write('<div class="info-item">')
|
||||
printWindow.document.write('<span>' + field.label + ': ' + (value || '-') + '</span>')
|
||||
printWindow.document.write('</div>')
|
||||
})
|
||||
|
||||
printWindow.document.write('</div>')
|
||||
printWindow.document.write('</div>')
|
||||
printWindow.document.write('</div>')
|
||||
})
|
||||
|
||||
printContent += `
|
||||
</body>
|
||||
</html>
|
||||
`
|
||||
printWindow.document.write('</div>')
|
||||
|
||||
// 添加生成二维码和打印的脚本
|
||||
printWindow.document.write('<script>')
|
||||
printWindow.document.write('window.onload = function() {')
|
||||
|
||||
// 生成二维码
|
||||
assetsToUse.forEach(asset => {
|
||||
const assetId = asset.id || asset.assetId
|
||||
printWindow.document.write(`
|
||||
(function() {
|
||||
var typeNumber = 0;
|
||||
var errorCorrectionLevel = "H";
|
||||
var qr = qrcode(typeNumber, errorCorrectionLevel);
|
||||
qr.addData("${assetId}");
|
||||
qr.make();
|
||||
document.getElementById("qrcode-${assetId}").innerHTML = qr.createImgTag(3);
|
||||
})();
|
||||
`)
|
||||
})
|
||||
|
||||
// 添加自动打印代码并在打印完成后关闭窗口
|
||||
printWindow.document.write(`
|
||||
// 给页面一点时间渲染二维码
|
||||
setTimeout(function() {
|
||||
// 监听打印事件
|
||||
var mediaQueryList = window.matchMedia('print');
|
||||
|
||||
// 打印前事件
|
||||
mediaQueryList.addListener(function(mql) {
|
||||
if (!mql.matches) {
|
||||
// 打印对话框关闭后执行
|
||||
setTimeout(function() {
|
||||
window.close();
|
||||
}, 100);
|
||||
}
|
||||
});
|
||||
|
||||
// 执行打印
|
||||
window.print();
|
||||
|
||||
// 添加取消按钮
|
||||
var cancelBtn = document.createElement('button');
|
||||
cancelBtn.innerText = '关闭窗口';
|
||||
cancelBtn.style.display = 'block';
|
||||
cancelBtn.style.margin = '20px auto';
|
||||
cancelBtn.style.padding = '10px 20px';
|
||||
cancelBtn.style.backgroundColor = '#409EFF';
|
||||
cancelBtn.style.color = 'white';
|
||||
cancelBtn.style.border = 'none';
|
||||
cancelBtn.style.borderRadius = '4px';
|
||||
cancelBtn.style.cursor = 'pointer';
|
||||
cancelBtn.onclick = function() {
|
||||
window.close();
|
||||
};
|
||||
document.body.appendChild(cancelBtn);
|
||||
}, 500);
|
||||
`)
|
||||
|
||||
printWindow.document.write('}')
|
||||
printWindow.document.write('<\/script>')
|
||||
printWindow.document.write('</body></html>')
|
||||
|
||||
// 写入打印窗口
|
||||
printWindow.document.open()
|
||||
printWindow.document.write(printContent)
|
||||
printWindow.document.close()
|
||||
|
||||
// 等待资源加载完成后打印
|
||||
printWindow.onload = function() {
|
||||
printWindow.print()
|
||||
printWindow.close()
|
||||
}
|
||||
},
|
||||
|
||||
/** 取消按钮 */
|
||||
@ -256,103 +390,110 @@ export default {
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.asset-print-container {
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.print-page {
|
||||
background-color: #fff;
|
||||
padding: 20px;
|
||||
|
||||
.print-options {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
margin-bottom: 20px;
|
||||
|
||||
.option-item {
|
||||
margin-right: 20px;
|
||||
margin-bottom: 10px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.option-label {
|
||||
margin-right: 10px;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.preview-container {
|
||||
margin-bottom: 20px;
|
||||
border: 1px solid #eee;
|
||||
padding: 15px;
|
||||
border-radius: 5px;
|
||||
|
||||
.preview-title {
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
margin-bottom: 15px;
|
||||
padding-bottom: 5px;
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
|
||||
.preview-content {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
|
||||
.label-item {
|
||||
width: 300px;
|
||||
margin: 0 15px 15px 0;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 5px;
|
||||
padding: 10px;
|
||||
|
||||
.label-header {
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
margin-bottom: 10px;
|
||||
padding-bottom: 5px;
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
|
||||
.label-content {
|
||||
padding: 5px;
|
||||
|
||||
.label-field {
|
||||
margin-bottom: 5px;
|
||||
|
||||
.field-label {
|
||||
font-weight: bold;
|
||||
display: inline-block;
|
||||
width: 80px;
|
||||
}
|
||||
|
||||
.field-value {
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
|
||||
.label-qrcode, .label-barcode {
|
||||
text-align: center;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.mock-qrcode {
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
background: repeating-conic-gradient(#000 0% 25%, #fff 0% 50%) 50% / 10px 10px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.mock-barcode {
|
||||
width: 150px;
|
||||
height: 40px;
|
||||
background: repeating-linear-gradient(to right, #000, #000 2px, #fff 2px, #fff 4px);
|
||||
margin: 0 auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.print-actions {
|
||||
text-align: center;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.print-header {
|
||||
text-align: right;
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.label-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
.label-item {
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 5px;
|
||||
padding: 10px;
|
||||
background-color: #fff;
|
||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
||||
page-break-inside: avoid;
|
||||
}
|
||||
|
||||
.label-content {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.qrcode-section {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
width: 120px;
|
||||
border-right: 1px dashed #ddd;
|
||||
padding-right: 10px;
|
||||
}
|
||||
|
||||
.asset-icon {
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
margin-bottom: 5px;
|
||||
i {
|
||||
font-size: 16px;
|
||||
color: #409EFF;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
.qrcode {
|
||||
margin: 5px 0;
|
||||
}
|
||||
|
||||
.asset-code {
|
||||
font-size: 12px;
|
||||
text-align: center;
|
||||
word-break: break-all;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.info-section {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.info-item {
|
||||
font-size: 12px;
|
||||
margin-bottom: 5px;
|
||||
color: #333;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.print-actions {
|
||||
text-align: center;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
@media print {
|
||||
.print-actions {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.print-page {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.label-grid {
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
@page {
|
||||
size: A4;
|
||||
margin: 1cm;
|
||||
}
|
||||
}
|
||||
</style>
|
@ -25,21 +25,26 @@
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-dropdown @command="handleColumnDisplay" split-button type="primary" size="mini">
|
||||
列显示
|
||||
<el-dropdown-menu slot="dropdown">
|
||||
<el-dropdown-item v-for="(item, index) in columns" :key="index" :command="index">
|
||||
<el-checkbox v-model="item.visible">{{ item.label }}</el-checkbox>
|
||||
</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</el-dropdown>
|
||||
<el-popover
|
||||
placement="bottom"
|
||||
width="200"
|
||||
trigger="click"
|
||||
v-model="columnFilterVisible"
|
||||
style="margin-left: 10px;">
|
||||
<el-checkbox-group v-model="selectedColumns">
|
||||
<el-checkbox label="all" @change="handleCheckAllChange">全部</el-checkbox>
|
||||
<el-divider></el-divider>
|
||||
<el-checkbox v-for="(item, index) in columns" :key="index" :label="item.prop" :disabled="item.disabled">{{ item.label }}</el-checkbox>
|
||||
</el-checkbox-group>
|
||||
<el-button slot="reference" type="primary" size="mini" icon="el-icon-s-operation">列显示</el-button>
|
||||
</el-popover>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<!-- 高级搜索条件,展开时显示 -->
|
||||
<el-form v-show="advanced" :model="queryParams" ref="advancedQueryForm" :inline="true" label-width="100px">
|
||||
<el-form-item label="资产状态" prop="status">
|
||||
<el-select v-model="queryParams.status" placeholder="请选择资产状态" clearable style="width: 180px">
|
||||
<el-form-item label="资产状态" prop="assetStatus">
|
||||
<el-select v-model="queryParams.assetStatus" placeholder="请选择资产状态" clearable style="width: 180px">
|
||||
<el-option v-for="dict in statusOptions" :key="dict.value" :label="dict.label" :value="dict.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
@ -52,27 +57,35 @@
|
||||
style="width: 180px"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="资产名称" prop="name">
|
||||
<el-input v-model="queryParams.name" placeholder="请输入资产名称" clearable style="width: 180px" />
|
||||
<el-form-item label="资产名称" prop="assetName">
|
||||
<el-input v-model="queryParams.assetName" placeholder="请输入资产名称" clearable style="width: 180px" />
|
||||
</el-form-item>
|
||||
<el-form-item label="所在位置" prop="locationId">
|
||||
<el-form-item label="所在位置">
|
||||
<el-cascader
|
||||
v-model="queryParams.locationId"
|
||||
:options="locationOptions"
|
||||
:props="{ checkStrictly: true, value: 'id', label: 'name', emitPath: false }"
|
||||
:props="{
|
||||
checkStrictly: true,
|
||||
emitPath: false,
|
||||
expandTrigger: 'hover',
|
||||
value: 'id',
|
||||
label: 'name'
|
||||
}"
|
||||
clearable
|
||||
filterable
|
||||
placeholder="请选择所在位置"
|
||||
style="width: 180px"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="资产编码" prop="code">
|
||||
<el-input v-model="queryParams.code" placeholder="请输入资产编码" clearable style="width: 180px" />
|
||||
<el-form-item label="资产编码" prop="assetCode">
|
||||
<el-input v-model="queryParams.assetCode" placeholder="请输入资产编码" clearable style="width: 180px" />
|
||||
</el-form-item>
|
||||
<el-form-item label="设备序列号" prop="serialNumber">
|
||||
<el-input v-model="queryParams.serialNumber" placeholder="请输入设备序列号" clearable style="width: 180px" />
|
||||
</el-form-item>
|
||||
<el-form-item label="管理员" prop="administratorId">
|
||||
<el-form-item label="管理员" prop="adminUserId">
|
||||
<el-select
|
||||
v-model="queryParams.administratorId"
|
||||
v-model="queryParams.adminUserId"
|
||||
placeholder="请选择管理员"
|
||||
clearable
|
||||
filterable
|
||||
@ -112,40 +125,43 @@
|
||||
style="width: 100%; margin-top: 15px;"
|
||||
>
|
||||
<el-table-column type="selection" width="55" align="center" />
|
||||
<el-table-column label="资产编码" prop="code" width="120" :show-overflow-tooltip="true">
|
||||
<el-table-column label="资产编码" prop="assetCode" width="120" :show-overflow-tooltip="true">
|
||||
<template slot-scope="scope">
|
||||
<el-link type="primary" @click="handleDetail(scope.row)">{{ scope.row.code }}</el-link>
|
||||
<el-link type="primary" @click="handleDetail(scope.row)">{{ scope.row.assetCode }}</el-link>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="标签链接" width="100" v-if="columns[1].visible" align="center">
|
||||
<el-table-column label="资产分类" width="120" v-if="isColumnVisible('classification')" :show-overflow-tooltip="true">
|
||||
<template slot-scope="scope">
|
||||
<el-button type="text" icon="el-icon-printer" @click="handlePrintSingle(scope.row)" />
|
||||
{{ getClassificationName(scope.row.classificationId) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="资产分类" prop="classificationName" width="120" v-if="columns[2].visible" :show-overflow-tooltip="true" />
|
||||
<el-table-column label="资产名称" prop="name" width="120" v-if="columns[3].visible" :show-overflow-tooltip="true" />
|
||||
<el-table-column label="资产状态" prop="status" width="100" v-if="columns[4].visible">
|
||||
<el-table-column label="资产名称" prop="assetName" width="120" v-if="isColumnVisible('assetName')" :show-overflow-tooltip="true" />
|
||||
<el-table-column label="资产状态" prop="assetStatus" width="100" v-if="isColumnVisible('assetStatus')">
|
||||
<template slot-scope="scope">
|
||||
<el-tag :type="getStatusType(scope.row.status)">{{ getStatusText(scope.row.status) }}</el-tag>
|
||||
<el-tag :type="getStatusType(scope.row.assetStatus)">{{ scope.row.assetStatus }}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="品牌" prop="brand" width="100" v-if="columns[5].visible" :show-overflow-tooltip="true" />
|
||||
<el-table-column label="型号" prop="model" width="100" v-if="columns[6].visible" :show-overflow-tooltip="true" />
|
||||
<el-table-column label="设备序列号" prop="serialNumber" width="140" v-if="columns[7].visible" :show-overflow-tooltip="true" />
|
||||
<el-table-column label="管理员" prop="administratorName" width="100" v-if="columns[8].visible" :show-overflow-tooltip="true" />
|
||||
<el-table-column label="所属公司" prop="companyName" width="140" v-if="columns[9].visible" :show-overflow-tooltip="true" />
|
||||
<el-table-column label="所在位置" prop="locationName" width="140" v-if="columns[10].visible" :show-overflow-tooltip="true" />
|
||||
<el-table-column label="购置时间" prop="purchaseTime" width="120" v-if="columns[11].visible" />
|
||||
<el-table-column label="购置方式" prop="purchaseType" width="100" v-if="columns[12].visible">
|
||||
<el-table-column label="品牌" prop="brand" width="100" v-if="isColumnVisible('brand')" :show-overflow-tooltip="true" />
|
||||
<el-table-column label="型号" prop="model" width="100" v-if="isColumnVisible('model')" :show-overflow-tooltip="true" />
|
||||
<el-table-column label="设备序列号" prop="serialNumber" width="140" v-if="isColumnVisible('serialNumber')" :show-overflow-tooltip="true" />
|
||||
<el-table-column label="管理员" prop="administratorName" width="100" v-if="isColumnVisible('administratorName')" :show-overflow-tooltip="true" />
|
||||
<el-table-column label="所属公司" prop="companyName" width="140" v-if="isColumnVisible('companyName')" :show-overflow-tooltip="true" />
|
||||
<el-table-column label="所在位置" width="140" v-if="isColumnVisible('location')" :show-overflow-tooltip="true">
|
||||
<template slot-scope="scope">
|
||||
{{ getLocationName(scope.row.locationId) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="购置时间" prop="purchaseDate" width="120" v-if="isColumnVisible('purchaseDate')" />
|
||||
<el-table-column label="购置方式" prop="purchaseType" width="100" v-if="isColumnVisible('purchaseType')">
|
||||
<template slot-scope="scope">
|
||||
{{ scope.row.purchaseType === '1' ? '采购' : '租赁' }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="购置金额(含税)" prop="purchaseAmount" width="130" v-if="columns[13].visible" />
|
||||
<el-table-column label="入库时间" prop="storageTime" width="120" v-if="columns[14].visible" />
|
||||
<el-table-column label="预计使用期限(月)" prop="expectedUsePeriod" width="150" v-if="columns[15].visible" />
|
||||
<el-table-column label="备注" prop="remark" width="150" v-if="columns[16].visible" :show-overflow-tooltip="true" />
|
||||
<el-table-column label="资产照片" width="100" v-if="columns[17].visible" align="center">
|
||||
<el-table-column label="购置金额(含税)" prop="purchaseAmount" width="130" v-if="isColumnVisible('purchaseAmount')" />
|
||||
<el-table-column label="入库时间" prop="storageDate" width="120" v-if="isColumnVisible('storageDate')" />
|
||||
<el-table-column label="预计使用期限(月)" prop="expectedDepreciationPeriod" width="150" v-if="isColumnVisible('expectedUsePeriod')" />
|
||||
<el-table-column label="备注" prop="remark" width="150" v-if="isColumnVisible('remark')" :show-overflow-tooltip="true" />
|
||||
<el-table-column label="资产照片" width="100" v-if="isColumnVisible('image')" align="center">
|
||||
<template slot-scope="scope">
|
||||
<el-image
|
||||
v-if="scope.row.imageUrl"
|
||||
@ -156,13 +172,13 @@
|
||||
<span v-else>无</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="保养到期时间" prop="maintenanceTime" width="130" v-if="columns[18].visible" />
|
||||
<el-table-column label="保养说明" prop="maintenanceDescription" width="150" v-if="columns[19].visible" :show-overflow-tooltip="true" />
|
||||
<el-table-column label="预计折旧期限(月)" prop="expectedDepreciationPeriod" width="150" v-if="columns[20].visible" />
|
||||
<el-table-column label="保养到期时间" prop="maintenanceDueDate" width="130" v-if="isColumnVisible('maintenanceDueDate')" />
|
||||
<el-table-column label="保养说明" prop="maintenanceDescription" width="150" v-if="isColumnVisible('maintenanceDescription')" :show-overflow-tooltip="true" />
|
||||
<el-table-column label="预计折旧期限(月)" prop="expectedDepreciationPeriod" width="150" v-if="isColumnVisible('expectedDepreciationPeriod')" />
|
||||
<el-table-column label="操作" width="150" align="center" fixed="right">
|
||||
<template slot-scope="scope">
|
||||
<el-button type="text" size="mini" @click="handleUpdate(scope.row)">修改</el-button>
|
||||
<el-button type="text" size="mini" @click="handleDelete(scope.row)" v-if="scope.row.status === '0'" style="color: #F56C6C;">删除</el-button>
|
||||
<el-button type="text" size="mini" @click="handleDelete(scope.row)" v-if="scope.row.assetStatus === '0'" style="color: #F56C6C;">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
@ -181,7 +197,7 @@
|
||||
</el-card>
|
||||
|
||||
<!-- 导入对话框 -->
|
||||
<el-dialog :title="importTitle" :visible.sync="importOpen" width="500px" append-to-body>
|
||||
<el-dialog :title="upload.title" :visible.sync="upload.open" width="500px" append-to-body>
|
||||
<el-upload
|
||||
ref="upload"
|
||||
:limit="1"
|
||||
@ -189,8 +205,9 @@
|
||||
:headers="upload.headers"
|
||||
:action="upload.url"
|
||||
:disabled="upload.isUploading"
|
||||
:on-progress="handleFileUploadProgress"
|
||||
:on-progress="handleFileUpload"
|
||||
:on-success="handleFileSuccess"
|
||||
:on-error="handleFileError"
|
||||
:auto-upload="false"
|
||||
drag>
|
||||
<i class="el-icon-upload"></i>
|
||||
@ -202,7 +219,7 @@
|
||||
</el-upload>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button type="primary" @click="submitFileForm">确 定</el-button>
|
||||
<el-button @click="importOpen = false">取 消</el-button>
|
||||
<el-button @click="upload.open = false">取 消</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
|
||||
@ -227,29 +244,26 @@
|
||||
<asset-label-print
|
||||
v-if="printOpen"
|
||||
:ids="ids"
|
||||
:selected-assets="assetsToPrint"
|
||||
@close="printOpen = false"
|
||||
/>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 隐藏的打印组件,用于生成打印内容 -->
|
||||
<asset-label-print
|
||||
ref="assetLabelPrint"
|
||||
:ids="ids"
|
||||
:selected-assets="assetsToPrint"
|
||||
style="display: none;"
|
||||
/>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {
|
||||
listAsset,
|
||||
getAsset,
|
||||
delAsset,
|
||||
delAssetBatch,
|
||||
exportAsset,
|
||||
downloadTemplate,
|
||||
importAsset,
|
||||
listAssetClassTree,
|
||||
listAssetLocationTree,
|
||||
listCompanies,
|
||||
listUsers,
|
||||
printAssetLabel,
|
||||
getAssetStatusOptions
|
||||
} from '@/api/asset/inventory'
|
||||
import { listAssets, deleteAsset, deleteAssets, listCompanies, listUsers, exportAsset, downloadTemplate, printAssetLabels, getLabelConfig } from '@/api/asset/inventory'
|
||||
import { getClassificationTree } from '@/api/asset/classification'
|
||||
import { getLocationTree } from '@/api/asset/location'
|
||||
import AssetDetail from './components/AssetDetail'
|
||||
import AssetForm from './components/AssetForm'
|
||||
import AssetLabelPrint from './components/AssetLabelPrint'
|
||||
@ -263,6 +277,7 @@ export default {
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
printOpen: false,
|
||||
// 遮罩层
|
||||
loading: false,
|
||||
// 选中数组
|
||||
@ -275,6 +290,8 @@ export default {
|
||||
total: 0,
|
||||
// 资产表格数据
|
||||
assetList: [],
|
||||
// 要打印的资产数据
|
||||
assetsToPrint: [],
|
||||
// 弹出层标题
|
||||
title: '',
|
||||
// 是否显示弹出层
|
||||
@ -283,8 +300,6 @@ export default {
|
||||
detailOpen: false,
|
||||
// 是否显示导入弹出层
|
||||
importOpen: false,
|
||||
// 是否显示打印弹出层
|
||||
printOpen: false,
|
||||
// 导入标题
|
||||
importTitle: '导入资产数据',
|
||||
// 详情标题
|
||||
@ -310,48 +325,53 @@ export default {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
keyword: '',
|
||||
status: '',
|
||||
assetStatus: '',
|
||||
classificationId: undefined,
|
||||
name: '',
|
||||
assetName: '',
|
||||
locationId: undefined,
|
||||
code: '',
|
||||
assetCode: '',
|
||||
serialNumber: '',
|
||||
administratorId: undefined,
|
||||
adminUserId: undefined,
|
||||
maintenanceExpired: ''
|
||||
},
|
||||
// 上传参数
|
||||
upload: {
|
||||
// 是否禁用上传
|
||||
// 是否显示弹出层
|
||||
open: false,
|
||||
// 弹出层标题
|
||||
title: '',
|
||||
isUploading: false,
|
||||
// 设置上传的请求头部
|
||||
headers: { },
|
||||
// 上传的URL
|
||||
url: process.env.VUE_APP_BASE_API + '/asset/inventory/import'
|
||||
headers: {},
|
||||
// 上传的地址
|
||||
url: process.env.VUE_APP_BASE_API + '/asset/import'
|
||||
},
|
||||
// 列显示设置
|
||||
columns: [
|
||||
{ label: '资产编码', visible: true, disabled: true },
|
||||
{ label: '标签链接', visible: true },
|
||||
{ label: '资产分类', visible: true },
|
||||
{ label: '资产名称', visible: true },
|
||||
{ label: '资产状态', visible: true },
|
||||
{ label: '品牌', visible: true },
|
||||
{ label: '型号', visible: true },
|
||||
{ label: '设备序列号', visible: true },
|
||||
{ label: '管理员', visible: true },
|
||||
{ label: '所属公司', visible: true },
|
||||
{ label: '所在位置', visible: true },
|
||||
{ label: '购置时间', visible: true },
|
||||
{ label: '购置方式', visible: true },
|
||||
{ label: '购置金额(含税)', visible: true },
|
||||
{ label: '入库时间', visible: true },
|
||||
{ label: '预计使用期限(月)', visible: true },
|
||||
{ label: '备注', visible: true },
|
||||
{ label: '资产照片', visible: true },
|
||||
{ label: '保养到期时间', visible: true },
|
||||
{ label: '保养说明', visible: true },
|
||||
{ label: '预计折旧期限(月)', visible: true }
|
||||
]
|
||||
{ prop: 'assetCode', label: '资产编码', visible: true, disabled: true },
|
||||
{ prop: 'tagLink', label: '标签链接', visible: true, disabled: false },
|
||||
{ prop: 'classification', label: '资产分类', visible: true, disabled: false },
|
||||
{ prop: 'assetName', label: '资产名称', visible: true, disabled: false },
|
||||
{ prop: 'assetStatus', label: '资产状态', visible: true, disabled: false },
|
||||
{ prop: 'brand', label: '品牌', visible: true, disabled: false },
|
||||
{ prop: 'model', label: '型号', visible: true, disabled: false },
|
||||
{ prop: 'serialNumber', label: '设备序列号', visible: true, disabled: false },
|
||||
{ prop: 'administratorName', label: '管理员', visible: true, disabled: false },
|
||||
{ prop: 'companyName', label: '所属公司', visible: true, disabled: false },
|
||||
{ prop: 'location', label: '所在位置', visible: true, disabled: false },
|
||||
{ prop: 'purchaseDate', label: '购置时间', visible: true, disabled: false },
|
||||
{ prop: 'purchaseType', label: '购置方式', visible: true, disabled: false },
|
||||
{ prop: 'purchaseAmount', label: '购置金额(含税)', visible: true, disabled: false },
|
||||
{ prop: 'storageDate', label: '入库时间', visible: true, disabled: false },
|
||||
{ prop: 'expectedUsePeriod', label: '预计使用期限(月)', visible: true, disabled: false },
|
||||
{ prop: 'remark', label: '备注', visible: true, disabled: false },
|
||||
{ prop: 'image', label: '资产照片', visible: true, disabled: false },
|
||||
{ prop: 'maintenanceDueDate', label: '保养到期时间', visible: true, disabled: false },
|
||||
{ prop: 'maintenanceDescription', label: '保养说明', visible: true, disabled: false },
|
||||
{ prop: 'expectedDepreciationPeriod', label: '预计折旧期限(月)', visible: true, disabled: false }
|
||||
],
|
||||
columnFilterVisible: false,
|
||||
selectedColumns: []
|
||||
}
|
||||
},
|
||||
created() {
|
||||
@ -359,54 +379,153 @@ export default {
|
||||
this.getStatusOptions()
|
||||
this.getClassificationOptions()
|
||||
this.getLocationOptions()
|
||||
this.getCompanyOptions()
|
||||
// this.getCompanyOptions()
|
||||
|
||||
// 初始化选中的列
|
||||
this.selectedColumns = this.columns
|
||||
.filter(col => col.visible)
|
||||
.map(col => col.prop)
|
||||
|
||||
// 检查是否所有列都被选中,如果是,添加 'all' 选项
|
||||
const allSelected = this.columns
|
||||
.filter(col => !col.disabled)
|
||||
.every(col => this.selectedColumns.includes(col.prop))
|
||||
|
||||
if (allSelected) {
|
||||
this.selectedColumns.push('all')
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
// 判断列是否可见
|
||||
isColumnVisible() {
|
||||
return (prop) => this.selectedColumns.includes(prop)
|
||||
},
|
||||
// 判断是否所有可选列都被选中
|
||||
isAllSelected() {
|
||||
const selectableColumns = this.columns
|
||||
.filter(col => !col.disabled)
|
||||
.map(col => col.prop)
|
||||
|
||||
return selectableColumns.every(prop => this.selectedColumns.includes(prop))
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
selectedColumns: {
|
||||
handler(newVal) {
|
||||
// 确保必选列始终存在
|
||||
if (!newVal.includes('assetCode')) {
|
||||
this.selectedColumns.push('assetCode')
|
||||
}
|
||||
|
||||
// 获取所有可选列(除了必选列)
|
||||
const selectableColumns = this.columns
|
||||
.filter(col => !col.disabled)
|
||||
.map(col => col.prop)
|
||||
|
||||
// 检查所有可选列是否都被选中
|
||||
const allSelected = selectableColumns.every(prop => newVal.includes(prop))
|
||||
|
||||
// 更新"全部"选项的状态
|
||||
if (allSelected && !newVal.includes('all')) {
|
||||
this.selectedColumns.push('all')
|
||||
} else if (!allSelected && newVal.includes('all')) {
|
||||
// 从选择中移除"全部"选项
|
||||
const index = this.selectedColumns.indexOf('all')
|
||||
if (index > -1) {
|
||||
this.selectedColumns.splice(index, 1)
|
||||
}
|
||||
}
|
||||
|
||||
// 更新 columns 中的 visible 属性
|
||||
this.columns.forEach(col => {
|
||||
col.visible = this.selectedColumns.includes(col.prop)
|
||||
})
|
||||
},
|
||||
deep: true
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
/** 查询资产列表 */
|
||||
/** 查询资产清单列表 */
|
||||
getList() {
|
||||
this.loading = true
|
||||
listAsset(this.queryParams).then(response => {
|
||||
listAssets(this.queryParams).then(response => {
|
||||
if (response.code === '000000') {
|
||||
this.assetList = response.data.list || []
|
||||
this.total = response.data.total
|
||||
} else {
|
||||
this.$message.error(response.msg || '获取资产列表失败')
|
||||
this.assetList = []
|
||||
this.total = 0
|
||||
}
|
||||
this.loading = false
|
||||
}).catch(() => {
|
||||
this.loading = false
|
||||
})
|
||||
},
|
||||
|
||||
/** 获取资产状态选项 */
|
||||
getStatusOptions() {
|
||||
getAssetStatusOptions().then(response => {
|
||||
if (response.code === '000000') {
|
||||
this.statusOptions = response.data || []
|
||||
}
|
||||
})
|
||||
this.statusOptions = [
|
||||
{ value: '空闲', label: '空闲' },
|
||||
{ value: '在用', label: '在用' },
|
||||
{ value: '借用', label: '借用' },
|
||||
{ value: '维修中', label: '维修中' },
|
||||
{ value: '报废', label: '报废' }
|
||||
]
|
||||
},
|
||||
|
||||
/** 获取资产分类树形选项 */
|
||||
getClassificationOptions() {
|
||||
listAssetClassTree().then(response => {
|
||||
getClassificationTree({ status: '1' }).then(response => {
|
||||
if (response.code === '000000') {
|
||||
this.classificationOptions = response.data || []
|
||||
this.classificationOptions = this.processClassificationTree(response.data || [])
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
/** 获取资产位置树形选项 */
|
||||
getLocationOptions() {
|
||||
listAssetLocationTree().then(response => {
|
||||
getLocationTree().then(response => {
|
||||
if (response.code === '000000') {
|
||||
this.locationOptions = response.data || []
|
||||
this.locationOptions = this.processLocationTree(response.data || [])
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
processLocationTree(data) {
|
||||
if (!data || !Array.isArray(data)) return []
|
||||
|
||||
const processNode = (node) => {
|
||||
const processedNode = {
|
||||
id: node.id,
|
||||
name: `${node.code || ''}-${node.locationName || node.label || ''}`,
|
||||
children: []
|
||||
}
|
||||
|
||||
if (node.children && Array.isArray(node.children) && node.children.length > 0) {
|
||||
processedNode.children = node.children.map(child => processNode(child))
|
||||
}
|
||||
|
||||
return processedNode
|
||||
}
|
||||
|
||||
return data.map(item => processNode(item))
|
||||
},
|
||||
|
||||
processClassificationTree(data) {
|
||||
if (!data || !Array.isArray(data)) return []
|
||||
|
||||
const processNode = (node) => {
|
||||
const processedNode = {
|
||||
id: node.id,
|
||||
name: `${node.classificationCode || node.code || ''}-${node.classificationName || node.label || ''}`,
|
||||
children: []
|
||||
}
|
||||
|
||||
if (node.children && Array.isArray(node.children) && node.children.length > 0) {
|
||||
processedNode.children = node.children.map(child => processNode(child))
|
||||
}
|
||||
|
||||
return processedNode
|
||||
}
|
||||
|
||||
return data.map(item => processNode(item))
|
||||
},
|
||||
|
||||
/** 获取公司选项 */
|
||||
getCompanyOptions() {
|
||||
listCompanies().then(response => {
|
||||
@ -432,33 +551,30 @@ export default {
|
||||
},
|
||||
|
||||
/** 获取资产状态显示文本 */
|
||||
getStatusText(status) {
|
||||
getStatusText(assetStatus) {
|
||||
const statusMap = {
|
||||
'0': '空闲',
|
||||
'1': '在用',
|
||||
'2': '借用',
|
||||
'3': '派发中',
|
||||
'4': '退库中',
|
||||
'5': '借出中',
|
||||
'6': '归还中',
|
||||
'7': '维修中'
|
||||
'3': '维修中',
|
||||
'4': '报废'
|
||||
}
|
||||
return statusMap[status] || '未知'
|
||||
return statusMap[assetStatus] || '未知'
|
||||
},
|
||||
|
||||
/** 获取资产状态显示类型 */
|
||||
getStatusType(status) {
|
||||
getStatusType(assetStatus) {
|
||||
const typeMap = {
|
||||
'0': 'success',
|
||||
'1': 'primary',
|
||||
'2': 'info',
|
||||
'3': 'warning',
|
||||
'4': 'warning',
|
||||
'空闲': 'success',
|
||||
'在用': 'primary',
|
||||
'借用': 'info',
|
||||
'维修中': 'warning',
|
||||
'报废': 'warning',
|
||||
'5': 'warning',
|
||||
'6': 'warning',
|
||||
'7': 'danger'
|
||||
}
|
||||
return typeMap[status] || 'info'
|
||||
return typeMap[assetStatus] || 'info'
|
||||
},
|
||||
|
||||
/** 切换高级搜索 */
|
||||
@ -474,6 +590,22 @@ export default {
|
||||
}
|
||||
},
|
||||
|
||||
/** 全选/取消全选处理 */
|
||||
handleCheckAllChange(checked) {
|
||||
// 获取所有可选列的 prop 值(除了必选列)
|
||||
const selectableColumns = this.columns
|
||||
.filter(col => !col.disabled)
|
||||
.map(col => col.prop)
|
||||
|
||||
if (checked) {
|
||||
// 如果选中"全部",则选择所有列
|
||||
this.selectedColumns = ['all', 'assetCode', ...selectableColumns]
|
||||
} else {
|
||||
// 如果取消选中"全部",则只保留必选列
|
||||
this.selectedColumns = ['assetCode']
|
||||
}
|
||||
},
|
||||
|
||||
/** 搜索按钮操作 */
|
||||
handleQuery() {
|
||||
this.queryParams.pageNum = 1
|
||||
@ -490,13 +622,13 @@ export default {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
keyword: '',
|
||||
status: '',
|
||||
assetStatus: '',
|
||||
classificationId: undefined,
|
||||
name: '',
|
||||
assetName: '',
|
||||
locationId: undefined,
|
||||
code: '',
|
||||
assetCode: '',
|
||||
serialNumber: '',
|
||||
administratorId: undefined,
|
||||
adminUserId: undefined,
|
||||
maintenanceExpired: ''
|
||||
}
|
||||
this.handleQuery()
|
||||
@ -521,42 +653,60 @@ export default {
|
||||
this.open = true
|
||||
this.title = '修改资产'
|
||||
this.isEdit = true
|
||||
this.currentAssetId = row.id
|
||||
this.currentAssetId = row.assetCode
|
||||
},
|
||||
|
||||
/** 详情按钮操作 */
|
||||
handleDetail(row) {
|
||||
this.detailOpen = true
|
||||
this.detailTitle = '资产详情'
|
||||
this.currentAssetId = row.id
|
||||
this.currentAssetId = row.assetCode
|
||||
},
|
||||
|
||||
/** 删除按钮操作 */
|
||||
handleDelete(row) {
|
||||
const assetId = row.id
|
||||
this.$confirm('是否确认删除该资产?', '警告', {
|
||||
this.$confirm('是否确认删除资产编码为"' + row.assetCode + '"的数据项?', '警告', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
delAsset(assetId).then(response => {
|
||||
if (response.code === '000000') {
|
||||
this.$message.success('删除成功')
|
||||
this.getList()
|
||||
} else {
|
||||
this.$message.error(response.msg || '删除失败')
|
||||
}
|
||||
})
|
||||
return deleteAsset(row.assetCode)
|
||||
}).then(response => {
|
||||
if (response.code === '000000') {
|
||||
this.$message.success('删除成功')
|
||||
this.getList()
|
||||
}
|
||||
}).catch(() => {})
|
||||
},
|
||||
|
||||
/** 批量删除按钮操作 */
|
||||
handleBatchDelete() {
|
||||
const assetCodes = this.selectedRows.map(item => item.assetCode)
|
||||
if (assetCodes.length === 0) {
|
||||
this.$message.warning('请至少选择一条记录')
|
||||
return
|
||||
}
|
||||
|
||||
this.$confirm('是否确认批量删除选中的' + assetCodes.length + '条数据?', '警告', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
return deleteAssets(assetCodes)
|
||||
}).then(response => {
|
||||
if (response.code === '000000') {
|
||||
this.$message.success('批量删除成功')
|
||||
this.getList()
|
||||
}
|
||||
}).catch(() => {})
|
||||
},
|
||||
|
||||
/** 导出按钮操作 */
|
||||
handleExport() {
|
||||
const queryParams = { ...this.queryParams }
|
||||
// 移除分页参数
|
||||
delete queryParams.pageNum
|
||||
delete queryParams.pageSize
|
||||
|
||||
queryParams.pageNum = undefined
|
||||
queryParams.pageSize = undefined
|
||||
|
||||
this.$confirm('是否确认导出所有资产数据项?', '警告', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
@ -565,27 +715,28 @@ export default {
|
||||
this.exportLoading = true
|
||||
return exportAsset(queryParams)
|
||||
}).then(response => {
|
||||
this.download(response, '资产清单_' + new Date().getTime() + '.xlsx')
|
||||
this.download(response, '资产数据.xlsx')
|
||||
this.exportLoading = false
|
||||
}).catch(() => {
|
||||
this.exportLoading = false
|
||||
})
|
||||
},
|
||||
|
||||
/** 导入按钮操作 */
|
||||
handleImport() {
|
||||
this.importOpen = true
|
||||
},
|
||||
|
||||
/** 下载导入模板 */
|
||||
/** 下载模板操作 */
|
||||
downloadImportTemplate() {
|
||||
downloadTemplate().then(response => {
|
||||
this.download(response, 'property_import.xlsx')
|
||||
this.download(response, '资产导入模板.xlsx')
|
||||
})
|
||||
},
|
||||
|
||||
/** 文件上传中处理 */
|
||||
handleFileUploadProgress() {
|
||||
/** 导入按钮操作 */
|
||||
handleImport() {
|
||||
this.upload.open = true
|
||||
this.upload.title = '导入资产数据'
|
||||
},
|
||||
|
||||
/** 处理文件上传中 */
|
||||
handleFileUpload() {
|
||||
this.upload.isUploading = true
|
||||
},
|
||||
|
||||
@ -593,40 +744,64 @@ export default {
|
||||
handleFileSuccess(response) {
|
||||
this.upload.isUploading = false
|
||||
this.$refs.upload.clearFiles()
|
||||
this.importOpen = false
|
||||
this.upload.open = false
|
||||
if (response.code === '000000') {
|
||||
this.$message.success('导入成功')
|
||||
this.$message.success('导入成功' + (response.data && response.data.successCount ? response.data.successCount : 0) + '条数据')
|
||||
this.getList()
|
||||
} else {
|
||||
this.$message.error(response.msg || '导入失败')
|
||||
}
|
||||
},
|
||||
|
||||
/** 文件上传失败处理 */
|
||||
handleFileError() {
|
||||
this.upload.isUploading = false
|
||||
this.$message.error('导入失败')
|
||||
},
|
||||
|
||||
/** 提交上传文件 */
|
||||
submitFileForm() {
|
||||
this.$refs.upload.submit()
|
||||
},
|
||||
|
||||
/** 打印标签按钮操作 */
|
||||
/** 打印标签 */
|
||||
handlePrint() {
|
||||
if (this.ids.length === 0) {
|
||||
this.$message.warning('请先选择要打印的资产')
|
||||
this.$message.warning('请选择要打印的资产')
|
||||
return
|
||||
}
|
||||
this.printOpen = true
|
||||
|
||||
// 从选中的列表项中获取相关数据
|
||||
this.assetsToPrint = this.assetList.filter(item => this.ids.includes(item.id || item.assetId))
|
||||
|
||||
// 直接调用浏览器打印功能
|
||||
this.$nextTick(() => {
|
||||
// const printWindow = window.open('', '_blank')
|
||||
// if (!printWindow) {
|
||||
// this.$message.error('打印窗口被阻止,请允许弹出窗口')
|
||||
// return
|
||||
// }
|
||||
|
||||
// 获取打印内容
|
||||
const printContent = this.$refs.assetLabelPrint.getPrintContent(this.assetsToPrint)
|
||||
|
||||
// 写入打印窗口
|
||||
printWindow.document.open()
|
||||
printWindow.document.write(printContent)
|
||||
printWindow.document.close()
|
||||
|
||||
// 等待资源加载完成后打印
|
||||
printWindow.onload = function() {
|
||||
printWindow.print()
|
||||
// 打印完成后关闭窗口
|
||||
printWindow.close()
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
/** 打印单个资产标签 */
|
||||
handlePrintSingle(row) {
|
||||
const ids = [row.id]
|
||||
printAssetLabel(ids).then(response => {
|
||||
if (response.code === '000000') {
|
||||
// 根据实际情况处理打印标签的逻辑
|
||||
this.$message.success('打印标签成功')
|
||||
} else {
|
||||
this.$message.error(response.msg || '打印标签失败')
|
||||
}
|
||||
})
|
||||
this.ids = [row.id || row.assetId]
|
||||
this.assetsToPrint = [row]
|
||||
this.handlePrint()
|
||||
},
|
||||
|
||||
/** 分页大小改变 */
|
||||
@ -639,6 +814,50 @@ export default {
|
||||
handleCurrentChange(val) {
|
||||
this.queryParams.pageNum = val
|
||||
this.getList()
|
||||
},
|
||||
|
||||
/** 获取分类名称 */
|
||||
getClassificationName(classificationId) {
|
||||
if (!classificationId) return '未知分类'
|
||||
|
||||
// 递归查找分类
|
||||
const findClassification = (items) => {
|
||||
for (const item of items) {
|
||||
if (item.id === classificationId) {
|
||||
return item.name
|
||||
}
|
||||
if (item.children && item.children.length > 0) {
|
||||
const found = findClassification(item.children)
|
||||
if (found) return found
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
const name = findClassification(this.classificationOptions)
|
||||
return name || '未知分类'
|
||||
},
|
||||
|
||||
/** 获取位置名称 */
|
||||
getLocationName(locationId) {
|
||||
if (!locationId) return '未知位置'
|
||||
|
||||
// 递归查找位置
|
||||
const findLocation = (items) => {
|
||||
for (const item of items) {
|
||||
if (item.id === locationId) {
|
||||
return item.name
|
||||
}
|
||||
if (item.children && item.children.length > 0) {
|
||||
const found = findLocation(item.children)
|
||||
if (found) return found
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
const name = findLocation(this.locationOptions)
|
||||
return name || '未知位置'
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -661,4 +880,4 @@ export default {
|
||||
margin-left: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</style>
|
654
pc/src/views/finance/feeType/index.vue
Normal file
654
pc/src/views/finance/feeType/index.vue
Normal file
@ -0,0 +1,654 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<el-row :gutter="20">
|
||||
<!-- 左侧:费用分类 -->
|
||||
<el-col :span="6">
|
||||
<div class="category-container">
|
||||
<div class="category-header">
|
||||
<h3>费用分类</h3>
|
||||
<el-button type="primary" size="mini" icon="el-icon-plus"
|
||||
@click="handleAddCategory">新增</el-button>
|
||||
</div>
|
||||
<div class="category-search">
|
||||
<el-input v-model="categoryQuery" placeholder="请输入分类名称" clearable size="small"
|
||||
@keyup.enter.native="handleCategorySearch">
|
||||
<el-button slot="append" icon="el-icon-search" @click="handleCategorySearch"></el-button>
|
||||
</el-input>
|
||||
</div>
|
||||
<el-menu :default-active="selectedCategoryId ? selectedCategoryId.toString() : ''"
|
||||
class="category-menu" @select="handleCategorySelect">
|
||||
<el-menu-item v-for="item in categoryList" :key="item.id" :index="item.id.toString()"
|
||||
class="category-item">
|
||||
<span>{{ item.categoryName }}</span>
|
||||
<div class="category-actions">
|
||||
<el-tooltip content="编辑" placement="top" :disabled="item.defauVerFlag === '1'">
|
||||
<el-button type="text" icon="el-icon-edit" @click.stop="handleEditCategory(item)"
|
||||
:disabled="item.defauVerFlag === '1'"></el-button>
|
||||
</el-tooltip>
|
||||
<el-tooltip content="删除" placement="top" :disabled="item.defauVerFlag === '1'">
|
||||
<el-button type="text" icon="el-icon-delete"
|
||||
@click.stop="handleDeleteCategory(item)"
|
||||
:disabled="item.defauVerFlag === '1'"></el-button>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
</el-menu-item>
|
||||
</el-menu>
|
||||
</div>
|
||||
</el-col>
|
||||
<!-- 右侧:费用类型 -->
|
||||
<el-col :span="18">
|
||||
<div class="fee-type-container">
|
||||
<div class="fee-type-header">
|
||||
<div class="header-title">
|
||||
<h3>费用类型</h3>
|
||||
<span v-if="selectedCategory">- {{ selectedCategory.categoryName }}</span>
|
||||
</div>
|
||||
<el-button type="primary" icon="el-icon-plus" @click="handleAddType"
|
||||
:disabled="!selectedCategoryId">新增费用类型</el-button>
|
||||
</div>
|
||||
<!-- 费用类型搜索区域 -->
|
||||
<div class="fee-type-search">
|
||||
<el-form :inline="true" :model="queryParams" class="search-form">
|
||||
<el-form-item label="费用名称">
|
||||
<el-input v-model="queryParams.feeTypeName" placeholder="请输入费用名称" clearable
|
||||
@keyup.enter.native="handleQuery"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="el-icon-search" @click="handleQuery">查询</el-button>
|
||||
<el-button icon="el-icon-refresh" @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
<!-- 费用类型表格 -->
|
||||
<el-table v-loading="loading" :data="typeList" border>
|
||||
<el-table-column type="index" width="50" align="center" label="序号"></el-table-column>
|
||||
<el-table-column prop="feeTypeName" label="费用名称" min-width="140"></el-table-column>
|
||||
<el-table-column label="费用分类" min-width="120" align="center">
|
||||
<template slot-scope="scope">
|
||||
{{ getCategoryNameById(scope.row.categoryId) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="status" label="状态" width="100" align="center">
|
||||
<template slot-scope="scope">
|
||||
<el-tag :type="scope.row.status === '1' ? 'success' : 'info'">
|
||||
{{ scope.row.status === '1' ? '开启' : '关闭' }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="150" align="center">
|
||||
<template slot-scope="scope">
|
||||
<el-button size="mini" type="text" icon="el-icon-edit"
|
||||
@click="handleEditType(scope.row)">编辑</el-button>
|
||||
<el-button size="mini" type="text" icon="el-icon-delete"
|
||||
@click="handleDeleteType(scope.row)"
|
||||
:disabled="scope.row.defauVerFlag === '1'">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<!-- 分页区域 -->
|
||||
<el-pagination v-show="total > 0" @size-change="handleSizeChange"
|
||||
@current-change="handleCurrentChange" :current-page="queryParams.pageNum"
|
||||
:page-sizes="[10, 20, 30, 50]" :page-size="queryParams.pageSize"
|
||||
layout="total, sizes, prev, pager, next, jumper" :total="total">
|
||||
</el-pagination>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<!-- 添加或修改费用分类对话框 -->
|
||||
<el-dialog :title="categoryTitle" :visible.sync="categoryOpen" width="500px" append-to-body
|
||||
@open="onCategoryDialogOpen">
|
||||
<el-form ref="categoryForm" :model="categoryForm" :rules="categoryRules" label-width="100px">
|
||||
<el-form-item label="分类名称" prop="categoryName">
|
||||
<el-input v-model="categoryForm.categoryName" placeholder="请输入分类名称" :disabled="categoryEdit"
|
||||
style="width: 100%"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="保证金类型" prop="feeTpNo">
|
||||
<el-radio-group v-model="categoryForm.feeTpNo">
|
||||
<el-radio label="1">是</el-radio>
|
||||
<el-radio label="0">否</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button @click="categoryOpen = false">取 消</el-button>
|
||||
<el-button type="primary" @click="submitCategoryForm">确 定</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 添加或修改费用类型对话框 -->
|
||||
<el-dialog :title="typeTitle" :visible.sync="typeOpen" width="500px" append-to-body @open="onTypeDialogOpen">
|
||||
<el-form ref="typeForm" :model="typeForm" :rules="typeRules" label-width="120px">
|
||||
<el-form-item label="费用分类" prop="categoryId">
|
||||
<el-select v-model="typeForm.categoryId" placeholder="请选择费用分类" style="width: 100%">
|
||||
<el-option
|
||||
v-for="item in categoryList"
|
||||
:key="item.id"
|
||||
:label="item.categoryName"
|
||||
:value="item.id">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="费用类型名称" prop="feeTypeName">
|
||||
<el-input v-model="typeForm.feeTypeName" placeholder="请输入费用类型名称" :disabled="typeEdit"
|
||||
style="width: 100%"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="状态" prop="status">
|
||||
<el-radio-group v-model="typeForm.status">
|
||||
<el-radio label="1">开启</el-radio>
|
||||
<el-radio label="0">关闭</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button @click="typeOpen = false">取 消</el-button>
|
||||
<el-button type="primary" @click="submitTypeForm">确 定</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {
|
||||
getFeeCategories,
|
||||
getAllFeeCategories,
|
||||
getFeeCategory,
|
||||
addFeeCategory,
|
||||
updateFeeCategory,
|
||||
deleteFeeCategory,
|
||||
getFeeTypes,
|
||||
getFeeType,
|
||||
addFeeType,
|
||||
updateFeeType,
|
||||
deleteFeeType
|
||||
} from '@/api/finance'
|
||||
|
||||
export default {
|
||||
name: 'FeeTypeManagement',
|
||||
data() {
|
||||
return {
|
||||
// 遮罩层
|
||||
loading: false,
|
||||
// 分类列表
|
||||
categoryList: [],
|
||||
// 费用类型列表
|
||||
typeList: [],
|
||||
// 总条数
|
||||
total: 0,
|
||||
// 分类查询条件
|
||||
categoryQuery: '',
|
||||
// 选中的分类ID
|
||||
selectedCategoryId: null,
|
||||
// 选中的分类对象
|
||||
selectedCategory: null,
|
||||
// 查询参数
|
||||
queryParams: {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
feeTypeName: undefined,
|
||||
categoryId: null
|
||||
},
|
||||
|
||||
// 分类对话框相关
|
||||
categoryOpen: false,
|
||||
categoryTitle: '',
|
||||
categoryEdit: false,
|
||||
categoryForm: {
|
||||
id: undefined,
|
||||
categoryName: undefined,
|
||||
feeTpNo: '0',
|
||||
defauVerFlag: '0'
|
||||
},
|
||||
categoryRules: {
|
||||
categoryName: [
|
||||
{ required: true, message: '分类名称不能为空', trigger: 'blur' },
|
||||
{ min: 2, max: 50, message: '分类名称长度必须在2-50个字符之间', trigger: 'blur' }
|
||||
],
|
||||
feeTpNo: [
|
||||
{ required: true, message: '保证金类型不能为空', trigger: 'change' }
|
||||
]
|
||||
},
|
||||
|
||||
// 费用类型对话框相关
|
||||
typeOpen: false,
|
||||
typeTitle: '',
|
||||
typeEdit: false,
|
||||
typeForm: {
|
||||
id: undefined,
|
||||
feeTypeName: '',
|
||||
categoryId: null,
|
||||
status: '1',
|
||||
defauVerFlag: '0'
|
||||
},
|
||||
typeRules: {
|
||||
feeTypeName: [
|
||||
{ required: true, message: '费用类型名称不能为空', trigger: 'blur' },
|
||||
{ min: 2, max: 50, message: '费用类型名称长度必须在2-50个字符之间', trigger: 'blur' }
|
||||
],
|
||||
status: [
|
||||
{ required: true, message: '状态不能为空', trigger: 'change' }
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.getCategoryList()
|
||||
},
|
||||
methods: {
|
||||
// 获取分类列表
|
||||
getCategoryList() {
|
||||
getAllFeeCategories().then(response => {
|
||||
if (response.code === '000000') {
|
||||
this.categoryList = response.data
|
||||
if (this.categoryList.length > 0 && !this.selectedCategoryId) {
|
||||
this.handleCategorySelect(this.categoryList[0].id.toString())
|
||||
}
|
||||
} else {
|
||||
this.$message.error(response.message || '获取费用分类失败')
|
||||
}
|
||||
})
|
||||
},
|
||||
// 查询分类
|
||||
handleCategorySearch() {
|
||||
if (this.categoryQuery) {
|
||||
const params = { categoryName: this.categoryQuery, pageNum: 1, pageSize: 100 }
|
||||
getFeeCategories(params).then(response => {
|
||||
if (response.code === '000000') {
|
||||
this.categoryList = response.data.list
|
||||
} else {
|
||||
this.$message.error(response.message || '查询失败')
|
||||
}
|
||||
})
|
||||
} else {
|
||||
this.getCategoryList()
|
||||
}
|
||||
},
|
||||
// 选择分类
|
||||
handleCategorySelect(categoryId) {
|
||||
this.selectedCategoryId = categoryId
|
||||
this.selectedCategory = this.categoryList.find(item => item.id.toString() === categoryId)
|
||||
this.queryParams.categoryId = parseInt(categoryId)
|
||||
this.queryParams.pageNum = 1
|
||||
this.getTypeList()
|
||||
},
|
||||
// 获取费用类型列表
|
||||
getTypeList() {
|
||||
this.loading = true
|
||||
getFeeTypes(this.queryParams).then(response => {
|
||||
if (response.code === '000000') {
|
||||
this.typeList = response.data.list
|
||||
this.total = response.data.total
|
||||
} else {
|
||||
this.$message.error(response.message || '查询失败')
|
||||
this.typeList = []
|
||||
this.total = 0
|
||||
}
|
||||
this.loading = false
|
||||
}).catch(() => {
|
||||
this.loading = false
|
||||
})
|
||||
},
|
||||
// 搜索按钮操作
|
||||
handleQuery() {
|
||||
this.queryParams.pageNum = 1
|
||||
this.getTypeList()
|
||||
},
|
||||
// 重置查询操作
|
||||
resetQuery() {
|
||||
this.queryParams.feeTypeName = undefined
|
||||
this.handleQuery()
|
||||
},
|
||||
// 每页条数改变
|
||||
handleSizeChange(size) {
|
||||
this.queryParams.pageSize = size
|
||||
this.getTypeList()
|
||||
},
|
||||
// 当前页改变
|
||||
handleCurrentChange(page) {
|
||||
this.queryParams.pageNum = page
|
||||
this.getTypeList()
|
||||
},
|
||||
|
||||
// 新增分类操作
|
||||
handleAddCategory() {
|
||||
this.categoryForm = {
|
||||
id: undefined,
|
||||
categoryName: undefined,
|
||||
feeTpNo: '0',
|
||||
defauVerFlag: '0'
|
||||
}
|
||||
this.categoryTitle = '新增费用分类'
|
||||
this.categoryEdit = false
|
||||
this.categoryOpen = true
|
||||
this.$nextTick(() => {
|
||||
if (this.$refs.categoryForm) {
|
||||
this.$refs.categoryForm.resetFields()
|
||||
}
|
||||
})
|
||||
},
|
||||
// 编辑分类操作
|
||||
handleEditCategory(row) {
|
||||
getFeeCategory(row.id).then(response => {
|
||||
if (response.code === '000000') {
|
||||
const categoryData = response.data
|
||||
// 确保保证金类型字段是字符串
|
||||
if (categoryData.feeTpNo !== undefined) {
|
||||
categoryData.feeTpNo = categoryData.feeTpNo.toString()
|
||||
}
|
||||
|
||||
this.categoryTitle = '修改费用分类'
|
||||
this.categoryEdit = true
|
||||
|
||||
// 先设置数据,再打开弹窗
|
||||
this.categoryForm = categoryData
|
||||
this.categoryOpen = true
|
||||
} else {
|
||||
this.$message.error(response.message || '获取详情失败')
|
||||
}
|
||||
})
|
||||
},
|
||||
// 提交分类表单
|
||||
submitCategoryForm() {
|
||||
this.$refs.categoryForm.validate(valid => {
|
||||
if (valid) {
|
||||
if (this.categoryForm.id) {
|
||||
updateFeeCategory(this.categoryForm.id, this.categoryForm).then(response => {
|
||||
if (response.code === '000000') {
|
||||
this.$message.success('修改成功')
|
||||
this.categoryOpen = false
|
||||
this.getCategoryList()
|
||||
} else {
|
||||
this.$message.error(response.message || '修改失败')
|
||||
}
|
||||
})
|
||||
} else {
|
||||
addFeeCategory(this.categoryForm).then(response => {
|
||||
if (response.code === '000000') {
|
||||
this.$message.success('新增成功')
|
||||
this.categoryOpen = false
|
||||
this.getCategoryList()
|
||||
} else {
|
||||
this.$message.error(response.message || '新增失败')
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
// 删除分类操作
|
||||
handleDeleteCategory(row) {
|
||||
this.$confirm('是否确认删除该费用分类?', '警告', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
deleteFeeCategory(row.id).then(response => {
|
||||
if (response.code === '000000') {
|
||||
this.$message.success('删除成功')
|
||||
this.getCategoryList()
|
||||
// 如果删除的是当前选中的分类,重置选中状态
|
||||
if (this.selectedCategoryId === row.id.toString()) {
|
||||
this.selectedCategoryId = null
|
||||
this.selectedCategory = null
|
||||
this.typeList = []
|
||||
}
|
||||
} else {
|
||||
this.$message.error(response.message || '删除失败')
|
||||
}
|
||||
})
|
||||
}).catch(() => { })
|
||||
},
|
||||
|
||||
// 新增费用类型按钮操作
|
||||
handleAddType() {
|
||||
this.typeTitle = '新增费用类型'
|
||||
this.typeEdit = false
|
||||
this.typeOpen = true
|
||||
|
||||
// 在下一个事件循环清空表单验证信息
|
||||
this.$nextTick(() => {
|
||||
// 重置表单数据
|
||||
this.typeForm = {
|
||||
id: undefined,
|
||||
feeTypeName: '',
|
||||
categoryId: this.selectedCategoryId ? parseInt(this.selectedCategoryId) : null,
|
||||
status: '1',
|
||||
defauVerFlag: '0'
|
||||
}
|
||||
if (this.$refs.typeForm) {
|
||||
this.$refs.typeForm.resetFields()
|
||||
}
|
||||
})
|
||||
},
|
||||
// 修改费用类型按钮操作
|
||||
handleEditType(row) {
|
||||
getFeeType(row.id).then(response => {
|
||||
if (response.code === '000000') {
|
||||
// 先设置数据
|
||||
const typeData = response.data
|
||||
// 确保所有字段都是字符串类型
|
||||
if (typeData.status !== undefined) {
|
||||
typeData.status = typeData.status.toString()
|
||||
}
|
||||
// 确保 categoryId 是正确类型
|
||||
if (typeData.categoryId !== undefined) {
|
||||
// 不转换为字符串,保持原始类型,确保能和select中的value匹配
|
||||
typeData.categoryId = parseInt(typeData.categoryId)
|
||||
}
|
||||
|
||||
this.typeTitle = '修改费用类型'
|
||||
this.typeEdit = true
|
||||
|
||||
// 先设置完整数据,然后再打开弹窗
|
||||
this.typeForm = typeData
|
||||
this.typeOpen = true
|
||||
} else {
|
||||
this.$message.error(response.message || '获取详情失败')
|
||||
}
|
||||
})
|
||||
},
|
||||
// 提交费用类型表单
|
||||
submitTypeForm() {
|
||||
this.$refs.typeForm.validate(valid => {
|
||||
if (valid) {
|
||||
// 创建提交的数据对象,只包含需要的字段
|
||||
const submitData = {
|
||||
id: this.typeForm.id,
|
||||
feeTypeName: this.typeForm.feeTypeName,
|
||||
categoryId: this.typeForm.categoryId,
|
||||
status: this.typeForm.status
|
||||
}
|
||||
|
||||
if (this.typeForm.id) {
|
||||
updateFeeType(this.typeForm.id, submitData).then(response => {
|
||||
if (response.code === '000000') {
|
||||
this.$message.success('修改成功')
|
||||
this.typeOpen = false
|
||||
this.getTypeList()
|
||||
} else {
|
||||
this.$message.error(response.message || '修改失败')
|
||||
}
|
||||
})
|
||||
} else {
|
||||
addFeeType(submitData).then(response => {
|
||||
if (response.code === '000000') {
|
||||
this.$message.success('新增成功')
|
||||
this.typeOpen = false
|
||||
this.getTypeList()
|
||||
} else {
|
||||
this.$message.error(response.message || '新增失败')
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
// 删除费用类型按钮操作
|
||||
handleDeleteType(row) {
|
||||
this.$confirm('是否确认删除该费用类型?', '警告', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
deleteFeeType(row.id).then(response => {
|
||||
if (response.code === '000000') {
|
||||
this.$message.success('删除成功')
|
||||
this.getTypeList()
|
||||
} else {
|
||||
this.$message.error(response.message || '删除失败')
|
||||
}
|
||||
})
|
||||
}).catch(() => { })
|
||||
},
|
||||
// 获取费用类型对应的分类名称
|
||||
getCurrentTypeCategoryName() {
|
||||
// 如果找不到分类,尝试从后端重新获取
|
||||
if (this.typeForm.categoryId) {
|
||||
const category = this.categoryList.find(item => item.id.toString() === this.typeForm.categoryId.toString())
|
||||
if (category) {
|
||||
return category.categoryName
|
||||
} else {
|
||||
// 如果typeForm中有categoryName,直接使用
|
||||
if (this.typeForm.categoryName) {
|
||||
return this.typeForm.categoryName
|
||||
}
|
||||
}
|
||||
}
|
||||
return ''
|
||||
},
|
||||
// 加载完整的分类列表
|
||||
loadFullCategoryList() {
|
||||
getAllFeeCategories().then(response => {
|
||||
if (response.code === '000000') {
|
||||
this.categoryList = response.data
|
||||
}
|
||||
})
|
||||
},
|
||||
// 获取分类名称
|
||||
getCategoryNameById(id) {
|
||||
const category = this.categoryList.find(item => item.id.toString() === id.toString())
|
||||
if (category) {
|
||||
return category.categoryName
|
||||
}
|
||||
return ''
|
||||
},
|
||||
// 处理费用类型对话框打开事件
|
||||
onTypeDialogOpen() {
|
||||
// 确保加载完整的分类列表
|
||||
this.loadFullCategoryList()
|
||||
|
||||
// 如果是新增且当前有选中的分类,设置默认分类
|
||||
if (!this.typeForm.id && this.selectedCategoryId) {
|
||||
this.typeForm.categoryId = parseInt(this.selectedCategoryId)
|
||||
this.$nextTick(() => {
|
||||
if (this.$refs.typeForm) {
|
||||
this.$refs.typeForm.validateField('categoryId')
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
// 处理费用分类对话框打开事件
|
||||
onCategoryDialogOpen() {
|
||||
// 确保加载完整的分类列表
|
||||
this.loadFullCategoryList()
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.app-container {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.category-container {
|
||||
background-color: #fff;
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.1);
|
||||
height: calc(100vh - 140px);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.category-header {
|
||||
padding: 15px;
|
||||
border-bottom: 1px solid #eee;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.category-header h3 {
|
||||
margin: 0;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.category-search {
|
||||
padding: 10px 15px;
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
|
||||
.category-menu {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
border-right: none;
|
||||
}
|
||||
|
||||
.category-item {
|
||||
position: relative;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.category-actions {
|
||||
display: none;
|
||||
position: absolute;
|
||||
right: 10px;
|
||||
}
|
||||
|
||||
.category-item:hover .category-actions {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.fee-type-container {
|
||||
background-color: #fff;
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.1);
|
||||
padding: 15px;
|
||||
min-height: calc(100vh - 140px);
|
||||
}
|
||||
|
||||
.fee-type-header {
|
||||
margin-bottom: 15px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.header-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.header-title h3 {
|
||||
margin: 0;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.fee-type-search {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
/* 确保表格不会超出容器 */
|
||||
.el-table {
|
||||
width: 100%;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
/* 分页组件样式 */
|
||||
.el-pagination {
|
||||
padding: 10px 0;
|
||||
text-align: right;
|
||||
}
|
||||
</style>
|
@ -55,12 +55,36 @@
|
||||
icon="el-icon-plus"
|
||||
size="mini"
|
||||
@click="handleAdd">新增楼宇</el-button>
|
||||
<el-popover
|
||||
|
||||
</div>
|
||||
|
||||
<!-- 搜索表单 -->
|
||||
<el-form :inline="true" :model="queryParams" class="demo-form-inline">
|
||||
<el-form-item label="所属项目">
|
||||
<el-select v-model="queryParams.projectId" placeholder="请选择所属项目" clearable size="small">
|
||||
<el-option
|
||||
v-for="item in projectOptions"
|
||||
:key="item.id"
|
||||
:label="item.name"
|
||||
:value="item.id">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="楼宇名称">
|
||||
<el-input v-model="queryParams.buildingName" placeholder="请输入楼宇名称" clearable size="small" />
|
||||
</el-form-item>
|
||||
<el-form-item label="楼宇编号">
|
||||
<el-input v-model="queryParams.buildingCode" placeholder="请输入楼宇编号" clearable size="small" />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
|
||||
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
|
||||
<el-popover
|
||||
placement="bottom"
|
||||
width="200"
|
||||
trigger="click"
|
||||
v-model="columnFilterVisible"
|
||||
style="float: right; margin: 3px 10px;">
|
||||
style="float: right; margin: 0 0 0 10px;">
|
||||
<el-checkbox-group v-model="selectedColumns">
|
||||
<el-checkbox label="all" @change="handleCheckAllChange">全部</el-checkbox>
|
||||
<el-divider></el-divider>
|
||||
@ -87,31 +111,8 @@
|
||||
<el-checkbox label="availableRentArea">待租面积(m²)</el-checkbox>
|
||||
<el-checkbox label="availableRoomCount">待租房间数</el-checkbox>
|
||||
</el-checkbox-group>
|
||||
<i slot="reference" class="el-icon-s-operation" style="cursor: pointer; font-size: 16px; color: #409EFF;"></i>
|
||||
<el-button slot="reference" type="primary" size="mini" icon="el-icon-s-operation">列显示</el-button>
|
||||
</el-popover>
|
||||
</div>
|
||||
|
||||
<!-- 搜索表单 -->
|
||||
<el-form :inline="true" :model="queryParams" class="demo-form-inline">
|
||||
<el-form-item label="所属项目">
|
||||
<el-select v-model="queryParams.projectId" placeholder="请选择所属项目" clearable size="small">
|
||||
<el-option
|
||||
v-for="item in projectOptions"
|
||||
:key="item.id"
|
||||
:label="item.name"
|
||||
:value="item.id">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="楼宇名称">
|
||||
<el-input v-model="queryParams.buildingName" placeholder="请输入楼宇名称" clearable size="small" />
|
||||
</el-form-item>
|
||||
<el-form-item label="楼宇编号">
|
||||
<el-input v-model="queryParams.buildingCode" placeholder="请输入楼宇编号" clearable size="small" />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
|
||||
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
@ -287,7 +288,7 @@
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="选择账户" prop="accountId">
|
||||
<el-select v-model="form.accountId" placeholder="请选择默认收支账户(非必填)" clearable @change="handleAccountChange">
|
||||
<el-select v-model="form.accountId" placeholder="请选择默认收支账户(必填)" clearable @change="handleAccountChange">
|
||||
<el-option
|
||||
v-for="item in accountOptions"
|
||||
:key="item.id"
|
||||
@ -791,7 +792,9 @@ export default {
|
||||
parkingArea: [
|
||||
{ type: 'number', message: '车位面积必须为数字', trigger: 'blur' }
|
||||
],
|
||||
accountId: []
|
||||
accountId: [
|
||||
{ required: true, message: '请选择默认收支账户', trigger: 'blur' },
|
||||
]
|
||||
},
|
||||
// 楼层表单校验
|
||||
floorRules: {
|
||||
|
Loading…
x
Reference in New Issue
Block a user