第一种
<template>
<div class="time_table">
<div style="margin-bottom: 10px">
<el-button @click="addRowFn">新增</el-button>
</div>
<el-form ref="costForm" :model="formData">
<el-table :data="formData.tableData" style="width: 100%" :value="tableData">
<el-table-column prop="productId" label="所属产品(集成选非产线)" type="productId">
<template #header>
<span style="color: red; margin-right: 4px">*</span>
<span>所属产品(集成选非产线)</span>
</template>
<template slot-scope="scope">
<div v-if="!selectSure">
<div style="display: flex; justify-content: space-between">
<div> {{ scope.row.productId }} </div>
<div v-if="scope.$index != cellIndexInput" @click="gropeFn(scope, scope.row)">
<el-icon class="el-icon-search"></el-icon>
</div>
</div>
</div>
<div v-if="scope.row.productId == '' || scope.row.productId == null">
<div class="titelno-style">
{{ `请填写所属产品` }}
</div>
</div>
<div v-if="scope.$index == cellIndexInput && tableId == scope.row.id" style="display: flex; justify-content: space-between">
<div class="about">
<el-select
v-model="selectValue"
placeholder="请选择"
:popper-append-to-body="false"
@remove-tag="removetag"
@clear="clearall"
clearable
filterable
collapse-tags
ref="select"
@change="changelabel"
>
<el-input style="width: 260px; margin: 10px" placeholder="输入关键字进行过滤" v-model="filterText"> </el-input>
<el-option :value="selectTree" class="setstyle" disabled>
<el-tree
:filter-node-method="filterNode"
:data="list"
@node-click="handleNodeClick"
:props="defaultProps"
ref="tree"
node-key="id"
default-expand-all
highlight-current
></el-tree>
</el-option>
</el-select>
</div>
</div>
<div v-if="scope.$index !== cellIndexInput && selectSure">
<div style="display: flex; justify-content: space-between">
<div> {{ scope.row.productId }} </div>
<div v-if="scope.$index != cellIndexInput" @click="gropeFn(scope, scope.row)"> <el-icon class="el-icon-search"></el-icon> </div>
</div>
</div>
</template>
</el-table-column>
<el-table-column prop="productMoney" label="产品金额" type="productMoney">
<template #header>
<span style="color: red; margin-right: 4px">*</span>
<span>产品金额</span>
</template>
<template slot-scope="scope">
<div v-if="!numberSure">
<div style="display: flex; justify-content: space-between">
<div> {{ scope.row.productMoney | currencyFormat }} </div>
<div v-if="scope.$index != cellIndexnumber" @click="gropesFn(scope, scope.row, scope.row.productMoney)">
<el-icon class="el-icon-search"></el-icon>
</div>
</div>
</div>
<div v-if="scope.row.productMoney == '' || scope.row.productMoney == null">
<div class="titelno-style">
{{ `请填写所属金额` }}
</div>
</div>
<div v-if="scope.$index == cellIndexnumber && tablelistId == scope.row.id" style="display: flex; justify-content: space-between">
<inputNumberA
:values="values"
:newDates="newDates"
:rowinputNumber="rowinputNumber"
@close="closeinputNumberFn"
@change="changeinputNumberFn"
></inputNumberA>
<!-- <el-form-item :prop="`tableData.${scope.$index}.productMoney`" :rules="[{ required: true, message: '请输入' }]">
<el-input v-model.trim="scope.row.productMoney" @keyup.native="handleNumberType" style="width: 250px" placeholder="请输入"></el-input>
</el-form-item> -->
</div>
<div style="display: flex; justify-content: space-between" v-if="scope.$index !== cellIndexnumber && numberSure">
<div>$ {{ scope.row.productMoney | currencyFormat }} </div>
<div @click="gropesFn(scope, scope.row)">
<el-icon class="el-icon-search"></el-icon>
</div>
</div>
</template>
</el-table-column>
<el-table-column prop="answer" label="操作">
<template slot-scope="scope">
<el-button @click="delOptionFn(scope.$index, tableData)">删除</el-button>
</template>
</el-table-column>
</el-table>
</el-form>
</div>
</template>
<script>
import inputNumberA from './inputNumber.vue'
function filterTreeData(treeData) {
return treeData.filter((item) => {
if (isNotEmpty(item.children)) {
item.disabled = true
item.children = filterTreeData(item.children)
}
return item
})
}
function isNotEmpty(arr) {
return arr && Array.isArray(arr) && arr.length > 0
}
function addToTreeFn(treeData, type1) {
treeData.forEach((node) => {
if (node.children && node.children.length > 0) {
addToTreeFn(node.children, type1)
} else {
node.sos = type1
}
})
}
export default {
name: 'timeTable',
props: {
value: {
type: Array,
default: () => [{}],
},
},
components: {
inputNumberA,
},
data() {
return {
dialogVisible: true,
selectValue: '',
selectTree: [],
expandedList: [],
filterText: '', //input搜索
rowinputNumber: {},
list: [],
defaultProps: {
children: 'children',
label: 'label',
},
nameValue: '',
defaultValue: [], //tree唯一的id
values: '',
newDates: {},
formData: {
// tableData: [...this.value],
tableData: [],
},
tableId: '',
cellIndexInput: null,
cellIndexnumber: null,
prodectmark: null,
options: [], //节点下拉框数据
selectSure: false,
numberSure: false,
tablelistId: '',
//验证规则
rules: {
// productId: [
// {
// required: true,
// message: '请输入姓名',
// trigger: ['blur', 'change'],
// },
// ],
sex: [
{
required: true,
message: '请选择性别',
trigger: ['blur', 'change'],
},
],
},
tableData: [],
}
},
watch: {
tableData: {
handler(newval) {
this.$emit('input', newval)
},
deep: true,
},
selectValue(newValue) {
this.changelabel(newValue)
},
// 搜索
filterText(val) {
this.$refs.tree.filter(val)
},
value: {
handler(newval) {
this.handleFn(newval)
console.log(newval, 'newval_____')
},
deep: true,
},
},
created() {
console.log(this.value, 'yyiyyyyyyyyyyyyy')
// this.fetchEntryTimeDic()
// this.listFn()
this.treeFn()
},
methods: {
handleFn(val) {
// this.formData.tableData = val
// const v = val
// const vo = v.map((item) => {
// return { productId: item.productName, productMoney: item.productMoney, productName: item.productId }
// })
this.formData.tableData = val
},
changelabel(val) {
console.log('changelabel----', val)
},
// 下拉框移除
removetag() {
this.$refs.tree.setCheckedKeys([])
},
// 可清空的单选模式下用户点击清空按钮时触发
clearall() {
this.selectTree = []
this.$nextTick(() => {
this.$refs.tree.setCheckedNodes([])
})
},
handleNodeClick(data, node) {
let arr = []
if (data.sos === '1') {
arr.push(data)
this.selectTree = arr[0]
this.selectValue = this.selectTree.label
this.$nextTick(() => {
if (this.selectValue !== '') {
this.$emit('treechagelist', this.selectTree, this.row1)
this.cellIndexInput = null
}
})
}
},
// 模糊查询(搜索过滤),实质为筛选出树形控件中符合输入条件的选项,过滤掉其他选项
filterNode(value, data) {
console.log(value, 'kkkkkkkkkkkkkkkk')
if (!value) return true
let filterRes = data.label.indexOf(value) !== -1
return filterRes
},
treeFn() {
// 接口
treeAPI().then((res) => {
this.list = res
this.selectValue = ''
addToTreeFn(this.list, '1')
filterTreeData(this.list)
})
},
gropeFn(v, row) {
console.log(row, v, 'gropeFn-----------', row.productId)
this.selectValue = row.productId
console.log(this.selectValue, ' this.selectValue ')
this.selectSure = true
this.tableId = row.id
this.cellIndexInput = v.$index
this.rows = row
this.row1 = v
console.log(row.id, ' row.id')
},
gropesFn(v, row, i) {
console.log(v, row, 'gropesFn', i)
this.numberSure = true
this.tablelistId = row.id
this.cellIndexnumber = v.$index
this.values = i
this.newDates = v
},
//表格的单元格单机 ---> 将每行的isEdit改成true
rowClickFn(row, column, event) {
this.$set(row, 'isEdit', true)
},
// 新增
addRowFn() {
this.formData.tableData.unshift({
productMoney: '',
productId: '',
productName: '',
})
this.selectValue = ''
},
// 下面的数据保存
addFn(id, tableData) {
tableData.orderNum = Number(tableData.orderNum)
// 存起来数据
localStorage.setItem('tableData', JSON.stringify(tableData)),
// 取出来
localStorage.getItem('tableData')
this.tableData = JSON.parse(localStorage.getItem('tableData'))
this.tableData.forEach((item) => {
item.orderNum = Number(item.orderNum)
})
if (!tableData[id].productMoney) {
return this.$message.error('请您填写描述信息哦~')
}
},
delOptionFn(index) {
this.formData.tableData.splice(index, 1)
},
async upOption(row) {
console.log(row)
},
closeinputNumberFn() {
this.handleChange()
},
handleChange() {
this.inputNumberSure = false
this.cellIndexNumber = null
},
changeinputNumberFn(val, v, row) {
this.$emit('inputnumberchagelist', Number(val), row)
this.cellIndexnumber = null
},
handleClose() {
this.dialogVisible = false
},
},
}
</script>
<style lang="scss" scoped>
/* ::v-deep.el-table--fit {
border-right: 0;
border-bottom: 0;
margin-left: -55px;
} */
.titelno-style {
color: red;
font-size: 8px;
}
.setstyle {
min-height: 200px;
padding: 0 !important;
margin: 0;
overflow: auto;
cursor: default !important;
}
</style>
inputNumber.vue文件
<template>
<div class="cell-input-number">
<input type="number" class="cell-input-inner" ref="inputEl" size="mini" v-model.trim="newValue" @blur="handleBlur" :min="mins" :max="maxs" />
</div>
</template>
<script>
export default {
props: {
values: {
type: [String, Number],
required: false,
default: '',
},
rowinputNumber: {
type: Object,
default: () => {},
},
newDates: {
type: Object,
default: () => {},
},
},
data() {
return {
newValue: '',
currentHeight: this.height,
mins: 0,
maxs: 0,
}
},
created() {
console.log(this.rowinputNumber, 'rowinputNumberrowinputNumber')
},
mounted() {
this.newValue = this.values
// 用户双击后,让其处于获取焦点的状态
this.$refs.inputEl.focus()
},
methods: {
formatInput(val) {
console.log(val, 'hhhhhhhhhhhhhhhhhhhh')
},
parseInput() {},
checknum() {},
numberChangeFn(event) {
console.log(event, 'yyyyyyy')
},
handleInput(event) {
console.log(event, 'event')
const { values, selectionStart, selectionEnd } = event.target
// 只保留数字和小数点
let pureValue = values.replace(/[^\d.]/g, '')
// 如果小数点超过一个,只保留第一个
const idx = pureValue.indexOf('.')
if (idx !== -1 && pureValue.indexOf('.', idx + 1) !== -1) {
pureValue = pureValue.slice(0, idx + 1) + pureValue.slice(idx + 1).replace(/\./g, '')
}
// 如果小数点在开头,前面加 0
const isBeginningWithDot = pureValue[0] === '.'
let newValue = isBeginningWithDot ? `0${pureValue}` : pureValue
// 根据光标位置修改输入值
const num = Number(newValue)
if (num > 0 && selectionStart !== selectionEnd) {
const start = Math.max(selectionStart, newValue.indexOf(num))
const end = Math.min(selectionEnd, newValue.indexOf(num) + String(num).length)
newValue = newValue.slice(0, start) + num + newValue.slice(end, newValue.length)
}
// 更新输入框中的值和组件中的值
event.target.values = newValue
this.newValue = newValue
},
handleBlur() {
if (this.newValue !== this.values) {
if (this.newValue === '') {
this.newValue = 0
}
this.$emit('change', this.newValue, this.rowinputNumber, this.newDates)
}
this.$emit('close')
},
},
}
</script>
<style lang="scss">
.cell-input-number {
width: 100%;
height: 100%;
background-color: #fff;
font-size: inherit;
box-shadow: 0 0 24px #0000002e;
.cell-input-inner {
margin: 0;
padding: 2px 8px;
font-size: inherit;
border: none;
outline: none;
width: 100%;
height: 100%;
background-color: transparent;
line-height: 23px;
resize: none;
overflow: hidden;
white-space: pre-wrap;
word-break: break-all;
font-family: inherit;
box-sizing: border-box;
}
}
</style>
父页面
拿到数据传递给子去,然后进项本地储存 ,监听
inputnumberchagelistFn(i, row) {
this.$set(this.value[row.$index], 'productMoney', i)
localStorage.setItem('mutate-1', JSON.stringify(this.value))
},
treechagelistFn(i, row) {
this.$set(this.value[row.$index], 'productId', i.label)
localStorage.setItem('mutate-1', JSON.stringify(this.value))
this.$set(this.value[row.$index], 'id', i.id)
},
第二种写法
<template>
<div class="time_table">
<el-card style="margin-bottom: 20px">
<div slot="header" class="clearfix">
<el-button type="text" @click="newlyAddedFn">新增</el-button>
</div>
<el-table border :data="tableData" style="width: 100%" :value="tableData">
<el-table-column label="序号" width="100px" align="center">
<template slot-scope="scope">
{{ scope.$index + 1 }}
</template>
</el-table-column>
<el-table-column prop="productId" label="xxxxx">
<template slot-scope="scope">
<el-select
:filter-method="filterMethod"
filterable
:ref="'productId' + scope.$index"
v-model="tableData[scope.$index]['productId']"
placeholder="请选择文档类别"
clearable
>
<el-option :value="tableData[scope.$index]['productId']" style="height: auto">
<el-tree
:filter-node-method="filterNode"
:ref="'categoryNameTree' + scope.$index"
:data="data"
node-key="id"
:props="defaultProps"
@node-click="getTypeList(scope.$index, scope)"
:expand-on-click-node="false"
default-expand-all
>
<span slot-scope="{ node }">{{ node.label }}</span>
</el-tree>
</el-option>
</el-select>
<div style="color: red; font-size: 12px" v-if="JSON.stringify(scope.row) == '{}' || scope.row.productId == ''"> 请选择所属产品(集成选非产线) </div>
</template>
</el-table-column>
<el-table-column prop="productMoney" label="产品金额" :sortable="true">
<template slot-scope="scope">
<el-input type="number" v-model="scope.row.productMoney" placeholder="请输入数字"> </el-input>
<div
style="color: red; font-size: 12px"
v-if="JSON.stringify(scope.row) == '{}' || scope.row.productMoney == null || scope.row.productMoney == 0 || scope.row.productMoney == ''"
>
请输入产品金额
</div>
</template>
</el-table-column>
<el-table-column prop="answer" label="操作" width="100px">
<template slot-scope="{ row }">
<el-button type="text" @click="delOption(row, tableData)">
<span style="color: red">删除</span>
</el-button>
</template>
</el-table-column>
</el-table>
<div class="money-style">
<div class="amount-to-style">合计:</div>
<div class="total-quotation-style">
{{ preSignMoney | currencyFormat }}
</div>
</div>
</el-card>
</div>
</template>
<script>
export default {
name: 'induction',
props: {
value: {
type: Array,
default: () => [],
},
},
data() {
return {
preSignMoney: '',
categoryId: null,
tableData: [{}],
options: [],
data: [],
dialogVisible: false,
defaultProps: {
children: 'children',
label: 'label',
},
}
},
created() {
this.getListFn()
this.tableData = this.value
},
watch: {
tableData: {
handler(newval) {
this.$emit('input', newval)
this.countFn(newval)
},
deep: true,
},
value(val) {
this.tableData = val
},
},
methods: {
countFn(data) {
const total = data.reduce((accumulator, currentItem) => {
return Number(accumulator) + Number(currentItem.productMoney)
}, 0)
this.preSignMoney = total
},
// 新增
newlyAddedFn() {
this.tableData.unshift({ productMoney: '', productId: '', productName: '' })
},
// 删除
delOption(index, data) {
data.splice(index, 1)
},
getListFn() {
treeAPI().then((res) => {
this.data = res
})
},
filterNode(value, data) {
if (!value) return true
return data.label.indexOf(value) !== -1
},
filterMethod(value) {
this.$refs.tree.filter(value)
},
clearValue() {
this.$refs.tree.setCurrentKey(null)
},
getTypeList(index, row) {
console.log(index, 'ccvcv', row)
// .getCurrentKey()获取到当前要选择节点的key值
// 使用此方法必须设置 node-key 属性,若没有节点被选中则返回 null
const nodeId = this.$refs['categoryNameTree' + index].getCurrentKey()
// .getNode(nodeId) 根据 data 或者 key 拿到 Tree 组件中的 node
const node = this.$refs['categoryNameTree' + index].getNode(nodeId)
if (node.childNodes.length === 0) {
// 根据index给当前元素的categoryName参数赋值
this.$set(this.tableData[index], 'productId', node.label)
this.$set(this.tableData[index], 'label', node.data.id)
// 此时页面上已经可以动态选择
// 这一步是通过判断当前元素的v-model是否有值来控制el-option是否隐藏
if (this.tableData[index].productId) {
// .blur()用来隐藏当前展开的下拉选择框
this.$refs['productId' + index].blur()
}
} else {
this.$message({
message: '请勾选子级',
type: 'warring',
})
}
},
},
}
</script>
<style lang="scss" scoped>
.money-style {
height: 46px;
font-size: 16px;
// margin-top: 20px;
border-right: 1px solid #d9dbe0;
border-left: 1px solid #d9dbe0;
border-bottom: 1px solid #d9dbe0;
line-height: 23px;
display: -webkit-box;
.amount-to-style {
width: 50%;
text-align: center;
line-height: 44px;
border-right: 1px solid #d9dbe0;
}
.total-quotation-style {
text-align: center;
line-height: 44px;
width: 50%;
}
}
</style>
父页面
inputChange(val) {
this.tablesProps = val
},