vue3中,el-table级联表格——default-expand-all & row-key & show-overflow-tooltip & 树状表格计算总价合计总计
效果
代码
1、静态页面
<!--
@Description 项目管理 - 预算编制
@author wdd
@date 2023/11/11
-->
<template>
<div id="budgetInfo">
<centerHead title="预算编制"></centerHead>
<div class="content">
<div class="title">
<el-button type="primary" @click="onSave">保存</el-button>
<el-button type="primary" @click="onBack">返回</el-button>
</div>
<el-table :data="numList" style="width: 100%; margin-bottom: 20px" row-key="id" border default-expand-all>
<el-table-column label="费用科目" show-overflow-tooltip #default="scope">
{{ scope.row.name }}
</el-table-column>
<el-table-column align="center" label="预算信息(元)" show-overflow-tooltip #default="scope">
<span v-if="scope.row.children.length == 0 && scope.row.grade != '0'">
<el-input v-model="scope.row.value" @input="onNumber(scope.row)"></el-input>
</span>
<span v-else>
{{ scope.row.value }}
</span>
</el-table-column>
</el-table>
</div>
</div>
</template>
<script setup>
import { ref, inject } from 'vue';
import { post } from "@/utils/path";
import { useRouter } from "vue-router";
const router = useRouter();
const numList = ref([
{
id: 1,
name: '(一)直接费',
value: 0,
grade: '1',
children: [
{
id: 2,
name: '1. 人工费',
value: 0,
grade: '2',
children: []
},
{
id: 3,
name: '2. 设备服务费',
value: 0,
grade: '2',
children: [
{
id: 4,
name: '(1)仪器设备使用费',
value: 0,
grade: '3',
children: []
},
{
id: 5,
name: '(2)软件使用费',
value: 0,
grade: '3',
children: []
},
]
},
{
id: 6,
name: '3. 业务费',
value: 0,
grade: '2',
children: [
{
id: 7,
name: '(1)材料费',
value: 0,
grade: '3',
children: []
},
{
id: 8,
name: '(2)资料、印刷及知识产权费',
value: 0,
grade: '3',
children: []
},
{
id: 9,
name: '(3)会议、差旅及合作交流费',
value: 0,
grade: '3',
children: []
}
]
},
{
id: 10,
name: '4. 场地使用费',
value: 0,
grade: '2',
children: [
{
id: 11,
name: '(1)场地物业费',
value: 0,
grade: '3',
children: []
},
{
id: 12,
name: '(2)场地使用租金',
value: 0,
grade: '3',
children: []
}
]
},
{
id: 13,
name: '5. 专家咨询费',
value: 0,
grade: '2',
children: []
}
]
},
{
id: 14,
name: '(二)间接费',
value: 0,
grade: '1',
children: []
},
{
id: 15,
name: '(三)外委支出费',
value: 0,
grade: '1',
children: [
{
id: 16,
name: '1. 外委研究支出费',
value: 0,
grade: '2',
children: []
},
{
id: 17,
name: '2. 仪器设备租赁费',
value: 0,
grade: '2',
children: []
},
{
id: 18,
name: '3. 外协测试试验与加工费',
value: 0,
grade: '2',
children: []
},
]
},
{
id: 19,
name: '(四)税金',
value: 0,
grade: '1',
children: []
},
{
id: 20,
name: '总计',
value: 0,
grade: '0',
children: []
}
])
const isValue = ref(false)
const message = inject('message')
const verification = inject('verification')
const onNumber = (val) => {
var myreg = /(^[0]{1}$)|(^[1-9]{1}[0-9]{0,8}$)|(^[0-9]{1,9}[\.]{1}[0-9]{0,2}$)/;
if (!myreg.test(val.value)) {
isValue.value = true
message.error('预算信息(元)只能输入0~999999999之间的正整数(保留两位小数)')
} else {
isValue.value = false
let temp = [], arr = [], totalValue = 0
for (let i = 0; i < numList.value.length; i++) {
temp = numList.value[i].children
if (temp.length > 0) {
numList.value[i].value = 0
for (let j = 0; j < temp.length; j++) {
arr = temp[j].children
if (arr.length > 0) {
temp[j].value = 0
for (let k = 0; k < arr.length; k++) {
if (temp[j].grade == '2') {
temp[j].value += Number(arr[k].value)
}
}
}
if (numList.value[i].grade == '1') {
numList.value[i].value += Number(temp[j].value)
}
}
}
if (i != numList.value.length - 1) {
totalValue += Number(numList.value[i].value)
}
}
numList.value[numList.value.length - 1].value = totalValue
}
}
const onSave = () => {
if (!isValue.value) {
} else {
message.error('预算信息(元)只能输入0~999999999之间的正整数(保留两位小数)')
}
}
// 返回
const onBack = () => {
router.back()
}
</script>
<style lang="scss">
#budgetInfo {
width: 100%;
.content {
width: 50%;
margin: 10px auto;
.title {
width: 100%;
text-align: right;
margin-bottom: 10px;
}
.el-input__inner {
text-align: center;
}
}
}
</style>
2、联调静态页面
<!--
@Description 项目管理 - 预算编制
@author wdd
@date 2023/11/11
-->
<template>
<div id="budgetInfo">
<centerHead title="预算编制"></centerHead>
<div class="content">
<div class="title">
<el-button type="primary" @click="onSave">保存</el-button>
<el-button type="primary" @click="onBack">返回</el-button>
</div>
<el-table :data="numList" style="width: 100%; margin-bottom: 20px" row-key="id" border default-expand-all>
<el-table-column label="费用科目" show-overflow-tooltip #default="scope">
{{ scope.row.name }}
</el-table-column>
<el-table-column align="center" label="预算信息(元)" show-overflow-tooltip #default="scope">
<span v-if="scope.row.children.length == 0 && scope.row.grade != '0'">
<el-input v-model="scope.row.value" @input="onNumber(scope.row)"></el-input>
</span>
<span v-else>
{{ scope.row.value }}
</span>
</el-table-column>
</el-table>
</div>
</div>
</template>
<script setup>
import { ref, inject, onMounted } from 'vue';
import { post } from "@/utils/path";
import { useRoute, useRouter } from "vue-router";
const route = useRoute()
const router = useRouter();
const numList = ref([])
const isValue = ref(false)
const message = inject('message')
const verification = inject('verification')
const constant = inject('constant')
const publicId = ref('')
onMounted(() => {
if (route.query.id) {
getList()
}
})
const getList = () => {
post(constant.ieopMtgAchieve + '/approval/manager/mould/detail', {
approvalId: route.query.id
}).then((res) => {
if (res.data.code = '200') {
publicId.value = res.data.data.approvalId
numList.value = res.data.data.children;
}
})
}
// 计算项目费用
const onNumber = (val) => {
var myreg = /(^[0]{1}$)|(^[1-9]{1}[0-9]{0,8}$)|(^[0-9]{1,9}[\.]{1}[0-9]{0,2}$)/;
if (!myreg.test(val.value)) {
isValue.value = true
message.error('预算信息(元)只能输入0~999999999之间的正整数(保留两位小数)')
} else {
isValue.value = false
let temp = [], arr = [], totalValue = 0
for (let i = 0; i < numList.value.length; i++) {
temp = numList.value[i].children
if (temp.length > 0) {
numList.value[i].value = 0
for (let j = 0; j < temp.length; j++) {
arr = temp[j].children
if (arr.length > 0) {
temp[j].value = 0
for (let k = 0; k < arr.length; k++) {
if (temp[j].grade == '2') {
temp[j].value += Number(arr[k].value)
}
}
}
if (numList.value[i].grade == '1') {
numList.value[i].value += Number(temp[j].value)
}
}
}
if (i != numList.value.length - 1) {
totalValue += Number(numList.value[i].value)
}
}
numList.value[numList.value.length - 1].value = totalValue
}
}
const onSave = () => {
if (!isValue.value) {
post(constant.ieopMtgAchieve + '/approval/manager/mould/edit', {
approvalId: publicId.value,
children: numList.value
}).then((res) => {
if (res.data.code == '200') {
message.success('操作成功!');
router.back()
} else {
message.error(res.data.message);
}
})
} else {
message.error('预算信息(元)只能输入0~999999999之间的正整数(保留两位小数)')
}
}
// 返回
const onBack = () => {
router.back()
}
</script>
<style lang="scss">
#budgetInfo {
width: 100%;
.el-table__expand-icon,
.el-table__placeholder {
display: none;
}
.content {
width: 50%;
margin: 10px auto;
.title {
width: 100%;
text-align: right;
margin-bottom: 10px;
}
.el-input__inner {
text-align: center;
}
}
}
</style>
src\utils\path.js
import request from "./request";
import { getApiUrl } from "@/utils/tool";
const baseUrl = getApiUrl();
// 通用请求
export function post(url, params = {}){
const data = request.post(baseUrl + url, params);
// const data = request.post(url, params);
return data
}
export function get(url, params = {}){
const data = request.get(baseUrl + url);
return data
}
src\utils\tool.js
export function getApiUrl(v) {
return process.env.VUE_APP_API_HOST
}
.env.dev
VUE_APP_API_HOST = '/gp'
VUE_APP_IMAGE_CM = '/cm'
VUE_APP_IMAGE_HOST = 'http://27.196.104.87:18080'
vue.config.js
const { defineConfig } = require('@vue/cli-service')
const AutoImport = require('unplugin-auto-import/webpack')
const Components = require('unplugin-vue-components/webpack')
const { ElementPlusResolver } = require('unplugin-vue-components/resolvers')
module.exports = defineConfig({
transpileDependencies: true,
lintOnSave: false,
devServer: {
proxy: {
// '/gp/ieop-pri-property': {
// target: 'http://27.196.104.87:18080',
// changeOrigin: true,
// pathRewrite: {
// '^/gp': '/'
// }
// },
// '/gp/yundu-file-wjm': {
// target: 'http://27.196.104.87:18080',
// changeOrigin: true,
// pathRewrite: {
// '^/gp': '/'
// }
// },
'/gp': {
target: 'http://27.196.111.15:18080', // 后端接口地址
changeOrigin: true,
pathRewrite: {
'^/gp': '/'
}
},
// '/img': {
// target: 'http://192.168.67.86:9595',
// changeOrigin: true,
// pathRewrite: {
// '^/img': '/'
// }
// },
},
port: 9000,
// host:'27.196.104.110',
host:'0.0.0.0',
open:true
},
// configureWebpack: {
// plugins: [
// AutoImport({
// resolvers: [ElementPlusResolver()]
// }),
// Components({
// resolvers: [ElementPlusResolver()]
// })
// ]
// },
})
3、css原生写法-静态页面
<!--
@Description 项目管理 - 预算编制
@author wdd
@date 2023/11/11
-->
<template>
<centerHead title="预算编制"></centerHead>
<div class="content">
<div class="title">
<el-button type="primary" v-if="see" @click="save">保存</el-button>
<el-button type="primary" v-if="!see" @click="edit">编辑</el-button>
<el-button type="primary" @click="examine">审核</el-button>
</div>
<div class="name-box" style="font-weight:700;text-align: center;font-size:16px">费用科目</div>
<div class="val-box" style="font-weight:700;text-align: center;font-size:16px">预算信息(万元)</div>
<div v-for="item in numList" :key="item.id">
<div class="name-box"><span
:style="styleList.find(el=>el==item.name)? styleObj:classObj">{{item.name}}</span> </div>
<div class="val-box">
<span v-if="showList.find(el=>el ==item.name)">{{item.value}}</span>
<span v-if="!see && !showList.find(el=>el ==item.name)">{{item.value}}</span>
<el-input v-if="see && !showList.find(el=>el ==item.name)" v-model="item.value" @blur="ChangeVal">
</el-input>
</div>
</div>
</div>
</template>
<script lang="ts" setup>
import { ref, } from 'vue';
const numList = ref([
{
id: 1,
name: '(一)直接费',
value: 0,
},
{
id: 2,
name: '1. 人工费',
value: 0,
},
{
id: 3,
name: '2. 设备服务费',
value: 0,
},
{
id: 4,
name: '(1)仪器设备使用费',
value: 0,
},
{
id: 5,
name: '(2)软件使用费',
value: 0,
},
{
id: 6,
name: '3. 业务费',
value: 0,
},
{
id: 7,
name: '(1)材料费',
value: 0,
},
{
id: 8,
name: '(2)资料、印刷及知识产权费',
value: 0,
},
{
id: 9,
name: '(3)会议、差旅及合作交流费',
value: 0,
},
{
id: 10,
name: '4. 场地使用费',
value: 0,
},
{
id: 11,
name: '(1)场地物业费',
value: 0,
},
{
id: 12,
name: '(2)场地使用租金',
value: 0,
},
{
id: 13,
name: '5. 专家咨询费',
value: 0,
},
{
id: 14,
name: '(二)间接费',
value: 0,
},
{
id: 15,
name: '(三)外委支出费',
value: 0,
},
{
id: 16,
name: '1. 外委研究支出费',
value: 0,
},
{
id: 17,
name: '2. 仪器设备租赁费',
value: 0,
},
{
id: 18,
name: '3. 外协测试试验与加工费',
value: 0,
},
{
id: 19,
name: '(四)税金',
value: 0,
},
{
id: 20,
name: '合计',
value: 0,
},
])
const styleObj = ref({ fontWeight: 700, fontSize: '16px', lineHeight: '38px' })
const classObj = ref({})
const see = ref(true)
const styleList = ref(['(一)直接费', '(二)间接费', '(三)外委支出费', '(四)税金', '合计'])
const showList = ref(['(一)直接费', '2. 设备服务费', '3. 业务费', '4. 场地使用费', '(三)外委支出费', '合计'])
const amount = () => {
numList.value[0].value = Number(numList.value[1].value) + Number(numList.value[2].value) + Number(numList.value[5].value) + Number(numList.value[9].value) + Number(numList.value[12].value)
numList.value[19].value = Number(numList.value[0].value) + Number(numList.value[13].value) + Number(numList.value[14].value) + Number(numList.value[18].value)
}
const ChangeVal = () => {
numList.value.forEach((el, index) => {
if (index == 2) {
el.value = Number(numList.value[3].value) + Number(numList.value[4].value)
}
if (index == 5) {
el.value = Number(numList.value[6].value) + Number(numList.value[7].value) + Number(numList.value[8].value)
}
if (index == 9) {
el.value = Number(numList.value[10].value) + Number(numList.value[11].value)
}
if (index == 14) {
el.value = Number(numList.value[15].value) + Number(numList.value[16].value) + Number(numList.value[17].value)
}
amount()
})
}
const save = () => {
see.value = false
}
const edit = () => {
see.value = true
}
const examine = () => { }
</script>
<style lang="scss" scoped>
.content {
margin: 70px 20px;
position: relative;
.title {
position: absolute;
top: -44px;
left: 406px;
}
.name-box {
display: inline-block;
width: 260px;
height: 40px;
line-height: 40px;
text-align: left;
padding-left: 10px;
border: 1px solid #666;
margin: 0 -1px -1px 0;
font-size: 14px;
}
.val-box {
display: inline-block;
width: 220px;
border: 1px solid #666;
margin: 0 0 -1px 0px;
height: 40px;
font-size: 14px;
text-align: center;
line-height: 40px;
.el-input {
width: 160px;
}
}
}
</style>