Browse Source

1

pull/1/head
zhaoguoqiang 3 years ago
parent
commit
16406872de
  1. 4
      .env.development
  2. 3
      .env.online
  3. 5
      .env.production
  4. 23
      .gitignore
  5. 25
      README.md
  6. 10
      babel.config.js
  7. 20016
      package-lock.json
  8. 88
      package.json
  9. 25
      postcss.config.js
  10. BIN
      public/favicon.ico
  11. 18
      public/index.html
  12. 39
      src/App.vue
  13. 20
      src/api/data.js
  14. 10
      src/api/index.js
  15. 20
      src/api/user.js
  16. 4
      src/config/translatedUnit_server.js
  17. 71
      src/main.js
  18. 54
      src/mixins/audit.scss
  19. 52
      src/mixins/coins.scss
  20. 94
      src/mixins/details.scss
  21. 110
      src/mixins/goods.js
  22. 69
      src/router/index.js
  23. 14878
      src/store/goods.js
  24. 25
      src/store/index.js
  25. 17
      src/store/info.js
  26. 24
      src/store/map.js
  27. 11
      src/store/order.js
  28. 41
      src/store/user.js
  29. 12
      src/utils/alioss.js
  30. 27
      src/utils/china.js
  31. 23
      src/utils/public.js
  32. 161
      src/utils/request.js
  33. 57
      src/utils/time.js
  34. 49
      src/utils/upload.js
  35. 53
      src/utils/utils.js
  36. 6
      src/utils/validateRegExp.js
  37. 13
      src/views/Home/home.vue
  38. 207
      src/views/PerformanceData/index.vue
  39. 288
      src/views/cityDistribution/index.vue
  40. 30
      src/views/dataOverview/index.vue
  41. 13
      src/views/error.vue
  42. 24
      src/views/login.vue
  43. 42
      vue.config.js

4
.env.development

@ -0,0 +1,4 @@
NODE_ENV=development
BUILD_ENV=development
VUE_APP_ENV=development
VUE_APP_BASE_URL="http://test.qingweilai888.xyz"

3
.env.online

@ -0,0 +1,3 @@
NODE_ENV=production
BUILD_ENV=online
VUE_APP_ENV=online

5
.env.production

@ -0,0 +1,5 @@
NODE_ENV=production
BUILD_ENV=production
VUE_APP_ENV=production
VUE_APP_BASE_URL="http://qwlapi.qwljk.com"

23
.gitignore

@ -0,0 +1,23 @@
.DS_Store
node_modules
# local env files
.env.local
.env.*.local
# Log files
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
# Editor directories and files
.idea
.vscode
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?

25
README.md

@ -1 +1,24 @@
qwl-data-report-h5
# qingweilai
## Project setup
```
npm install
```
### Compiles and hot-reloads for development
```
npm run serve
```
### Compiles and minifies for production
```
npm run build
```
### Lints and fixes files
```
npm run lint
```
### Customize configuration
See [Configuration Reference](https://cli.vuejs.org/config/).

10
babel.config.js

@ -0,0 +1,10 @@
module.exports = {
presets: ["@vue/cli-plugin-babel/preset"],
plugins: [
['import', {
libraryName: 'vant',
libraryDirectory: 'es',
style: true
}, 'vant']
]
};

20016
package-lock.json
File diff suppressed because it is too large
View File

88
package.json

@ -0,0 +1,88 @@
{
"name": "qingweilai",
"version": "0.1.0",
"private": true,
"scripts": {
"serve": "vue-cli-service serve --mode development",
"build:dev": "vue-cli-service build --mode development",
"build:pro": "vue-cli-service build --mode production",
"lint": "vue-cli-service lint"
},
"dependencies": {
"@vant/area-data": "^1.1.1",
"ali-oss": "^6.15.2",
"axios": "^0.21.1",
"core-js": "^3.6.5",
"cssnano": "^5.0.7",
"dayjs": "^1.10.5",
"echarts": "^5.1.2",
"element-ui": "^2.15.2",
"fuse.js": "^6.4.6",
"html2canvas": "^1.1.0",
"image-to-base64": "^2.2.0",
"js-base64": "^3.6.1",
"js-md5": "^0.7.3",
"jspdf": "^2.3.1",
"less": "^4.1.1",
"less-loader": "^9.0.0",
"lib-flexible": "^0.3.2",
"lrz": "^4.9.41",
"postcss-aspect-ratio-mini": "^1.1.0",
"postcss-cssnext": "^3.1.0",
"postcss-px-to-viewport": "^1.1.1",
"postcss-viewport-units": "^0.1.6",
"postcss-write-svg": "^3.0.1",
"qrcodejs2": "0.0.2",
"scss": "^0.2.4",
"swiper": "^6.6.1",
"v-viewer": "^1.6.3",
"vant": "^2.12.18",
"vue": "^2.6.11",
"vue-awesome-swiper": "^4.1.1",
"vue-photo-preview": "^1.1.3",
"vue-router": "^3.2.0",
"vuex": "^3.6.2"
},
"devDependencies": {
"@vue/cli-plugin-babel": "~4.5.0",
"@vue/cli-plugin-eslint": "~4.5.0",
"@vue/cli-plugin-router": "~4.5.0",
"@vue/cli-plugin-vuex": "~4.5.0",
"@vue/cli-service": "~4.5.0",
"@vue/eslint-config-prettier": "^6.0.0",
"babel-eslint": "^10.1.0",
"babel-plugin-import": "^1.13.3",
"cssnano-preset-advanced": "^5.1.3",
"eslint": "^6.7.2",
"eslint-plugin-prettier": "^3.3.1",
"eslint-plugin-vue": "^6.2.2",
"node-sass": "^6.0.1",
"postcss-import": "^14.0.2",
"postcss-url": "^10.1.3",
"prettier": "^2.2.1",
"sass": "^1.26.5",
"sass-loader": "^8.0.2",
"sass-resources-loader": "^2.2.3",
"vue-template-compiler": "^2.6.11"
},
"eslintConfig": {
"root": true,
"env": {
"node": true
},
"extends": [
"plugin:vue/essential",
"eslint:recommended",
"@vue/prettier"
],
"parserOptions": {
"parser": "babel-eslint"
},
"rules": {}
},
"browserslist": [
"> 1%",
"last 2 versions",
"not dead"
]
}

25
postcss.config.js

@ -0,0 +1,25 @@
module.exports = {
"plugins": {
"postcss-import": {},
"postcss-url": {},
"postcss-aspect-ratio-mini": {},
"postcss-write-svg": {
utf8: false
},
"postcss-cssnext": {},
"postcss-px-to-viewport": {
viewportWidth: 750, // 视窗的宽度,对应的是我们设计稿的宽度,移动端一般是750,如果是pc端那就是类似1920这样的尺寸
viewportHeight: 1344, // 视窗的高度,移动端一般指定1334,也可以不配置
unitPrecision: 3, // 指定`px`转换为视窗单位值的小数位数(很多时候无法整除)
viewportUnit: 'vw', // 指定需要转换成的视窗单位,建议使用vw
selectorBlackList: ['.ignore', '.hairlines'], // 指定不转换为视窗单位的类,可以自定义,可以无限添加,建议定义一至两个通用的类名
minPixelValue: 1, // 小于或等于`1px`不转换为视窗单位,你也可以设置为你想要的值
mediaQuery: false // 允许在媒体查询中转换`px`
},
"postcss-viewport-units":{},
"cssnano": {
preset: "default", // 设置成default将不会启用autoprefixer
"postcss-zindex": false
}
}
}

BIN
public/favicon.ico

Binary file not shown.

18
public/index.html

@ -0,0 +1,18 @@
<!DOCTYPE html>
<html lang="">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge" >
<!-- <meta name="viewport" content="width=device-width,initial-scale=1.0" > -->
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1" />
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<title><%= htmlWebpackPlugin.options.title %></title>
</head>
<body>
<noscript>
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
</noscript>
<div id="app"></div>
<!-- built files will be auto injected -->
</body>
</html>

39
src/App.vue

@ -0,0 +1,39 @@
<template>
<div id="app">
<keep-alive include="beiHuo,tiHuo">
<router-view v-if="isRouterAlive"></router-view>
</keep-alive >
</div>
</template>
<script>
export default {
name:'APP',
provide(){ //provideinject
return{
reload:this.reload
}
},
data(){
return{
isRouterAlive:true
}
},
methods: {
reload () {
this.isRouterAlive = false; //
this.$nextTick(function () {
this.isRouterAlive = true; //
})
}
}
};
</script>
<style lang="scss">
*{
margin: 0;
box-sizing: border-box;
}
</style>

20
src/api/data.js

@ -0,0 +1,20 @@
import { get, post, put, _delete } from '@/utils/request.js'
//首页
class data{
// 业绩数据
async earningReport(){
return await get("/admin/DataReport/ShopDataReport/earningReport")
}
//业绩报表
async overview(){
return await get("/admin/DataReport/ShopDataReport/overview")
}
//全国服务商数据
async dataDistribution(){
return await get("/admin/DataReport/ShopDataReport/dataDistribution")
}
}
export default new data()

10
src/api/index.js

@ -0,0 +1,10 @@
import { get, post, put, _delete } from '@/utils/request.js'
//首页
class Index{
async index(){
return await get("/api/Index/index")
}
}
export default new Index()

20
src/api/user.js

@ -0,0 +1,20 @@
import { get, post, put, _delete } from '@/utils/request.js'
class User {
// constructor() {}
// 查询个人信息
async userInfo() {
return await get('/api/User/User/config')
}
// 修改个人信息
async updateInfo(param) {
return await get('/api/User/User/updateInfo',param)
}
//用户协议
async protocol(){
return await get('/api/User/User/protocol')
}
}
export default new User()

4
src/config/translatedUnit_server.js

@ -0,0 +1,4 @@
module.exports = {
vw: 'vw',
vh: 'vh',
};

71
src/main.js

@ -0,0 +1,71 @@
import Vue from "vue";
import Vuex from "vuex"
import App from "./App.vue";
import router from "./router";
import 'lib-flexible';
// import '@/assets/font/font.css'
import ElementUI from 'element-ui';
// import 'element-ui/lib/theme-chalk/index.css';
import store from '@/store/index.js';
import md5 from 'js-md5';
import { Badge } from 'vant';
import * as echarts from 'echarts';
Vue.prototype.$echarts = echarts
Vue.config.productionTip = false;
//图片放大插件
// import preview from 'vue-photo-preview'
// import 'vue-photo-preview/dist/skin.css'
// Vue.use(preview)
// vant插件
import { Swipe, SwipeItem, NavBar, Toast, Search, Tab, Tabs, Card, Button, Stepper, ContactCard, Icon, Image as VanImage, AddressEdit, ActionSheet, Picker,RadioGroup, Radio, Sticky, Uploader, Step, Steps, Popup, Field, Calendar, Overlay, DropdownMenu, DropdownItem, Empty, Area,Dialog,Pagination, Checkbox, CheckboxGroup,List ,Tabbar, TabbarItem,Skeleton,Loading} from 'vant';
//验证码md5
Vue.prototype.$md5 = md5;
Vue.use(Loading);
Vue.use(Swipe);
Vue.use(SwipeItem);
Vue.use(NavBar);
Vue.use(Tabbar);
Vue.use(TabbarItem);
Vue.use(Toast);
Vue.use(Search);
Vue.use(Tab);
Vue.use(Tabs);
Vue.use(Card);
Vue.use(Button);
Vue.use(Stepper);
Vue.use(ContactCard);
Vue.use(Icon);
Vue.use(VanImage);
Vue.use(AddressEdit);
Vue.use(ActionSheet);
Vue.use(RadioGroup);
Vue.use(Radio);
Vue.use(Sticky);
Vue.use(Uploader);
Vue.use(Step);
Vue.use(Steps);
Vue.use(Popup);
Vue.use(Field);
Vue.use(Calendar);
Vue.use(Overlay);
Vue.use(DropdownMenu);
Vue.use(DropdownItem);
Vue.use(Empty);
Vue.use(Area);
Vue.use(Picker);
Vue.use(Dialog);
Vue.use(Pagination);
Vue.use(List);
Vue.use(Checkbox);
Vue.use(CheckboxGroup);
Vue.use(Skeleton);
Vue.use(Vuex);
Vue.use(ElementUI);
Vue.use(Badge);
new Vue({
router,
store,
render: (h) => h(App),
}).$mount("#app");

54
src/mixins/audit.scss

@ -0,0 +1,54 @@
.news-list {
// padding: 0 20px;
.search {
height: 65px;
line-height: 65px;
display: flex;
::v-deep .van-search {
flex: 1;
}
}
.backbuo{
padding: 0 20px;
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
border-bottom: 0.1px solid black;
padding-bottom: 10px;
.left{
display: flex;
align-items: center;
.TX{
margin-right: 10px;
img{
width: 65px;
height: 65px;
border-radius: 50%;
}
}
div{
.WZ{
font-size: 15px;
color: black;
}
p{
font-size: 13px;
color: #999;
}
}
}
.right{
width: 50px;
height: 25px;
background: rgb(237, 175, 139);;
p{
color: white;
text-align: center;
line-height: 25px;
}
}
}
}

52
src/mixins/coins.scss

@ -0,0 +1,52 @@
div{
.header {
::v-deep .van-icon {
color: black;
}
}
.Content{
margin: 15px;
box-sizing: border-box;
height: 150px;
background: #edaf8b;
border-radius: 10px;
.Crest{
div{
text-align: center;
img{
margin-top: 18px;
width: 35px;
height: 35px;
}
p{
line-height: 80px;
font-size: 15px;
color: white;
}
}
}
.RoolBox{
text-align: right;
p{
margin: 30px 0px 15px 0px;
font-size: 13px;
color: #999;
}
}
.footer{
.Box{
display: flex;
justify-content: space-between;
align-items: center;
border-bottom: 0.5px solid #999;
padding-bottom: 18px;
margin-bottom: 18px;
div p{
font-size: 14px;
color: black;
}
}
}
}
}

94
src/mixins/details.scss

@ -0,0 +1,94 @@
div {
.header {
::v-deep .van-icon {
color: black;
}
}
.body {
margin-top: 25px;
padding: 0 40px;
margin-bottom: 45px;
.top {
display: flex;
.img {
margin-right: 10px;
img {
width: 65px;
height: 65px;
border-radius: 50%;
}
}
.username {
margin-top: 15px;
font-size: 15px;
color: #333333;
span {
font-size: 13px;
color: #999999;
}
}
}
.level {
display: flex;
justify-content: space-between;
font-size: 15px;
color: #333333;
padding: 15px 0;
border-bottom: 1px solid #cccccc;
}
.plan {
font-size: 15px;
color: #333333;
padding: 15px 0;
border-bottom: 1px solid #cccccc;
}
.progress {
margin-left: 30px;
margin-right: 40px;
margin-top: 30px;
margin-bottom: 45px;
}
::v-deep .van-step {
color: #333333;
font-size: 15px;
p {
font-size: 13px;
color: #999;
}
}
}
.picture {
div {
display: flex;
flex-wrap: wrap;
justify-content: center;
img {
width: 100px;
height: 100px;
}
}
}
.footer {
position: fixed;
bottom: 0;
width: 100vw;
display: flex;
height: 45px;
line-height: 45px;
color: #fff;
font-size: 18px;
.false {
text-align: center;
flex: 50%;
background-color: #cccccc;
}
.true {
flex: 50%;
text-align: center;
background-color: #f1ac84;
}
}
}

110
src/mixins/goods.js

@ -0,0 +1,110 @@
import shop from "@/api/shop.js";
import { Toast } from "vant";
export default {
data() {
return {
type: 0, //备货:0,提货:1
active: 0,
total: 0, //总价
tabs: [],
selectedList: [],
};
},
created() {
this.type = this.$route.query.type;
this.getTabs();
},
computed: {
//获取已选商品数量
amount() {
let amount = 0;
this.selectedList.forEach((item) => (amount += item.amount));
return amount;
},
},
methods: {
onClickLeft() {
this.$router.go(-1);
},
//获取商品分类
async getTabs() {
const res = await shop.goodsType();
this.tabs = res.data.data;
},
//获取商品总价
getTotal(subtotal, type) {
type === "add" ? (this.total += subtotal) : (this.total -= subtotal);
},
//获取已选商品列表(购物车)
getGoods(goods) {
let index = this.selectedList.findIndex(
(item) => item.goods_id === goods.goods_id
);
// 如果有且已选数量不为0就替换 数量为0就删除 没有就添加
if (index !== -1) {
if (goods.amount == 0) {
this.selectedList.splice(index, 1);
} else {
this.selectedList[index] = goods;
}
} else {
this.selectedList.push(goods);
}
},
// 搜索
onSearch() {
this.$router.push({ path: '/search', query: { type: this.type } })
},
//确认订单
async confirm(list) {
const billing = [];
list.forEach((item) => {
let obj = {
goods_id: item.goods_id,
goods_number: item.amount,
};
billing.push(obj); //构造body数据
});
let res;
if (this.type == 0) {
//备货确认
res = await shop.shopStockBilling({
shop_billing: billing,
});
} else {
//提货确认
res = await shop.shopGoodsDelivery({
delivery_billing: billing,
});
}
if ((res.data.code == 0)) {
let info = res.data.data
this.$router.push({ path: "/stockDetail", query: { info: JSON.stringify(info), type: this.type } },);
}else{
this.$toast(res.data.msg)
}
},
//结算
handle() {
if (this.amount == 0) return Toast("请选择产品数量");
this.confirm(this.selectedList)
// .then(()=>{
// this.load = true
// setTimeout(()=>{
// location.reload()
// },1000)
// }).catch(()=>{
// this.load = false;
// })
},
},
};

69
src/router/index.js

@ -0,0 +1,69 @@
import Vue from "vue";
import VueRouter from "vue-router";
import Login from "../views/login.vue";
import Error from "../views/error.vue";
import store from '@/store/index.js';
const originalPush = VueRouter.prototype.push
VueRouter.prototype.push = function push(location) {
return originalPush.call(this, location).catch(err => err)
}
Vue.use(VueRouter);
const userinfo = JSON.parse(localStorage.getItem('userInfo'));
const routes = [{
path: "/",
redirect: '/login'
},
{
path: '/login',
name: 'Login',
component: Login,
},
{
path: "/error",
name: 'Error',
component: Error,
},
{
path: "/home",
name: 'home',
component: () => import('../views/Home/home.vue'),
},
{
path: "/cityDistribution",
name: 'cityDistribution',
component: () => import('../views/cityDistribution/index.vue'),
},
{
path: "/PerformanceData",
name: 'PerformanceData',
component: () => import('../views/PerformanceData/index.vue'),
},
{
path: "/dataOverview",
name: 'dataOverview',
component: () => import('../views/dataOverview/index.vue'),
},
];
const router = new VueRouter({
routes,
});
// 导航守卫
router.afterEach((to, from) => {
document.documentElement.scrollTop = 0;
// console.log(to.meta.title);
if (to.meta.title) {
document.title = to.meta.title;
} else {
document.title = '轻未来';
}
// console.log(from);
});
export default router;

14878
src/store/goods.js
File diff suppressed because it is too large
View File

25
src/store/index.js

@ -0,0 +1,25 @@
import Vue from 'vue'
import Vuex from 'vuex'
// 模块化
import user from './user'
import map from './map'
import goods from './goods'
import info from "./info"
import order from "./order"
Vue.use(Vuex)
const store = new Vuex.Store({
// 模块化
modules: {
user,
map,
goods,
info,
order
}
})
export default store

17
src/store/info.js

@ -0,0 +1,17 @@
export default{
namespaced: true,
state:()=>({
prower:{},
}),
mutations: {
authority(state,data){
state.prower = data;
}
},
getters: {
},
actions: {
}
}

24
src/store/map.js

@ -0,0 +1,24 @@
export default {
namespaced: true,
state: () => ({
address: {},
}),
mutations: {
selectAddr(state, data) {
state.address = data;
}
},
getters: {
selectedAddr(state) {
return {
address: `${state.address.provice}${state.address.city}${state.address.area}${state.address.street}${state.address.district}`,
name: state.address.receive_name,
phone: state.address.phone,
addressId: state.address.id
}
},
},
actions: {
}
}

11
src/store/order.js

@ -0,0 +1,11 @@
export default {
namespaced: true,
state: () => ({
info:{}//退货订单详情
}),
mutations: {
saveInfo(state, data) {
state.info = data;
}
}
}

41
src/store/user.js

@ -0,0 +1,41 @@
import router from '@/router/index.js';
export default {
namespaced: true,
state: {
token: '',
userInfo: {}
},
mutations: {
setToken(state, token) {
state.token = token
window.localStorage.setItem('token', token)
},
clearToken(state) {
state.token = ''
window.localStorage.setItem('token', '')
},
setUserInfo(state, userInfo) {
state.userInfo = userInfo
localStorage.setItem('userInfo',JSON.stringify(state.userInfo))
}
},
actions: {
async getUserInfo({ commit, state }, user) {
try {
const res = await user.userInfo()
if (res.data.code === 0) {
commit('setUserInfo', res.data.data)
if (state.userInfo.status === 1) {
router.push("home");
} else if (state.userInfo.status === 0) {
state.userInfo.parent_id ? router.push('Enroll') : router.push('Error')
} else {
router.push('Check2')
}
}
} catch (err) {
console.log(err)
}
}
}
}

12
src/utils/alioss.js

@ -0,0 +1,12 @@
var OSS = require('ali-oss');
export function client() {
var client = new OSS({
region: 'oss-cn-beijing',
accessKeyId: 'LTAI5tEzUQa5pok6Y5mjcHaT',
accessKeySecret: 'HTU9OMUtqgwjkZAKgFrXhXGhN9KD0p',
bucket: 'qingweilaikeji'
}) //后端提供数据
return client
}
//阿里云图片上传

27
src/utils/china.js
File diff suppressed because it is too large
View File

23
src/utils/public.js

@ -0,0 +1,23 @@
//防抖
let timeout;
export function Debounce(func, wait, immediate = false) {
// 清除定时器
if (timeout !== null) clearTimeout(timeout);
// 立即执行,此类情况一般用不到
if (immediate) {
var callNow = !timeout;
timeout = setTimeout(function () {
timeout = null;
}, wait);
if (callNow) typeof func === 'function' && func();
} else {
// 设置定时器,当最后一次操作后,timeout不会再被清除,所以在延时wait毫秒后执行func回调方法
timeout = setTimeout(function () {
typeof func === 'function' && func();
}, wait);
}
}
export default {
Debounce
}

161
src/utils/request.js

@ -0,0 +1,161 @@
import axios from 'axios'
import {Toast} from 'vant'
// axios.defaults.baseURL = 'http://test.qingweilai888.xyz' //测试环境
// axios.defaults.baseURL = 'http://qwlapi.qwljk.com' //正式环境
axios.defaults.baseURL= process.env.VUE_APP_BASE_URL
axios.defaults.headers.post['Content-Type'] = 'application/json'
// 添加请求拦截器
axios.interceptors.request.use(function (config) {
// console.log('经过了拦截器');
// 1.获取token
// let token = localStorage.getItem('token') //登陆token
let token = localStorage.getItem('token') //后台token
config.headers.Authorization = token
// 2.判断是否有token,如果有则进行请求头的设置
// if (token,token1) {
// console.log(config,"this.config");
// config.headers.Authorization = token
// }
// if(config.url.indexOf("admin") == 1){
// console.log(`1111111111111111`);
// // 如果这URL存在admin这个字符串就会返回1,不存在就返回 -1
// config.headers['X-Requested-With'] = 'XMLHttpRequest'
// config.headers.Authorization = token1
// }else{
// console.log(`22222222222222`);
// config.headers.Authorization = token
// }
// 拦截器只是对请求的数据进行“加工”处理,但是不会代替你去发请求
return config;
}, function (error) {
// 对请求错误做些什么
return Promise.reject(error);
});
// 响应拦截器
axios.interceptors.response.use(
response => {
if (response.status === 200) {
return Promise.resolve(response)
} else {
return Promise.reject(response)
}
},
// 服务状态码不是200的情况
error => {
if (error.response.data.http_code) {
switch (error.response.data.http_code) {
// 401 未登录
// 未登录则跳转登录页面,并携带当前页面的路径
// 在登录成功后返回当前页面,这一步需要在登录页操作。
case 401:
router.replace({
message: '感谢你的关注,请注册后再登录!',
path: '/error',
query: {redirect: router.currentRoute.fullPath}
})
break
// 403 token过期
// 登录过期对用户进行提示
// 清除本地token和清空vuex中token对象
// 跳转登录页面
case 403:
Toast({
message: '登录过期,请重新登录',
duration: 1000,
forbidClick: true
})
localStorage.removeItem('token')
store.commit('loginSuccess', null)
// 跳转登录页面,并将要浏览的页面fullpath传过去,登录成功后跳转到要访问的页面
setTimeout(() => {
router.replace({
path: '/login',
query: {
redirect: router.currentRoute.fullPath
}
})
}, 1000)
break
// 404 请求不存在
case 404:
Toast({
message: '服务器繁忙,请稍后再操作!',
duration: 1500,
forbidClick: true
})
break
// 其他错误直接抛出错误提示
default:
Toast({
message: error.response.data.msg,
duration: 1500,
})
}
return Promise.reject(error.response)
}
}
)
// 导出常用函数
/**
* @param {string} url
* @param {object} data
* @param {object} params
*/
export function post(url, data = {}, params = {}) {
return axios({
method: 'post',
url,
data,
params,
})
}
/**
* @param {string} url
* @param {object} params
*/
export function get(url, params = {}) {
return axios({
method: 'get',
url,
params,
})
}
/**
* @param {string} url
* @param {object} data
* @param {object} params
*/
export function put(url, data = {}, params = {}) {
return axios({
method: 'put',
url,
params,
data,
})
}
/**
* @param {string} url
* @param {object} params
*/
export function _delete(url, params = {}) {
return axios({
method: 'delete',
url,
params,
})
}
export default axios

57
src/utils/time.js

@ -0,0 +1,57 @@
// 获取统计周期范围
const
getDayFanWei=(year, weekOrMonth, type)=> {
if (weekOrMonth != "") {
let startDate = '';
let endDate = '';
if (type == 1) {
let day = 7 * (weekOrMonth - 1);
// 那一年第一天是星期几
let firstDay = new Date(year + "-01-01");
let yearFirstDay = firstDay.getDay() || 7;
if (yearFirstDay == 1) {
startDate = this.dateAddDays(year + "-01-01", day);
endDate = this.dateAddDays(year + "-01-01", day + 6);
} else {
day = day + (8 - yearFirstDay);
startDate = this.dateAddDays(year + "-01-01", day);
endDate = this.dateAddDays(year + "-01-01", day + 6);
}
} else {
if (weekOrMonth < 10) {
startDate = year + "-0" + weekOrMonth + "-01";
} else {
startDate = year + "-" + weekOrMonth + "-01";
}
let dateC = new Date(year + "-" + weekOrMonth + "-01");
// 获取天数
let days = new Date(year, weekOrMonth, 0).getDate();
if (days < 10) {
days = "0" + days;
}
if (weekOrMonth < 10) {
weekOrMonth = "0" + weekOrMonth;
}
endDate = year + "-" + weekOrMonth + "-" + days;
}
return startDate + "~" + endDate;
// return startDate + " 00:00:00~" + endDate + " 23:59:59";
}
};
const dateAddDays=(dataStr, dayCount)=>{
let strdate = dataStr; // 日期字符串
let isdate = new Date(strdate.replace(/-/g, "/")); // 把日期字符串转换成日期格式
isdate = new Date((isdate / 1000 + (86400 * dayCount)) * 1000); // 日期加1天
let month = isdate.getMonth() + 1;
let day = isdate.getDate();
if (month < 10) {
month = "0" + month;
}
if (day < 10) {
day = "0" + day;
}
let pdate = isdate.getFullYear() + "-" + month + "-" + day; // 把日期格式转换成字符串
return pdate;
}
export {getDayFanWei,dateAddDays}

49
src/utils/upload.js

@ -0,0 +1,49 @@
import {
client
} from "./alioss.js";
const Beijing = {
Upload(file) {
var fileName = 'banner' + `${Date.parse(new Date())}` + '.jpeg'; //定义唯一的文件名
//定义唯一的文件名,打印出来的uid其实就是时间戳
client().multipartUpload(fileName, file.file).then(
result => {
//此处为给自己属性进行赋值,http后面的代码很有可能会和我的不一样,一切与自己阿里云上的数据为准
this.contacts.conImg = 'http://qingweilaikeji.oss-cn-beijing.aliyuncs.com/' + fileName;
// 大功搞成
//下面是如果对返回结果再进行处理,根据项目需要,下面是我们自己项目所用的,仅供参考
this.fileList[0] = {
'name': result.name,
'url': result.url
}
uploadBannerPic(this.fileList).then(res => {
//此处为给自己属性进行赋值,http后面的代码很有可能会和我的不一样,一切与自己阿里云上的数据为准
//根据需要可能项目还需对自己的数据库进行保存
this.contacts.conImg = 'http://qingweilaikeji.oss-cn-beijing.aliyuncs.com/' + this.fileList[0].result.name;
})
})
},
/**
* 图片限制
* 图片限制在理论上来说可以不用写如果想要简单可以不写
* 上传图片切记不要过大可能会导致上传失败
*/
beforeAvatarUpload(file) {
const isJPEG = file.name.split('.')[1] === 'jpeg';
const isJPG = file.name.split('.')[1] === 'jpg';
const isPNG = file.name.split('.')[1] === 'png';
const isLt500K = file.size / 1024 / 500 < 2;
if (!isJPG && !isJPEG && !isPNG) {
this.$message.error('上传图片只能是 JPEG/JPG/PNG 格式!');
}
if (!isLt500K) {
this.$message.error('单张图片大小不能超过 500KB!');
}
return (isJPEG || isJPG || isPNG) && isLt500K;
}
}
export{
Beijing
}
//阿里云图片配置

53
src/utils/utils.js

@ -0,0 +1,53 @@
import store from '@/store'
export const GET_LOCAL_ITEM = (key) => {
return localStorage.getItem(key)
}
export const SET_LOCAL_ITEM = (key, value) => {
return localStorage.setItem(key, value)
}
//搜索防抖
export const DEBOUNCE = (func, wait=500) => {
let timer = null;
return function(...args) {
if(timer) clearTimeout(timer)
timer = setTimeout( () => {
func.apply(this,...args)
},wait)
}
}
/**
* 角色权限校验
* @param {Array} value 权限校验值
* 4为分公司拥有进入'轻未来'权限
*/
export const CHECK_ROLE = (value) => {
// return store.state.user.userInfo.level_id === value
// return localStorage.getItem("userInfo",'level_id') === value
const userinfo = JSON.parse(localStorage.getItem('userInfo'));
return userinfo.level_id === value
}
/**
* 操作权限校验
* @param {Array} value 权限校验值
* 1为存在后台用户拥有进入'后台审批'权限
*/
export const CHECK_CAN = (value) => {
// return store.state.user.userInfo.admin_id === value
const userinfo = JSON.parse(localStorage.getItem('userInfo'));
return userinfo.level_id === value
}
/**
* 后台审批校验
* is_aadmin = 1 显示后台审批页面
* 1为存在后台用户拥有进去后台审批权限
*/
export const CHECK_KOB = (value) =>{
const userinfo = JSON.parse(localStorage.getItem('userInfo'));
return userinfo.is_admin === value
}

6
src/utils/validateRegExp.js

@ -0,0 +1,6 @@
export default {
phone: {
regExp: /^(13[0-9]|14[579]|(17[0135678])|(15[0-9])|(18[0-9])|16[6]|19[89])\d{8}$/,
message: '手机号码格式不正确',
},
};

13
src/views/Home/home.vue

@ -0,0 +1,13 @@
<template>
<div class="home">
<div class="pp">
66666666666666666666666666666666666666666666
</div>
</div>
</template>
<style lang="scss" scoped>
.pp{
font-size: 36px;
}
</style>

207
src/views/PerformanceData/index.vue

@ -0,0 +1,207 @@
<template>
<div class="PerformanceData">
<div class="dataInfo">
<p class="title">2021年总业绩</p>
<p class="money" v-if="year_count_order_money">¥{{year_count_order_money | capitalize}}</p>
</div>
<div class="time">
<div class="active"></div>
</div>
<div class="list">
<div class="title">营业额</div>
<div class="money" v-if="money_count_order_money"><span>¥</span>{{money_count_order_money | capitalize}}
</div>
<div class="name">轻未来阻燃粉100,000/</div>
<div class="cartogram" ref="cartogram"></div>
</div>
</div>
</template>
<script>
import * as echarts from 'echarts';
import data from "@/api/data.js";
export default {
data() {
return {
opinionData: [0, 0, 0, 0, 15904960, 0, 0, 0, 0],
year_count_order_money: '',
money_count_order_money: '',
}
},
async mounted() {
await this.getData()
this.drawLine(this.opinionData)
},
filters: {
capitalize: function (val) {
return (+val || 0).toFixed(0).replace(/\d{1,3}(?=(\d{3})+(\.\d*)?$)/g, '$&,')
}
},
methods: {
async getData() {
this.opinionData = []
// let data = new Date()
let month = new Date().getMonth() + 1;
const res = await data.earningReport();
let list = res.data.month_list_money_count
this.year_count_order_money = res.data.year_count_order_money
this.money_count_order_money = res.data.money_count_order_money
for (let key in list) {
this.opinionData.push(list[key])
}
this.opinionData.splice(month)
console.log(res, '---rthis.opinionDataes');
},
drawLine(opinionData) {
var chartBar = echarts.init((this.$refs.cartogram));
chartBar.setOption({
deep: true,
tooltip: {
trigger: 'axis'
},
// legend: {
// // data: ['']
// },
grid: {
left: '3%',
right: '4%',
bottom: '3%',
containLabel: true
},
// toolbox: { //
// feature: {
// saveAsImage: {}
// }
// },
xAxis: {
type: 'category',
boundaryGap: false,
data: ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12"]
},
yAxis: {
type: 'value'
},
series: [{
// name: '',
type: 'line',
stack: '总量',
data: opinionData
}]
})
}
},
}
</script>
<style lang="scss" scoped>
.PerformanceData {
background: #3C3F50;
min-height: 100vh;
.dataInfo {
padding: 50px 70px;
width: 750px;
height: 258px;
background: linear-gradient(90deg, #729EFF, #5D48E1);
box-shadow: 0px 17px 35px 0px rgba(58, 61, 80, 0.2);
border-radius: 0px 0px 20px 20px;
margin-bottom: 52px;
.title {
font-size: 40px;
font-family: Microsoft YaHei;
font-weight: 400;
color: #FFFFFF;
margin-bottom: 43px;
}
.money {
height: 76px;
line-height: 76px;
font-size: 76px;
font-weight: normal;
color: #FFFFFF;
}
}
.time {
display: flex;
justify-content: space-around;
margin-bottom: 28px;
div {
width: 202px;
height: 62px;
border: 2px solid #FFFFFF;
border-radius: 31px;
text-align: center;
line-height: 62px;
color: #fff;
font-size: 36px;
}
.active {
width: 202px;
height: 62px;
background: linear-gradient(0deg, #729EFF, #5D48E1);
border: 2px solid #FFFFFF;
box-shadow: 0px 17px 35px 0px rgba(61, 64, 83, 0.36);
border-radius: 31px;
}
}
.list {
width: 750px;
min-height: 910px;
background: linear-gradient(0deg, #4D5169, #272A3B);
border-radius: 20px;
padding: 50px 70px;
.title {
font-size: 40px;
font-family: Microsoft YaHei;
font-weight: 400;
color: #FFFFFF;
height: 40px;
line-height: 40px;
margin-bottom: 24px;
}
.money {
height: 80px;
line-height: 80px;
font-size: 76px;
font-family: OPPOSans;
font-weight: normal;
color: #27F0F1;
margin-bottom: 30px;
span {
color: #FFFFFF;
}
}
.name {
width: 502px;
height: 60px;
background: rgb(255 255 255 / 14%);
border-radius: 30px;
font-size: 34px;
font-family: Microsoft YaHei;
font-weight: 400;
color: #FFFFFF;
line-height: 60px;
padding: 0 33px;
margin-bottom: 50px;
}
.cartogram {
width: 610px;
height: 490px;
margin: 0 auto;
}
}
}
</style>

288
src/views/cityDistribution/index.vue

@ -0,0 +1,288 @@
<template>
<div class="cityDistribution">
<div class="top">
<p class="title">服务商总数量</p>
<p class="num">{{poxy_sum | capitalize}}</p>
</div>
<div ref="area" id="area"></div>
<div class="info">
<p><span>股东</span>1,000</p>
<p><span>分公司</span>100,000,000</p>
<p><span>分公司</span>100,000</p>
<p><span>总代</span>1,000</p>
<div ref='chartBar' id="home"></div>
</div>
<div class="ranking">
<p class="title">代理城市排名</p>
<div class="rankingCity">
<div class="item">
<p class="city">广东省</p>
<p class="number">1,000</p>
</div>
<div class="item">
<p class="city">湖南省</p>
<p class="number">100,000,00</p>
</div>
<div class="item">
<p class="city">上海市</p>
<p class="number">100,000</p>
</div>
<div class="item">
<p class="city">四川省</p>
<p class="number">1,000</p>
</div>
</div>
</div>
</div>
</template>
<script>
import * as echarts from 'echarts';
import '../../utils/china'
import data from "@/api/data.js";
export default {
name: 'cityDistribution',
data() {
return {
chinachart: null,
chartOption: null,
poxy_sum:'',
city:{},
cityName:'广东',
cityInfo:{},
}
},
filters: {
capitalize: function (val) {
return (+val || 0).toFixed(0).replace(/\d{1,3}(?=(\d{3})+(\.\d*)?$)/g, '$&,')
}
},
async mounted() {
await this.getData()
this.drawarea();
this.aa()
},
methods: {
async getData() {
const res = await data.dataDistribution();
console.log(res,'-----res');
this.poxy_sum = res.data.poxy_sum
this.city = res.data.city
console.log(this.city, '---res');
this.cityInfo = this.city[this.cityName]
},
drawarea() {
const _this = this
this.$nextTick(() => {
_this.myChinaMap = echarts.init(this.$refs.area)
_this.myChinaMap.on('click', function (param) {
console.log(param.name)
})
_this.myChinaMap.setOption({ //
backgroundColor: '#fff',
tooltip: {}, //
dataRange: {
show: false,
min: 0,
max: 1000,
text: ['High', 'Low'],
realtime: true,
calculable: true,
color: ['orangered', 'yellow', 'lightskyblue']
},
geo: { //
map: 'china', //
roam: false, //
selectedMode: 'single',
label: {
normal: {
show: false, //
textStyle: {
color: 'rgba(0,0,0,0.4)'
}
}
},
itemStyle: {
normal: {
borderColor: 'rgba(0, 0, 0, 0.2)'
},
emphasis: {
areaColor: null,
shadowOffsetX: 0,
shadowOffsetY: 0,
shadowBlur: 20,
borderWidth: 0,
shadowColor: 'rgba(0, 0, 0, 0.5)'
}
}
}
})
})
},
aa() {
var chartBar = echarts.init((this.$refs.chartBar));
var option = {
// title: {
// text: '访',
// subtext: '',
// x: 'center'
// },
tooltip: {
trigger: 'item',
formatter: "{a} <br/>{b} : {c} ({d}%)"
},
// legend: {
// orient: 'vertical',
// left: 'left',
// data: ['访', '', '广']
// },
series: [{
name: '访问来源',
type: 'pie',
radius: '55%',
center: ['50%', '60%'],
data: [{
value: 335,
name: '总代'
},
{
value: 3101,
name: '分公司'
},
{
value: 234,
name: '分公司1'
},
{
value: 2344,
name: '股东'
}
],
itemStyle: {
emphasis: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: 'rgba(0, 0, 0, 0.5)'
}
}
}]
};
chartBar.setOption(option)
}
}
}
</script>
<style lang="scss" scoped>
.cityDistribution {
min-height: 100vh;
// background: linear-gradient(0deg, #424558, #202335);
.top {
height: 258px;
background: linear-gradient(90deg, #729EFF, #5D48E1);
box-shadow: 0px 17px 35px 0px rgba(58, 61, 80, 0.2);
border-radius: 0px 0px 20px 20px;
padding: 0 68px;
padding-top: 50px;
.title {
font-size: 40px;
font-family: Microsoft YaHei;
font-weight: 400;
color: #FFFFFF;
margin-bottom: 42px;
height: 40px;
line-height: 40px;
}
.num {
font-size: 76px;
font-family: OPPOSans;
font-weight: normal;
color: #FFFFFF;
height: 76px;
line-height: 76px;
}
}
#area {
height: 400px;
width: 750px;
}
#home {
width: 690px;
height: 364px;
margin: 0 auto;
margin-top: 60px;
}
.info {
margin: 0 auto;
width: 690px;
height: 724px;
background: linear-gradient(0deg, #729EFF, #5D48E1);
border-radius: 20px;
padding: 46px 24px;
margin-bottom: 50px;
p {
font-size: 34px;
font-family: Microsoft YaHei;
font-weight: 400;
color: #FFFFFF;
}
}
.ranking {
padding: 37px 40px;
margin: 0 auto;
width: 690px;
min-height: 509px;
background: #373A4A;
margin-bottom: 40px;
.title {
font-size: 40px;
font-family: Microsoft YaHei;
font-weight: 400;
color: #FFFFFF;
height: 40px;
line-height: 40px;
margin-bottom: 20px;
}
.rankingCity {
.item {
display: flex;
justify-content: space-between;
height: 94px;
background: #4A4D5C;
padding: 0 30px;
border-bottom: 1px solid #fff;
.city {
font-size: 34px;
font-family: Microsoft YaHei;
font-weight: 400;
color: #FFFFFF;
line-height: 94px;
height: 94px;
}
.number {
font-size: 34px;
font-family: OPPOSans;
font-weight: normal;
color: #27F0F1;
line-height: 94px;
height: 94px;
}
}
}
}
}
</style>

30
src/views/dataOverview/index.vue

@ -0,0 +1,30 @@
<template>
<div class="dataOverview">
</div>
</template>
<script>
import data from "@/api/data.js";
export default {
name:"dataOverview",
data(){
return{
}
},
created(){
this.getData()
},
methods:{
async getData(){
const res = await data.overview();
console.log(res,'---res');
},
}
}
</script>
<style lang="scss" scoped>
.dataOverview{
}
</style>

13
src/views/error.vue

@ -0,0 +1,13 @@
<template>
<van-empty description="没有访问权限~" />
</template>
<script>
export default {
}
</script>
<style>
</style>

24
src/views/login.vue

@ -0,0 +1,24 @@
<template></template>
<script>
import user from "@/api/user.js";
export default {
beforeMount() {
let url = this.$route.query;
let token;
let url_string = JSON.stringify(url);
// if (url_string == "{}") {
// this.$toast('')
// } else {
// token = url.token_type + " " + url.access_token;
// this.$store.commit("user/setToken", token);
// this.$store.dispatch("user/getUserInfo", user); //
// }
token ="bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwOlwvXC90ZXN0LnFpbmd3ZWlsYWk4ODgueHl6XC9hZG1pblwvbG9naW4iLCJpYXQiOjE2Mjc0NjU1ODksImV4cCI6MTk4NzQ2NTU4OSwibmJmIjoxNjI3NDY1NTg5LCJqdGkiOiJ6clVHYnJCOXlPWkpRanRUIiwic3ViIjoxNjEsInBydiI6IjBiMzZjMGUwMjMyZGVlZTlkOTZhZDA0NGY3YWE2MjQ2YTUwYTU3ZmEifQ.aFc5fCUffmDN7zBRn-D13kx1LuLNG1Ej7vQOu4O2_AA"
this.$store.commit("user/setToken", token);
this.$store.dispatch("user/getUserInfo", user); //
},
};
</script>
<style></style>

42
vue.config.js

@ -0,0 +1,42 @@
module.exports = {
css: {
loaderOptions: {
postcss: {
plugins: [
require("postcss-px-to-viewport")({
unitToConvert: "px", // 要转化的单位
viewportWidth: 750, // UI设计稿的宽度
unitPrecision: 3, // 转换后的精度,即小数点位数
propList: [
"*"
], // 指定转换的css属性的单位,*代表全部css属性的单位都进行转换
viewportUnit: "vw", // 指定需要转换成的视窗单位,默认vw
fontViewportUnit: "vw", // 指定字体需要转换成的视窗单位,默认vw
landscapeUnit: 'vh', // 横屏时使用的单位
landscapeWidth: 667, // 横屏时使用的视口宽度
selectorBlackList: [], // 指定不转换为视窗单位的类名
minPixelValue: 1, // 默认值1,小于或等于1px则不进行转换
mediaQuery: false, // 是否在媒体查询的css代码中也进行转换,默认false
replace: true, // 是否转换后直接更换属性值
// landscape: false, // 是否处理横屏情况
})
]
}
},
},
lintOnSave: false,
// devServer: {
// proxy: { //配置跨域
// '/admin': {
// target: 'http://test.qingweilai888.xyz', //这里后台的地址模拟的;应该填写你们真实的后台接口
// changOrigin: true, //允许跨域
// pathRewrite: {
// /* 重写路径,当我们在浏览器中看到请求的地址为:http://localhost:8080/api/core/getData/userInfo 时
// 实际上访问的地址是:http://121.121.67.254:8185/core/getData/userInfo,因为重写了 /api
// */
// '^/admin': 'admin'
// }
// },
// }
// },
}
Loading…
Cancel
Save