SpringBoot+Vue


一、任务要求

  1. 对多张表增删改查 (数据表字段类型包括字符、数值、时间)
  2. Controller、Dao、 Service 分层
  3. 代码及命名规范
  4. 页面展示使用多种形式(radio 、checkbox 、下拉框、日期选择等)
  5. 多种条件查询( 文本框、radio 、checkbox 、下拉框、日期选择等 ),多种匹配模式(精确匹配、模糊匹配、范围匹配等)
  6. 查询分页
  7. 前台JS 控制
  8. 前、后台校验
  9. 查询页面,包括显示列的字典翻译、URL、查询条件的字典、字典级联。
  10. 表单页面,包括字段的字典、字典级联、字典过滤、自动带值、操作校验等。

二、页面搭建

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-bindv-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>		


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM