Vue实战狗尾草博客管理平台第六章
源码地址:https://github.com/18291907191/gwc_manage
Vue实现狗尾草博客后台管理系统第六章
本章节内容
文章列表
文章详情
草稿箱
文章发布。
本章节内容呢,开发的很是随意哈,因为多数就是element-ui的使用,熟悉的童鞋,是可以很快完成本章节的内容的。
为啥文章模块会有这么多东西呢?
因为狗尾草想着以后,文章如果是待发布的话就需要一个地方去存放起来,一开始删除的文章呢,也将会被移入到草稿箱中,这样的话,文章就不会被随便的更改啦。
文章列表
先给大家一张效果图

是不是感觉非常轻松,一个table就可以搞定,
这里的代码呢,我就直接贴出来,因为没有什么值得注意的地方都是基础。
article>list.vue
<template>
<div class="article-wrap">
<el-table
:data="articleList"
height="100%"
stripe> <el-table-column
prop="id"
align="center"
label="文章编号">
</el-table-column> <el-table-column
prop="create_time"
align="center"
label="创建时间">
<template slot-scope="scope">
{{$moment(scope.row.create_time).format('YYYY-MM-DD HH:mm')}}
</template>
</el-table-column> <el-table-column
prop="tags"
align="center"
label="标签">
<template slot-scope="scope">
{{$utils.formatTableFont(scope.row.tags)}}
</template>
</el-table-column> <el-table-column
prop="title"
align="center"
label="标题">
<template slot-scope="scope">
{{$utils.formatTableFont(scope.row.title)}}
</template>
</el-table-column> <el-table-column
prop="title_image"
align="center"
label="标题图片">
<template slot-scope="scope">
<img v-if="scope.row.title_image" class="title-img" :src="scope.row.title_image" />
<span v-else>-</span>
</template>
</el-table-column> <el-table-column
prop="reader_number"
align="center"
label="阅读数">
<template slot-scope="scope">
{{$utils.formatTableData(scope.row.reader_number)}}
</template>
</el-table-column> <el-table-column
prop="good_number"
align="center"
label="点赞数">
<template slot-scope="scope">
{{$utils.formatTableData(scope.row.good_number)}}
</template>
</el-table-column> <el-table-column
label="操作"
align="center"
fixed="right">
<template slot-scope="scope">
<el-button size="mini" @click.stop="$router.push({path:'/article/detail',query:{articleId:scope.row.id,status:1}})">编辑</el-button>
</template>
</el-table-column>
</el-table>
</div>
</template>
<script>
export default {
data() {
return {
articleList: [],
params: {
searchParams: '',
page: ,
size: ,
status:
},
}
},
methods: {
// 获取文章列表
async getArticleList() {
try {
const { articleData } = await this.$http.getRequest('/article/api/v1/article_list',this.params);
this.articleList = articleData;
} catch(err) {
throw new Error('获取文章列表失败',err);
}
}
},
mounted() {
this.getArticleList();
}
}
</script>
<style lang="less" scoped>
.article-wrap {
height: %;
overflow: hidden;
/deep/.title-img {
width: 90px;
height: 90px;
}
}
</style>
这里呢,接口呢,都已经完成了。这类先不做说明,后面会单独将node.js抽离出来的哈。
不过呢,这里的formatTableData方法呢,是因为我们在做表格数据显示的时候呢,会有没有数据的情景,所以这里。我封装了一个方法,专门的针对表格的数据进行一个处理,在没有数据的时候呢就显示'-',如果是数字类型的呢,这里就显示0
给大家把方法贴出来,至于如果把方法挂在到全局,前面有讲到啦。这里也不需要这样做,因为直接方法utils文件中,utils挂载到全局,是可以直接使用的了。
utils>plugins.js
import * as http from './http';
import VueCookies from 'vue-cookies'
import moment from 'moment';
import utils from './plugins'; const install = (Vue, opts = {}) => {
if (install.installed) return;
Vue.prototype.$http = http;
Vue.prototype.$cookies = VueCookies;
Vue.prototype.$moment = moment;
Vue.prototype.$utils = utils;
} export default install
utils>index.js
/**
* @description 封装的工具类
* @author chaizhiyang
*/
class Util {
/**
* 保留小数点后两位
* @param {Number} data 需要处理的数值
* @return {Number} 保留两位小数的数值
* @author Czy 2018-10-25
*/
returnFloat(data) {
return data.toFixed()
} //el-table表格数据的处理
formatTableFont(val) {
//格式化数据,为空或0或null时,显示无
let formatTableData;
if (!val) {
formatTableData = "-";
} else {
formatTableData = val;
}
return formatTableData;
}; //el-table表格数据的处理
formatTableData(val) {
//格式化数据,为空或0或null时,显示无
let formatTableData;
if (!val) {
formatTableData = "";
} else {
formatTableData = val;
}
return formatTableData;
}; // 返回性别
sexStatus(status) {
if (!status) return
switch (status) {
case :
return '男';
break;
case :
return '女';
break;
default:
return '未知';
break;
}
} /**
* 正则验证
* @param {Number,String} str 需要验证的内容如:手机号,邮箱等
* @param {String} type 需要正则验证的类型
* @return {Boolean} true: 正则通过,输入无误。false: 正则验证失败,输入有误
* @author Czy 2018-10-25
*/
checkStr(str, type) {
switch (type) {
case 'phone': //手机号码
return /^[||||][-]{}$/.test(str);
case 'tel': //座机
return /^(\d{,}-\d{,})(-\d{,})?$/.test(str);
case 'card': //身份证
return /^\d{}|\d{}$/.test(str);
case 'account': //账号 ,长度4~16之间,只能包含数字,中文,字母和下划线
return /^(\w|[\u4E00-\u9FA5])*$/.test(str);
case 'pwd': //密码以字母开头,长度在6~18之间,只能包含字母、数字和下划线
return /^[a-zA-Z]\w{,}$/.test(str);
case 'postal': //邮政编码
return /[-]\d{}(?!\d)/.test(str);
case 'QQ': //QQ号
return /^[-][-]{,}$/.test(str);
case 'email': //邮箱
return /^[\w-]+(\.[\w-]+)*@[\w-]+(\.[\w-]+)+$/.test(str);
case 'money': //金额(小数点2位)
return /^\d*(?:\.\d{,})?$/.test(str);
case 'URL': //网址
return /(http|ftp|https):\/\/[\w\-_]+(\.[\w\-_]+)+([\w\-\.,@?^=%&:/~\+#]*[\w\-\@?^=%&/~\+#])?/.test(str);
case 'IP': //IP
return /((?:(?:[-]|[-]\\d|[]?\\d?\\d)\\.){}(?:[-]|[-]\\d|[]?\\d?\\d))/.test(str);
case 'date': //日期时间
return /^(\d{})\-(\d{})\-(\d{}) (\d{})(?:\:\d{}|:(\d{}):(\d{}))$/.test(str) || /^(\d{})\-(\d{})\-(\d{})$/.test(str);
case 'number': //数字
return /^[-]$/.test(str);
case 'english': //英文
return /^[a-zA-Z]+$/.test(str);
case 'chinese': //中文
return /^[\u4E00-\u9FA5]+$/.test(str);
case 'lower': //小写
return /^[a-z]+$/.test(str);
case 'upper': //大写
return /^[A-Z]+$/.test(str);
case 'HTML': //HTML标记
return /<("[^"]*"|'[^']*'|[^'">])*>/.test(str);
default:
return true;
}
} /**
* 类型判断
* @param {*} o 进行判断的内容
* @return {Boolean} true: 是该类型,false: 不是该类型
* @author Czy 2018-10-25
*/
isString(o) { //是否字符串
return Object.prototype.toString.call(o).slice(, -) === 'String'
} isNumber(o) { //是否数字
return Object.prototype.toString.call(o).slice(, -) === 'Number'
} isObj(o) { //是否对象
return Object.prototype.toString.call(o).slice(, -) === 'Object'
} isArray(o) { //是否数组
return Object.prototype.toString.call(o).slice(, -) === 'Array'
} isDate(o) { //是否时间
return Object.prototype.toString.call(o).slice(, -) === 'Date'
} isBoolean(o) { //是否boolean
return Object.prototype.toString.call(o).slice(, -) === 'Boolean'
} isFunction(o) { //是否函数
return Object.prototype.toString.call(o).slice(, -) === 'Function'
} isNull(o) { //是否为null
return Object.prototype.toString.call(o).slice(, -) === 'Null'
} isUndefined(o) { //是否undefined
return Object.prototype.toString.call(o).slice(, -) === 'Undefined'
} isFalse(o) {
if (o == '' || o == undefined || o == null || o == 'null' || o == 'undefined' || o == || o == false || o == NaN) {
return true
}
return false
} isTrue(o) {
return !this.isFalse(o)
}
} export default new Util();
这里直接挂在到全局。使用方法呢就是this.$utils.func就可以了
文章详情
这里的主要功能呢就是根据id去回显该文章的所有信息,并可以进行修改,删除,移入草稿箱等得操作。这里呢,因为详情和发布是相同的,所以呢,这里也就发一份。当然了就有同学问我,为什么不讲两个页面放到一个页面中呢。
这里给大家解释一下哈:
项目初期往往会比较简单,大多人选择将相同的地方进行封装,给前妻开发带来很大方便,但是项目越往后,会发现,在一个页面反复的添加,修改判断。页面的逻辑处理变得十分复杂,便后悔当初没有还不如分开处理。当然,另一个原因就是,这里路由也做了懒加载,我们在不进入另一个路由的同时呢。他是不会被加载的。性能损耗而言呢,也就是多占了份空间,当然,不要为了封装而封装,不要过度封装。适用才是最合适的!
article>publish
<template>
<section class="wraper">
<el-form ref="form" :model="form" label-width="92px" :rules="rules">
<!--S 标题 -->
<admin-title :title="title.tit1"></admin-title>
<el-form-item label="Article Title" prop="title">
<el-col :span="">
<el-input v-model="form.title"></el-input>
</el-col>
</el-form-item>
<el-form-item label="Title Image" prop="title_image"
>
<el-col :span="">
<el-input v-model="form.title_image"></el-input>
</el-col>
</el-form-item>
<admin-title :title="title.tit2"></admin-title>
<el-form-item label="Article Tags" prop="tags">
<el-col :span="">
<el-select
style="width: 100%;"
v-model="form.tags"
multiple
filterable
allow-create
default-first-option
placeholder="请选择文章标签">
<el-option
v-for="item in tagList"
:key="item.id"
:label="item.tag"
:value="item.id">
</el-option>
</el-select>
</el-col>
</el-form-item>
<admin-title :title="title.tit3"></admin-title>
<el-form-item label="Abstract" prop="describe" align="left">
<textarea class="abstract" v-bind:maxlength="" v-model="form.describe" rows="" cols="" type="text" name="abstract">
</textarea>
<span style="font-size:16px;"><font style="color: #3576e0;">{{ - form.describe.length}}</font>/</span>
</el-form-item>
<el-form-item label="Content" prop="content">
<mavon-editor v-model="form.content"/>
</el-form-item>
<el-form-item align="left">
<el-col>
<el-button type="primary" @click.native="handleSubmit('rules')" :loading="buttonLoading.publishLoading">文章发布</el-button>
<el-button type="primary" @click.native="handleMoveDraft('rules')" :loading="buttonLoading.draftLoading">保存草稿</el-button>
</el-col>
</el-form-item>
</el-form>
</section>
</template>
<script>
import AdminTitle from '@/components/commons/Title'; export default {
components: {
AdminTitle,
},
watch: {
'form.describe'(curVal, oldVal) {
if (curVal.length > this.textNum) {
this.textareaValue = String(curVal).slice(, this.textNum);
}
}
},
data() {
return {
title: {
tit1: '文章标题',
tit2: '文章标签',
tit3: '文章摘要',
}, //标题
form: {
title: '',
tags: [],
title_image: '',
describe: '',
content: '',
status: ,
}, //提交数据
tagList: [], //标签选择器
textNum: ,
previewMarkdown: '<h1>测试</h1>',
buttonLoading: {
publishLoading: false,
draftLoading: false
},
rules: {
title: [
{ required: true, message: '请输入文章标题', trigger: 'blur'}
],
title_img: [
{ required: false, message: '请输入标题图片', trigger: 'blur'}
],
tags: [
{ required: false, message: '请选择文章标签', trigger: 'change'}
],
describe: [
{ required: true, message: '请输入文章摘要', trigger: ['change','blur']}
],
content: [
{ required: true, message: '请输入文章内容', trigger: ['blur','change']}
]
}, // 表单规则校验
}
},
methods: {
//发布文章
async handleSubmit() {
let isOk = this.validata();
if(!isOk) {
return ;
}
this.form.status = ;
this.publishLoading = true;
try {
const result = await this.$http.postRequest('/article/api/v1/article_add',this.form);
this.publishLoading = false;
this.$message({
type: 'success',
message: '文章发布成功!'
})
this.$router.push({
path: '/article/list'
})
} catch(err) {
throw new Error('文章更新失败',err);
this.publishLoading = false;
}
},
// 保存草稿
async handleMoveDraft() {
this.form.status = ;
this.publishLoading = true;
try {
const result = await this.$http.postRequest('/article/api/v1/article_add',this.form);
this.publishLoading = false;
this.$message({
type: 'success',
message: '保存草稿箱成功!'
})
this.$router.push({
path: '/article/draft'
})
} catch(err) {
this.publishLoading = false;
throw new Error('保存草稿失败',err);
}
},
// 表单校验
validata() {
let isForm;
this.$refs.form.validate(valid => {
isForm = valid;
});
if (!isForm) {
return false;
}
return true;
},
// 获取文章所有标签
getTags() {
let hash = {};
let arr = [];
axios.get('/article/api/v1/articleTags')
.then(res => {
arr = res.reduce((item,next) => {
hash[next.tag] ? '' : hash[next.tag] = true && item.push(next);
return item;
},[]);
this.tagList = arr;
})
}
},
}
</script>
<style lang="less" scoped>
.wraper {
width: %;
height: %;
.abstract {
padding: 10px;
font-size: 14px;
}
/deep/.el-form-item__label {
text-align: left;
padding-right: ;
}
} </style>
这里有一个重点,需要大家着重记一下的是,表单的校验,我们在添加好了以后,往往在需要提交的时候去进行判断,将不符合规则的表单给提示出来。不会使用的人,便会去写很多的if判断,this.$message({type:'error',message:'xxx'})的方法给出来,
但是element_ui明明已经给了一个合理的解决方案了。大家就要学会去使用,给我们带来便捷!
// 表单校验
validata() {
let isForm;
this.$refs.form.validate(valid => {
isForm = valid;
});
if (!isForm) {
return false;
}
return true;
},
这块的表单校验,通过给 form表单起一个名称,在提交的时候,调用validate方法就可以方便的达到校验表单的效果。根据返回结果去判断是否继续往下执行就可以啦。get到了有木有。
封装的一个subtitle组件
compoents/commons/Title.vue
<template>
<p class="title">{{title}}</p>
</template> <script>
export default {
name: "AdminTitle",
props: {
title: String
},
data () {
return { };
}
};
</script> <style lang="less">
.title {
display: flex;
align-items: center;
margin: 20px ;
color: #;
position: relative;
&::before {
content: "";
display: inline-block;
position: absolute;
left: -15px;
width: 2px;
height: 13px;
background-color: #3576e0;
border-radius: 1px;
}
}
</style>
这里呢,狗尾草选择使用了<mavon-editor v-model="form.content"/>富文本编辑器,富文本编辑器很多哈。这里就不做特殊说明,有使用遇到坎坷的童鞋呢,可以留言咨询哦。(大家可以查看后期我的react前端文章详情的回显效果)
草稿箱
这里的草稿箱呢,其实表面上看和列表页是一样的。但是呢。文章没有写完的依旧可以放在草稿箱中。待发布的也可以放在草稿箱中,这也就是像个完全不同功能的模块了。
article>draft.vue
<template>
<div class="article-wrap">
<el-table
:data="articleList"
height="100%"
stripe> <el-table-column
prop="id"
align="center"
label="文章编号">
</el-table-column> <el-table-column
prop="create_time"
align="center"
label="创建时间">
<template slot-scope="scope">
{{$moment(scope.row.create_time).format('YYYY-MM-DD HH:mm')}}
</template>
</el-table-column> <el-table-column
prop="tags"
align="center"
label="标签">
<template slot-scope="scope">
{{$utils.formatTableFont(scope.row.tags)}}
</template>
</el-table-column> <el-table-column
prop="title"
align="center"
label="标题">
<template slot-scope="scope">
{{$utils.formatTableFont(scope.row.title)}}
</template>
</el-table-column> <el-table-column
prop="title_image"
align="center"
label="标题图片">
<template slot-scope="scope">
<img v-if="scope.row.title_image" class="title-img" :src="scope.row.title_image" />
<span v-else>-</span>
</template>
</el-table-column> <el-table-column
prop="reader_number"
align="center"
label="阅读数">
<template slot-scope="scope">
{{$utils.formatTableData(scope.row.reader_number)}}
</template>
</el-table-column> <el-table-column
prop="good_number"
align="center"
label="点赞数">
<template slot-scope="scope">
{{$utils.formatTableData(scope.row.good_number)}}
</template>
</el-table-column> <el-table-column
label="操作"
align="center"
fixed="right">
<template slot-scope="scope">
<el-button size="mini" @click.stop="$router.push({path:'/article/detail',query:{articleId:scope.row.id,status:2}})">编辑</el-button>
<el-button size="mini" type="danger" @click.stop="handleDeleteDraft(scope.row.id)">删除</el-button>
</template>
</el-table-column>
</el-table>
</div>
</template>
<script>
export default {
data() {
return {
articleList: [],
params: {
searchParams: '',
page: ,
size: ,
status:
}
}
},
methods: {
//获取文章列表
async getArticleList() {
try {
const { articleData } = await this.$http.getRequest('/article/api/v1/article_list',this.params);
this.articleList = articleData;
} catch(err) {
throw new Error('获取文章列表失败',err);
}
},
handleDeleteDraft(id) {
this.$confirm('此操作将永久删除该文章,不可复原, 是否继续?', '删除提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(async () => {
try {
const result = await this.$http.postRequest('/article/api/v1/article_delete',{ id });
this.$message({
type: 'success',
message: '文章已删除!'
})
this.getArticleList();
} catch(err) {
throw new Error('删除草稿失败',err);
}
this.$message({
type: 'success',
message: '删除成功!'
});
}).catch(() => {
this.$message({
type: 'info',
message: '已取消删除'
});
});
}
},
mounted() {
this.getArticleList();
}
}
</script>
<style lang="less" scoped>
.article-wrap {
height: %;
overflow: hidden;
/deep/.title-img {
width: 90px;
height: 90px;
}
}
</style>
这里给大家理一下这里的思路哈。
文章列表可编辑,编辑时,可选择将文章进行更新发布或者移入草稿箱。发布没有啥说的,移入草稿箱呢,其实也就是将该文章的状态进行更改。
在草稿箱中,主需要根据状态去查询文章即可。 但是草稿箱中的删除操作也就会将文章彻底的删除。
最后呢,附上更改后的路由
router>index.js
import Vue from 'vue'
import Router from 'vue-router'
// import HelloWorld from '@/components/HelloWorld'
Vue.use(Router) const _import = file => () => import('@/pages/' + file + '.vue');
const _import_ = file => () => import('@/components/' + file + '.vue'); const asyncRouterMap = []; const constantRouterMap = [
{
path: '/login',
name: 'Login',
component: _import('login/index'),
},
{
path: '/',
name: '概况',
component: _import_('commons/Layout'),
redirect: '/index',
children: [
{
path: '/index',
name: '总览',
component: _import('home/index'),
meta: {
isAlive: false,
auth: true,
title: '概况数据'
}
}
]
},
{
path: '/article',
name: '文章',
component: _import_('commons/Layout'),
redirect: '/article/publish',
children: [
{
path: '/article/publish',
name: '文章发布',
component: _import('article/publish'),
meta: {
auth: true,
isAlive: true,
isFooter: false,
title: '文章发布'
}
},
{
path: '/article/list',
name: '列表',
component: _import('article/list'),
meta: {
auth: true,
isAlive: false,
isFooter: true,
title: '列表'
}
},
{
path: '/article/draft',
name: '草稿箱',
component: _import('article/draft'),
meta: {
auth: true,
isAlive: false,
isFooter: true,
title: '草稿箱'
}
},
{
path: '/article/detail',
name: '文章详情',
component: _import('article/detail'),
meta: {
auth: true,
isAlive: false,
isFooter: false,
title: '文章详情'
}
}
]
},
{
path: '/404',
name: '',
component: _import('error/index'),
meta: {
title: "请求页面未找到",
auth: false
},
},
{
path: '*',
meta: {
title: "请求页面未找到",
auth: false
},
redirect: '/404'
}
]; const router = new Router({
mode: 'history',
routes: constantRouterMap,
linkActiveClass: "router-link-active",
}); export default router
总结
1.表单提交时的校验。
2.不要为了封装而封装。避免过度封装。适用才是王道。
下一章节
Vuex的进阶使用
Vue实战狗尾草博客管理平台第六章的更多相关文章
- Vue实战狗尾草博客管理平台第四章
本章主要内容如下: 填补上期的坑. iconfont仓库的关联,引入. 开发登录页面 填坑 上期中我们功能都已正常使用.但不知道有没有小伙伴测试过error页面,当访问地址不存在时,路由是否能正常挑战 ...
- Vue实战狗尾草博客管理平台第五章
本章主要内容如下: 静态资源服务器的配置.学会如何使用静态资源服务器引入静态资源.并给大家推荐一个免费可使用的oss服务器~ 页面的开发由于近期做出的更改较大.就放在下一篇中. 静态资源服务器 静态资 ...
- Vue实战狗尾草博客后台管理系统第七章
Vue实战狗尾草博客后台管理平台第七章 本章内容为借助模块化来阐述Vuex的进阶使用. 在复杂项目的架构中,对于数据的处理是一个非常头疼的问题.处理不当,不仅对维护增加相当的工作负担,也给开发增加巨大 ...
- Vue实战狗尾草博客后台管理系统第三章
Vue实现狗尾草博客后台管理系统第三章 本章节,咱们开发管理系统侧边栏及面包屑功能. 先上一张效果图 样式呢,作者前端初审,关于设计上毫无美感可言,大家可根据自己情况设计更好看的哦~ 侧边栏 这里我们 ...
- Vue实战狗尾草博客管理系统第一章
Vue实战狗尾草博客后台管理系统第一章 这里准备采用的技术栈为:vue全家桶+element-ui 这里因为是后台管理系统,没有做SSR的必要.所以这里就采用前后端分离来昨晚这个项目~ 项目搭建 vu ...
- Vue实战狗尾草博客管理系统第二章
伙伴们出来啦,探讨各问题,关于项目中大量的表单,大家是怎么处理的? 本章主要内容如下:底层布局,路由配置,github仓库推送关联. 关联GitHub仓库 关联建立在github已创建账号的基础上 登 ...
- 一个 Vue + Node + MongoDB 博客系统
源码 耗时半载(半个月)的大项目终于完成了.这是一个博客系统,使用 Vue 做前端框架,Node + express 做后端,数据库使用的是 MongoDB.实现了用户注册.用户登录.博客管理(文章的 ...
- 关于vue项目管理项目的架构管理平台
关于vue项目管理项目的架构管理平台 https://panjiachen.github.io/vue-element-admin-site/#/zh-cn/faq 31.4k 次浏览 完整项目地址: ...
- python drf+xadmin+react+dva+react-native+sentry+nginx 搭建前后端分离的博客完整平台
前言: 经过差不多半年的开发,搭建从前端到服务器,实现了前后端分离的一个集PC端.移动端的多端应用,实属不易,今天得空,好好写篇文章,记录这些天的成果.同时也做个分享. 演示网站地址: http:// ...
随机推荐
- JVM从入门开始深入每一个底层细节
1 官网 1.1 寻找JDK文档过程 www.oracle.com -> 右下角Product Documentation -> 往下拉选择Java -> Java SE docum ...
- 数字图像处理:图像的灰度变换(Matlab实现)
(1)线性变换:通过建立灰度映射来调整源图像的灰度. k>1增强图像的对比度:k=1调节图像亮度,通过改变d值达到调节亮度目的:0 i = imread('theatre.jpg');i = i ...
- C#&.Net干货分享-构建Aocr_ImageHelper读取图片文字做解析
直接源码,就是这么干脆... namespace Frame.Image{ /// <summary> /// /// </summary> publ ...
- SQL Server 查询某一个数据库存储过程、函数是否包含某一个内容或者脚本
SELECT obj.Name 名称, sc.TEXT 内容FROM syscomments scINNER JOIN sysobjects obj ON sc.Id = obj.IDWHERE sc ...
- Python3+Requests+Excel完整接口自动化框架
框架整体使用Python3+Requests+Excel:包含对实时token的获取 框架结构图 1.------base -------runmethond.py runmethond:对不同的请求 ...
- leetcode 752. 打开转盘锁
地址 https://leetcode-cn.com/problems/open-the-lock/ 你有一个带有四个圆形拨轮的转盘锁.每个拨轮都有10个数字: '0', '1', '2', '3', ...
- 算法问题实战策略 WORDCHAIN
地址 https://algospot.com/judge/problem/read/WORDCHAIN 解答: 1 书上的解法是制作有向图 然后查找欧拉回路 代码实现稍后 假设一定存在欧拉路径的 ...
- LG5003 跳舞的线 - 乱拐弯 线性DP
问题描述 LG5003 题解 设 \(mx[i][j][0/1]\)代表当前位置.朝向的最大拐弯数,最小同理. 来源为左边和上边. 坑点:起点可能为#. \(\mathrm{Code}\) #incl ...
- 【转】MyBatis缓存机制
转载:https://blog.csdn.net/bjweimengshu/article/details/79988252. 本文转载自公众号 美团技术点评 前言 MyBatis是常见的Java数据 ...
- Codeforces Round #602 (Div. 2, based on Technocup 2020 Elimination Round 3) E. Arson In Berland Forest 二分 前缀和
E. Arson In Berland Forest The Berland Forest can be represented as an infinite cell plane. Every ce ...