表單校驗參考了https://blog.csdn.net/iamlujingtao/article/details/105186117
效果如圖所示,主要做了一些美化和解決一些看着難受的點
代碼如下,有時間再介紹
<template>
<div class="app-container">
<div class="filter-container">
<el-input
v-model="listQuery.car"
placeholder="車輛id"
style="width: 200px"
class="filter-item"
clearable
@keyup.enter.native="handleFilter"
/>
<el-autocomplete
v-model="listQuery.project"
:fetch-suggestions="querySearchAsync"
placeholder="項目名稱"
class="filter-item"
clearable
@clear="setBlur()"
@keyup.enter.native="handleFilter"
/>
<el-date-picker
v-model="listQuery.startTime"
type="datetime"
placeholder="選擇開始日期時間"
class="filter-item"
:picker-options="pickerOptions"
value-format="yyyy-MM-dd HH:mm:ss"
/>
<el-date-picker
v-model="listQuery.endTime"
type="datetime"
placeholder="選擇結束日期時間"
class="filter-item"
:picker-options="pickerOptions"
value-format="yyyy-MM-dd HH:mm:ss"
/>
<el-button-group>
<el-button
class="filter-item"
style="margin-left: 20px"
icon="el-icon-search"
plain
round
@click="handleFilter"
> 搜索
</el-button>
<el-button
class="filter-item"
style="margin-left: 10px"
icon="el-icon-circle-plus-outline"
plain
round
@click="add"
> 新增
</el-button>
</el-button-group>
</div>
<el-form ref="form" :model="form" :rules="rules">
<el-table v-loading="loading" :data="form.tableData" style="width: 100%" border fit>
<el-table-column label="車輛" min-width="15%" prop="car" align="center">
<template v-slot="{row,$index}">
<template v-if="row.edit">
<el-form-item :prop="'tableData.'+$index+'.car'" :rules="rules.car">
<el-input v-model="row.car" clearable size="small" />
</el-form-item>
</template>
<span v-else>{{ row.car }}</span>
</template>
</el-table-column>
<el-table-column label="項目" min-width="15%" prop="project" align="center">
<template v-slot="{row,$index}">
<template v-if="row.edit">
<el-form-item :prop="'tableData.'+$index+'.project'" :rules="rules.project">
<el-input v-model="row.project" clearable size="small" />
</el-form-item>
</template>
<span v-else>{{ row.project }}</span>
</template>
</el-table-column>
<el-table-column label="開始日期" min-width="20%" align="center">
<template v-slot="{row,$index}">
<template v-if="row.edit">
<el-form-item :prop="'tableData.'+$index+'.startTime'" :rules="rules.startTime">
<el-date-picker
v-model="row.startTime"
type="datetime"
placeholder="請選擇日期"
align="center"
size="small"
:picker-options="pickerOptions"
value-format="yyyy-MM-dd HH:mm:ss"
/>
</el-form-item>
</template>
<template v-else>
<i class="el-icon-time" />
<span>{{ row.startTime }}</span>
</template>
</template>
</el-table-column>
<el-table-column label="結束日期" min-width="20%" align="center">
<template v-slot="{row,$index}">
<template v-if="row.edit">
<el-form-item :prop="'tableData.'+$index+'.endTime'" :rules="rules.endTime">
<el-date-picker
v-model="row.endTime"
type="datetime"
placeholder="請選擇日期"
align="center"
size="small"
:picker-options="pickerOptions"
value-format="yyyy-MM-dd HH:mm:ss"
/>
</el-form-item>
</template>
<template v-else>
<i class="el-icon-time" />
<span>{{ row.endTime }}</span>
</template>
</template>
</el-table-column>
<el-table-column label="操作" min-width="20%" align="center">
<template slot-scope="{row,$index}">
<template v-if="!row.edit">
<!--加div是為了和下面else中的button不一樣,可以避免點擊按鈕后不失焦-->
<div>
<el-button
id="edit-button"
size="small"
plain
round
icon="el-icon-edit"
type="primary"
@click="handleEdit(row)"
>
修改
</el-button>
<el-button
:id="'deleteButton'+$index"
size="small"
style="margin-left: 15px"
plain
round
icon="el-icon-delete"
type="danger"
@click="confirmDelete($index,row)"
>
刪除
</el-button>
</div>
</template>
<template v-else>
<el-button
id="confirm-save-button"
size="small"
plain
round
icon="el-icon-circle-check"
type="success"
@click="confirmSave($index,row)"
>{{
'保存'
}}
</el-button>
<el-button
id="cancel-save-button"
style="margin-left: 15px"
size="small"
plain
round
icon="el-icon-circle-close"
type="info"
@click="cancelSave($index,row)"
>{{
'取消保存'
}}
</el-button>
</template>
</template>
</el-table-column>
</el-table>
</el-form>
<pagination
v-show="total > 0"
:total="total"
:page.sync="listQuery.page"
:limit.sync="listQuery.limit"
:page-sizes.sync="pageSizes"
@pagination="getTableData"
/>
</div>
</template>
<script>
import Pagination from '@/components/Pagination'
// import api8899 from '@/api/api8899'
export default {
components: { Pagination },
data() {
return {
// 輸入建議
restaurants: [],
// 加載狀態
loading: true,
list: null,
total: 0,
listQuery: {
page: 1,
limit: 12,
car: undefined,
project: undefined,
startTime: undefined,
endTime: undefined
},
pageSizes: [12, 24, 36],
form: {
tableData: []
},
rules: {
car: [{
type: 'string',
required: true,
trigger: 'change',
message: '車輛不能為空'
}],
project: [{
type: 'string',
required: true,
trigger: 'change',
message: '項目不能為空'
}],
startTime: [{
type: 'string',
required: true,
trigger: 'change',
message: '開始時間不能為空'
}]
},
// 時間選項
pickerOptions: {
shortcuts: [
// {
// text: '現在',
// onClick (picker) {
// picker.$emit('pick', new Date())
// }
// },
{
text: '昨天',
onClick(picker) {
const date = new Date()
date.setTime(date.getTime() - 3600 * 1000 * 24)
picker.$emit('pick', date)
}
}, {
text: '三天前',
onClick(picker) {
const date = new Date()
date.setTime(date.getTime() - 3600 * 1000 * 24 * 3)
picker.$emit('pick', date)
}
}, {
text: '七天前',
onClick(picker) {
const date = new Date()
date.setTime(date.getTime() - 3600 * 1000 * 24 * 7)
picker.$emit('pick', date)
}
}]
}
}
},
mounted() {
this.getTableData()
this.inputSuggest()
},
methods: {
async getTableData() {
// const res = await api8899.search_car(this.listQuery)
// this.total = res.data.code === 200 ? res.data.data.count : 0
// this.form.tableData = res.data.data.data
this.form.tableData = [
{
car: 'Aaa012',
projectId: 'aaa',
project: '某個項目',
startTime: '2021-09-21 13:51:43',
endTime: '2021-09-26 13:51:43'
},
{
car: 'Aaa234',
projectId: 'aaa',
project: '某個項目',
startTime: '2021-08-26 13:51:43',
endTime: ''
},
{
car: 'Aaa345',
projectId: 'bbb',
project: '其他項目',
startTime: '2021-07-26 13:51:43',
endTime: '2021-07-26 13:51:43'
},
{
car: 'Aaa222',
projectId: 'bbb',
project: '其他項目',
startTime: '2021-09-09 13:51:43',
endTime: ''
}
]
this.form.tableData.map((v) => {
this.$set(v, 'edit', false)
// v.edit = false // 不能被v-if監聽到
return v
})
this.loading = false
},
handleFilter() {
this.loading = true
this.getTableData()
this.loading = false
},
handleEdit(row) {
if (row.temp === undefined) {
row.temp = Object.assign({}, row) // 復制對象,為了取消修改后還原數據
} else if (row.temp.car === '') {
delete row.temp
row.temp = Object.assign({}, row) // 復制對象,為了取消修改后還原數據
}
row.edit = !row.edit
},
validateField(form, index) {
let result = true
for (const item of this.$refs[form].fields) {
if (parseInt(item.prop.split('.')[1]) === index) {
this.$refs.form.validateField(item.prop, (error) => {
if (error) {
result = false
}
})
}
if (!result) break
}
return result
},
async confirmSave(index, row) {
if (!this.validateField('form', index)) {
this.$message({
type: 'info',
message: '保存修改失敗,請檢查是否有未填字段',
center: true
})
return
}
// 判斷值是否有改變,如果沒有則不做下面的操作
const tmp = Object.assign({}, row)
const rowTmp = Object.assign({}, tmp.temp)
delete rowTmp.edit
delete tmp.temp
delete tmp.edit
if (JSON.stringify(rowTmp) === JSON.stringify(tmp)) {
row.edit = !row.edit
return
}
// 配置發送的請求參數
// const params = {
// 'car': row.car,
// 'project': row.project,
// 'startTime': row.startTime,
// 'endTime': row.endTime,
// 'oCar': row.temp.car,
// 'oProject': row.temp.project,
// 'oStartTime': row.temp.startTime,
// 'oEndTime': row.temp.endTime
// }
this.loading = true
// const response = await api8899.upsert_car(params)
const response = { 'data': { 'code': 200 }}
// const response = { 'data': { 'code': 23423,'message':'自定義提示' }}
this.loading = false
let type, message
if (response.data.code === 500) {
type = 'error'
message = '保存出錯,請聯系開發人員修復'
} else if (response.data.code === 200) {
type = 'success'
message = '保存成功'
} else {
type = 'info'
message = response.data.message
}
this.$message({
type: type,
message: message,
center: true
})
// info為保存數據重復等問題,直接返回
if (type === 'info') {
return
}
row.edit = !row.edit
delete row.temp
row.temp = Object.assign({}, row) // 復制對象,為了取消修改后還原數據
},
cancelSave(index, row) {
if (row.temp.car === '') {
this.$delete(this.form.tableData, index)
return
}
this.$set(this.form.tableData, index, row.temp) // 取消后還原數據到修改前狀態
},
// 刪除數據
async confirmDelete(index, row) {
// 讓按鈕失焦防止在提示時按多次enter鍵導致多次提交
document.getElementById('deleteButton' + index).blur()
// 設置彈窗樣式
const h = this.$createElement
const confirmText1 = ['車輛 : ', '項目 : ', '開始時間 : ', '結束時間 : ']
const confirmText2 = [row.car, row.project, row.startTime, row.endTime]
const newData = []
for (const i in confirmText1) {
newData.push(h('span', null, confirmText1[i]))
newData.push(h('i', { style: 'color: teal' }, confirmText2[i]))
newData.push(h('div', null, null))
}
const confirm = await this.$msgbox({
title: '確定刪除該條數據嗎',
message: h('p', null, newData),
showCancelButton: true,
confirmButtonText: '確定',
cancelButtonText: '取消'
}).catch(() => {
this.$message({
type: 'info',
message: '已取消刪除',
center: true
})
})
if (confirm === 'confirm') {
this.loading = true
// const response = await api8899.delete_car({ 'car': row.car, 'project': row.project, 'startTime': row.startTime })
const response = { 'data': { 'code': 200 }}
const type = response.data.code === 200 ? 'success' : 'error'
const message = response.data.code === 200 ? '成功刪除數據' : '刪除數據失敗,請聯系開發人員修復'
this.$delete(this.form.tableData, index)
this.loading = false
this.$message({
type: type,
message: message,
center: true
})
}
},
// 新增時重新初始化一個插入第一行
add() {
const temp = {
car: '',
project: '',
projectId: '',
startTime: '',
endTime: '',
edit: true,
temp: {
car: '',
project: '',
startTime: '',
endTime: ''
}
}
this.form.tableData.unshift(temp)
},
// 獲取項目輸入框建議
async inputSuggest() {
// const tmp = await api8899.search_project()
const tmp = { data: { data: [{ value: '某個項目b' }, { value: '某個項目a' }] }}
this.restaurants = tmp.data.data
},
// 處理輸入框建議,restaurants必須是包含value屬性的對象 [ {value:'xxx'} , ...]
querySearchAsync(queryString, cb) {
const restaurants = this.restaurants
const results = queryString ? restaurants.filter(this.createStateFilter(queryString)) : restaurants
cb(results)
},
// 輸入框建議過濾規則
createStateFilter(queryString) {
return (state) => {
return (state.value.toLowerCase().indexOf(queryString.toLowerCase()) === 0)
}
},
// 清空輸入框時取消聚焦 使用戶重新點擊來展示建議下拉框
setBlur() {
document.activeElement.blur()
}
}
}
</script>
<style scoped>
.filter-container {
text-align: left;
padding-bottom: 10px;
}
.filter-item {
display: inline-block;
vertical-align: middle;
margin-bottom: 10px;
}
.app-container {
padding: 20px;
}
/deep/ .el-form-item {
margin-bottom: 0
}
/deep/ .el-input__inner {
text-align: center;
}
/deep/ .el-button--text {
display: none;
}
</style>
