Commit 699780c5 by tangjiale

更新代码

parents
TENCENT_APP_ID=1256104560
TENCENT_SECRET_ID=AKIDIL7SXMUkPnvmTut9OAhfNpoX0CE09l4E
TENCENT_SECRET_KEY=4x1xfFMnDQN2VJwJuXx7WoreBZyEEEtM
# Created by .ignore support plugin (hsz.mobi)
### Node template
# Logs
/logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
# nyc test coverage
.nyc_output
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# Bower dependency directory (https://bower.io/)
bower_components
# node-waf configuration
.lock-wscript
# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules/
jspm_packages/
# TypeScript v1 declaration files
typings/
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variables file
# .env
# parcel-bundler cache (https://parceljs.org/)
.cache
# next.js build output
.next
# nuxt.js build output
.nuxt
# Nuxt generate
dist
# vuepress build output
.vuepress/dist
# Serverless directories
.serverless
# IDE / Editor
.idea
# Service worker
sw.*
# macOS
.DS_Store
# Vim swap files
*.swp
<!--
* @Author: tangjiale
* @eMail: 932055106@qq.com
* @Date: 2022-02-11 15:14:19
* @LastEditors: tangjiale
* @LastEditTime: 2022-02-21 10:27:29
-->
# vue+nuxt+element 商城后台系统
- 生产环境:
- 后端域名: http://goodsadminapi.xiaobentiyu.cn
- 测试环境:
- 后端域名:http://tgoodsadmin.xiaobentiyu.cn
## 开源文档
- [nuxt.js ](https://zh.nuxtjs.org/)
- [element文档 ](https://element.eleme.cn/#/zh-CN/component/installation)
- [交互地址 ](https://app.mockplus.cn/run/rp/SheMp1kCCs8Sr/NQ5IDMVXYO9w9M?ps=0&ha=0&la=0&fc=0&out=1)
## 产品原型:
## dev-1.0.0
设计
https://lanhuapp.com/url/lZgom-rwY4X
## 接口swagger:
- [基础服务接口文档](http://tgoodsadmin.xiaobentiyu.cn/doc.html)
## 管理平台地址
- 生产环境:
- http://goodsadmin.xiaobentiyu.cn/
- 测试环境:
- http://goodsadminapi.xiaobentiyu.cn/
## 代码注解
@font-face {
font-family: "iconfont"; /* Project id 2804669 */
src: url('//at.alicdn.com/t/font_2804669_t90edttnz7.woff2?t=1636014691761') format('woff2'),
url('//at.alicdn.com/t/font_2804669_t90edttnz7.woff?t=1636014691761') format('woff'),
url('//at.alicdn.com/t/font_2804669_t90edttnz7.ttf?t=1636014691761') format('truetype');
}
.iconfont {
font-family: "iconfont" !important;
font-size: 16px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.icon-tzjk_icon_chengji:before {
content: "\e61e";
}
.icon-tzjk_icon_user:before {
content: "\e61b";
}
.icon-tzjk_icon_pas:before {
content: "\e61c";
}
.icon-tzjk_icon_con:before {
content: "\e61d";
}
.icon-tzjk_icon_excel:before {
content: "\e61a";
}
.icon-tzjk_icon_progress:before {
content: "\e619";
}
.icon-tzjk_icon_check:before {
content: "\e617";
}
.icon-tzjk_icon_look:before {
content: "\e618";
}
.icon-tzjk_icon_shanchu2:before {
content: "\e616";
}
.icon-tzjk_icon_guanbi:before {
content: "\e615";
}
.icon-tzjk_icon_chakan:before {
content: "\e611";
}
.icon-tzjk_icon_daochu:before {
content: "\e612";
}
.icon-tzjk_icon_xiugai:before {
content: "\e613";
}
.icon-tzjk_icon_daoru2:before {
content: "\e614";
}
.icon-tzjk_icon_shanchu:before {
content: "\e60e";
}
.icon-tzjk_icon_erweima:before {
content: "\e60f";
}
.icon-tzjk_icon_bianji:before {
content: "\e610";
}
.icon-tzjk_icon_jiang:before {
content: "\e60d";
}
.icon-tzjk_icon_sheng:before {
content: "\e60c";
}
.icon-tzjk_icon_caiji:before {
content: "\e604";
}
.icon-tzjk_icon_fenxi:before {
content: "\e605";
}
.icon-tzjk_icon_shitu:before {
content: "\e606";
}
.icon-tzjk_icon_dangan:before {
content: "\e607";
}
.icon-tzjk_icon_shangbao:before {
content: "\e608";
}
.icon-tzjk_icon_yujing:before {
content: "\e609";
}
.icon-tzjk_icon_baogao:before {
content: "\e60a";
}
.icon-tzjk_icon_daoru:before {
content: "\e60b";
}
<!--
* @Author: tangjiale
* @eMail: 932055106@qq.com
* @Date: 2022-02-15 15:13:44
* @LastEditors: tangjiale
* @LastEditTime: 2022-02-15 15:13:45
-->
<template>
<div>
<el-dialog :title="title" :before-close="handleClose"
:width="width" :close-on-click-modal="false"
:visible.sync="show">
<div v-if="show">
<slot></slot>
</div>
</el-dialog>
</div>
</template>
<script>
export default {
name:'c-dialog',
props:{
title:String,
width:{
type:String,
default:'50%'
}
},
data(){
return{
show:false
}
},
methods:{
handleClose(){
this.show = false
},
change(absolutely){
this.show = absolutely ? false : !this.show
if(this.show == false) this.$emit('close')
}
}
}
</script>
<style scoped lang="less">
</style>
<template>
<div>
<!-- :with-header="false" -->
<el-drawer :withHeader="false"
:visible.sync="drawer" :wrapperClosable="false"
direction="btt"
:before-close="handleClose">
<template v-if="drawer">
<div class="popup-c" :style="{backgroundColor:bgColor}">
<div class="title flex-s">
<span class="title">{{title}}</span>
<i @click="change" class="iconfont icon-tzjk_icon_guanbi"></i>
</div>
<slot></slot>
</div>
</template>
</el-drawer>
</div>
</template>
<script>
import { elDrawer } from 'element-ui';
export default{
name:'c-popup',
props:{
bgColor:{
type:String,
default:'#FFF'
},
title:String
},
mounted() {
},
data(){
return{
drawer:false
}
},
methods:{
handleClose(){
this.drawer = false
},
change(){
this.drawer = !this.drawer
if(this.drawer == false) this.$emit('close')
}
}
}
</script>
<style scoped lang="less">
.title{
font-size: 22px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: #2A3C5A;
line-height: 28px;
.iconfont{
font-size: 18px;
cursor: pointer;
}
}
.popup-c{
position: relative;
width: 90%;
border-radius: 15px;
padding: 20px 0px;
margin: 0px 5%;
background-color: #fff;
}
/deep/ .el-drawer{
height: 95% !important;
// background-color: #FFF !important;
}
/deep/ .el-drawer__body{
overflow-y: scroll;
margin-bottom: 30px;
}
/deep/ .el-drawer{
border-top-left-radius: 16px;
border-top-right-radius: 16px;
}
/deep/ .el-drawer__body::-webkit-scrollbar {
/*滚动条整体样式*/
width: 0px;
height: 0px;
}
/deep/ .el-drawer__body::-webkit-scrollbar{
display: none !important;
}
</style>
\ No newline at end of file
<!--
* @Author: tangjiale
* @eMail: 932055106@qq.com
* @Date: 2022-02-11 16:51:59
* @LastEditors: tangjiale
* @LastEditTime: 2022-02-18 18:08:22
-->
<template>
<div class="layout-r">
<el-menu class="el-menu-demo" mode="horizontal" background-color="#f0f2f5" active-text-color="#f0f2f5">
<el-menu-item :id="routeActive == item.url ? 'tab-border' : ''" @click="goLink(item)" v-for="(item, index) in historyRoute" :index="item.url">
<div class="route-tab">{{item.name}} <i @click.stop="delRoute(item,index)" class="el-icon-close"></i></div>
</el-menu-item>
</el-menu>
</div>
</template>
<script>
export default {
name: "history-router",
data(){
return{
}
},
mounted(){
},
methods:{
//删除路由
delRoute(data,idx){
if(data.url === '/') return
let list = [...[],...this.historyRoute]
list.splice(idx,1)
//更新最新历史路由
this.$store.commit("updateRoute",list);
//如果不是删除当前路由,就不跳转路由最后一级
if(data.url != this.$route.path){
return
}
this.$router.push(list[list.length - 1].url);
this.$forceUpdate();
},
goLink(data){
this.$router.push(data.url)
}
},
computed:{
routeActive(){
let path = this.$route.path
let routes = this.historyRoute
return ((routes.find(v => v.url == path) && (routes.find(v => v.url == path)).url) || '')
}
}
}
</script>
<style scoped lang="less">
.layout-r{
z-index: 9;
position: fixed;
padding-left: 16px;
top: 64px;
left: 248px;
height: 48px;
width: calc(100vw - 264px);
background: #f0f2f5;
display: flex;align-items: center;
}
.route-tab{
font-size: 14px;
font-family: Microsoft YaHei UI;
font-weight: 400;
color: #606266;
display: flex;
align-items: center;
}
#tab-border .route-tab{
color: #1890FF !important;
}
#tab-border{
border-bottom: 2px solid;
border-bottom-color:#1890FF !important;
}
/deep/ .el-menu{
background:none !important;
}
/deep/ .el-menu .route-tab:hover{
color: #1890FF !important;
}
/deep/ .el-menu-item:hover{
background: none !important;
}
/deep/ .el-menu-item{
border-bottom-color: #f0f2f5 !important;
}
/deep/ .el-menu--horizontal{
display: flex;justify-content: flex-end;height: 100%;
}
/deep/ .el-menu--horizontal>.el-submenu .el-submenu__title,.el-menu--horizontal>.el-menu-item{
height: calc(100% + 1px);line-height: 50px !important;
}
</style>
<template>
<div class="com">
<div class="com_nav">
<el-menu
:default-active="$route.path"
class="com_menu" :unique-opened="true"
:collapse-transition="false"
router background-color="#FFF"
text-color="#8a979e"
active-text-color="#c5cbcf">
<div v-for="(item,index) in leftNav" :key="index">
<!-- 一级菜单(有子级菜单)-->
<el-submenu :index="index + ''" v-if="item.list && item.list.length">
<template slot="title">{{item.name}}</template>
<!-- 遍历二级菜单容器 -->
<div v-for="(i,idx) in item.list" :key="idx">
<!-- 判断二级菜单(有三级菜单)-->
<el-submenu :index="index + '-' + idx" v-if="i.list">
<template slot="title">{{i.name}}</template>
<el-menu-item class="child-nav" :index="j.url" @click="updateRoute(j)" v-for="(j,iIndex) in i.list" :key="iIndex">{{j.name}}</el-menu-item>
</el-submenu>
<!-- 判断二级菜单(没有三级菜单)-->
<el-menu-item :index="i.url" v-else @click="updateRoute(i)">{{i.name}}</el-menu-item>
</div>
</el-submenu>
<!-- 一级菜单(没有任何子级菜单)-->
<el-menu-item :index="item.url || ''" v-else @click="updateRoute(item)">
<!--<i v-if="item.icon" class="iconfont" :class="[item.icon,item.url == $route.path?'active-a':'active-n']"></i>-->
{{item.name}}
</el-menu-item>
</div>
</el-menu>
</div>
</div>
</template>
<script>
export default {
name: "left-nav",
services:['base'],
props:{
// leftNav:{
// type:Array,
// default:[]
// }
},
data() {
return {
// leftNav:[],
leftNav:[
{name:'首页',url: '/'},
// {
// name:'学生管理',
// list:[
// {name:'页面1',url:'/demo',},
// {name:'页面1--2',url:'/1',},
// {name:'页面1--3',
// list:[
// {name:'页面1--3--1',url:'/2'},
// {name:'页面1--3--2',url:'/3',},
// ]
// }
// ]
// },
{name:'学生管理',url: '/studentManage'},
{name:'课程发布',url:'/courseManage'},
{name:'体验课订单',url:'/experienceOrder'},
{name:'班课报名',url:'/courseJoin'},
]
};
},
mounted() {
// this.getNavList()
},
methods:{
getNavList(){
//菜单列表
this.$service.base.getPermissions().then((res) => {
this.leftNav = res || [];
this.leftNav.unshift({name:'首页',url:'/'})
});
},
updateRoute(item){
let route = this.unique([...this.historyRoute,...[item]],'url')
this.$store.commit("updateRoute",route);
},
unique(arr,val) {
const res = new Map();
return arr.filter(item => !res.has(item[val]) && res.set(item[val], 1))
}
}
};
</script>
<style lang="less" scoped>
.com {
position: fixed;
top: 64px;
left: 0px;
bottom: 0px;
height:calc(100vh - 64px);
width: 232px;
background: #FFF;
&_nav{
height:calc(100vh - 60px);
overflow-y: auto;
&::-webkit-scrollbar {
display: none;
}
}
.el-menu{
border-right: none !important;
}
/*子导航选中*/
/deep/ .com_menu .el-menu .is-active{
background: #ECF5FF !important;
color: #1890FF !important;
}
// 子集悬浮样式
.el-menu-item:hover {
background: #ECF5FF !important;
}
// 一级导航栏选中样式
/deep/ .com_menu div .is-active{
background: #ECF5FF !important;
font-family: Microsoft YaHei UI;
font-weight: 400;
line-height: 22px;
color: #1890FF !important;
}
// 一二级级导航头
/deep/ .el-submenu__title{
display: flex;
align-items: center;
width: 100%;
height: 62px;
margin-left: 0;
padding: 0;
font-size: 16px;
font-family: Microsoft YaHei UI;
font-weight: 400;
line-height: 22px;
color: #606266 !important;
}
/deep/ .el-submenu__title:hover{
background: #ECF5FF !important;
}
/deep/ .el-submenu__title .el-icon-arrow-down{
font-size: 18px;
}
/deep/ .el-menu{
border-left: none !important;
}
/*二三级子集样式*/
/deep/ .is-opened .el-menu-item{
height: 48px !important;
font-size: 14px;
font-family: Microsoft YaHei UI;
font-weight: 400;
line-height: 22px;
color: #606266;
}
.el-menu-item {
display: flex;
align-items: center;
width: 100%;
height: 62px;font-size: 16px;
margin-left: 0;
padding: 0;
font-weight: 500 !important;
line-height: 22px;
color: rgba(0, 0, 0, 0.85) !important;
.menu-name {
font-size: 18px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
}
.menu-img {
width: 32px;
height: 32px;
margin-left: 10px;
margin-right: 15px;
}
}
}
</style>
<!--
* @Author: tangjiale
* @eMail: 932055106@qq.com
* @Date: 2022-02-22 09:17:53
* @LastEditors: tangjiale
* @LastEditTime: 2022-02-22 10:08:11
-->
<template>
<div>
<el-form
:model="dataForm"
:rules="dataRule"
ref="dataForm"
@keyup.enter.native="dataFormSubmit()"
label-width="90px"
>
<el-form-item label="账号">
<span>{{myUserInfo.account}}</span>
</el-form-item>
<el-form-item label="原密码" prop="password">
<el-input type="password" v-model="dataForm.password"></el-input>
</el-form-item>
<el-form-item label="新密码" prop="newPassword">
<el-input type="password" v-model="dataForm.newPassword"></el-input>
</el-form-item>
<el-form-item label="确认密码" prop="confirmPassword">
<el-input type="password" v-model="dataForm.confirmPassword"></el-input>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="$emit('close')">取消</el-button>
<el-button type="primary" @click="dataFormSubmit()">确定</el-button>
</span>
</div>
</template>
<script>
export default {
services:['base'],
data(){
var validateConfirmPassword = (rule, value, callback) => {
if (this.dataForm.newPassword !== value) {
callback(new Error("确认密码与新密码不一致"));
} else {
callback();
}
};
return{
dataForm: {
password: "",
newPassword: "",
confirmPassword: "",
},
dataRule: {
password: [
{ required: true, message: "原密码不能为空", trigger: "blur" },
],
newPassword: [
{ required: true, message: "新密码不能为空", trigger: "blur" },
],
confirmPassword: [
{ required: true, message: "确认密码不能为空", trigger: "blur" },
{ validator: validateConfirmPassword, trigger: "blur" },
],
},
}
},
methods:{
dataFormSubmit() {
this.$refs["dataForm"].validate((valid) => {
if (valid) {
var params = {
oldPassword: this.dataForm.password,
newPassword: this.dataForm.newPassword,
};
this.$service.base.resetPassword(params).then(res =>{
this.$notifySuccess()
setTimeout(() =>{
this.$store.commit("logout");
},1500)
})
}
});
},
}
}
</script>
<style lang="less" scoped>
</style>
\ No newline at end of file
<template>
<div>
<div class="layout-t">
<div class="head-title">
奔腾宝贝培训学校管理系统
</div>
<div class="flex-c">
<!--权限配置栏-->
<el-dropdown class="margin-r" @command="changeRole" v-if="roleList && roleList.length">
<span class="el-dropdown-link">{{roleList[roleList.findIndex(v => v.currentRole == true)].description}}<i class="el-icon-arrow-down el-icon--right"></i></span>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item :command="role" v-for="(role,idx) in roleList" :key="idx">{{role.description}}</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
<!--信息操作栏-->
<el-dropdown class="margin-r" @command="doneOption">
<span class="el-dropdown-link">
<div class="flex-c">
<img class="header" src="../../assets/images/boy.png" alt=""> {{myUserInfo && myUserInfo.userName}}
</div>
</span>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item command="update">修改密码</el-dropdown-item>
<el-dropdown-item command="layout">退出</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</div>
</div>
<!-- 修改密码 -->
<c-dialog ref="r-dialog" title="修改密码" width="950px">
<reset-password @close="$refs['r-dialog'].change()"></reset-password>
</c-dialog>
</div>
</template>
<script>
import resetPassword from './reset-password.vue'
export default {
name: "top-head",
components:{resetPassword},
services:['base'],
data(){
return{
activeIndex:'0',
roleList:[],
}
},
mounted(){
//获取权限列表
this.getRoleList()
},
methods:{
getRoleList(){
this.$service.base.queryRoleList().then((res) => {
this.roleList = res || [];
});
},
//切换角色
changeRole(e){
if(e.roleId == this.myUserInfo.roleId){
return
}
this.$service.base.changeRole(e.roleId).then(res =>{
this.$notifySuccess()
//获取最近用户信息更新
this.$service.base.getUserInfo(this.myUserInfo.token).then(result =>{
this.$store.commit('updateUserInfo', result);
setTimeout(() =>{
location.href = '/'
},500)
})
})
},
//其他操作配置方法
doneOption(type){
switch (type) {
//修改密码
case 'update':
this.$refs['r-dialog'].change()
break
case 'layout':
this.$showConfirm("是否确认退出登录?").then(() => {
this.$store.commit("logout");
});
break
}
}
}
}
</script>
<style scoped lang="less">
.layout-t{
z-index: 9;
position: fixed;
padding-right: 50px;
padding: 0px 24px 0px 17px;
top: 0px;
left: 0px;
height: 64px;
width: 100%;
background: #fff;
display: flex;
align-items: center;
justify-content: space-between;
box-shadow: 0 2px 4px rgba(0,0,0,.08);
.nav-logo{
width:265px;
}
.head-title{
font-size: 22px;
color:#096DD9;
font-weight: 600;
}
}
.header{
display: block;margin-left: 10px;margin-right: 8px;flex: none;
height: 36px;width: 36px;object-fit: cover;object-position: center;
}
.margin-r{margin-right: 20px;cursor: pointer}
/deep/ .el-menu--horizontal{
display: flex;justify-content: flex-end;height: 100%;
}
/deep/ .el-menu--horizontal>.el-submenu .el-submenu__title,.el-menu--horizontal>.el-menu-item{
height: 100%;line-height: 50px !important;
}
</style>
<!--
* @Author: tangjiale
* @eMail: 932055106@qq.com
* @Date: 2022-02-15 09:35:14
* @LastEditors: tangjiale
* @LastEditTime: 2022-02-17 10:27:26
-->
<template>
<el-dialog title="匹配订单物流信息" class="model-bg" :visible.sync="show"
:close-on-click-modal="false" width="1200px">
<p>
下载模板:<span class="upload-btn" @click="downloadModel">点击下载模板</span>
</p>
<div class="flex-c" style="margin-top:20px">
上传文件:
<el-upload accept="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,application/vnd.ms-excel"
class="upload-demo" :action="uploadUrl()" :headers="myHeader" ref="upload"
:on-exceed="handleExceed"
:before-upload="beforeAvatarUpload"
:on-success="onSuccess"
:on-remove="handleRemove"
:show-file-list="false">
<template>
<el-button type="primary">点击上传(.xls文件)</el-button>
</template>
</el-upload>
</div>
<span slot="footer" class="dialog-footer">
<el-button type="primary" @click="updateList">完 成</el-button>
</span>
</el-dialog>
</template>
<script>
export default {
services:['order','base'],
data(){
return{
show:false,
fileName:'',
file:null,
}
},
methods:{
updateList(){
this.$emit('updateList')
this.changeShow()
},
downloadModel(){
this.$service.order.downloadModel('订单物流信息表').then(res =>{
this.$notifySuccess()
})
},
uploadUrl(){
var url = "";
url = this.$ctx.$config.baseUrl + "/order/updateOrderExpressInfo";
return url;
},
beforeAvatarUpload(file) {
//验证资源格式
let canUpload = ['application/vnd.ms-excel'].includes(file.type);
//限制大小
//const isLt3M = file.size / 1024 / 1024 < 5;
if (!canUpload) {
this.$message.error('资源格式不正确');
return
}
this.fileName = file.name
this.file = file
},
handleExceed() {
this.$message.error('最多上传一份');
},
handleSub(){
if(!this.file){
this.$message.error('请先上传文件');
return
}
},
// 上传成功
onSuccess(e) {
console.log(e);
if (e.code == 200) {
this.$message({ type: "success", message: "导入成功" });
} else {
this.$message({ type: "error", message: e.message });
this.$refs.upload.clearFiles();
}
},
changeShow(){
this.show = !this.show
},
handleRemove(file, fileList) {
//删除重置数据
this.fileList = []
},
},
computed:{
myHeader(){
return {
token:this.myUserInfo.token
}
}
}
}
</script>
<style lang="less" scoped>
.upload-btn{
cursor: pointer;
}
.upload-btn:hover{
color: #409EFF;
}
</style>
\ No newline at end of file
<!--
* @Author: tangjiale
* @eMail: 932055106@qq.com
* @Date: 2022-02-15 14:43:57
* @LastEditors: tangjiale
* @LastEditTime: 2022-02-15 15:43:50
-->
<template>
<el-dialog title="填写商品发货信息" class="model-bg" :visible.sync="show"
:close-on-click-modal="false" width="1000px">
<el-form :model="form" :rules="rules" ref="ruleForm" label-width="90px">
<el-row :gutter="10" v-if="goods">
<el-col :span="8">收件人:{{goods.contactName}}</el-col>
<el-col :span="8">联系电话:{{goods.phone || ''}}</el-col>
<el-col :span="8">收件地址:{{goods.address || ''}}</el-col>
</el-row>
<el-form-item label="快递公司" prop="expressCompany">
<t-select v-model="form.expressCompany" :ds="ds" placeholder="请选择快递公司" clearable></t-select>
</el-form-item>
<el-form-item label="快递单号" prop="expressNo">
<el-input v-model="form.expressNo" placeholder="请输入快递单号" style="width:220px"></el-input>
</el-form-item>
<el-form-item label="发货时间" prop="sendTime">
<el-date-picker placeholder="请选择发货时间" value-format="yyyy-MM-dd"
v-model="form.sendTime"></el-date-picker>
</el-form-item>
<div name="footer" class="footer">
<el-button type="info" @click="show=false">关闭</el-button>
<el-button type="primary" @click="submitForm">确定</el-button>
</div>
</el-form>
</el-dialog>
</template>
<script>
export default {
services:['base','order'],
data(){
return{
goods:{},
ds: { service: "base", func: "queryExpress" },
show:false,
form:{
expressCompany:'',expressNo:'',sendTime:''
},
rules:{
expressCompany: [
{ required: true, message: '请选择快递公司', trigger: 'change' }
],
expressNo: [
{ required: true, message: '请输入快递单号', trigger: 'blur' }
],
sendTime: [
{ required: true, message: '请选择发货时间', trigger: 'change' }
],
}
}
},
methods:{
handleShow(data){
this.goods = data
this.form = {expressCompany:'',expressNo:'',sendTime:'' }
this.show = true
},
submitForm(){
let that = this
this.$refs.ruleForm.validate((valid) => {
if (valid) {
let param = that.form
Object.assign(param,{id:that.goods.id})
that.$service.order.orderDeliver(param).then(res => {
that.$notifySuccess()
that.show = false
that.$emit('updateList')
})
}
})
}
}
}
</script>
<style lang="less" scoped>
.el-row {
margin-bottom: 20px;
&:last-child {
margin-bottom: 0;
}
}
.footer{
display: flex;
justify-content: flex-end;
}
</style>
\ No newline at end of file
<!--
* @Author: tangjiale
* @eMail: 932055106@qq.com
* @Date: 2022-02-15 11:27:11
* @LastEditors: tangjiale
* @LastEditTime: 2022-03-03 10:58:01
-->
<template>
<el-dialog title="商品订单详情" class="model-bg" :visible.sync="show"
:close-on-click-modal="false" width="1200px">
<el-row :gutter="10">
<el-col :span="8">订单类型:{{orderType[detail.orderType] || '腾讯订单'}}</el-col>
<el-col :span="8">订单编号:{{detail.orderNo || ''}}</el-col>
<el-col :span="8">订单状态:{{orderState[detail.orderStatus] || ''}}</el-col>
</el-row>
<el-row :gutter="10">
<el-col :span="8">订单商品:{{detail.productName || ''}}</el-col>
<el-col :span="8">商品规格:{{detail.colorInfo || ''}}</el-col>
<el-col :span="8">商品数量:{{detail.goodsNum || 0}}</el-col>
</el-row>
<el-row :gutter="10">
<el-col :span="8">缴费金额:{{detail.orderTotal / 100 || 0}}</el-col>
<el-col :span="8">下单时间:{{detail.orderTime || ''}}</el-col>
<el-col :span="8">用户类型:{{detail.peopleType == 'Student' ? '学生' : detail.peopleType == 'Teacher' ? '老师' : detail.peopleType == 'OrganMember' ? '机构职员' : ''}}</el-col>
</el-row>
<el-row :gutter="10">
<el-col :span="8">用户姓名:{{detail.userName || ''}}</el-col>
<el-col :span="8">班级名称:{{detail.className || ''}}</el-col>
<el-col :span="8">学校名称: {{detail.schoolName || ''}}</el-col>
</el-row>
<el-divider></el-divider>
<el-row :gutter="10">
<el-col :span="8">收件人:{{detail.contactName || ''}}</el-col>
<el-col :span="8">收件地址:{{detail.address || ''}}</el-col>
<el-col :span="8">联系电话:{{detail.phone || ''}}</el-col>
</el-row>
<el-row :gutter="10">
<el-col :span="8">快递公司:{{detail.expressCompany || ''}}</el-col>
<el-col :span="8">快递单号:{{detail.expressNo || ''}}</el-col>
<el-col :span="8">发货时间:{{detail.sendTime || ''}}</el-col>
</el-row>
<el-row :gutter="10">
<el-col :span="8">收货时间:{{detail.receiveTime || ''}}</el-col>
</el-row>
<el-divider></el-divider>
<el-row :gutter="10">
<el-col :span="8">退货处理:{{detail.refundStatus == 1 ? '部分退货' : detail.refundStatus == 2 ? '全部退货' : ''}}</el-col>
<el-col :span="8">退货商品数量:{{detail.refundNum || ''}}</el-col>
<el-col :span="8">退款理由:{{detail.refundComment || ''}}</el-col>
</el-row>
<el-row :gutter="10">
<el-col :span="8">运费处理:{{detail.refundExpressAmt ? '客户承担运费' : detail.refundNum ? '公司承担运费' : ''}}</el-col>
<el-col :span="8">承担运费金额:{{detail.refundExpressAmt ? (detail.refundExpressAmt / 100).toFixed(2) : ''}}</el-col>
<el-col :span="8">退款金额:{{detail.refundAmt ? (detail.refundAmt / 100).toFixed(2) : ''}}</el-col>
</el-row>
<el-row :gutter="10">
<el-col :span="8">退款时间:{{detail.refundTime || ''}}</el-col>
</el-row>
<span slot="footer" class="dialog-footer">
<el-button type="primary" @click="show = false">关 闭</el-button>
</span>
</el-dialog>
</template>
<script>
export default {
services:['order'],
data(){
return{
show:false,
detail:{},
orderType:['','自营订单','移动订单','','天天订单'], //订单类型
orderState:['待支付','待发货','已退款','已收货','已取消','待收货'],
}
},
methods:{
queryOrderDetail(id){
this.detail = {}
this.show = true
this.$service.order.queryOrderDetail(id).then(res =>{
this.detail = res
})
}
}
}
</script>
<style lang="less" scoped>
.el-row {
margin-bottom: 20px;
&:last-child {
margin-bottom: 0;
}
}
</style>
\ No newline at end of file
<!--
* @Author: tangjiale
* @eMail: 932055106@qq.com
* @Date: 2022-02-16 08:45:51
* @LastEditors: tangjiale
* @LastEditTime: 2022-03-03 15:59:57
-->
<template>
<el-dialog title="订单信息" class="model-bg" :visible.sync="show"
:close-on-click-modal="false" width="1200px">
<el-form :model="form" :rules="rules" ref="ruleForm" >
<el-row :gutter="10">
<el-col :span="8">订单类型:{{orderType[detail.orderType] || '腾讯订单'}}</el-col>
<el-col :span="8">订单编号:{{detail.orderNo || ''}}</el-col>
<el-col :span="8">订单状态:{{orderState[detail.orderStatus] || ''}}</el-col>
</el-row>
<el-row :gutter="10">
<el-col :span="8">订单商品:{{detail.productName || ''}}</el-col>
<el-col :span="8">商品规格:{{detail.colorInfo || ''}}</el-col>
<el-col :span="8">商品数量:{{detail.goodsNum || 0}}</el-col>
</el-row>
<el-row :gutter="10">
<el-col :span="8">缴费金额:{{detail.orderTotal / 100 || 0}}</el-col>
<el-col :span="8">下单时间:{{detail.orderTime || ''}}</el-col>
<el-col :span="8">用户类型:{{detail.peopleType == 'Student' ? '学生' : detail.peopleType == 'Teacher' ? '老师' : detail.peopleType == 'OrganMember' ? '机构职员' : ''}}</el-col>
</el-row>
<el-row :gutter="10">
<el-col :span="8">用户姓名:{{detail.userName || ''}}</el-col>
<el-col :span="8">班级名称:{{detail.className || ''}}</el-col>
<el-col :span="8">学校名称: {{detail.schoolName || ''}}</el-col>
</el-row>
<el-divider></el-divider>
<el-row :gutter="10">
<el-col :span="8">收件人:{{detail.contactName || ''}}</el-col>
<el-col :span="8">收件地址:{{detail.address || ''}}</el-col>
<el-col :span="8">联系电话:{{detail.phone || ''}}</el-col>
</el-row>
<el-row :gutter="10">
<el-col :span="8">快递公司:{{detail.expressCompany || ''}}</el-col>
<el-col :span="8">快递单号:{{detail.expressNo || ''}}</el-col>
<el-col :span="8">发货时间:{{detail.sendTime || ''}}</el-col>
</el-row>
<el-row :gutter="10">
<el-col :span="8">收货时间:{{detail.receiveTime || ''}}</el-col>
</el-row>
<el-divider></el-divider>
<div class="tab-title">填写退货信息:</div>
<el-row :gutter="10">
<!-- <el-col :span="8">
<el-form-item label="退款时间" prop="refundTime">
<el-date-picker placeholder="请选择退款时间" value-format="yyyy-MM-dd"
v-model="form.refundTime"></el-date-picker>
</el-form-item>
</el-col> -->
<el-col :span="8">
<el-form-item label="退货处理" prop="refundStatus">
<t-select @input="changeVal" v-model="form.refundStatus" :ds="[{name:'部分退货',value:1},{name:'全部退货',value:2}]" placeholder="请选择退货处理方式" clearable></t-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="退货商品数量" prop="refundNum">
<el-input-number v-model="form.refundNum" :min="1" :max="detail.refundNum ? detail.goodsNum - detail.refundNum : detail.goodsNum" :disabled="form.refundStatus == 2" label="描述文字"></el-input-number>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="退款理由" prop="refundComment">
<t-select v-model="form.refundComment" :ds="ds" placeholder="请选择退款理由" clearable></t-select>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="10" >
<el-col :span="8">
<el-form-item label="运费处理" prop="yunfeiType">
<t-select @input="changeYunfei" v-model="form.yunfeiType" :ds="[{name:'客户承担运费',value:1},{name:'公司承担运费',value:2}]" placeholder="请选择运费处理" clearable></t-select>
</el-form-item>
</el-col>
<el-col :span="8" v-if="form.yunfeiType != 2">
<el-form-item label="扣除运费金额" prop="refundExpressAmt">
<el-input v-model="form.refundExpressAmt" onkeyup="this.value=this.value.replace(/^\D*(\d*(?:\.\d{0,2})?).*$/g,'$1')"
onafterpaste="this.value=this.value.replace(/^\D*(\d*(?:\.\d{0,2})?).*$/g,'$1')" placeholder="请输入扣除运费金额" style="width:220px"></el-input>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="退款金额">
{{refundTotal}}
</el-form-item>
</el-col>
</el-row>
<div name="footer" class="footer">
<el-button type="info" @click="show=false">关闭</el-button>
<el-button type="primary" @click="submitForm">确定</el-button>
</div>
</el-form>
</el-dialog>
</template>
<script>
export default {
services:['order'],
data(){
return{
detail:{},
show:false,
orderType:['','自营订单','移动订单','','天天订单'], //订单类型
orderState:['待支付','待发货','已退款','已收货','已取消','待收货'],
ds:[{name:'商品货物不符合',value:'商品货物不符合'},{name:'多拍/拍错/不想要',value:'多拍/拍错/不想要'},{name:'地址/电话信息填写错误',value:'地址/电话信息填写错误'},
{name:'7天无理由退换货',value:'7天无理由退换货'},{name:'商品质量',value:'商品质量'}],
form:{
refundComment:'',refundStatus:'',refundNum:'',refundExpressAmt:'',id:'',refundTime:''
},
rules:{
// refundTime: [
// { required: true, message: '请选择退款时间', trigger: 'change' }
// ],
refundStatus: [
{ required: true, message: '请选择退货处理方式', trigger: 'change' }
],
refundNum:[
{ required: true, message: '请选择退货商品数量', trigger: 'change' }
],
refundComment: [
{ required: true, message: '请选择退款理由', trigger: 'change' }
],
yunfeiType:[
{ required: true, message: '请选择运费处理方式', trigger: 'change' }
],
refundExpressAmt:[
{ required: true, message: '请输入扣除运费金额', trigger: 'change' }
]
}
}
},
methods:{
//退货处理
changeVal(val){
if(val == 2){
this.form.refundNum = this.detail.refundNum ? this.detail.goodsNum - this.detail.refundNum : this.detail.goodsNum
}
},
changeYunfei(val){
if(val == 2){
this.form.refundExpressAmt = ''
}
},
queryOrderDetail(id){
this.detail = {}
this.show = true
this.$service.order.queryOrderDetail(id).then(res =>{
this.detail = res
this.form.id = id
})
},
submitForm(){
let that = this
this.$refs.ruleForm.validate((valid) => {
if (valid) {
that.$showConfirm(`${that.detail.userName}退货(${that.detail.productName},数量${that.form.refundNum})处理,退款金额${that.refundTotal}元!是否确定退货?`, "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(res =>{
let param = {...{},...that.form}
param['refundAmt'] = (that.refundTotal * 100)
param.refundExpressAmt = param.refundExpressAmt ? (param.refundExpressAmt * 100) : ''
delete param.yunfeiType
that.$service.order.refundOrder(param).then(res => {
that.$notifySuccess()
that.show = false
that.$emit('updateList')
})
})
}
})
}
},
computed:{
refundTotal(){
//单价
let unitPrice = (this.detail.unitPrice / 100) //0.01
//退款金额
let refundPrice = this.form.refundNum * unitPrice - (this.form.refundExpressAmt || 0)
return (refundPrice).toFixed(2)
}
},
watch:{
show (newVal, oldVal) {
if(newVal == false){
this.form = {refundComment:'',refundStatus:'',refundNum:'',refundExpressAmt:'',id:'',refundTime:''}
this.$nextTick(() => {
this.$refs['ruleForm'].clearValidate()
})
}
}
}
}
</script>
<style lang="less" scoped>
.el-row {
margin-bottom: 20px;
&:last-child {
margin-bottom: 0;
}
}
/deep/ .el-form-item{
margin-bottom: 0px !important;
}
.tab-title{
font-size: 16px;
padding-bottom: 15px;
}
/deep/ .el-input-number__increase{
right: 2px !important;
}
.footer{
display: flex;
justify-content: flex-end;
}
</style>
\ No newline at end of file
{
"env": "dev",
"baseUrl": "http://tgoodsadmin.xiaobentiyu.cn",
"loginUrl":"http://tgoodsadminh5.xiaobentiyu.cn/login",
"user":"http://tbaseh5.xiaobentiyu.cn/"
}
{
"env": "pro",
"baseUrl": "http://goodsadminapi.xiaobentiyu.cn",
"loginUrl":"http://portal.xiaobentiyu.cn/login",
"user":"http://portal.xiaobentiyu.cn/"
}
<!--
* @Author: tangjiale
* @eMail: 932055106@qq.com
* @Date: 2022-02-11 16:53:37
* @LastEditors: tangjiale
* @LastEditTime: 2022-06-02 14:25:18
-->
<template>
<div class="customer">
<template v-if="showTop">
<!--左侧导航-->
<left-nav></left-nav>
<!--页面历史路由-->
<history-router></history-router>
<!--页面头部-->
<top-head></top-head>
</template>
<div :class="showTop ? 'customer-main':''">
<nuxt keep-alive/>
</div>
</div>
</template>
<script>
import LeftNav from '@/components/layout/left-nav'
import TopHead from '@/components/layout/top-head'
import HistoryRouter from '@/components/layout/history-router'
export default {
components: {
LeftNav,TopHead,HistoryRouter
},
data () {
return {
showTop: false,
};
},
mounted () {
//若第一次打开页面的路径不为首页,强制跳转
// if(!this.$route.path || (this.$route.path && this.$route.path != '/' && this.$route.path != '/login')){
// location.href = '/'
// return
// }
this.checkRoute();
},
watch: {
$route () {
this.checkRoute();
}
},
methods: {
checkRoute () {
this.showTop = !(this.$route.name === 'login' || this.$route.name === 'forget');
}
}
};
</script>
<style lang="less">
*,
*:before,
*:after {
box-sizing: border-box;
margin: 0;
padding: 0;
font-size: 14px;
}
.customer{
position: relative;
min-height: 100vh;
// padding: 10px;
overflow: hidden;
width: 100%;
background-color: rgba(240, 242, 245, 1);
&-main{
padding: 0;
width: calc(100% - 264px);
min-height: calc(100vh - 112px);
margin: 112px 16px 32px 248px;
}
}
</style>
<!-- 错误页 -->
<template>
<div class="error-page">
<div class="error-msg">{{error.message}}</div>
</div>
</template>
<script>
export default {
props: [ 'error' ],
data () {
return {};
},
methods: {}
};
</script>
<style scoped lang="less">
.error-page {
.page {
height: calc(100vh - 142px);
}
.error-msg{
display: flex;
align-items: center;
justify-content: center;
height: 100%;
font-size: 30px;
color: #C1D9FF;
}
}
</style>
/*
* @Author: tangjiale
* @eMail: 932055106@qq.com
* @Date: 2022-02-10 15:24:49
* @LastEditors: tangjiale
* @LastEditTime: 2022-02-17 14:15:51
*/
import Vue from 'vue';
import service from '../plugins/framework/core/service';
//用户中心免密登录
const goLogin = function(param){
return Vue.prototype.$ctx.$bean.makeBean("base").userCenterLogin(param);
}
//获取用户信息
const userLogin = function(token){
return Vue.prototype.$ctx.$bean.makeBean("base").getUserInfo(token);
}
export default function({redirect, route, store}) {
if(route.query&&route.query.tbase){
store.commit('updateStateVal', {
key:'tbase',val:route.query.tbase
});
}
//不仅登陆还要带上其他参数赋予指定身份
if(route.query&&route.query.token && route.query.roleId){
let param = {
roleId:route.query.roleId || '',
token:route.query.token
}
return goLogin(param).then(res=>{
return userLogin(route.query.token).then(res=>{
res['token'] = route.query.token
store.commit('updateUserInfo', res);
//跳指定路由
redirect(route.query.url?decodeURIComponent(route.query.url):'/')
})
})
//来源外部的登录
}else if(route.query&&route.query.token){
return goLogin(route.query).then(res=>{
res['token'] = route.query.token
store.commit('updateUserInfo', res);
redirect('/')
})
//人人通免密登录
}else if(route.query&&route.query.code){
return rrtLogin(route.query.code).then(res=>{
res['token'] = route.query.token
store.commit('updateUserInfo', res);
redirect('/')
})
}else if(!store.state.myUserInfo) { // 处理没登录的情况
let cache = sessionStorage.getItem('myUserInfo');
if (cache) {
let myUserInfo = JSON.parse(cache);
store.commit('updateUserInfo', myUserInfo);
return Promise.resolve();
} else {
if (route.name !== 'login')
return redirect('/login');
}
}
}
/*
* @Author: tangjiale
* @eMail: 932055106@qq.com
* @Date: 2022-02-11 15:07:57
* @LastEditors: tangjiale
* @LastEditTime: 2022-02-18 09:31:59
*/
const envMap = {
'dev': {
NODE_ENV: 'development',
ENV_CONFIG: 'dev'
},
'pro': {
NODE_ENV: 'production',
ENV_CONFIG: 'pro'
}
}
//获取环境变量
//配置连接 https://www.wenjiangs.com/doc/nuxt-api-configuration-build
const envValue = process.env.ENV_CONFIG;
const env = envMap[envValue]
const ENV_SCRIPT = {
'dev': [
// {src: ''}
],
'pro': [
// {src: ''}
]
};
module.exports = {
mode: 'spa',
head: {
meta: [{charset: 'utf-8'},
{
name: 'viewport',
content: 'width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0'
},
{name: 'applicable-device', content: 'mobile'},
],
link:[
{ rel: "icon", href: "img/tjl_favicon.ico" },
],
script: ENV_SCRIPT[env]
},
css: [
'element-ui/lib/theme-chalk/index.css',
'~/plugins/index.less',
'@/assets/css/icon-font.css',
],
router: {
base: '',
middleware: ['auth']
},
plugins: [
'~/plugins/element-ui',
'~/plugins/index',
'~/plugins/framework-install',
{
src:'~/plugins/plTable',
ssr:false
}
],
loadingIndicator: {
name: 'folding-cube',
color: '#1890FF',
background :'#f0f2f5'
},
server: {
host: '0.0.0.0'
},
build: {
transpile: [ /^element-ui/ ],
postcss: [
require('postcss-px2rem')({
remUnit: 75,
remPrecision: 8
}),
require('autoprefixer')
],
extend (config, ctx) {
}
},
generate: {
routes: null,
fallback: false
},
env: {
...env
}
}
This source diff could not be displayed because it is too large. You can view the blob instead.
{
"name": "house",
"version": "1.0.0",
"description": "",
"author": "tjl",
"private": true,
"scripts": {
"dev": "cross-env ENV_CONFIG=dev nuxt -o --profile",
"dev-prod": "cross-env ENV_CONFIG=pro nuxt -o --profile",
"generate": "cross-env ENV_CONFIG=dev nuxt generate",
"generate-prod": "cross-env ENV_CONFIG=pro nuxt generate"
},
"dependencies": {
"@babel/preset-env": "7.12.17",
"@nuxtjs/axios": "5.11.0",
"cross-env": "^5.2.0",
"element-ui": "2.13.2",
"less-loader": "6.1.1",
"nuxt": "2.12.2",
"sass": "^1.26.10",
"sass-loader": "^9.0.1",
"screenfull": "5.0.2",
"spark-md5": "3.0.1",
"vuex": "3.4.0",
"postcss-loader": "3.0.0",
"autoprefixer": "9.8.5",
"postcss-px2rem": "0.3.0",
"mercury-wrap": "1.2.3",
"pl-table": "^2.7.5",
"aegis-web-sdk": "1.35.25"
},
"devDependencies": {}
}
<!--
* @Author: tangjiale
* @eMail: 932055106@qq.com
* @Date: 2022-06-02 15:02:39
* @LastEditors: tangjiale
* @LastEditTime: 2022-06-02 16:28:28
-->
<template>
<div>
<c-dialog title="新增学生" ref="c-dialog" width="600px">
<el-form ref="ruleForm" :model="param" :rules="rules">
<el-form-item label="学生姓名" prop="name">
<el-input v-model="param.name" placeholder="请输入学生姓名" style="width:222px"></el-input>
</el-form-item>
<el-form-item label="学生性别" prop="sex">
<el-select v-model="param.sex" placeholder="请选择">
<el-option label="男" :value="1"></el-option>
<el-option label="女" :value="2"></el-option>
</el-select>
</el-form-item>
<el-form-item label="出生日期" prop="date">
<el-date-picker v-model="param.date" value-format="yyyy-MM-dd" type="date" placeholder="请选择日期"></el-date-picker>
</el-form-item>
<el-form-item label="爸爸手机号" prop="tel1">
<el-input v-model="param.tel1" placeholder="请输入手机号" style="width:222px"></el-input>
</el-form-item>
<el-form-item label="妈妈手机号" prop="tel2">
<el-input v-model="param.tel2" placeholder="请输入手机号" style="width:222px"></el-input>
</el-form-item>
<el-form-item label="其它人手机号" prop="tel3">
<el-input v-model="param.tel3" placeholder="请输入手机号" style="width:222px"></el-input>
</el-form-item>
<!-- <el-form-item label="所在校区" prop="areaId">
<t-select v-model="param.areaId"></t-select>
</el-form-item> -->
<div class="btns">
<el-button type="primary" @click="change">取消</el-button>
<el-button type="primary" @click="onSubmit('ruleForm')">确定</el-button>
</div>
</el-form>
</c-dialog>
</div>
</template>
<script>
export default {
data(){
return{
param: {
name:'',
sex:'',
tel1:'',
tel2:'',
tel3:'',
areaId:''
},
rules:{
name: [
{ required: true, message: '请输入学生姓名', trigger: 'change' }
],
sex:[
{ required: true, message: '请选择学生性别', trigger: 'change' }
],
date:[{ required: true, message: '请选择生日日期', trigger: 'change' }],
}
}
},
methods:{
change(){
this.$refs['c-dialog'].change()
}
}
}
</script>
<style lang="less" scoped>
/deep/ .el-form-item__label{
width: 120px;
}
.btns{
display: flex;
justify-content: center;
}
/deep/ .el-dialog__body{
padding: 20px 100px;
}
</style>
\ No newline at end of file
<template>
<div class="page-bg">
<t-table autoLoad ref="table" :options="options" :params="params" @row-btn-click="onRowButtonClick">
<template slot="form-order-search">
<div class="search-bottom">
<el-button type="primary" size="mini" plain @click="exportOrder"><i class="el-icon-download"></i> 导出</el-button>
</div>
</template>
<template slot="custom-view-field" slot-scope="scope">
<div v-if="scope.idx === 7">
<t-select v-model="scope.row.taskStatus" :ds="[{name:'同意取消',value:1},{name:'不同意取消',value:2}]" required></t-select>
</div>
</template>
</t-table>
</div>
</template>
<script>
const orderState = ['待支付','待发货','全部退货','已收货','已取消','待收货']
export default {
services:['order','base'],
data(){
return{
params:{
regionCode:'',schName:''
},
options: {
title: "班课报名",
search: [
{
label: '所属校区:',field: 'orderStatus', type: 'select',autoSelect:true,required:true,
ds: [{name:'全部',value:''}, {name:'待发货',value:1}, {name:'已退货',value:2}, {name:'已收货',value:3}, {name:'已取消',value:4}, {name:'待收货',value:5}]
},{
label: '报名状态:', field: 'valid', type: 'select',autoSelect:true,required:true,
ds: [{name:'全部',value:''}, {name:'待确认报名',value:1}, {name:'待取消报名',value:0},{name:'已确认报名',value:0}]
},{
label: '课程日期' ,field :'valid',type :'daterange'
},{
placeholder: "请输入学生姓名或课程名称 ",field: "productName",type: "text",label: "名字/名称",
},
],
table: {
service: "order", height:(screen.height - (482 * this.$px2rem)),
func: "getOrderPcList",
selectable: false,customRow:true,
columns: [
{title: "学生姓名",field: "orderNo",width:'150px',},
{
title: "性别",width:'120px',
type: 'customField',
fieldFunction: row => true ? '男' : '女',
},
{title: "联系方式",field: "orderNo"},
{title: "课程名称",field: "orderNo"},
{title: "所选校区",field: "orderNo"},
{
title: "报名状态",width:'120px',
type: 'customField',
fieldFunction: row => (orderState[row.orderStatus] || ''),
},
{title: "价格",field: "orderNo",width:'150px'},
{title: "操作",type: "customViewField",width:'150px'}
],
},
},
}
},
methods:{
onRowButtonClick(data, i) {
let self = this
let {event,row} = data
if(!event) return
switch (event) {
case 'agree': //同意退款
break
case 'refuce': //同意退款
break
}
},
exportOrder(){
}
}
}
</script>
<style lang="less" scoped>
.page-bg{
position: relative;
background-color: #fff;
padding: 10px 10px;
}
.search-bottom{
width: calc(100% - 2px);
background-color: #fff;
padding: 15px 0px 10px 0px;
height: 60px;
display: flex;
align-items: center;
border-top: 1px solid #E4E7ED;
margin: 0px 12px;
button{
min-width: 100px !important;
}
}
</style>
\ No newline at end of file
<!--
* @Author: tangjiale
* @eMail: 932055106@qq.com
* @Date: 2022-06-02 14:08:46
* @LastEditors: tangjiale
* @LastEditTime: 2022-06-02 17:23:17
-->
<template>
<div class="page-bg">
<t-table autoLoad ref="table" :options="options" :params="params"
@row-btn-click="onRowButtonClick">
<!-- 操作栏 -->
<template slot="form-order-search">
<div class="search-bottom">
<el-button type="primary" size="mini" plain @click="exportOrder"><i class="el-icon-plus"></i> 新增课程</el-button>
</div>
</template>
</t-table>
</div>
</template>
<script>
export default {
services:['order','base'],
data(){
return{
params:{
regionCode:'',schName:''
},
options: {
title: "订单管理",
search: [
{
label: '所属校区:',field: 'orderStatus', type: 'select',autoSelect:true,required:true,
ds: [{name:'全部',value:''}, {name:'待发货',value:1}, {name:'已退货',value:2}, {name:'已收货',value:3}, {name:'已取消',value:4}, {name:'待收货',value:5}]
},{
label: '课程属性:', field: 'valid', type: 'select',autoSelect:true,required:true,
ds: [{name:'全部',value:''}, {name:'小学组',value:1}, {name:'初中组',value:0},{name:'高中组',value:0}]
},{
label: '课程类型:', field: 'valid', type: 'select',autoSelect:true,required:true,
ds: [{name:'全部',value:''}, {name:'体验课',value:1}, {name:'正式班课',value:0}]
},{
label: '课程状态:', field: 'valid', type: 'select',autoSelect:true,required:true,
ds: [{name:'全部',value:''}, {name:'已发布',value:1}, {name:'未发布',value:0}]
},{
placeholder: "请输入课程名称 ",field: "productName",type: "text",label: "课程名称:",
},
],
table: {
service: "order", height:(screen.height - (482 * this.$px2rem)),
func: "getOrderPcList",
selectable: false,customRow:true,
columns: [
{title: "课程名单",field: "orderNo"},
{title: "所属小区",field: "orderNo"},
{title: "课程属性",field: "orderNo"},
{
title: "课时",width:'100px',
type: 'customField',
fieldFunction: row => 4 + '课时',
},
{title: "课程价格",field: "orderNo"},
{title: "课程类型",field: "orderNo"},
{
title: "操作",
width: "220px",fixed:'right',
type: "buttons",
//orderType 1:智慧体育订单 2移动活动订单 3腾讯同步订单 4 h5天天订单
buttons: [
{
name: "修改", event: "emit" ,type:'primary'
},{
name: "发布", type:'success',event: "publish",
controlBtn:function(data){ return true}
},{
name: "取消发布", type:'success',event: "publish",
controlBtn:function(data){ return data.orderStatus == 3 && (data.orderType == 1 || data.orderType == 4)}
}, {
name: "删除", event: "delete" ,type:'danger'
}
],
},
],
},
},
}
},
methods:{
onRowButtonClick(data, i) {
let self = this
let {event,row} = data
if(!event) return
switch (event) {
case 'emit': //修改
break
}
}
}
}
</script>
<style lang="less" scoped>
.page-bg{
position: relative;
background-color: #fff;
padding: 10px 15px;
}
.search-bottom{
width: calc(100% - 2px);
background-color: #fff;
padding: 15px 0px 10px 0px;
height: 60px;
display: flex;
align-items: center;
border-top: 1px solid #E4E7ED;
margin: 0px 8px;
button{
min-width: 100px !important;
}
}
</style>
\ No newline at end of file
<template>
<div class="page-bg">
<t-table autoLoad ref="table" :options="options" :params="params" @row-btn-click="onRowButtonClick">
<!-- 操作栏 -->
<template slot="form-order-search">
<div class="search-bottom">
<el-button type="primary" size="mini" plain @click="exportOrder"><i class="el-icon-download"></i> 导出</el-button>
</div>
</template>
<template slot="custom-view-field" slot-scope="scope">
<div v-if="scope.idx === 7">
<t-select v-model="scope.row.taskStatus" :ds="[{name:'同意取消',value:1},{name:'不同意取消',value:2}]" required></t-select>
</div>
</template>
</t-table>
</div>
</template>
<script>
const orderState = ['待支付','待发货','全部退货','已收货','已取消','待收货']
export default {
services:['order','base'],
data(){
return{
params:{
regionCode:'',schName:''
},
options: {
title: "体验课订单",
search: [
{
label: '所属校区:',field: 'orderStatus', type: 'select',autoSelect:true,required:true,
ds: [{name:'全部',value:''}, {name:'待发货',value:1}, {name:'已退货',value:2}, {name:'已收货',value:3}, {name:'已取消',value:4}, {name:'待收货',value:5}]
},{
label: '课程属性:', field: 'valid', type: 'select',autoSelect:true,required:true,
ds: [{name:'全部',value:''}, {name:'小学组',value:1}, {name:'初中组',value:0},{name:'高中组',value:0}]
},{
label: '课程类型:', field: 'valid', type: 'select',autoSelect:true,required:true,
ds: [{name:'全部',value:''}, {name:'体验课',value:1}, {name:'正式班课',value:0}]
},{
label: '课程状态:', field: 'valid', type: 'select',autoSelect:true,required:true,
ds: [{name:'全部',value:''}, {name:'已发布',value:1}, {name:'未发布',value:0}]
},{
placeholder: "请输入课程名称 ",field: "productName",type: "text",label: "课程名称:",
},
],
table: {
service: "order", height:(screen.height - (482 * this.$px2rem)),
func: "getOrderPcList",
selectable: false,customRow:true,
columns: [
{title: "学生姓名",field: "orderNo",width:'150px',},
{
title: "性别",width:'120px',
type: 'customField',
fieldFunction: row => true ? '男' : '女',
},
{title: "联系方式",field: "orderNo"},
{title: "课程名称",field: "orderNo"},
{title: "所选校区",field: "orderNo"},
{title: "价格",field: "orderNo",width:'150px',},
{
title: "订单状态",width:'120px',
type: 'customField',
fieldFunction: row => (orderState[row.orderStatus] || ''),
},
{title: "操作",type: "customViewField",width:'150px'}
],
},
},
}
},
methods:{
onRowButtonClick(data, i) {
let self = this
let {event,row} = data
if(!event) return
switch (event) {
case 'agree': //同意退款
break
case 'refuce': //同意退款
break
}
},
exportOrder(){
}
}
}
</script>
<style lang="less" scoped>
.page-bg{
position: relative;
background-color: #fff;
padding: 10px 10px;
}
.search-bottom{
width: calc(100% - 2px);
background-color: #fff;
padding: 15px 0px 10px 0px;
height: 60px;
display: flex;
align-items: center;
border-top: 1px solid #E4E7ED;
margin: 0px 12px;
button{
min-width: 100px !important;
}
}
</style>
\ No newline at end of file
<!--
* @Author: tangjiale
* @eMail: 932055106@qq.com
* @Date: 2022-02-11 16:54:02
* @LastEditors: tangjiale
* @LastEditTime: 2022-02-18 17:52:34
-->
<template>
<div class="page-bg">
<div class="card">
你好!
</div>
</div>
</template>
<script>
export default {
name: "test",
head:{title:'中小学生智慧体育运营平台'},
data(){
return{
}
},
methods:{
}
}
</script>
<style scoped lang="less">
.page-bg{
width: 100%;
.card{
padding: 40px 20px;
background-color: #fff;
}
}
</style>
<template>
<div class="page-bg">
<div class="page-bg-l">
<!-- <img class="login-logo" src="../assets/images/login-logo.png" alt=""> -->
<div class="banner-bg">
<img src="../assets/images/login-image.png" alt="">
<!-- <img src="../static/img/login/login-banner1.png" alt=""> -->
</div>
</div>
<div class="page-bg-r">
<div class="title">登录系统</div>
<div class="input-item">
<i class="iconfont icon-tzjk_icon_user"></i>
<input type="text" maxlength="20" placeholder="账号" v-model="account">
</div>
<div class="input-item">
<i class="iconfont icon-tzjk_icon_pas"></i>
<input type="password" maxlength="20" placeholder="密码" v-model="password">
</div>
<div class="code-bg">
<div class="code-item">
<i class="iconfont icon-tzjk_icon_con"></i>
<input type="text" maxlength="4" placeholder="验证码" v-model="inputCode" @keyup.enter="login">
</div>
<img class="code-img" @click="queryCode" :src="codeUrl" alt="">
</div>
<div class="btn" @click="login">登录</div>
<div class="forget-btn" @click="forgetPw">忘记密码</div>
</div>
</div>
</template>
<script>
export default {
name: "login",
services:['base'],
head:{title:'中小学生智慧体育运营平台'},
data(){
return{
codeUrl:'',
account:'',
password:'',
inputCode:'',
}
},
mounted(){
// 初中帐号:6932230410
//高中帐号:6932230507
//密码都是 pw888888
//test pw123456
//prod 66590816 pw590816
this.queryCode()
},
methods:{
//验证码
queryCode(){
this.$service.base.getCode().then(res =>{
let url = JSON.parse(res)
this.codeUrl = "data:image/png;base64," + url
})
},
login(){
if(!this.account || !this.password || !this.inputCode) return
let that = this
this.$service.base.postUserLogin({
account:this.account,
password: this.password,
inputCode: this.inputCode,
}).then(res =>{
this.$service.base.getUserInfo(res.token).then(result =>{
result.token = res.token
this.$store.commit('updateUserInfo', result);
this.$router.push('/');
})
})
},
forgetPw(){
window.location.href = this.$ctx.$config.user + 'forgetPwd'
}
}
}
</script>
<style scoped lang="less">
input{
height: 26px;
width: 352px;
font-size: 14px;
border: none;
font-family: PingFang SC;
font-weight: bold;
color: #97C5FF;
background:none;
outline:none;
}
.iconfont{
font-size: 24px;
color: #97C5FF;
margin-right: 10px;
line-height: 24px;
}
::-webkit-input-placeholder{/*Webkit browsers*/
font-size: 14px;
font-family: PingFang SC;
font-weight: bold;
color: #97C5FF;
}
:-moz-placeholder{/*Mozilla Firefox 4 to 8*/
font-size: 14px;
font-family: PingFang SC;
font-weight: bold;
color: #97C5FF;
}
::moz-placeholder{/*Mozilla Firefox 19+*/
font-size: 14px;
font-family: PingFang SC;
font-weight: bold;
color: #97C5FF;
}
:-ms-input-placeholder{/*Internet Explorer 10+*/
font-size: 14px;
font-family: PingFang SC;
font-weight: bold;
color: #97C5FF;
}
/deep/ .el-carousel__container{
height: 100% !important;
}
/deep/ .el-carousel__indicator .el-carousel__button{
width: 12px !important;
height: 12px !important;
background: rgba(87, 170, 255, 0.35);
border-radius: 50% !important;
}
/deep/ .is-active .el-carousel__button{
background: #57AAFF !important;
}
.page-bg{
height: 100vh;
width: 100%;
display: flex;
background: #E6F0F6;
&-l{
width: calc(100% - 608px);
height: 100vh;
.login-logo{
height: 42px;
width: 358px;
margin-left: 42px;
margin-top: 35px;
}
.banner-bg{
height: calc(100vh - 213px);
margin-top: 88px;
margin-left: auto;
margin-right: auto;
padding: 80px;
img
{height: 100%;display: block;margin: 0px auto;}
}
}
&-r{
padding-top: 202px;
padding-left: 145px;
padding-right: 145px;
height: 100vh;
width: 708px;
background: #096DD9;
.title{
font-size: 36px;
font-family: PingFang SC;
font-weight: bold;
color: #FFFFFF;
}
.input-item{
margin-top: 47px;
width: 100%;
height: 56px;
background: #0E58B4;
border-radius: 4px;
padding: 16px;
display: flex;
align-items: center;
}
.code-bg{
width: 100%;
margin-top: 47px;
display: flex;
justify-content: space-between;
.code-img{
height: 52px;
width: 155px;
cursor: pointer;
}
.code-item{
height: 52px;
width: calc( 100% - 204px);
background: #0E58B4;
border-radius: 4px;
padding: 16px;
display: flex;
align-items: center;
}
}
.btn{
margin-top: 49px;
height: 56px;
width: 100%;
line-height: 56px;
text-align: center;
background: #22D3F9;
border-radius: 4px;
font-size: 16px;
font-family: PingFang SC;
font-weight: bold;
color: #01517B;cursor: pointer;
}
.forget-btn{
cursor: pointer;
margin-top: 41px;
text-align: center;
font-size: 14px;
font-family: PingFang SC;
font-weight: bold;
color: #97C5FF;
text-decoration:underline;
letter-spacing:3px;
}
}
}
</style>
<!--
* @Author: tangjiale
* @eMail: 932055106@qq.com
* @Date: 2022-02-11 16:58:50
* @LastEditors: tangjiale
* @LastEditTime: 2022-02-18 16:10:14
-->
<template>
<!-- 订单统计页面 -->
<div class="page-bg">
<t-table
ref="table"
:options="options"
:params="params"
autoLoad
@reload="reloadParam"
@row-btn-click="onRowButtonClick"
>
<!-- 自定义懒加载联级地区组件 -->
<template slot="slot-area">
<el-cascader
placeholder="请选择区域" :show-all-levels="false"
v-model="params.regionCode"
:props="adressProps"
></el-cascader>
</template>
<!-- 自定义模糊搜索组件 -->
<template slot="slot-school">
<el-autocomplete
v-model="params.schName"
:fetch-suggestions="querySearchAsync"
placeholder="请输入内容"
></el-autocomplete>
</template>
<template slot="form-order-search">
<div class="search-bottom">
<el-button size="mini" @click="exportOrderAnalysis"
><i class="el-icon-download"></i> 导出</el-button
>
</div>
</template>
</t-table>
</div>
</template>
<script>
export default {
services: ["order", "base", "analysis"],
head:{title:'中小学生智慧体育运营平台'},
data() {
return {
adressProps: {
lazy: true, //可以理解为开关,什么时候结束
checkStrictly: true,
expandTrigger: "hover",
lazyLoad: this.cascaderLazyLoad,
emitPath: false,
},
params: {
regionCode: "",
schName: "",
},
options: {
title: "订单统计",
search: [
{
field: "startDate,endDate",
type: "daterange",
label: "统计时间",
},
{ type: "slot", slotName: "slot-area", label: "区域:",field:'regionCode'},
//自定义筛选组件插槽
{ type: "slot", slotName: "slot-school", label: "学校:",field:'schName'},
// 选择器值从接口获取
{
label: "学年学期:",
autoSelect: true,
field: "inYearAndTerm",
type: "select",
ds: { service: "analysis", func: "getInYearAndTermList" },
},
{
field: "productId",
autoSelect: true,
label: "商品:",
type: "select",
ds: { service: "analysis", func: "getGoodsList" },
}
],
table: {
service: "analysis",
func: "getOrderAnalysisList",
selectable: false,
customRow: true,
columns: [
{ title: "机构名称", field: "schName"},
{
title: "总人数",type: "customField",
fieldFunction: (row) =>
row.totalPeople > 0 ? row.totalPeople : "-",
},
{
title: "学生人数",type: "customField",
fieldFunction: (row) => (row.totalStu > 0 ? row.totalStu : "-"),
},
{
title: "教师人数",type: "customField",
fieldFunction: (row) => (row.totalTea > 0 ? row.totalTea : "-"),
},
{
title: "订单数",type: "customField",
fieldFunction: (row) =>
row.orderPeople > 0 ? row.orderPeople : "-",
},
{
title: "商品数量",type: "customField",
fieldFunction: (row) => (row.goodsNum > 0 ? row.goodsNum : "-"),
},
{
title: "学生订单数",
type: "customField",
fieldFunction: (row) => (row.orderStu > 0 ? row.orderStu : "-"),
},
{
title: "教师订单数",
type: "customField",
fieldFunction: (row) => (row.orderTea > 0 ? row.orderTea : "-"),
},
{
title: "机构订单数",
type: "customField",
fieldFunction: (row) =>
row.orderMember > 0 ? row.orderMember : "-",
},
{
title: "转化率",
showDisable: true,
type: "customField",
fieldFunction: (row) => row.changePercent + "%",
},
],
},
},
};
},
methods: {
onRowButtonClick(data, i) {
let { event, row } = data;
},
//模糊搜索学校
querySearchAsync(queryString, cb) {
console.log(queryString);
this.$service.base.getUserAllSchList(queryString).then((res) => {
cb(res);
});
},
reloadParam(){
this.params = {
regionCode:'',schName:''
}
},
//导出订单列表
exportOrderAnalysis() {
let param = {
...this.$refs["table"].searchForm,
...this.params,
};
if (
param["startDate,endDate"] &&
param["startDate,endDate"].length
) {
param.startDate = param["startDate,endDate"][0];
param.endDate = param["startDate,endDate"][1];
}
delete param["startDate,endDate"];
delete param.undefined
let failName = `订单统计列表${
param.startDate ? "-" + param.endDate : ""
}`;
this.$service.analysis
.exportOrderAnalysisList(param, failName)
.then((res) => {
this.$notifySuccess();
});
},
cascaderLazyLoad(node, resolve) {
if (!node) {
return false;
}
const { level } = node;
let code = node.value || "";
this.$service.order
.getUserOrganList(
level == 0
? {}
: {
code,
regionLevel: level == 1 ? 2 : 4, //2省 4市 6区
}
)
.then((res) => {
let list = [];
if (res && res.length) {
list = res.map((val) => {
return {
value: val.code,
label: val.shortName,
leaf: level >= 2, //因为省市区三项,所以第三次点击就不用在加载了,所以 >=2
};
});
}
if(level == 0){
list.unshift({
value:'all',label:'全国',leaf: level >= 0,
})
}
resolve(list);
});
},
},
};
</script>
<style lang="less" scoped>
.search-bottom {
width: calc(100% - 2px);
background-color: #fff;
padding: 10px;
border-top: 1px solid #e4e7ed;
margin-bottom: 16px;
}
</style>
<!--
* @Author: tangjiale
* @eMail: 932055106@qq.com
* @Date: 2022-02-11 16:58:50
* @LastEditors: tangjiale
* @LastEditTime: 2022-03-03 10:03:01
-->
<template>
<!-- 订单管理页面 -->
<div class="page-bg">
<t-table ref="table" :options="options" :params="params"
@reload="reloadParam"
@row-btn-click="onRowButtonClick">
<!-- 自定义懒加载联级地区组件 -->
<template slot="slot-area">
<el-cascader placeholder="请选择区域" :show-all-levels="false" v-model="params.regionCode" :props="adressProps"></el-cascader>
</template>
<!-- 自定义模糊搜索组件 -->
<template slot="slot-school">
<el-autocomplete
v-model="params.schName"
:fetch-suggestions="querySearchAsync"
placeholder="请输入内容"
></el-autocomplete>
</template>
<template slot="form-order-search">
<div class="search-bottom">
<el-button size="mini" @click="exportOrder"><i class="el-icon-download"></i> 导出订单</el-button>
<!-- 超级管理员和客服有次权限 产品+ -->
<el-button v-if="myUserInfo.roleId == 11 || myUserInfo.roleId == 1" size="mini" @click="$refs['logistics'].changeShow()"><i class="el-icon-upload"></i> 导入(物流信息匹配)</el-button>
</div>
</template>
</t-table>
<!-- 物流匹配信息 -->
<export-logistics ref="logistics" @updateList="$refs['table'].reload()"></export-logistics>
<!-- 订单详情 -->
<order-detail ref="order-detail"></order-detail>
<!-- 订单发货 -->
<goods-deliver ref="goods-deliver" @updateList="$refs['table'].reload()"></goods-deliver>
<!-- 订单退款 -->
<order-refund ref="order-refund" @updateList="$refs['table'].reload()"></order-refund>
</div>
</template>
<script>
const orderState = ['待支付','待发货','全部退货','已收货','已取消','待收货']
const orderType = ['','小奔线上自营订单','移动活动订单','腾讯同步订单','渠道专属运营订单']
import exportLogistics from '../components/order/export-logistics.vue'
import orderDetail from '../components/order/order-detail.vue'
import goodsDeliver from '../components/order/goods-deliver'
import orderRefund from '../components/order/order-refund.vue'
export default {
services:['order','base'],
head:{title:'中小学生智慧体育运营平台'},
components:{exportLogistics,orderDetail,goodsDeliver,orderRefund},
data(){
return{
adressProps: {
lazy: true, //可以理解为开关,什么时候结束
checkStrictly:true,expandTrigger: 'hover',
lazyLoad: this.cascaderLazyLoad,
emitPath:false
},
params:{
regionCode:'',schName:''
},
options: {
title: "订单管理",
search: [
{
label: '订单状态:',field: 'orderStatus', type: 'select',autoSelect:true,required:true,
ds: [{name:'全部',value:''}, {name:'待发货',value:1}, {name:'已退货',value:2}, {name:'已收货',value:3}, {name:'已取消',value:4}, {name:'待收货',value:5}]
},
{type:'slot',slotName:'slot-area',label: "区域:",field:'regionCode'},
{
label: '支付状态:',placeholder: '请选择', field: 'payStatus', type: 'select',autoSelect:true,required:true,
ds: [{name:'全部',value:''}, {name:'待支付',value:0}, {name:'已支付',value:1},{name:'已退款',value:2}]
},
{ field: "startOrderTime,endOrderTime", type: "daterange", label: "统计时间:" },
{
label: '有效状态:', field: 'valid', type: 'select',autoSelect:true,required:true,
ds: [{name:'全部',value:''}, {name:'有效',value:1}, {name:'无效',value:0}]
},
// 选择器值从接口获取
{
label: "订单类型:",autoSelect:true,required:true,
field: "orderType",
type: "select",
ds: { service: "order", func: "getSysUserOrderTypeList" },
},
//自定义筛选组件插槽
{type:'slot',slotName:'slot-school',label: "学校:",field:'schName'},
//选择器值前端写死
{
label: '用户类型:', field: 'peopleType', type: 'select',autoSelect:true,required:true,
ds: [{name:'全部',value:''}, {name:'老师',value:'Teacher'}, {name:'学生',value:'Student'},{name:'机构职员',value:'OrganMember'}]
},
{
placeholder: "请输入商品名称 ",field: "productName",type: "text",label: "商品名称:",
},
{
placeholder: "请输入手机号码 ",field: "phone",type: "text",label: "手机号码:",
}
],
table: {
service: "order", height:(screen.height - (462 * this.$px2rem)),
func: "getOrderPcList",
selectable: false,customRow:true,
columns: [
{title: "订单类型",width:'130px',type: 'customField',
fieldFunction: row => (orderType[row.orderType] || ''),
},
{title: "订单编号",field: "orderNo",width:'130px'},
{title: "收货人",field: "contactName",width:'120px'},
{title: "收件地址",field: "address",width:'130px'},
{title: "联系电话",field: "phone",width:'130px'},
{title: "下单时间",field: "orderTime",width:'130px'},
// 自定义表格展示内容
{
title: "订单状态",width:'110px',
type: 'customField',
fieldFunction: row => (orderState[row.orderStatus] || ''),
},
{
title: "支付状态",width:'110px',
type: 'customField',
fieldFunction: row => row.payStatus == 0 ? '待支付' : row.payStatus == 1 ? '已支付' : '已退款',
},
{title: "订单商品",field: "productName",width:'130px'},
{title: "商品规格",field: "colorInfo",width:'120px'},
{title: "商品数量",field: "goodsNum",width:'100px'},
{title: "学校",field: "schName",width:'130px'},
{title: "快递单号",field: "expressNo",width:'130px'},
{title: "快递公司",field: "expressCompany",width:'110px'},
{title: "退货处理",width:'110px',
type: 'customField',
fieldFunction: row => row.refundStatus == 1 ? '部分退货' : row.refundStatus == 2 ? '全部退货' : '-',},
{title: "退货数量",field: "refundNum",width:'80px'},
{
title: "备注",width:'160px',type: 'customField',
fieldFunction:row => row.refundExpressAmt?`扣除运费(${row.refundExpressAmt / 100}元)` : '-',
},
{
title: "操作",
width: "100px",fixed:'right',
type: "buttons",
showDisable:true,
noDisabledFn: (row, i) => {
return this.canClickBtnFn(row, i);
},
//orderType 1:智慧体育订单 2移动活动订单 3腾讯同步订单 4 h5天天订单
buttons: [],
},
],
},
},
}
},
mounted(){
//权限为超级管理员跟客服才可以有操作栏
let tabs = [{ name: "详情", event: "detail" ,type:'primary',}]
if(this.myUserInfo.roleId == 1 || this.myUserInfo.roleId == 11){
tabs = [...tabs,...[{
name: "取消订单", event: "cancel",type:'warning',
controlBtn:function(data){ return data.orderStatus == 0 && (data.orderType == 1 || data.orderType == 4)}
},{
name: "商品发货",event: "deliver",type:'success',
controlBtn:function(data){
return data.orderStatus == 1 && (data.orderType == 1 || data.orderType == 4)
}
},{
name: "已退款",type:'info',
controlBtn:function(data){ return data.orderStatus == 2 && (data.orderType == 1 || data.orderType == 4)}
},{
name: "已签收", type:'info',
controlBtn:function(data){ return data.orderStatus == 3 && (data.orderType == 1 || data.orderType == 4)}
},{
name: "已取消",type:'info',
controlBtn:function(data){ return data.orderStatus == 4 && (data.orderType == 1 || data.orderType == 4) }
},{
name: "签收", event: "collect" ,type:'success',
controlBtn:function(data){ return data.orderStatus == 5 && (data.orderType == 1 || data.orderType == 4) }
},{
name: "退货", event: "refund",type:'danger',
controlBtn:function(data){ return (data.orderStatus == 1 || data.orderStatus == 3 || data.orderStatus == 5) && (data.orderType == 1 || data.orderType == 4) }
}]]
this.options.table.columns[17].width = '240px'
}
this.options.table.columns[17].buttons = tabs
this.$nextTick(() =>{
this.$refs.table.reload(true);
})
},
methods:{
onRowButtonClick(data, i) {
let self = this
let {event,row} = data
if(!event) return
switch (event) {
case 'detail': //订单详情
this.$refs['order-detail'].queryOrderDetail(row.id)
break;
case 'deliver': //商品发货
this.$refs['goods-deliver'].handleShow(row)
break;
case 'cancel': //取消订单
this.$showConfirm("确认取消该订单吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(res =>{
self.$service.order.cancelOrder(row.id).then(ress =>{
self.$notifySuccess()
self.$refs['table'].reload()
})
})
break
case 'collect':
this.$showConfirm("确认将该订单置为签收状态吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(res =>{
self.$service.order.receiveOrder(row.id).then(ress =>{
self.$notifySuccess()
self.$refs['table'].reload()
})
})
break;
case 'refund':
this.$refs['order-refund'].queryOrderDetail(row.id)
break;
}
},
//模糊搜索学校
querySearchAsync(queryString, cb){
console.log(queryString)
this.$service.base.getUserAllSchList(queryString).then(res =>{
cb(res)
})
},
// 当公共表格重置搜索时,需手动去重置自定义插槽的组件值
reloadParam(){
this.params = {
regionCode:'',schName:''
}
},
//导出订单列表
exportOrder(){
let param = {
...this.$refs['table'].searchForm,
...this.params
}
if(param['startOrderTime,endOrderTime'] && param['startOrderTime,endOrderTime'].length){
param.startOrderTime = param['startOrderTime,endOrderTime'][0]
param.endOrderTime = param['startOrderTime,endOrderTime'][1]
}
delete param['startOrderTime,endOrderTime']
let failName = `订单列表${param.startOrderTime ? '-' + param.startOrderTime : ''}`
this.$service.order.exportOrderList(param,failName).then(res => {
this.$notifySuccess()
})
},
cascaderLazyLoad(node, resolve) {
if (!node) {
return false
}
const { level } = node
let code = node.value || ''
this.$service.order.getUserOrganList(level == 0 ? {} : {
code,regionLevel:level == 1 ? 2 :4 //2省 4市 6区
}).then(res => {
let list = []
if(res && res.length){
list = res.map((val) => {
return {
value: val.code,
label: val.shortName,
leaf: level >= 2, //因为省市区三项,所以第三次点击就不用在加载了,所以 >=2
}
})
}
if(level == 0){
list.unshift({
value:'all',label:'全国',leaf: level >= 0,
})
}
resolve(list)
})
}
}
}
</script>
<style lang="less" scoped>
.search-bottom{
width: calc(100% - 2px);
background-color: #fff;
padding: 10px 16px;
height: 80px;
display: flex;
align-items: center;
border-top: 1px solid #E4E7ED;
margin-top: 16px;
}
</style>
<!--
* @Author: tangjiale
* @eMail: 932055106@qq.com
* @Date: 2022-06-02 14:08:46
* @LastEditors: tangjiale
* @LastEditTime: 2022-06-02 17:23:22
-->
<template>
<div class="page-bg">
<t-table autoLoad ref="table" :options="options" :params="params"
@row-btn-click="onRowButtonClick">
<!-- 操作栏 -->
<template slot="form-order-search">
<div class="search-bottom">
<el-button type="primary" size="mini" plain @click="handleOption('add')"><i class="el-icon-plus"></i> 新增学生</el-button>
<el-button type="primary" size="mini" plain @click="handleOption('import')"><i class="el-icon-upload2"></i> 导入学生</el-button>
</div>
</template>
</t-table>
<!-- 新增学校 -->
<add-student ref="add-student"></add-student>
</div>
</template>
<script>
import addStudent from './components/add-student.vue'
export default {
components:{addStudent},
services:['order','base'],
data(){
return{
params:{
regionCode:'',schName:''
},
options: {
title: "订单管理",
search: [{
placeholder: "请输入姓名或手机号 ",field: "productName",type: "text",label: "",
},
],
table: {
service: "order", height:(screen.height - (482 * this.$px2rem)),
func: "getOrderPcList",
selectable: false,customRow:true,
columns: [
{title: "学生姓名",field: "orderNo",width:'120px',},
{
title: "性别",width:'100px',
type: 'customField',
fieldFunction: row => true ? '男' : '女',
},
{title: "出生日期",field: "orderNo"},
{title: "爸爸手机号",field: "orderNo"},
{title: "妈妈手机号",field: "orderNo"},
{title: "其它人手机号",field: "orderNo"},
{title: "所在校区",field: "orderNo"},
{
title: "操作",
width: "160px",fixed:'right',
type: "buttons",
//orderType 1:智慧体育订单 2移动活动订单 3腾讯同步订单 4 h5天天订单
buttons: [
{
name: "修改", event: "emit" ,type:'primary'
},{
name: "删除", event: "delete" ,type:'danger'
}
],
},
],
},
},
}
},
mounted(){
},
methods:{
onRowButtonClick(data, i) {
let self = this
let {event,row} = data
if(!event) return
switch (event) {
case 'emit': //修改
break
}
},
handleOption(type){
switch(type) {
case 'add': //新增学生
this.$refs['add-student'].change()
break
case 'import': //导入学生
// this.$refs['add-student'].change()
break
}
}
}
}
</script>
<style lang="less" scoped>
.page-bg{
position: relative;
background-color: #fff;
padding: 10px 15px;
}
.search-bottom{
width: calc(100% - 2px);
background-color: #fff;
padding: 15px 0px 10px 0px;
height: 60px;
display: flex;
align-items: center;
border-top: 1px solid #E4E7ED;
margin: 0px 8px;
button{
min-width: 100px !important;
}
}
</style>
\ No newline at end of file
/*
* @Author: tangjiale
* @eMail: 932055106@qq.com
* @Date: 2022-02-10 15:24:49
* @LastEditors: tangjiale
* @LastEditTime: 2022-02-18 16:06:35
*/
import Vue from 'vue'
import Element from 'element-ui'
import './element.less'
Vue.use(Element)
@fontColor: #303133;
@fontColor05: rgba(193, 217, 255, 0.5);
.flex-c{
display: flex;
align-items: center;
}
.el-table {
background: none;
border-radius: 4px;
.el-table th, .el-table tr {
background-color: transparent;
}
}
// 设置label最小宽度
.el-form-item .el-form-item__label{
font-size: 15px !important;
min-width: 80px;
text-align: right;
flex: none;
}
// 设置选择框 输入框的高宽
.search-form .el-input .el-input__inner{
width: 230px;
height: 32px;
font-size: 14px;
font-family: Microsoft YaHei UI;
font-weight: 400;
color: #303133;
}
.search-form .search-form-r{
float: none !important;
}
//表单内日期选择宽度
.el-form-item__content{
height: 32px;
}
.search-form .el-date-editor--daterange{
width: 230px;height: 32px;
}
.search-form .el-form-item__content .el-input__inner {
padding: 0px 10px !important;
}
.el-date-editor .el-range-separator{
width:12%;
}
//表头样式
.el-table th, .el-table tr {
background: none;
font-size: 14px;
font-family: Microsoft YaHei UI;
font-weight: bold;
color: #303133;
border-right: none !important;
}
// 表格字体
.el-table__header .el-table th, .el-table tr {
font-size: 14px;
font-family: Microsoft YaHei UI;
font-weight: 400;
color: #606266;
}
.el-table--enable-row-transition .el-table__body td {
background: none;
border-color: none;
}
.el-table--border::after, .el-table--group::after, .el-table::before, .el-table--border::after, .el-table--group::after {
background: none;
}
.el-table td, .el-table th.is-leaf {
border-bottom: none;
}
.el-table--border td {
border-right: none !important;
}
.el-form-item__error{
padding-top: 12px !important;
}
// 表格内容
.el-table .cell {
text-align: left;
}
// 表格内容hover
.el-table--enable-row-hover .el-table__body tr:hover > td {
background: none;
}
.el-radio-button__orig-radio:checked + .el-radio-button__inner {
// background: rgba(51, 124, 243, 1);
// color: ;
}
.el-radio-button:first-child .el-radio-button__inner {
// border-left: 1px solid rgba(37, 52, 134, 1);
}
.el-radio-button__inner {
// border-left: 1px solid rgba(37, 52, 134, 1);
// width: 120px;
}
.el-radio-button__inner {
color: #5391F3;
background: none;
border: 1px solid rgba(37, 52, 134, 1);
}
.el-breadcrumb__inner a, .el-breadcrumb__inner.is-link, .el-breadcrumb__item:last-child .el-breadcrumb__inner, .el-breadcrumb__item:last-child .el-breadcrumb__inner a, .el-breadcrumb__item:last-child .el-breadcrumb__inner a:hover, .el-breadcrumb__item:last-child .el-breadcrumb__inner:hover {
// color: @fontColor;
}
// 时间组件
.el-date-editor .el-range-separator {
// color: @fontColor;
}
.el-input__inner, .el-range-editor .el-range-input, .el-textarea__inner {
&::placeholder {
color: #C0C4CC;
}
}
// 分页组件
.el-pager li,.el-pagination button{
background-color: #fff !important;
}
.el-pagination.is-background .el-pager li:not(.disabled).active {
background-color: #1890FF !important;
border-radius: 4px;
}
.table-layout{
padding: 7px 10px 27px 10px !important;
}
.table-layout .el-table--border, .el-table--group{
border: 1px solid #E8E8E8;
}
.el-pagination.is-background .btn-next, .el-pagination.is-background .btn-prev, .el-pagination.is-background .el-pager li {
color: #606266;
border-radius: 0px;
border: 1px solid #D9D9D9;
}
// 输入框的图标
.el-date-editor .el-range__icon, .el-select .el-input .el-select__caret, .el-date-editor .el-range__close-icon {
// color: #5391F3;
}
.el-form-item__label {
padding-right: 12px;
}
//单选的背景色
.el-switch__core {
background: none;
}
.el-switch.is-checked .el-switch__core {
border-color: #409EFF;
background-color: #409EFF;
}
.el-table__empty-text {
color: @fontColor;
}
[class*=" el-icon-"], [class^=el-icon-] {
font-size: 18px;
line-height: 14px;
}
.el-tree {
.el-tree-node__content {
height: 60px;
.el-tree-node__label {
font-size: 18px;
line-height: 60px;
}
}
}
;(function(win, lib) {
var doc = win.document;
var docEl = doc.documentElement;
var metaEl = doc.querySelector('meta[name="viewport"]');
var flexibleEl = doc.querySelector('meta[name="flexible"]');
var dpr = 0;
var scale = 0;
var tid;
var flexible = lib.flexible || (lib.flexible = {});
if (metaEl) {
console.warn('将根据已有的meta标签来设置缩放比例');
var match = metaEl.getAttribute('content').match(/initial\-scale=([\d\.]+)/);
if (match) {
scale = parseFloat(match[ 1 ]);
dpr = parseInt(1 / scale);
}
} else if (flexibleEl) {
var content = flexibleEl.getAttribute('content');
if (content) {
var initialDpr = content.match(/initial\-dpr=([\d\.]+)/);
var maximumDpr = content.match(/maximum\-dpr=([\d\.]+)/);
if (initialDpr) {
dpr = parseFloat(initialDpr[ 1 ]);
scale = parseFloat((1 / dpr).toFixed(2));
}
if (maximumDpr) {
dpr = parseFloat(maximumDpr[ 1 ]);
scale = parseFloat((1 / dpr).toFixed(2));
}
}
}
if (!dpr && !scale) {
var isAndroid = win.navigator.appVersion.match(/android/gi);
var isIPhone = win.navigator.appVersion.match(/iphone/gi);
var devicePixelRatio = win.devicePixelRatio;
if (isIPhone) {
// iOS下,对于2和3的屏,用2倍的方案,其余的用1倍方案
if (devicePixelRatio >= 3 && (!dpr || dpr >= 3)) {
dpr = 3;
} else if (devicePixelRatio >= 2 && (!dpr || dpr >= 2)) {
dpr = 2;
} else {
dpr = 1;
}
} else {
// 其他设备下,仍旧使用1倍的方案
dpr = 1;
}
scale = 1 / dpr;
}
docEl.setAttribute('data-dpr', dpr);
if (!metaEl) {
metaEl = doc.createElement('meta');
metaEl.setAttribute('name', 'viewport');
metaEl.setAttribute('content', 'initial-scale=' + scale + ', maximum-scale=' + scale + ', minimum-scale=' + scale + ', user-scalable=no');
if (docEl.firstElementChild) {
docEl.firstElementChild.appendChild(metaEl);
} else {
var wrap = doc.createElement('div');
wrap.appendChild(metaEl);
doc.write(wrap.innerHTML);
}
}
function refreshRem () {
var width = docEl.getBoundingClientRect().width;
var rem = width / 1920 * 75 * dpr;
docEl.style.fontSize = rem + 'px';
flexible.rem = win.rem = rem;
}
win.addEventListener('resize', function() {
clearTimeout(tid);
tid = setTimeout(refreshRem, 300);
}, false);
win.addEventListener('pageshow', function(e) {
if (e.persisted) {
clearTimeout(tid);
tid = setTimeout(refreshRem, 300);
}
}, false);
if (doc.readyState === 'complete') {
doc.body.style.fontSize = 12 * dpr + 'px';
} else {
doc.addEventListener('DOMContentLoaded', function(e) {
doc.body.style.fontSize = 12 * dpr + 'px';
}, false);
}
refreshRem();
flexible.dpr = win.dpr = dpr;
flexible.refreshRem = refreshRem;
flexible.rem2px = function(d) {
var val = parseFloat(d) * this.rem;
if (typeof d === 'string' && d.match(/rem$/)) {
val += 'px';
}
return val;
};
flexible.px2rem = function(d) {
var val = parseFloat(d) / this.rem;
if (typeof d === 'string' && d.match(/px$/)) {
val += 'rem';
}
return val;
};
})(window, window[ 'lib' ] || (window[ 'lib' ] = {}));
/*
* @Author: tangjiale
* @eMail: 932055106@qq.com
* @Date: 2022-02-11 09:41:38
* @LastEditors: tangjiale
* @LastEditTime: 2022-05-26 16:47:20
*/
import Vue from 'vue';
import Aegis from 'aegis-web-sdk'
import framework from './framework';
//环境遍历
let config = require(`@/config/${process.env.ENV_CONFIG||'pro'}.config.json`);
//监控调试
const aegis = new Aegis({
id: 'JjmvzClOovrjreQrQv', // 上报 id
reportApiSpeed: true, // 接口测速
reportAssetSpeed: true, // 静态资源测速
spa: true, // spa 应用页面跳转的时候开启 pv 计算
api: {
apiDetail: true,
retCodeHandler:(data,url,xhr) => {
try {
data = JSON.parse(data)
} catch(e) {}
return {
// isErr 如果是 true 的话,会上报一条 retcode 异常的日志。
isErr: data.code && data.code != 200,
code: data.code
}
}
},
//计算公式 = (PV + API 统计次数 + 静态资源统计次数 + 错误日志次数 + 自定义上报次数) - 50万
beforeRequest:log =>{
if(log.logType == 'speed') return false
if(log.logType == 'pv'){
return false
}
let msg = log.logs?.msg
if(msg){
for (let i in ignoreMsgs){
if(msg.indexOf(ignoreMsgs[i]) !== -1){
return false
}
}
}
if(log.logType == 'log' && log.logs && log.logs.level == 8) return false
return log
}
});
//全局js捕获异常上报
Vue.config.errorHandler = function(err,vm,info) {
//页面全路径
let fullUrl = window.location.href
aegis.error({
msg:err,
ext1:`报错页面:${fullUrl}`,
trace: 'trace',
})
}
export default ({store}) => {
Vue.use(framework, {
config: config,
resolveHttpSuccess: (res, options) => {
//验证码规则不返回data格式,特殊处理
if(options.data && options.data.getCode){
return res
}else if(res.code === 200){
return res.data.data || res.data;
}else if(res.code === 401){
Vue.prototype.$confirm('登录已过期,请重新登录', '提示', {
confirmButtonText: '确定',
showCancelButton: false,
type: 'warning',
showClose: false
}).then(() => {
store.commit("logout");
});
}else if(options.downloadFile){
//属性名:fileName 后缀:suffix
//下载文件
const link = document.createElement('a')
let blob = new Blob([res], {type:'application/vnd.ms-excel'})
link.style.display = 'none'
link.href = URL.createObjectURL(blob)
link.download = options.downloadFile.fileName + (options.downloadFile.suffix || '.xls') //下载的文件名  注意:加.xls是兼容火狐浏览器
document.body.appendChild(link)
link.click()
document.body.removeChild(link)
}else {
return Promise.reject(res)
}
},
catchHttpError: (options,err) => {
let fullUrl = window.location.href
// report 默认是 aegis.report 的日志类型,但是现在您可以传入任何日志类型了
//上报请求异常
// aegis.report({
// msg: err,
// level: Aegis.logType.AJAX_ERROR,
// ext1: JSON.stringify(options),
// ext2: `页面全路径:${fullUrl}`,
// });
// aegis.report({
// msg: '这是一个ajax错误日志',
// level: Aegis.logType.AJAX_ERROR,
// ext1: 'ext1',
// ext2: 'ext2',
// ext3: 'ext3',
// trace: 'trace',
// });
return Promise.reject(err);
},
beforeHttp: options => {
let userInfo = store.state.myUserInfo
if (userInfo) {
options.headers = {
...options.headers || {},
token: userInfo.token || ''
};
}
options.timeout = 20000;
return options;
},
showLoading: text => {
window._loading = Vue.prototype.$loading({text});
},
hideLoading: () => {
window._loading && window._loading.close();
},
toastError: text => {
Vue.prototype.$message.error(text);
}
});
}
/*
* @Author: tangjiale
* @eMail: 932055106@qq.com
* @Date: 2022-02-10 15:24:49
* @LastEditors: tangjiale
* @LastEditTime: 2022-02-16 12:13:34
*/
const BEANS = {}; // 存放所有的bean
export default class Bean {
constructor ($ctx) {
this.$ctx = $ctx;
}
injectClass (o, pageCtx) { // 注入service类
const services = o.services || [];
const service = {};
services.forEach(v => {
service[ v ] = this.makeBean(v);
});
pageCtx && services.length && (pageCtx.$service = service);
return service;
}
makeBean (v) {
let service = BEANS[ v ];
if (!service) {
let serviceClass = require(`@/services/${v}`).default;
service = new serviceClass(this.$ctx);
BEANS[ v ] = service;
service.init && service.init();
}
return service;
}
}
class Context {
constructor() {}
}
const context = new Context()
export default context
class EventBus {
constructor () {
this.listeners = {};
}
$on (type, callback, scope) {
let args = [];
let numOfArgs = arguments.length;
for (let i = 0; i < numOfArgs; i++) {
args.push(arguments[ i ]);
}
args = args.length > 3 ? args.splice(3, args.length - 1) : [];
if (typeof this.listeners[ type ] != 'undefined') {
this.listeners[ type ].push({scope: scope, callback: callback, args: args});
} else {
this.listeners[ type ] = [ {scope: scope, callback: callback, args: args} ];
}
}
$un (type, callback, scope) {
if (typeof this.listeners[ type ] != 'undefined') {
let numOfCallbacks = this.listeners[ type ].length;
let newArray = [];
for (let i = 0; i < numOfCallbacks; i++) {
let listener = this.listeners[ type ][ i ];
if (listener.scope === scope && listener.callback === callback) {
} else {
newArray.push(listener);
}
}
this.listeners[ type ] = newArray;
}
}
$fire (type, target) {
let event = {
type: type,
target: target
};
let args = [];
let numOfArgs = arguments.length;
for (let i = 0; i < numOfArgs; i++) {
args.push(arguments[ i ]);
}
args = args.length > 2 ? args.splice(2, args.length - 1) : [];
args = [ event ].concat(args);
if (typeof this.listeners[ type ] != 'undefined') {
let listeners = this.listeners[ type ].slice();
let numOfCallbacks = listeners.length;
for (let i = 0; i < numOfCallbacks; i++) {
let listener = listeners[ i ];
if (listener && listener.callback) {
let concatArgs = args.concat(listener.args);
if (concatArgs[ 0 ]) {
concatArgs[ 0 ] = concatArgs[ 0 ].target;
}
listener.callback.apply(listener.scope, concatArgs);
}
}
}
}
}
const event = new EventBus();
export default event;
\ No newline at end of file
const flatHooks = function(configHooks, hooks, parentName) {
for (const key in configHooks) {
const subHook = configHooks[ key ];
const name = parentName ? `${parentName}:${key}` : key;
if (typeof subHook === 'object' && subHook !== null) {
flatHooks(subHook, hooks, name);
} else {
hooks[ name ] = subHook;
}
}
return hooks;
};
const serial = function(tasks, fn) {
return tasks.reduce(function(promise, task) {
return promise.then(function(previous) {
return fn(task, previous);
});
}, Promise.resolve(null));
};
class Hook {
constructor () {
this._hooks = {};
}
ready () {
this.on = this.on.bind(this);
this.callHook = this.callHook.bind(this);
}
on (name, fn) {
if (!name || typeof fn !== 'function') {
return;
}
this._hooks[ name ] = this._hooks[ name ] || [];
this._hooks[ name ].push(fn);
}
addHooks (configHooks) {
const hooks = flatHooks(configHooks);
for (const key in hooks) {
this.on(key, hooks[ key ]);
}
}
callHook (name, ...args) {
if (!this._hooks[ name ]) {
return;
}
return serial(this._hooks[ name ], (fn) => fn(...args)).catch((err) => {
if (name !== 'error') {
this.callHook('error', err);
}
});
}
clearHook (name) {
if (name) {
delete this._hooks[ name ];
}
}
clearHooks () {
this._hooks = {};
}
}
const hook = new Hook();
export default hook;
\ No newline at end of file
import axios from 'axios';
import util from '@/plugins/framework/utils/tools'
const DATASOURCE_CACHE = new Map();
const LOCK_PROMISE = {};
const CONTENT_TYPE_MAP = {
'json': 'application/json',
'form': 'application/x-www-form-urlencoded'
};
export default class Service {
constructor ($ctx) {
this.$ctx = $ctx;
}
/**
* 请求之前的处理
*/
sendBefore (options) {
if(options.data){
//过滤对象null/undefined/''/[]/{}的属性值
options.data = util.clearDeep(options.data)
}
if (LOCK_PROMISE[ options.lock ]) {
return LOCK_PROMISE[ options.lock ];
}
/**
* 支持内存缓存
*/
if (!options.hasUpdateCache && options.cacheKey && DATASOURCE_CACHE.has(options.cacheKey)) {
return Promise.resolve(DATASOURCE_CACHE.get(options.cacheKey));
}
}
// 真正的发送请求
sendTo (options) {
options.loadingText && this.$ctx.showLoading && this.$ctx.showLoading(options.loadingText);
options.contentType = options.contentType || 'json';
if (!this.instance) {
this.instance = axios.create({
baseURL: this.$ctx.$config.baseUrl
});
}
let o = {
url: options.url,
method: options.method,
timeout: options.timeout || 5000,
headers: {
...options.headers || {},
'content-type': CONTENT_TYPE_MAP[ options.contentType || 'json'.toLowerCase() ]
}
};
if (options.downloadFile || options.playAudio) { // 下载文件
o.responseType = 'blob';
}
if(options.uuid){
Object.assign(options.data,{
uuid:util.getClientID()
})
}
if (options.method === 'get') {
o.params = options.data;
} else {
if (options.contentType === 'form') {
let form = new FormData();
let keys = Object.keys(options.data);
keys.forEach(key => {
form.append(key, options.data[ key ]);
});
o.data = form;
} else {
o.data = options.data;
}
}
if (options.uploadFiles) { // 上传文件
let form = new FormData();
options.uploadFiles.forEach(v => {
form.append(v.name, v.file);
});
o.data = form;
o.headers[ 'content-type' ] = 'multipart/form-data';
}
if (this.$ctx.beforeHttp) {
o = this.$ctx.beforeHttp(o);
}
return this.instance(o).then(res => {
options.loadingText && this.$ctx.hideLoading && this.$ctx.hideLoading();
return this.$ctx.resolveHttpSuccess(res.data, options, o);
}).catch(err => {
options.loadingText && this.$ctx.hideLoading && this.$ctx.hideLoading();
let defaultCatch = e => {
if (options.isToastError !== false) { // 除非明确指出不需要弹toast,否则接口失败默认弹出toast
if (e.message && e.message.includes('timeout')) {
e.message = '网络请求超时';
}
this.$ctx.toastError(e.message || e.Message || '网络请求失败');
}
return Promise.reject(err);
};
if (this.$ctx.catchHttpError) {
return this.$ctx.catchHttpError(options,err).catch(e => {
return defaultCatch(e);
});
} else {
return defaultCatch(err);
}
});
}
/**
* 处理结果
*/
handlerRes (res, options) {
if (options.cacheKey && !DATASOURCE_CACHE.has(options.cacheKey)) {
DATASOURCE_CACHE.set(options.cacheKey, res);
}
options.lock && delete LOCK_PROMISE[ options.lock ];
return res;
}
/**
* 处理请求Error
*/
handlerError (error, options) {
options.cacheKey && DATASOURCE_CACHE.delete(options.cacheKey);
options.lock && delete LOCK_PROMISE[ options.lock ];
return Promise.reject(error);
}
/**
* 请求之后处理
*/
sendAfter (options) {
const _sendTo = options => {
let promise = this.sendTo(options);
if (options.lock) {
LOCK_PROMISE[ options.lock ] = promise;
}
return promise;
};
return _sendTo(options);
}
get (options) {
options.method = 'get';
return this.send(options);
}
post (options) {
options.method = 'post';
return this.send(options);
}
put (options) {
options.method = 'put';
return this.send(options);
}
delete (options) {
options.method = 'delete';
return this.send(options);
}
/**
* 请求
*/
send (options) {
let result = this.sendBefore(options);
if (!result) {
return this.sendAfter(options).then(res => {
return this.handlerRes(res, options);
}).catch(error => {
return this.handlerError(error, options);
});
}
return result;
}
}
import Context from './core/context'; // 应用上下文,在vue文件和service对象内可通过this.$ctx获取所有功能
import bean from './core/bean'; // bean管理器
import Service from './core/service'; // 用于发送请求和处理model层逻辑
import * as Utils from './utils'; // 工具类
import Event from './core/event'; // 事件通知
import Hook from './core/hook'; // 钩子
const Bean = new bean(Context);
const proto = {
$utils: Utils,
$bean: Bean,
$em: Event,
$hook: Hook
};
Object.assign(Context, proto); // 把各种功能赋予context实例
export default {
install: function(vue, options) {
Context.showLoading = options.showLoading;
Context.hideLoading = options.hideLoading;
Context.toastError = options.toastError;
Context.beforeHttp = options.beforeHttp;
Context.$config = options.config;
Context.resolveHttpSuccess = options.resolveHttpSuccess;
Context.catchHttpError = options.catchHttpError;
Object.assign(vue.prototype, proto); // 把各种功能赋予vue实例
Context.doInit = function() { // context初始化,暂时没啥做的
if (!Context._initPromise) {
Context._initPromise = Promise.resolve();
}
return Context._initPromise;
};
vue.prototype.$ctx = Context;
vue.mixin(require('./mixins/event').default);
vue.mixin(require('./mixins/create').default);
vue.mixin(require('./mixins/user-info').default);
}
};
export {
Context,
Utils,
Bean,
Service,
Event
};
Object.assign(window, {
Context,
Utils,
Bean,
Service,
Event
});
/*
* @Author: tangjiale
* @eMail: 932055106@qq.com
* @Date: 2022-02-10 15:24:49
* @LastEditors: tangjiale
* @LastEditTime: 2022-02-16 12:13:36
*/
import {
Bean
} from '../';
export default {
beforeCreate () {
Bean.injectClass(this.$options, this); // 注入service
}
};
import {
Context
} from '../';
export default {
mounted () {
let {
events
} = this.$options;
if (events) {
Object.keys(events).forEach(v => {
Context.$em.$on(v, this[ events[ v ] ]);
});
}
},
destroyed () {
let {
events
} = this.$options;
if (events) {
Object.keys(events).forEach(v => {
Context.$em.$un(v, this[ events[ v ] ]);
});
}
}
};
export default {
computed: {
myUserInfo() {
return this.$store.state.myUserInfo
},
historyRoute() {
return this.$store.state.historyRoute
}
}
}
const hasOwn = Object.prototype.hasOwnProperty;
const getProto = Object.getPrototypeOf;
const toString = Object.prototype.toString;
const nativeIsArray = Array.isArray;
const fnToString = hasOwn.toString;
const ObjectFunctionString = fnToString.call(Object);
const isPlainObject = (obj) => {
var proto, Ctor;
if (!obj || toString.call(obj) !== "[object Object]") {
return false;
}
proto = getProto(obj);
if (!proto) {
return true;
}
Ctor = hasOwn.call(proto, "constructor") && proto.constructor;
return typeof Ctor === "function" && fnToString.call(Ctor) === ObjectFunctionString;
}
const isArray = nativeIsArray || function(obj) {
return toString.call(obj) === '[object Array]'
}
const isObject = function(obj) {
var type = typeof obj
return type === 'function' || type === 'object' && !!obj;
}
const isBoolean = function(obj) {
return obj === true || obj === false || toString.call(obj) === '[object Boolean]';
}
const isEmptyObject = function(obj) {
for (const name in obj) {
return false;
}
return true;
}
const isEmptyValue = function(obj) {
if (isEmpty(obj)) return true;
for (const name in obj) {
if (obj[name] !== undefined) return false;
}
return true;
}
const isEmpty = function(obj) {
if (isObject(obj)) return isEmptyObject(obj);
return obj === undefined || obj === null || obj === '';
}
const apply = (o, c) => {
if (o && c && typeof c == 'object') {
for (var p in c) {
var v = c[p];
if (hasOwn.call(o, p) || v !== undefined) {
o[p] = v;
}
}
}
return o;
}
const applyVal = (o, c) => {
if (o && c && typeof c == 'object') {
for (var p in o) {
var v = o[p];
if (!v) {
o[p] = c[p];
}
}
}
return o;
}
const applyAll = (o, c) => {
if (o && c && typeof c == 'object') {
for (var p in c) {
var v = c[p];
if (isObject(v)) {
if (isObject(o[p])) {
applyAll(o[p], v);
} else {
o[p] = v;
}
} else if (o.hasOwnProperty(p) || v !== undefined) {
o[p] = v;
}
}
}
return o;
}
const applyIf = function(o, c) {
if (o && c) {
for (var p in c) {
if (o[p] === undefined && c[p] !== undefined) {
o[p] = c[p];
}
}
}
return o;
}
const copy = function() {
let args = Array.prototype.slice.call(arguments)
let obj = {};
args.forEach(v => {
obj = apply(obj, v || {})
})
return obj
}
const copyValid = function() {
let args = Array.prototype.slice.call(arguments)
let obj = {};
args.forEach(v => {
obj = _copySingleValid(obj, v || {})
})
return obj
}
const _copySingleValid = (t, s) => {
if (isObject(s)) {
for (var f in s) {
let firstChar = f.charAt(0);
if (/^[a-zA-Z]+$/.test(firstChar)) {
t[f] = s[f]
}
}
}
return t;
}
const _is = {};
['Arguments', 'Function', 'String', 'Number', 'Date', 'RegExp', 'Error'].forEach(v => {
_is['is' + v] = function(obj) {
let s = toString.call(obj);
let t = '[object ' + v + ']'
if (v === 'Function') {
return s === t || s === '[object AsyncFunction]'
}
return s === t;
}
})
const pathJoin = function() {
let args = Array.prototype.slice.call(arguments);
let path = '';
if (args.length) {
path = args[0];
function hasChar(str, index) {
var indexChar = str.charAt(index);
return indexChar == "/";
}
for (var i = 1; i < args.length; i++) {
let v = args[i];
if (v && typeof v === 'string') {
let lastIndex = v.length - 1;
v = hasChar(v, lastIndex) ? v.substring(0, lastIndex - 1) : v;
path += hasChar(v, 0) ? v : '/' + v;
}
}
}
return path
}
const toParams = (params) => {
let param = ""
for (const name in params) {
if (typeof params[name] != 'function') {
param += "&" + name + "=" + encodeURI(params[name])
}
}
return param.substring(1)
}
/**
*
* 转成Array
*
* @param str
* @param split
* @returns {Array}
*/
const toArray = (str, split) => {
return _is.isString(str) ?
isJson(str) ? JSON.parse(str) : str.split(split || /,|\\*|;|#/) :
isArray(str) ? str : [];
}
const toField = (str, data, thiv) => {
return str.replace(/(?:\$\{([^{}]+)\})/gi,
function(f) {
f = f.replace(/\$|\{|\}/gi, '');
return toValue(data, f, thiv);
});
}
const toValue = (d, f, thiv) => {
d = d || {};
var sf = f.split(":");
var s = sf[0].split(".");
var p = s[0];
var v = d[p];
if (v && isObject(v)) {
for (var j = 1; j < s.length; ++j) {
v = v[s[j]];
}
}
return v != undefined ? v : "";
}
const result = function(e, t) {
if (null == e) return null;
var r = _is.isFunction(t) ? t.call(e, e) : e[t];
return _is.isFunction(r) ? r.call(e) : r;
}
const isJson = function(str) {
return typeof str === 'string' && /(?:^\{|^\[)/gi.test(str);
}
const getClassName = function(o) {
if (o && o.constructor) {
let s = o.toString();
let arrs = s.match(/class\s*(\w+)/);
if (arrs && arrs.length == 2) {
return arrs[1];
}
}
return undefined;
}
const isEqual = function(t, s) {
return t == s || isObject(t) && isObject(s) ? JSON.stringify(t) === JSON.stringify(s) : t === s;
}
function assignKey(to, from, key) {
const val = from[key];
const hasKey = hasOwn.call(to, key);
if (hasKey) {
return;
}
if (!hasKey || !isObject(val)) {
to[key] = val;
} else {
to[key] = assign(Object(to[key]), from[key]);
}
}
function assign(to, from) {
for (const key in from) {
if (hasOwn.call(from, key)) {
assignKey(to, from, key);
}
}
return to;
}
function copyKey(to, from, key) {
const val = from[key];
if (isObject(val) || isArray(val)) {
to[key] = deepCloneAll(val)
} else {
to[key] = val;
}
}
function deepCloneAll(obj) {
let to = {};
if (isArray(obj)) {
return obj.map(item => deepCloneAll(item));
} else if (isObject(obj)) {
for (const key in obj) {
copyKey(to, obj, key);
}
}
return to;
}
function deepClone(obj) {
if (Array.isArray(obj)) {
return obj.map(item => deepClone(item));
} else if (typeof obj === 'object') {
return assign({}, obj);
}
return obj;
}
function formatterValue(option, fn, field, joinChar) {
if (isArray(option)) {
return option.map(v => formatterValue(v, fn, field));
}
if (_is.isFunction(fn)) {
return fn(option)
}
return isObject(option) && field in option ? option[field] : option
}
function applyPromise(fn, target, agrs, defaultValues) {
let _defaultRes;
if (_is.isFunction(fn)) {
_defaultRes = fn.apply(target, agrs)
if (_defaultRes && _defaultRes instanceof Promise) {
return _defaultRes.then(res => {
return res;
})
}
}
return Promise.resolve(_defaultRes || defaultValues);
}
module.exports = apply({
hasOwn: hasOwn,
applyPromise: applyPromise,
getClassName: getClassName,
result: result,
isPlainObject: isPlainObject,
toValue: toValue,
toField: toField,
toArray: toArray,
toParams: toParams,
formatterValue: formatterValue,
isJson: isJson,
isEqual: isEqual,
isArray: isArray,
isObject: isObject,
isBoolean: isBoolean,
isEmptyObject: isEmptyObject,
isEmptyValue: isEmptyValue,
isEmpty: isEmpty,
apply: apply,
copy: copy,
deepClone: deepClone,
deepCloneAll: deepCloneAll,
pathJoin: pathJoin,
copyValid: copyValid,
applyVal: applyVal,
applyIf: applyIf,
applyAll: applyAll
}, _is);
import _ from './_.js';
const DAY_SECONDS = 86400000;
const HOUR_SECONDS = 3600000;
const MINUTE_SECONDS = 60000;
const MS_SECONDS = 1000;
const WEEKS = ['日', '一', '二', '三', '四', '五', '六', '七', '八', '九', '十', '十一', '十二']
const STR_INTERVALS = ['s', 'n', 'h', 'd', 'w', 'q', 'm', 'y'];
const GAPS = [{
s: "年",
l: 365 * DAY_SECONDS
},
{
s: "个月",
l: 30 * DAY_SECONDS
},
{
s: "天",
l: DAY_SECONDS
},
{
s: "时",
l: HOUR_SECONDS
},
{
s: "分",
l: MINUTE_SECONDS
},
{
s: "秒",
l: MS_SECONDS
}
]
const _dataFormat = function(d, f) {
if (!d) return ''
//d = toDate(d);
d = _.isDate(d) ? d : toDate(d);
f = f || 'yyyy-MM-dd hh:mm:ss';
let w = '星期',
r = {
yyyy: d.getFullYear(),
MM: d.getMonth() + 1,
dd: d.getDate(),
hh: d.getHours(),
mm: d.getMinutes(),
ss: d.getSeconds(),
ww: w + WEEKS[d.getDay()],
SSS: d.getMilliseconds()
}
for (let k in r) {
let v = r[k]
if (k != 'yyyy' && v < 10) r[k] = '0' + v
}
return f.replace(/(?!\\)(yyyy|MM|dd|SSS|hh|mm|ss|ww)/gi, function(f) {
return r[f]
})
}
function toDate(v) {
if (_.isDate(v)) {
return v;
}
let t;
if (typeof v == "string") {
if (v.indexOf('+') != -1 || v.indexOf("T") != -1) {
t = new Date(v);
}
if (!t && v.indexOf('-') != -1) {
t = new Date(Date.parse(v.replace(/-/g, '/')))
}
}
if (!t && !isNaN(v)) {
t = new Date(Number(v))
}
if (!t && v) {
t = new Date(v);
}
return t
}
function toUp(dtTmp, strInterval, num) {
switch (strInterval) {
case 's':
return new Date(Date.parse(dtTmp) + (MS_SECONDS * num));
case 'n':
return new Date(Date.parse(dtTmp) + (MINUTE_SECONDS * num));
case 'h':
return new Date(Date.parse(dtTmp) + (HOUR_SECONDS * num));
case 'd':
return new Date(Date.parse(dtTmp) + (DAY_SECONDS * num));
case 'w':
return new Date(Date.parse(dtTmp) + ((DAY_SECONDS * 7) * num));
case 'q':
return new Date(dtTmp.getFullYear(), (dtTmp.getMonth()) + num * 3, dtTmp.getDate(), dtTmp.getHours(), dtTmp.getMinutes(),
dtTmp.getSeconds());
case 'm':
return new Date(dtTmp.getFullYear(), (dtTmp.getMonth()) + num, dtTmp.getDate(), dtTmp.getHours(), dtTmp.getMinutes(),
dtTmp.getSeconds());
case 'y':
return new Date((dtTmp.getFullYear() + num), dtTmp.getMonth(), dtTmp.getDate(), dtTmp.getHours(), dtTmp.getMinutes(),
dtTmp.getSeconds());
}
return dtTmp;
}
function toDown(dtTmp, strInterval, num) {
switch (strInterval) {
case 's':
return new Date(Date.parse(dtTmp) - (MS_SECONDS * num));
case 'n':
return new Date(Date.parse(dtTmp) - (MINUTE_SECONDS * num));
case 'h':
return new Date(Date.parse(dtTmp) - (HOUR_SECONDS * num));
case 'd':
return new Date(Date.parse(dtTmp) - (DAY_SECONDS * num));
case 'w':
return new Date(Date.parse(dtTmp) - ((DAY_SECONDS * 7) * num));
case 'q':
return new Date(dtTmp.getFullYear(), (dtTmp.getMonth()) - num * 3, dtTmp.getDate(), dtTmp.getHours(), dtTmp.getMinutes(),
dtTmp.getSeconds());
case 'm':
return new Date(dtTmp.getFullYear(), (dtTmp.getMonth()) - num, dtTmp.getDate(), dtTmp.getHours(), dtTmp.getMinutes(),
dtTmp.getSeconds());
case 'y':
return new Date((dtTmp.getFullYear() - num), dtTmp.getMonth(), dtTmp.getDate(), dtTmp.getHours(), dtTmp.getMinutes(),
dtTmp.getSeconds());
}
return dtTmp;
}
function getUpTime(expires, date) {
let len = expires.length;
if (len > 1) {
for (var i = 1; i < len; i++) {
var v = expires.charAt(i).toLowerCase();
var index = STR_INTERVALS.indexOf(v);
if (index != -1) {
var n = expires.substring(0, i);
var s = STR_INTERVALS[index];
date = toUp(date || new Date(), s, Number(n));
let _expires = expires.substring(i + 1);
if (_expires) {
return getUpTime(_expires, date);
}
}
}
}
return date;
}
function getGapTimes(t, s, c = 2) {
t = toDate(t), s = toDate(s);
let gap = Math.abs(t.getTime() - s.getTime());
let results = []
let count = 0
function calc(remain) {
for (let i = 0; i < GAPS.length; i++) {
let v = GAPS[i]
let val = Math.floor(remain / v.l);
if (val > 0) {
results.push(val, v.s)
count += 1
if (count >= c) {
return
} else {
calc(remain - val * v.l)
break;
}
}
}
}
calc(gap)
return results
}
function setCountDownInterval(s, e, layer = 4, callback, clearTimer = 0) {
let count = Math.abs(toDate(s).getTime() - toDate(e).getTime());
let sleep = 1000;
let joinChar = ":"
let countDownTimer = clearTimer;
function countDown(tatal) {
if (tatal > 0) {
let gaps = GAPS.slice(GAPS.length - layer)
let results = [];
while (gaps.length) {
let v = gaps.shift();
if (results.length) {
let s = results[results.length - 1];
s.value && (tatal = tatal - s.value * s.v.l)
}
let value = Math.floor(tatal / v.l);
if (value) {
results.push({
value,
v
})
} else {
if (results.length) {
results.push({
value: 0,
v
})
}
}
}
return results.map(s => {
return {
value: s.value < 10 ? '0' + s.value : s.value,
label: s.v.s
}
});
}
countDownTimer && window.clearInterval(countDownTimer)
return []
}
function resHandler(res) {
let values = res.map(v => v.value).join(joinChar);
let labels = res.map(v => v.value + v.label).join('');
return [res, values, labels];
}
function run() {
let res = countDown(count);
count = count - sleep;
callback && callback.apply(null, resHandler(res))
}
countDownTimer && window.clearInterval(countDownTimer);
return run(), (countDownTimer = window.setInterval(run, sleep)), countDownTimer;
}
const date = {
toUp,
toDown,
toDate,
toFormat: _dataFormat,
getUpTime,
getGapTimes,
setCountDownInterval,
format: function(v, f) {
let d = toDate(v)
return _dataFormat(d, f)
},
splitFormat(v, f, splitStr) {
let vals = [];
if (v) {
let _values = [];
if (splitStr && _.isString(v)) {
_values = v.split(splitStr)
}
if (_values.length == 0) {
if (v instanceof Date) {
_values.push(v)
} else if (_.isNumber(v)) {
_values.push(new Date(v).getTime())
} else if (_.isString(v)) {
_values.push(new Date(v).getTime())
}
}
_values.forEach(v => {
vals.push(_dataFormat(toDate(v), f))
})
}
return vals
},
now: function(f) {
return _dataFormat(new Date(), f || 'yyyy-MM-dd hh:mm:ss.SSS')
},
toTime: function(n) {
function a(v) {
return (v >= 10 ? v : "0" + v);
}
if (n < 60) {
return "00:" + a(n);
} else {
var ss = n % 60;
var mm = Math.floor(n / 60);
if (mm < 60) {
return a(mm) + ":" + a(ss);
} else {
mm = mm % 60;
var hh = Math.floor(mm / 60);
return a(hh) + ":" + a(mm) + ":" + a(ss);
}
}
return "00:00";
},
gapTime: function(t, s) {
t = toDate(t), s = toDate(s);
let v = Math.abs(t.getTime() - s.getTime());
function gapTo(i) {
let d = GAPS[i]
let val = Math.floor(v / d.l);
if (val > 0) {
return val + d.s;
}
return i < 5 ? gapTo(i + 1) : "刚刚";
}
return gapTo(0)
},
// 详细的时间间隔
detailGapTime: function(t, s, c = 2) {
return getGapTimes(t, s, c).join('')
},
gapTimeInterval: function(option) {
let begin = option.begin
let end = option.end
let up = option.up
if (begin && up) {
end = getUpTime(up, toDate(begin))
}
if (!end) {
return
}
let intervalId = setInterval(() => {
let now = new Date()
option.counter && option.counter(this.detailGapTime(now, end))
if (now.getTime() >= end.getTime()) {
option.finish && option.finish()
clearInterval(intervalId)
}
}, 1000)
}
}
export default date
export {
default as _
}
from './_'
export {
default as date
}
from './date'
/*
* @Author: tangjiale
* @eMail: 932055106@qq.com
* @Date: 2022-02-10 15:24:49
* @LastEditors: tangjiale
* @LastEditTime: 2022-02-17 09:40:52
*/
const MYCP_CLIENT_ID = 'MYCP-CLIENT-ID-NEW';
const newUUID = (nonce) => {
let d = new Date().getTime();
let tpl = nonce ? 'xxxxxxxxxxxxxyxxxxyxxxxxxxxxxxxx' : 'xxxxxxx-xxxx-5xxx-yxxx-xxxxxxxxx';
let uuid = tpl.replace(/[xy]/g,
function (c) {
let r = (d + Math.random() * 16) % 16 | 0;
d = Math.floor(d / 16);
return (c == 'x' ? r : (r & 0x3 | 0x8)).toString(16);
});
return uuid;
};
const getClientID = () => {
let _clientID = window.localStorage.getItem(MYCP_CLIENT_ID)
if (!_clientID) {
_clientID = newUUID();
window.localStorage.setItem(MYCP_CLIENT_ID, _clientID)
}
return _clientID;
};
const randomInt = (min, max) => {
return Math.floor(Math.random() * (max - min + 1) + min);
};
const getPageRoute = page => {
let route = page.route;
let index = route.indexOf('?');
let key = index == -1 ? route : route.substring(0, index);
return key.startsWith("/") ? key.substring(1) : key;
}
const getCurrentPage = () => {
let pages = getCurrentPages() //获取加载的页面
return pages[pages.length - 1]
}
const getPrePage = () => {
let pages = getCurrentPages() //获取加载的页面
if (pages.length >= 2) {
return pages[pages.length - 2]
}
}
//过滤对象中为null/undefined/''/[]/{}的属性值
const clearDeep = (obj) => {
if (!obj || !typeof obj === 'object') return obj
const keys = Object.keys(obj)
if(!keys) return {}
for (var key of keys) {
const val = obj[key]
if (
typeof val === 'undefined' ||
((typeof val === 'object' || typeof val === 'string') && !val)
) {
// 如属性值为null或undefined或'',则将该属性删除
delete obj[key]
} else if (typeof val === 'object') {
// 属性值为对象,递归调用
clearDeep(obj[key])
if (Object.keys(obj[key]).length === 0) {
// 如某属性的值为不包含任何属性的独享,则将该属性删除
delete obj[key]
}
}
}
return obj
}
export default {
newUUID,
getClientID,
randomInt,
getCurrentPage: getCurrentPage,
getPrePage: getPrePage,
getPageRoute: getPageRoute,
clearDeep
}
/*
* @Author: tangjiale
* @eMail: 932055106@qq.com
* @Date: 2022-02-10 15:24:49
* @LastEditors: tangjiale
* @LastEditTime: 2022-06-02 15:11:42
*/
import Vue from 'vue';
require('./flexiable');
import pcsite from 'mercury-wrap/pcsite';
Vue.use(pcsite);
import cDialog from '@/components/common/c-dialog.vue'
import cPopup from '@/components/common/c-popup.vue'
Vue.component(cDialog.name, cDialog)
Vue.component(cPopup.name, cPopup)
Vue.prototype.$showConfirm = msg => Vue.prototype.$confirm(msg || '是否确定删除对应的记录?', '提示', {type: 'warning'});
Vue.prototype.$notifySuccess = msg => Vue.prototype.$notify.success({
title: '提示',
message: msg || '操作成功',
position: 'bottom-right'
});
Vue.prototype.$px2rem = Number(document.documentElement.style.fontSize.replace('px', '')) / 75 * (window.dpr || 1);
export default ({store}) => {
Vue.directive('auth', {
bind: function(el, binding) {
let authCode = binding.value;
if (!authCode) return;
if (store.state.buttonAuthList.indexOf(authCode) === -1) { // 没有那个权限则隐藏按钮
el.style.display = 'none';
}
}
});
}
@fontColor: #C1D9FF;
body{
font-family: PingFangSC-Medium, PingFang SC !important;
}
body::-webkit-scrollbar{
display: none !important;
}
.el-cascader-panel{
height: 200px;
}
.flex-c{
display: flex;
align-items: center;
}
.flex-s{
display: flex;
align-items: center;
justify-content: space-between;
}
.max-h{
max-height: 200px !important;
overflow-y: auto;
}
.drop-input{
margin: 0px 10px !important;
width: calc(100% - 20px) !important;
}
.cannel-btn{
height: 48px;
width: 118px;
text-align: center;
line-height: 48px;
border-radius: 6px;
border: 1px solid #D7D7D7;
cursor: pointer;
font-size: 16px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #859DC3;
}
.config-btn{
height: 50px;
width: 118px;
text-align: center;
line-height: 48px;
border-radius: 6px;
background: #1890FF;
cursor: pointer;
font-size: 16px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #FFFFFF;
}
.search-btn{
margin-left: 32px;
background: rgba(24, 144, 255, 0.1);
border-radius: 8px;
height: 42px;
line-height: 42px;
border: 1px solid #1890FF;
padding: 0px 30px;
font-size: 16px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #1890FF;
cursor: pointer;
}
.uploader-drop {
background: none !important;
}
.uploader-btn {
color: @fontColor !important;
border: 1px solid @fontColor !important;
}
::-webkit-scrollbar {
// display: none !important;
}
&::-webkit-scrollbar-thumb {
/*滚动条里面小方块*/
}
&::-webkit-scrollbar-track {
/*滚动条里面轨道*/
}
.app-content .device-page .el-dialog{
background: #fff;
.el-input__inner{
text-align: left !important;
background-color: #fff;
border: 1PX solid #DCDFE6;
color: #606266;
}
::placeholder {
color: rgba(32, 46, 53, 0.67);
}
}
.el-scrollbar__wrap{
margin-bottom: 0px !important;
}
.el-pagination__total{
color: #626266 !important;
font-size: 16px !important;
}
\ No newline at end of file
/*
* @Author: tangjiale
* @eMail: 932055106@qq.com
* @Date: 2022-06-02 09:11:31
* @LastEditors: tangjiale
* @LastEditTime: 2022-06-02 09:11:47
*/
import Vue from 'vue'
import plTable from 'pl-table'
import 'pl-table/themes/index.css'
export default(()=>{
//决表格万级数据渲染卡顿问题
Vue.use(plTable);
})
/*
* @Author: tangjiale
* @eMail: 932055106@qq.com
* @Date: 2022-02-16 11:28:42
* @LastEditors: tangjiale
* @LastEditTime: 2022-02-17 09:44:32
*/
export default class AnalysisService extends Service {
//获取学年学期列表
getInYearAndTermList() {
return this.get({
url: "/common/list",
data: {},
}).then((res)=>{
let arr = []
res.forEach(inYearAndTerm =>{
arr.push({
name:inYearAndTerm.schYear+'学年'+(inYearAndTerm.schTerm==0?'上学期':'下学期'),value:inYearAndTerm.schYear+','+inYearAndTerm.schTerm
})
})
arr.unshift({name:'全部',value:''})
return arr
});
}
//获取商品列表
getGoodsList() {
return this.get({
url: "/common/getProductList",
data: {},
}).then((res)=>{
let arr = []
res.forEach(goods =>{
arr.push({
name:goods.productName,value:goods.id
})
})
arr.unshift({name:'全部',value:''})
return arr
});
}
//订单统计列表
getOrderAnalysisList(param) {
if(param.inYearAndTerm){
let inYearAndTermArr=param.inYearAndTerm.split(",")
param.schYear=inYearAndTermArr[0];
param.schTerm=inYearAndTermArr[1];
delete param.inYearAndTerm
}
if(param.regionCode && param.regionCode == 'all') {
param.regionCode = ''
}
return this.get({
url: "/sport/order/report/getOrderReportList",
data: param,
}).then((res) => {
this.get({
url: "/sport/order/report/getOrderCountReportInfo",
data: param,
}).then((response) => {
let obj = {
schName: "合计",
totalPeople:response.totalPeople,
totalStu:response.totalStu,
totalTea:response.totalTea,
orderPeople:response.orderPeople,
goodsNum:response.goodsNum,
orderStu:response.orderStu,
orderTea:response.orderTea,
orderMember:response.orderMember,
changePercent:response.changePercent
};
res.list.push(obj);
});
return res;
});
}
getOrderCountReportInfo(param) {
return this.get({
url: "/sport/order/report/getOrderCountReportInfo",
data: param,
})
}
// 订单统计列表导出
exportOrderAnalysisList(param, fileName) {
if(param.inYearAndTerm){
let inYearAndTermArr=param.inYearAndTerm.split(",")
param.schYear=inYearAndTermArr[0];
param.schTerm=inYearAndTermArr[1];
delete param.inYearAndTerm
}
return this.get({
url: "/sport/order/report/export/getOrderReportList",
downloadFile: {
fileName,
},
data: param,
});
}
}
/*
* @Author: tangjiale
* @eMail: 932055106@qq.com
* @Date: 2022-02-11 10:04:50
* @LastEditors: tangjiale
* @LastEditTime: 2022-02-22 10:01:29
*/
export default class BaseService extends Service {
//获取验证码
getCode() {
return this.get({
url: '/user/checkcode', uuid:true,
data: {
getCode:true
}
})
}
//登录
postUserLogin(param){
return this.post({
url: '/user/login', uuid:true,
data: param
})
}
//获取用户信息
getUserInfo(token){
return this.get({
url:'/user/getUserInfo',
headers:{
token
}
})
}
//获取登录角色列表
queryRoleList(){
return this.get({
url: '/user/role/list',
data:{}
})
}
//切换角色
changeRole(roleId){
return this.get({url: '/user/switch',data:{roleId}})
}
//用户中心免密登录
userCenterLogin(param){
return this.get({
url: '/user/userCenterLogin',
data:param
})
}
//用户菜单列表
getPermissions(){
return this.get({
url: '/permissions/user',
contentType: 'form',
loadingText: '请求中...',
data:{}
});
}
//获取学校列表
getUserAllSchList(schName){
return this.get({
url: '/common/getUserAllSchList',
data:{schName}
}).then(res =>{
let list = []
if(res && res.length){
res.forEach(v =>{
list.push({
value:v.name
})
})
}
return list
});
}
//物流公司列表
queryExpress(param){
return this.get({
url:'/order/express',
data: param
}).then(res =>{
let list = []
res && res.length && res.forEach(v =>{
list.push({name:v.name,value:v.name})
})
return list
})
}
//修改密码
resetPassword(param){
return this.put({
url:'/user/modify/password',
data: param
})
}
queryList(param){
return this.get({
url:'/healthy/body/selectOverweightStatus',
data: param
})
}
}
/*
* @Author: tangjiale
* @eMail: 932055106@qq.com
* @Date: 2022-02-11 09:23:35
* @LastEditors: tangjiale
* @LastEditTime: 2022-02-17 18:23:31
*/
import service from '../plugins/framework/core/service'
export default class OrderService extends Service {
queryList(param){
return service.get({
url: '/healthy/body/selectOverweightStatus',
data: param
})
}
//获取当前用户省市区列表 code,regionLevel省市区246
getUserOrganList(param){
return this.get({
url: '/common/getUserOrganList',
data: param
})
}
//订单管理列表
getOrderPcList(param){
if(param.regionCode && param.regionCode == 'all') {
param.regionCode = ''
}
return this.get({
url: '/order',
data: param
})
}
//获取用户订单类型列表列表
getSysUserOrderTypeList(){
return this.get({
url:'/common/getSysUserOrderTypeList',
}).then(res =>{
let list = []
let stateName = ['','小奔线上自营订单','移动活动订单','腾讯同步订单','渠道专属运营订单']
if(res && res.length){
res.forEach(v =>{
list.push({
name:stateName[v],value:v
})
})
}
list.unshift({name:'全部',value:''})
return list
})
}
// 订单列表导出
exportOrderList(param,fileName){
return this.get({
url: '/order/export',
downloadFile:{
fileName
},
data: param
})
}
// 订单物流信息excel模版下载
downloadModel(fileName){
return this.get({
url: '/order/model',
downloadFile:{
fileName
}
})
}
//订单详情
queryOrderDetail(id){
return this.get({
url: '/order/detail',
data:{id}
})
}
//商品订单发货
orderDeliver(param){
return this.post({
url: '/order/deliver',
contentType:'form',
data:param
})
}
//取消订单
cancelOrder(id){
return this.post({
url: '/order/canal',
contentType:'form',
data:{id}
})
}
//订单收货
receiveOrder(id){
return this.post({
url: 'order/receive',contentType:'form',
data:{id}
})
}
//订单退款
refundOrder(param){
return this.post({
url: '/order/refund',
contentType:'form',
data:param
})
}
}
<!DOCTYPE html>
<html {{ HTML_ATTRS }}>
<head {{ HEAD_ATTRS }}>
{{ HEAD }}
</head>
<body {{ BODY_ATTRS }}>
{{ APP }}
</body>
</html>
<style>
</style>
/*
* @Author: tangjiale
* @eMail: 932055106@qq.com
* @Date: 2022-02-11 15:54:33
* @LastEditors: tangjiale
* @LastEditTime: 2022-02-22 09:07:41
*/
import Vue from 'vue'
//配置对象
let config = require(`@/config/${process.env.ENV_CONFIG||'pro'}.config.json`);
export default {
state: () => ({
myUserInfo: null,
//公共静态数据
_commonData:{
},
//历史路由
historyRoute:[
{name:'首页',url:'/'}
],
//登陆来源 老板要求从哪里登陆过来,退出登陆后回哪里去
//已知: 1/用户中心 2/智慧体育 3/人人通
tbase:'',
sourceOption:['','loginUrl','zhtyLoginUrl','rrtLoginUrl','','']
}),
mutations: {
updateUserInfo(state, userInfo) {
let info = {...state.myUserInfo || {}, ...userInfo};
state.myUserInfo = info;
sessionStorage.setItem('myUserInfo', JSON.stringify(info));
},
logout(state) {
const source = state.tbase || ''
state.myUserInfo = null;
sessionStorage.removeItem('myUserInfo');
location.href = source ? config[state.sourceOption[source]] : '/login';
},
//更新理由
updateRoute(state,list){
state.historyRoute = list;
},
//更新普通state数据
updateStateVal(state,data){
state[data.key] = data.val
}
}
};
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment