一、任務要求
- 對多張表增刪改查 (數據表字段類型包括字符、數值、時間)
- Controller、Dao、 Service 分層
- 代碼及命名規范
- 頁面展示使用多種形式(radio 、checkbox 、下拉框、日期選擇等)
- 多種條件查詢( 文本框、radio 、checkbox 、下拉框、日期選擇等 ),多種匹配模式(精確匹配、模糊匹配、范圍匹配等)
- 查詢分頁
- 前台JS 控制
- 前、后台校驗
- 查詢頁面,包括顯示列的字典翻譯、URL、查詢條件的字典、字典級聯。
- 表單頁面,包括字段的字典、字典級聯、字典過濾、自動帶值、操作校驗等。
二、頁面搭建
Ant Design Vue【任務要求使用】
三、曲折過程
1、ant-design-vue的button失效
問題所在:float:left
解決:加個 z-index: 99;
<style>
.editable-add-btn {
margin-bottom: 8px;
float: left;
z-index: 99;
}
</style>
2、跨域問題
解決方案:
1、前端vue設置全局參數withCredentials : true
2、后端相關Controller添加跨域注解@CrossOrigin
3、后端新建CorsConfig類,繼承WebMvcConfigurerAdapter,並重寫addCorsMappings方法
@Configuration
@EnableWebMvc
public class CorsConfig implements WebMvcConfigurer {
public void addCorsMappings(CorsRegistry registry) {
//設置允許跨域的路徑
registry.addMapping("/**")
//設置允許跨域請求的域名
.allowedOrigins("*")
//這里:是否允許證書 不再默認開啟
.allowCredentials(true)
//設置允許的方法
.allowedMethods("*")
//跨域允許時間
.maxAge(3600);
}
}
3、字典翻譯
<!-- 字典翻譯:性別 -->
<span slot="switchStuSex" slot-scope="stuSex">
<span v-if="stuSex === 1">男</span>
<span v-else>女</span>
</span>
<!-- 關聯上面的 slot -->
{
title: '性別',
dataIndex: 'stuSex',
key: 'stuSex',
align:'center',
fixed:'left',
width: 60,
scopedSlots: { customRender: 'switchStuSex' }, // 關聯那個 <a slot='switchStuSex'>
},
4、獲取表格當前行的數據
<!-- text:文本數據,record:行對象數據 -->
<a slot="name" slot-scope="text,record" @click="fetch(record.id)">{{text}}</a>
5、彈窗信息信息
通過控制 visible 的值進行控制彈窗
<a-modal v-model="visible" title="Basic Modal" @ok="handleOk">
<p>Some contents...</p>
<p>Some contents...</p>
<p>Some contents...</p>
</a-modal>
6、表格標簽自閉和導致插槽失效
結果就是所有的 slot 的字典翻譯都失效了,我看了所有的邏輯代碼,沒有一點毛病。。。我還以為遇上什么詭異的bug了,后來才發現,我不小心把第一個 a-table
標簽自閉和了!因為最后我把去官網重新拷了一份表格代碼,重新改了一次。。。。靠!好氣啊!
但是 axios 查詢出來的數據還能遍歷顯示。。。因為這個情況,導致我一直沒想到和標簽閉合有關。
7、限制輸入文本長度在 1-6 個字符
使用ui表單自帶的校驗api
<a-form-item label="姓名">
<a-input
v-decorator="['note', { rules: [{ required: true, message: '姓名為1-6個漢字!', min: 1, max: 6 }] }]"
/>
</a-form-item>
8、限制選擇今天之后的日期
前提:ui(antd vue )
<template>
<a-form-item label="入學日期" has-feedback >
<a-date-picker format="YYYY-MM-DD"
:disabled-date="disabledDate"
style="width: 100%" />
</a-form-item>
</template>
<script>
import moment from 'moment';
export default {
name: 'StuAdd',
data() {},
methods: {
moment,
disabledDate(current) {
// 不能選擇今天之后作為入學時間
return current > moment().endOf('day');
},
},
}
</script>
9、表單項的 name
對前端不是很熟悉,當時提交表單時,發現請求體中各表單項都沒有 name 屬性!!!最后一頓百度,發現沒有結果,可能是因為這個問題太簡單了。。。然后沒辦法,對着ui庫的文檔死磕,最后發現了v-decorator
里面的值,就是name屬性,我...@!#$%&*(!@#$%^&*()!!!
例如:stuName
<a-input v-decorator="['stuName']" />
10、自定義表單項校驗,姓名在 1-6個漢字
例如:stuName
<a-form-item label="姓名">
<a-input
v-decorator="['stuName', {
rules: [
{ required: true},
{ validator: this.checkStuName }
]
}]"
/>
</a-form-item>
methods:
<script>
methods: {
// 檢查名字
checkStuName(rule, value, callback){
const pwdRegex = new RegExp('^[\\u4E00-\\u9FA5]{1,6}$');
if (!pwdRegex.test(value)) {
callback(new Error('名字應為1-6個漢字!'))
}
callback()
},
}
</script>
11、給表單項賦默認值為一個變量
錯誤做法:
<a-form-item label="必修技能">
<a-input disabled v-bind:value="stuSkill" />
</a-form-item>
會報錯:
warning.js?d96e:34 Warning: `getFieldDecorator` will override `value`, so please don't set `value and v-model` directly and use `setFieldsValue` to set it.
原因:v-bind 和 v-decorator 不能同時使用!
正確做法:
<a-form-item label="必修技能">
<a-input disabled v-decorator="['stuSkill']" />
</a-form-item>
在級聯下拉框的 onChange 方法里:
// 級聯選擇
onChange(value, selectedOptions) {
// alert('院系——'+value[0]);
// alert('專業——'+value[1]);
if(value[0] == 1){
this.form.setFieldsValue({stuSkill:'C語言'});
}else if(value[0] == 2){
this.form.setFieldsValue({stuSkill:'基礎急救'});
}else {
this.form.setFieldsValue({stuSkill:''});
}
},
12、可輸入值的級聯選擇框的name(7-17: 好看不會用...已換~)
這個不能通過 v-decorator 定義 name,好像很冷門,百度了好久,試了好多,才發現是 v-decorator="['depMajName']" !
<a-form-item label="院系及專業">
<a-cascader
:options="options"
:show-search="{ filter }"
placeholder="請選擇"
@change="onChange"
v-decorator="['depMajName']"
/>
</a-form-item>
13、成功往數據庫添加的數據中,日期比傳遞的日期時間提前一天
時區問題,解決:在連接庫url地址后面加上 ?serverTimezone=GMT%2B8
14、對話框和表格同時使用的bug
把對話框的代碼放到表格外面即可!
15、表單數據回顯:setFieldsValue
1.radio 數據回顯
ant design vue 推薦使用 this.form.setFieldsValue
進行不賦值,而不是 v-bind
和 v-model
。
而且必須 a-radio
中的value
,必須要是 :value='1'
,注意要有冒號:,就無法設置值了。。。
<a-form-item label="性別">
<a-radio-group v-decorator="['stuSex']" @change="onRadioChange">
<a-radio :value='1'>
男
</a-radio>
<a-radio :value='0'>
女
</a-radio>
</a-radio-group>
</a-form-item>
2、select 數據回顯(靜態option)
例如:因為年級選項 “大一”的 value 是數字 1,但是顯示的是字符串“大一”。故 setFieldsValue 的時候,需要把 value的值 用 toString() 轉為 String。
例如:
this.form.setFieldsValue({
stuGrade: this.stu.stuGrade.toString(),
});
3、checkbox 數據回顯
直接 setFieldsValue 即可。(日期控件
例如:this.stu.stuLoves = "2,3,4"
setTimeout(() => {
this.form.setFieldsValue({
stuLoves: this.stu.stuLoves,
});
}, 300);
4、select 數據回顯(動態option)
這是第二種情況,動態option:
:value ,產生動態 value。
<a-form-item label="院系">
<a-select
show-search
placeholder="請選擇"
:filter-option="filterOption"
@change="handleChange"
v-decorator="['depName']"
>
<a-select-option v-for="dep in departments" :key="dep.depId" :value="dep.depName">
{{dep.depName == 1 ? '計算機系' : ''}}
{{dep.depName == 2 ? '醫學系' : ''}}
</a-select-option>
</a-select>
</a-form-item>
<a-form-item label="專業">
<a-select
show-search
placeholder="請選擇"
:filter-option="filterOption2"
@change="handleChange2"
v-decorator="['majName']"
>
<a-select-option v-for="major in majors" :key="major.majId" :value="major.majName">
{{major.majName == 1 ? '軟工' : ''}}
{{major.majName == 2 ? '計科' : ''}}
{{major.majName == 3 ? '網工' : ''}}
{{major.majName == 4 ? '信管' : ''}}
{{major.majName == 5 ? '醫學檢驗' : ''}}
{{major.majName == 6 ? '臨床醫學' : ''}}
{{major.majName == 7 ? '法醫' : ''}}
</a-select-option>
</a-select>
</a-form-item>
然后賦值:
setTimeout(() => {
this.form.setFieldsValue({
// stuGrade: stuGradeStr,
stuGrade: this.stu.stuGrade.toString(),
depName: this.stu.depName.toString(),
majName: this.stu.majName.toString(),
});
}, 0);
卻發現不可以,於是把 toString 給去掉,就可以了!應該是因為下拉框的value是整數,而非字符串,顯示的字符是我們的字典翻譯!!!
setTimeout(() => {
this.form.setFieldsValue({
// stuGrade: stuGradeStr,
stuGrade: this.stu.stuGrade.toString(),
depName: this.stu.depName,
majName: this.stu.majName,
});
}, 0);
16、條件查詢整合分頁查詢
// 翻頁
onChange(pagination) {
console.log('Page: ', pagination.current);
/* 帶過濾條件的分頁查詢 */
// 在這個方法里,可以直接獲取表單的屬性
this.form.validateFields((err, values) => {
const _this = this;
this.axios.post("/list/"+ pagination.current +'/'+ pagination.pageSize,
{
stuName: values.stuName,
stuLoves: values.stuLoves.toString(),
stuGrade: values.stuGrade,
startDate:values.startDate,
endDate: values.endDate,
}).then(resp => {
_this.data = resp.data.records;
_this.pagination.total = resp.data.total;
_this.pagination.ipages = resp.data.pages;
});
});
},
17、checkbox 提交數據的格式問題
解決:轉字符串
問題:提交不上去,如圖 ,這樣的數據,后端對接不上!
報錯信息如下:
2020-07-17 19:34:12.080 WARN 18856 --- [io-8081-exec-10] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Cannot deserialize instance of `java.lang.String` out of START_ARRAY token; nested exception is com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize instance of `java.lang.String` out of START_ARRAY token
at [Source: (PushbackInputStream); line: 1, column: 26] (through reference chain: com.feng.pojo.QueryCondition["stuLoves"])]
加上了 toString(),轉為字符串后成功解決:
18、刪除后的條件分頁查詢(根據情況,修改當前頁)
此處如果不對查詢參數 當前頁 進行處理,則會出現一個不友好的情況:當最后一頁只有一條數據時,刪除后,該頁面就為空白了!
<script>
// 刪除學生信息
delStu(record){
const _this = this;
this.$confirm({
title: '刪除提示',
content: '您確定要刪除 “'+record.stuName+'” 嗎?',
// content: 'Some descriptions',
okText: '確定',
okType: 'danger',
cancelText: '取消',
onOk() {
_this.axios.delete('/delete/'+record.stuId).then(resp => {
if(resp.data.flag){
// 再查詢一次
/* 帶過濾條件的分頁查詢 */
// 在這個方法里,可以直接獲取表單的屬性
_this.form.validateFields((err, values) => {
let stuLovesStr = values.stuLoves+'';
// 如果刪除時,本頁只有一條數據,name當前頁減一
let refreshPage = _this.pagination.current;
if(_this.pagination.total % _this.pagination.pageSize == 1){
refreshPage -= 1;
}
// 刪除后的條件分頁查詢
_this.axios.post("/list/"+ refreshPage +'/'+ _this.pagination.pageSize,
{
stuName: values.stuName,
stuLoves: stuLovesStr,
stuGrade: values.stuGrade,
startDate:values.startDate,
endDate: values.endDate,
}).then(resp => {
_this.data = resp.data.records;
_this.pagination.total = resp.data.total;
_this.pagination.ipages = resp.data.pages;
_this.pagination.current = resp.data.current;
});
});
}
});
console.log('OK');
},
onCancel() {
console.log('Cancel');
}
});
},
</script>