Commit 80a8b6a3 authored by liyan's avatar liyan

init

parents
[*.{js,jsx,ts,tsx,vue}]
indent_style = space
indent_size = 2
trim_trailing_whitespace = true
insert_final_newline = true
module.exports = {
root: true,
env: {
node: true
},
'extends': [
'plugin:vue/essential'
],
rules: {
'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'off',
'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off'
},
parserOptions: {
parser: 'babel-eslint'
}
}
*.js linguist-language=vue
*.css linguist-language=vue
*.html linguist-language=vue
\ No newline at end of file
.DS_Store
node_modules
/dist
# local env files
.env.local
.env.*.local
# Log files
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# Editor directories and files
.idea
.vscode
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
module.exports = {
plugins: {
'autoprefixer': {
overrideBrowserslist: [
"Android 4.1",
"iOS 7.1",
"Chrome > 31",
"ff > 31",
"ie >= 8"
//'last 10 versions', // 所有主流浏览器最近10版本用
],
grid: true
},
'postcss-pxtorem': {
rootValue: 37.5, //vant-UI的官方根字体大小是37.5
propList: ['*']
}
}
}
This diff is collapsed.
![](static-files/newbee-mall.png)
![Build Status](https://img.shields.io/badge/build-passing-green.svg)
![Version 2.0.0](https://img.shields.io/badge/version-2.0.0-yellow.svg)
[![License](https://img.shields.io/badge/license-GPL3.0-blue.svg)](https://github.com/newbee-ltd/newbee-mall-vue-app/blob/master/LICENSE)
newbee-mall 项目是一套电商系统,包括 newbee-mall 商城系统及 newbee-mall-admin 商城后台管理系统,基于 Spring Boot 2.X 和 Vue 以及相关技术栈开发。 前台商城系统包含首页门户、商品分类、新品上线、首页轮播、商品推荐、商品搜索、商品展示、购物车、订单结算、订单流程、个人订单管理、会员中心、帮助中心等模块。 后台管理系统包含数据面板、轮播图管理、商品管理、订单管理、会员管理、分类管理、设置等模块。
本仓库中的源码为新蜂商城前后端分离版本的 Vue 项目(Vue 版本为 2.x),主要面向前端开发人员,后端 API 源码在另外一个仓库 [newbee-mall-api](https://github.com/newbee-ltd/newbee-mall-api)
新蜂商城 Vue 版本线上预览地址:[http://vue-app.newbee.ltd](http://47.99.134.126:5000),账号可自行注册,建议使用手机模式打开。
前后端分离版本包括四个仓库:
- [新蜂商城后端接口 newbee-mall-api](https://github.com/newbee-ltd/newbee-mall-api)
- [新蜂商城 Vue2 版本 newbee-mall-vue-app](https://github.com/newbee-ltd/newbee-mall-vue-app)
- [新蜂商城 Vue3 版本 newbee-mall-vue3-app](https://github.com/newbee-ltd/newbee-mall-vue3-app)
- [新蜂商城后台管理系统 Vue3 版本 vue3-admin](https://github.com/newbee-ltd/vue3-admin)
>Vue2 版本与 Vue3 版本分成两个仓库,大家需要哪个版本就去对应的仓库即可。
**坚持不易,如果觉得项目还不错的话可以给项目一个 Star 吧,也是对我一直更新代码的一种鼓励啦,谢谢各位的支持。**
![newbee-mall-info](https://newbee-mall.oss-cn-beijing.aliyuncs.com/poster/store/newbee-mall-star.png)
关注公众号:**程序员十三**,回复"勾搭"进群交流。
![wx-gzh](https://newbee-mall.oss-cn-beijing.aliyuncs.com/wx-gzh/%E7%A8%8B%E5%BA%8F%E5%91%98%E5%8D%81%E4%B8%89-%E5%85%AC%E4%BC%97%E5%8F%B7.png)
## 开发及部署文档
- [向“全栈”进发!大型线上商城实战项目,Spring Boot + Vue 前后端分离版本的商城来了!](https://juejin.im/book/6844733826191589390)
- [项目须知和课程约定](https://juejin.im/book/6844733826191589390)
- [全栈开发!你必须要知道的“前后端分离”](https://juejin.im/book/6844733826191589390)
- [前端模块化的发展历史](https://juejin.im/book/6844733826191589390)
- [传统页面和单页面的权衡与抉择](https://juejin.im/book/6844733826191589390)
- [准备工作及基础环境搭建(后端)](https://juejin.im/book/6844733826191589390)
- [Spring Boot 项目初体验--项目搭建及启动](https://juejin.im/book/6844733826191589390)
- [项目编码简化利器!Spring Boot 整合 Lombok](https://juejin.im/book/6844733826191589390)
- [Lombok 插件问题处理](https://juejin.im/book/6844733826191589390)
- [商城后端项目启动和运行注意事项](https://juejin.im/book/6844733826191589390)
- [VSCode 的相关配置及插件介绍](https://juejin.im/book/6844733826191589390)
- [基础篇:Vue 指令](https://juejin.im/book/6844733826191589390)
- [基础篇:Vue全局API及生命周期介绍](https://juejin.im/book/6844733826191589390)
- [基础篇: CSS 预处理工具Less的介绍及使用](https://juejin.im/book/6844733826191589390)
- [Vue 脚手架工具 Vue-Cli 配置介绍](https://juejin.im/book/6844733826191589390)
- [Vue-Router 浅析原理及使用](https://juejin.im/book/6844733826191589390)
- [全局状态管理插件 Vuex 介绍及使用](https://juejin.im/book/6844733826191589390)
- [商城前端 H5 开发环境搭建及项目启动](https://juejin.im/book/6844733826191589390)
- [前后端交互文档利器!Spring Boot 整合 Swagger](https://juejin.im/book/6844733826191589390)
- [接口参数处理和统一响应结果](https://juejin.im/book/6844733826191589390)
- [口设计规范及接口调用实践](https://juejin.im/book/6844733826191589390)
- [商城开发实战-用户登录接口开发](https://juejin.im/book/6844733826191589390)
- [商城开发实战-用户身份认证详解](https://juejin.im/book/6844733826191589390)
- [商城开发实战-首页模块接口开发](https://juejin.im/book/6844733826191589390)
- [商城开发实战-分类模块接口开发](https://juejin.im/book/6844733826191589390)
- [商城开发实战-商品搜索模块接口开发](https://juejin.im/book/6844733826191589390)
- [商城开发实战-购物车模块接口开发](https://juejin.im/book/6844733826191589390)
- [商城开发实战-个人信息及收货地址接口开发](https://juejin.im/book/6844733826191589390)
- [商城开发实战-下单流程接口开发](https://juejin.im/book/6844733826191589390)
- [商城开发实战-订单处理流程详解](https://juejin.im/book/6844733826191589390)
- [商城移动端开发实战-新蜂商城底部导航(抽离公共组件)](https://juejin.im/book/6844733826191589390)
- [商城移动端开发实战-新蜂商城登录注册页(前端鉴权)](https://juejin.im/book/6844733826191589390)
- [商城移动端开发实战-商城首页制作(轮播图、首页商品列表)](https://juejin.im/book/6844733826191589390)
- [商城移动端开发实战-商品分类页面制作(better-scrol的介绍及使用)](https://juejin.im/book/6844733826191589390)
- [商城移动端开发实战-商品列表页面制作(无限滚动加载)](https://juejin.im/book/6844733826191589390)
- [商城移动端开发实战-商品详情页面制作(Vuex 购物车数量全局管理)](https://juejin.im/book/6844733826191589390)
- [商城移动端开发实战-商城购物车页面制作(购物车页)](https://juejin.im/book/6844733826191589390)
- [商城移动端开发实战-确认订单页面制作](https://juejin.im/book/6844733826191589390)
- [商城移动端开发实战-地址栏管理页面制作](https://juejin.im/book/6844733826191589390)
- [商城移动端开发实战-我的订单页面制作](https://juejin.im/book/6844733826191589390)
- [Vue 3.x 新特性概览](https://juejin.im/book/6844733826191589390)
- [新蜂商城迁移至 Vue 3.x 流程讲解](https://juejin.im/book/6844733826191589390)
## 联系作者
> 大家有任何问题或者建议都可以在 [issues](https://github.com/newbee-ltd/newbee-mall-vue-app/issues) 中反馈给我,我会慢慢完善这个项目。
- 我的邮箱:2449207463@qq.com
- QQ技术交流群:932227898 719099151 796794009
## 软件著作权
>本系统已申请软件著作权,受国家版权局知识产权以及国家计算机软件著作权保护!
![](https://newbee-mall.oss-cn-beijing.aliyuncs.com/poster/store/newbee-mall-copyright-02.png)
## 页面展示
以下为新蜂商城 Vue 版本的页面预览:
- 登录页
![](static-files/登录.png)
- 首页
![](static-files/首页.png)
- 商品搜索
![](static-files/商品搜索.png)
- 商品详情页
![](static-files/详情页.png)
- 购物车
![](static-files/购物车.png)
- 生成订单
![](static-files/生成订单.png)
- 地址管理
![](static-files/地址管理.png)
- 订单列表
![](static-files/订单列表.png)
- 订单详情
![](static-files/订单详情.png)
## 感谢
- [Vue](https://github.com/vuejs/vue)
- [Vant](https://github.com/youzan/vant)
- [vue2-verify](https://github.com/mizuka-wu/vue2-verify)
- [better-scroll](https://github.com/ustbhuangyi/better-scroll)
- [Vuex](https://github.com/vuejs/vuex)
module.exports = {
presets: [
'@vue/cli-plugin-babel/preset'
],
plugins: [
['import', {
libraryName: 'vant',
libraryDirectory: 'es',
style: true
}, 'vant']
]
}
/**
* 严肃声明:
* 开源版本请务必保留此注释头信息,若删除我方将保留所有法律责任追究!
* 本系统已申请软件著作权,受国家版权局知识产权以及国家计算机软件著作权保护!
* 可正常分享和学习源码,不得用于违法犯罪活动,违者必究!
* Copyright (c) 2020 陈尼克 all rights reserved.
* 版权所有,侵权必究!
*/
var server = require('pushstate-server');
server.start({
port: 5000,
directory: './dist'
});
This diff is collapsed.
{
"name": "vue-newbee-shop",
"version": "0.1.0",
"private": true,
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build",
"lint": "vue-cli-service lint"
},
"dependencies": {
"axios": "^0.19.2",
"better-scroll": "^1.15.2",
"core-js": "^3.4.3",
"js-md5": "^0.7.3",
"lib-flexible": "^0.3.2",
"postcss-px2rem": "^0.3.0",
"pushstate-server": "^3.1.0",
"vant": "^2.12.30",
"vue": "^2.6.10",
"vue-router": "^3.0.7",
"vue2-verify": "^1.1.5",
"vuex": "^3.1.2"
},
"devDependencies": {
"@vue/cli-plugin-babel": "^4.1.0",
"@vue/cli-plugin-eslint": "^4.1.0",
"@vue/cli-plugin-router": "^4.1.0",
"@vue/cli-plugin-vuex": "^4.1.0",
"@vue/cli-service": "^4.1.0",
"@vue/eslint-config-standard": "^4.0.0",
"babel-eslint": "^10.0.3",
"babel-plugin-import": "^1.13.0",
"eslint": "^5.16.0",
"eslint-plugin-vue": "^5.0.0",
"less": "^3.0.4",
"less-loader": "^5.0.0",
"postcss-pxtorem": "^4.0.1",
"vue-template-compiler": "^2.6.10"
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no">
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<title>新蜂商城</title>
<link rel="stylesheet" href="//at.alicdn.com/t/font_1623819_3g3arzgtlmk.css">
</head>
<body>
<noscript>
<strong>We're sorry but vue-newbee-shop 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>
<!--
* 严肃声明:
* 开源版本请务必保留此注释头信息,若删除我方将保留所有法律责任追究!
* 本系统已申请软件著作权,受国家版权局知识产权以及国家计算机软件著作权保护!
* 可正常分享和学习源码,不得用于违法犯罪活动,违者必究!
* Copyright (c) 2020 陈尼克 all rights reserved.
* 版权所有,侵权必究!
*
-->
<template>
<div id="app">
<transition :name="transitionName">
<router-view class="router-view" />
</transition>
</div>
</template>
<script>
export default {
data () {
return {
transitionName: 'slide-left'
}
},
watch: {
$route(to, from) {
// 有主级到次级
if (to.meta.index > from.meta.index) {
this.transitionName = 'slide-left' // 向左滑动
} else if (to.meta.index < from.meta.index) {
// 由次级到主级
this.transitionName = 'slide-right'
} else {
this.transitionName = '' //同级无过渡效果
}
}
}
}
</script>
<style lang="less">
#app {
font-family: 'Avenir', Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
// text-align: center;
color: #2c3e50;
}
.router-view{
width: 100%;
height: auto;
position: absolute;
top: 0;
bottom: 0;
margin: 0 auto;
-webkit-overflow-scrolling: touch;
background-color: #f0f1f5;
}
.slide-right-enter-active,
.slide-right-leave-active,
.slide-left-enter-active,
.slide-left-leave-active{
height: 100%;
will-change: transform;
transition: all 500ms;
position: absolute;
backface-visibility: hidden;
}
.slide-right-enter{
opacity: 0;
transform: translate3d(-100%, 0, 0);
}
.slide-right-leave-active{
opacity: 0;
transform: translate3d(100%, 0, 0);
}
.slide-left-enter{
opacity: 0;
transform: translate3d(100%, 0, 0);
}
.slide-left-leave-active{
opacity: 0;
transform: translate3d(-100%, 0, 0);
}
</style>
This diff is collapsed.
/**
* 严肃声明:
* 开源版本请务必保留此注释头信息,若删除我方将保留所有法律责任追究!
* 本系统已申请软件著作权,受国家版权局知识产权以及国家计算机软件著作权保护!
* 可正常分享和学习源码,不得用于违法犯罪活动,违者必究!
* Copyright (c) 2020 陈尼克 all rights reserved.
* 版权所有,侵权必究!
*/
// *{
// margin: 0;
// padding: 0;
// }
//移动端点击高亮
html,body{
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
}
input{
border: none;
outline: none;
-webkit-appearance: none;
-webkit-appearance: none;
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
}
textarea{
border: none;
outline: none;
}
button{
border: none;
outline: none;
}
a{
text-decoration: none;
color: #333;
}
li{
list-style-type: none;
}
//解决端遮罩层穿透
body.dialog-open {
position: fixed;
width: 100%;
}
.page{
padding: 0 50px;
width: 100%;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
/**
* 严肃声明:
* 开源版本请务必保留此注释头信息,若删除我方将保留所有法律责任追究!
* 本系统已申请软件著作权,受国家版权局知识产权以及国家计算机软件著作权保护!
* 可正常分享和学习源码,不得用于违法犯罪活动,违者必究!
* Copyright (c) 2020 陈尼克 all rights reserved.
* 版权所有,侵权必究!
*/
@import './base.less';
@primary: #1baeae; // 主题色
@orange: #FF6B01;
@bc: #F7F7F7;
@fc:#fff;
// // 背景图片地址和大小
.bis(@url) {
background-image: url(@url);
background-repeat: no-repeat;
background-size: 100% 100%;
}
// //圆角
.borderRadius(@radius) {
-webkit-border-radius: @radius;
-moz-border-radius: @radius;
-ms-border-radius: @radius;
-o-border-radius: @radius;
border-radius: @radius;
}
// //1px底部边框
.border-1px(@color){
position: relative;
&:after{
display: block;
position: absolute;
left: 0;
bottom: 0;
width: 100%;
border-top: 1px solid @color;
content: '';
}
}
// //定位全屏
.allcover{
position:absolute;
top:0;
right:0;
}
// //定位上下左右居中
.center {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
// //定位上下居中
.ct {
position: absolute;
top: 50%;
transform: translateY(-50%);
}
// //定位左右居中
.cl {
position: absolute;
left: 50%;
transform: translateX(-50%);
}
// //宽高
.wh(@width, @height){
width: @width;
height: @height;
}
// //字体大小,颜色
.sc(@size, @color){
font-size: @size;
color: @color;
}
.boxSizing {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
// //flex 布局和 子元素 对其方式
.fj(@type: space-between){
display: flex;
justify-content: @type;
}
<!--
* 严肃声明:
* 开源版本请务必保留此注释头信息,若删除我方将保留所有法律责任追究!
* 本系统已申请软件著作权,受国家版权局知识产权以及国家计算机软件著作权保护!
* 可正常分享和学习源码,不得用于违法犯罪活动,违者必究!
* Copyright (c) 2020 陈尼克 all rights reserved.
* 版权所有,侵权必究!
*
-->
<template>
<div ref="wrapper" class="scroll-wrapper">
<slot></slot>
</div>
</template>
<script>
import BScroll from 'better-scroll'
export default {
props: {
/**
* 1 滚动的时候会派发scroll事件,会截流。
* 2 滚动的时候实时派发scroll事件,不会截流。
* 3 除了实时派发scroll事件,在swipe的情况下仍然能实时派发scroll事件
*/
probeType: {
type: Number,
default: 1
},
// 点击列表是否派发click事件
click: {
type: Boolean,
default: true
},
// 是否开启横向滚动
scrollX: {
type: Boolean,
default: false
},
// 是否派发滚动事件
listenScroll: {
type: Boolean,
default: false
},
// 列表的数据
scrollData: {
type: Array,
default: null
},
// 是否派发滚动到底部的事件,用于上拉加载
pullup: {
type: Boolean,
default: false
},
// 是否派发顶部下拉的事件,用于下拉刷新
pulldown: {
type: Boolean,
default: false
},
// 是否派发列表滚动开始的事件
beforeScroll: {
type: Boolean,
default: false
},
// 当数据更新后,刷新scroll的延时
refreshDelay: {
type: Number,
default: 20
}
},
mounted() {
// 在 DOM 渲染完毕后初始化 better-scroll
setTimeout(() => {
this.initScroll()
}, 20)
},
methods: {
initScroll() {
if (!this.$refs.wrapper) {
return
}
// better-scroll 初始化
this.scroll = new BScroll(this.$refs.wrapper, {
probeType: this.probeType,
click: this.click,
scrollX: this.scrollX
})
// 是否派发滚动事件
if (this.listenScroll) {
const self = this
this.scroll.on('scroll', (position) => {
self.$emit('scroll', position)
})
}
if (this.pullup) {
this.scroll.on('scrollEnd', () => {
// 滚动到底部
if (this.scroll.y <= (this.scroll.maxScrollY + 50)) {
// 派发滚动到底部的事件
this.$emit('scrollToEnd')
}
})
}
if (this.pulldown) {
this.scroll.on('touchend', (pos) => {
// 下拉动作
if (pos.y > 50) {
// 下拉刷新
this.$emit('pulldown')
}
})
}
if (this.beforeScroll) {
this.scroll.on('beforeScrollStart', () => {
// 列表滚动前触发
this.$emit('beforeScroll')
})
}
},
disable() {
// 代理 better-scroll 的 disable 方法
this.scroll && this.scroll.disable()
},
enable() {
// 代理 better-scroll 的 enable 方法
this.scroll && this.scroll.enable()
},
refresh() {
// 代理 better-scroll 的 refresh 方法
this.scroll && this.scroll.refresh()
},
scrollTo() {
// 代理 better-scroll 的 scrollTo 方法
this.scroll && this.scroll.scrollTo.apply(this.scroll, arguments)
},
scrollToElement() {
// 代理 better-scroll 的 scrollToElement 方法
this.scroll && this.scroll.scrollToElement.apply(this.scroll, arguments)
}
},
watch: {
// 监听数据的变化,重新计算高度
data() {
setTimeout(() => {
this.refresh()
}, this.refreshDelay)
}
}
}
</script>
<style lang="less" scoped>
.scroll-wrapper {
width: 100%;
height: 100%;
overflow: hidden;
}
</style>
<!--
* 严肃声明:
* 开源版本请务必保留此注释头信息,若删除我方将保留所有法律责任追究!
* 本系统已申请软件著作权,受国家版权局知识产权以及国家计算机软件著作权保护!
* 可正常分享和学习源码,不得用于违法犯罪活动,违者必究!
* Copyright (c) 2020 陈尼克 all rights reserved.
* 版权所有,侵权必究!
*
-->
<template>
<div class="nav-bar">
<ul class="nav-list">
<router-link tag="li" class="nav-list-item active" to="home">
<i class="nbicon nblvsefenkaicankaoxianban-1"></i>
<span>首页</span>
</router-link>
<router-link tag="li" class="nav-list-item" to="category">
<i class="nbicon nbfenlei"></i>
<span>分类</span>
</router-link>
<router-link tag="li" class="nav-list-item" to="cart">
<van-icon name="shopping-cart-o" :info="!count ? '' : count" />
<span>购物车</span>
</router-link>
<router-link tag="li" class="nav-list-item" to="user">
<i class="nbicon nblvsefenkaicankaoxianban-"></i>
<span>我的</span>
</router-link>
</ul>
</div>
</template>
<script>
import { getLocal } from '../common/js/utils'
export default {
mounted() {
const token = getLocal('token')
const path = this.$route.path
if (token && path != '/home') {
this.$store.dispatch('updateCart')
}
},
data() {
return {}
},
computed: {
count () {
return this.$store.state.cartCount
}
}
}
</script>
<style lang="less" scoped >
@import '../common/style/mixin';
.nav-bar{
position: fixed;
left: 0;
bottom: 0;
width: 100%;
padding: 5px 0;
z-index: 1000;
background: #fff;
transform: translateZ(0);
-webkit-transform: translateZ(0);
.nav-list {
width: 100%;
.fj();
flex-direction: row;
padding: 0;
.nav-list-item {
display: flex;
flex: 1;
flex-direction: column;
text-align: center;
color: #666;
&.router-link-active {
color: @primary;
}
i {
text-align: center;
font-size: 22px;
}
span{
font-size: 12px;
}
.van-icon-shopping-cart-o {
margin: 0 auto;
margin-bottom: 2px;
}
}
}
}
</style>
<!--
* 严肃声明:
* 开源版本请务必保留此注释头信息,若删除我方将保留所有法律责任追究!
* 本系统已申请软件著作权,受国家版权局知识产权以及国家计算机软件著作权保护!
* 可正常分享和学习源码,不得用于违法犯罪活动,违者必究!
* Copyright (c) 2020 陈尼克 all rights reserved.
* 版权所有,侵权必究!
*
-->
<template>
<header class="simple-header">
<i class="nbicon nbfanhui" @click="goBack"></i>
<div class="simple-header-name">{{ name }}</div>
<i class="nbicon nbmore"></i>
</header>
</template>
<script>
export default {
props: {
name: {
type: String,
default: ''
},
back: {
type: String,
default: ''
}
},
methods: {
goBack() {
if (!this.back) {
this.$router.go(-1)
} else {
this.$router.push({ path: this.back })
}
this.$emit('callback')
}
}
}
</script>
<style lang="less" scoped>
@import '../common/style/mixin';
.simple-header {
position: fixed;
top: 0;
left: 0;
z-index: 10000;
.fj();
.wh(100%, 44px);
line-height: 44px;
padding: 0 10px;
.boxSizing();
color: #252525;
background: #fff;
border-bottom: 1px solid #dcdcdc;
.simple-header-name {
font-size: 14px;
}
}
</style>
<!--
* 严肃声明:
* 开源版本请务必保留此注释头信息,若删除我方将保留所有法律责任追究!
* 本系统已申请软件著作权,受国家版权局知识产权以及国家计算机软件著作权保护!
* 可正常分享和学习源码,不得用于违法犯罪活动,违者必究!
* Copyright (c) 2020 陈尼克 all rights reserved.
* 版权所有,侵权必究!
*
-->
<template>
<van-swipe class="my-swipe" :autoplay="5000" indicator-color="#1baeae">
<van-swipe-item v-for="(item, index) in list" :key="index">
<img :src="item.carouselUrl" alt="" @click="goTo(item.redirectUrl)">
</van-swipe-item>
</van-swipe>
</template>
<script>
export default {
props: {
list: {
type: Array,
default: null
}
},
methods: {
goTo(url) {
window.open(url)
}
}
}
</script>
<style lang='less' scoped>
.my-swipe .van-swipe-item {
img {
width: 100%;
height: 100%;
}
}
</style>
<template>
<div>
<van-tabbar v-model="active" @change="onChange">
<van-tabbar-item
v-for="(item,index) in tabBarList"
:key="item.key"
:icon="active == index?item.imgUrlActive: item.imgUrl"
:to="item.path"
>{{ item.text }}</van-tabbar-item
>
</van-tabbar>
</div>
</template>
<script>
export default {
props:{
index: {
type: Number,
default: 0
},
},
data() {
return {
active: "0",
tabBarList: [
{
key: "1",
name:'0',
imgUrl: require("@/assets/tabBar/new.png"),
imgUrlActive: require("@/assets/tabBar/new-active.png"),
path: "/MessageCenter",
text: "消息中心"
},
{
key: "2",
name:'1',
imgUrl: require("@/assets/tabBar/workbench.png"),
imgUrlActive: require("@/assets/tabBar/workbench-active.png"),
path: "/SaveWorkbench",
text: "安全工作台"
},
{
key: "3",
name:'2',
imgUrl: require("@/assets/tabBar/my.png"),
imgUrlActive: require("@/assets/tabBar/my-active.png"),
path: "/My",
text: "我的地盘"
}
]
};
},
mounted() {
this.active = this.index
this.tabBarList.forEach((item)=>{
if(item.name==this.active){
this.$router.push(item.path)
}
})
},
methods: {
onChange(index) {
this.active = index;
}
}
};
</script>
<style scoped>
/* @import url(); 引入css类 */
</style>
<!--
* 严肃声明:
* 开源版本请务必保留此注释头信息,若删除我方将保留所有法律责任追究!
* 本系统已申请软件著作权,受国家版权局知识产权以及国家计算机软件著作权保护!
* 可正常分享和学习源码,不得用于违法犯罪活动,违者必究!
* Copyright (c) 2020 陈尼克 all rights reserved.
* 版权所有,侵权必究!
*
-->
<template>
<div>
<header class="header">
<van-icon @click="to" name="arrow-left" class="iconColorLeft"/>
<span>{{text}}</span>
<van-icon name="bars" class="iconColorRight"/>
</header>
</div>
</template>
<script>
export default {
props:{
text:{
default:"未知",
type:String
}
},
data() {
return {
}
},
mounted() {
},
methods: {
/* 左侧图标跳转方法 */
to(){
history.go(-1)
}
}
}
</script>
<style lang="less" scoped>
.header{
width:100%;
height:1.5rem;
background:#2980F7;
text-align: center;
line-height: 1.5rem;
}
.iconColorLeft{
color: white;
transform: scale(2);
float: left;
position: relative;
top: 40%;
left: 5%;
}
.header span{
color: white;
font-size: 16px;
margin: auto;
font-weight: 600;
font-family: 'Microsoft YaHei';
}
.header .iconColorRight{
color: white;
float: right;
position: relative;
top: 40%;
right: 5%;
transform: scale(2);
}
</style>
/**
* 严肃声明:
* 开源版本请务必保留此注释头信息,若删除我方将保留所有法律责任追究!
* 本系统已申请软件著作权,受国家版权局知识产权以及国家计算机软件著作权保护!
* 可正常分享和学习源码,不得用于违法犯罪活动,违者必究!
* Copyright (c) 2020 陈尼克 all rights reserved.
* 版权所有,侵权必究!
*/
import Vue from 'vue'
import md5 from 'js-md5';
import App from './App.vue'
import router from './router'
import store from './store'
import './permission'
import { prefix } from '@/common/js/utils'
import { Divider, Popup, Overlay, Loading, Dialog, ContactCard, Form, AddressEdit, AddressList, Field, CellGroup, Cell, SwipeCell, Icon, Stepper, Card, Checkbox, CheckboxGroup, Button, Swipe, SwipeItem, PullRefresh, List, Tab, Tabs, GoodsAction, GoodsActionIcon, GoodsActionButton, SubmitBar, Toast ,Search,Picker,Uploader,Notify ,ContactList,Calendar,Radio,RadioGroup,Tag,Tabbar,TabbarItem,Sticky, Grid, GridItem,Skeleton,Col,Row, Image as VanImage, Badge,} from 'vant'
import 'lib-flexible/flexible'
Vue.use(Divider).use(Popup).use(Overlay).use(Loading).use(Dialog).use(Toast).use(ContactCard).use(Form).use(AddressEdit).use(AddressList).use(Field).use(CellGroup).use(Cell).use(SwipeCell).use(Icon).use(Stepper).use(Card).use(Button).use(Swipe).use(SwipeItem).use(PullRefresh).use(List).use(Tab).use(Tabs).use(GoodsAction).use(GoodsActionIcon).use(GoodsActionButton).use(SubmitBar).use(Checkbox).use(CheckboxGroup).use(Search).use(Picker).use(Uploader).use(Notify)
.use(ContactList).use(Calendar).use(Radio).use(RadioGroup).use(Tag).use(Tabbar).use(TabbarItem).use(Sticky)
.use(Grid).use(GridItem).use(Skeleton).use(Col).use(Row).use(VanImage)
Vue.config.productionTip = false
new Vue({
router,
store,
render: h => h(App)
}).$mount('#app')
Vue.prototype.$md5 = md5;
Vue.prototype.prefix = prefix;
Array.prototype.remove = function(val) {
var index = this.indexOf(val);
if (index > -1) {
this.splice(index, 1);
}
}
import router from './router'
//设置白名单,指不需要登录就可以直接进入的页面
var whiteList = ["/login2"]
//这里使用cookie.js,登录成功后将后台返回的token保存在cookie中
// Cookies.set('admin_token','token_value');
var hasToken = localStorage.getItem('admin_token');
router.beforeEach(async(to, from, next) => {
//to: 即将要进入的目标 [路由对象]
//from:当前导航正要离开的路由
//next:一定要调用该方法来 resolve 这个钩子
console.log(hasToken)
if (hasToken) {
if (to.path === '/login2') {
next({ path: '/MessageCenter' })
} else {
next()
}
}else {
if (whiteList.indexOf(to.path) !== -1) {
next()//这里是即将进入的页面是白名单的页面就直接进入
} else {
next({ path: '/login2' })//这里是即将进入的页面不是白名单的页面又没有token的情况下重定向到登录页面进行登录操作
}
}
})
\ No newline at end of file
/**
* 严肃声明:
* 开源版本请务必保留此注释头信息,若删除我方将保留所有法律责任追究!
* 本系统已申请软件著作权,受国家版权局知识产权以及国家计算机软件著作权保护!
* 可正常分享和学习源码,不得用于违法犯罪活动,违者必究!
* Copyright (c) 2020 陈尼克 all rights reserved.
* 版权所有,侵权必究!
*/
import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from '../views/Home.vue'
import Cart from '../views/Cart.vue'
import Category from '../views/Category.vue'
import ProductList from '../views/ProductList.vue'
import ProductDetail from '../views/ProductDetail.vue'
import User from '../views/User.vue'
import Order from '../views/Order.vue'
import OrderDetail from '../views/OrderDetail.vue'
import Setting from '../views/Setting.vue'
import Address from '../views/Address.vue'
import AddressEdit from '../views/AddressEdit.vue'
import Login from '../views/Login.vue'
import About from '../views/About.vue'
import CreateOrder from '../views/CreateOrder.vue'
// 登录页
import Login2 from '../views/Login2.vue'
// 消息中心
import MessageCenter from '../views/MessageCenter/MessageCenter.vue'
// 安全工作台
import SaveWorkbench from '../views/SaveWorkbench.vue'
// 我的地盘
import My from '../views/My.vue'
Vue.use(VueRouter)
const routes = [
{
path: '/',
name: 'home',
redirect: '/login2'
},
{
path: '/login',
name: 'login',
meta: {
index: 2
},
component: () => import(/* webpackChunkName: "login" */ '../views/Login.vue'),
},
{
path: '/home',
name: 'home',
meta: {
index: 1
},
component: () => import(/* webpackChunkName: "home" */ '../views/Home.vue'),
},
{
path: '/cart',
name: 'cart',
meta: {
index: 1
},
component: () => import(/* webpackChunkName: "cart" */ '../views/Cart.vue'),
},
{
path: '/category',
name: 'category',
meta: {
index: 1
},
component: () => import(/* webpackChunkName: "category" */ '../views/Category.vue'),
},
{
path: '/product-list',
name: 'product-list',
meta: {
index: 2
},
component: () => import(/* webpackChunkName: "product-list" */ '../views/ProductList.vue'),
},
{
path: '/product/:id',
name: 'product',
meta: {
index: 3
},
component: () => import(/* webpackChunkName: "product" */ '../views/ProductDetail.vue'),
},
{
path: '/user',
name: 'user',
meta: {
index: 1
},
component: () => import(/* webpackChunkName: "user" */ '../views/User.vue'),
},
{
path: '/order',
name: 'order',
meta: {
index: 2
},
component: () => import(/* webpackChunkName: "order" */ '../views/Order.vue'),
},
{
path: '/order-detail',
name: 'order-detail',
meta: {
index: 3
},
component: () => import(/* webpackChunkName: "order-detail" */ '../views/OrderDetail.vue'),
},
{
path: '/setting',
name: 'setting',
meta: {
index: 2
},
component: () => import(/* webpackChunkName: "setting" */ '../views/Setting.vue'),
},
{
path: '/address',
name: 'address',
meta: {
index: 2
},
component: () => import(/* webpackChunkName: "address" */ '../views/Address.vue'),
},
{
path: '/address-edit',
name: 'address-edit',
meta: {
index: 3
},
component: () => import(/* webpackChunkName: "address-edit" */ '../views/AddressEdit.vue'),
},
{
path: '/about',
name: 'about',
meta: {
index: 2
},
component: () => import(/* webpackChunkName: "about" */ '../views/About.vue'),
},
{
path: '/create-order',
name: 'create-order',
meta: {
index: 2
},
component: () => import(/* webpackChunkName: "create-order" */ '../views/CreateOrder.vue'),
},
{
path: '/checked',
name: 'checked',
meta: {
title:'检查执行',
index: 3
},
component: () => import(/* webpackChunkName: "create-order" */ '../views/checked'),
},
{
path: '/problem',
name: 'problem',
meta: {
title:'问题上报',
index: 3
},
component: () => import(/* webpackChunkName: "create-order" */ '../views/checked/problem'),
},
{
path: '/list',
name: 'list',
meta: {
title:'检查问题',
index: 3
},
component: () => import(/* webpackChunkName: "create-order" */ '../views/checked/problem/list'),
},
{
path: '/note',
name: 'note',
meta: {
title:'问题记录',
index: 3
},
component: () => import(/* webpackChunkName: "create-order" */ '../views/checked/problem/note'),
},
{
path: '/formwork',
name: 'formwork',
meta: {
title:'问题上报表',
index: 3
},
component: () => import(/* webpackChunkName: "create-order" */ '../views/checked/problem/formwork'),
},
{
path: '/correct',
name: 'correct',
meta: {
title:'检查记录',
index: 3
},
component: () => import(/* webpackChunkName: "create-order" */ '../views/correct'),
},
{
path: '/notice',
name: 'notice',
meta: {
title:'整改通知',
index: 3
},
component: () => import(/* webpackChunkName: "create-order" */ '../views/notice'),
},
{
path: '/noticeList',
name: 'noticeList',
meta: {
title:'整改通知管理列表',
index: 3
},
component: () => import(/* webpackChunkName: "create-order" */ '../views/notice/noticeList'),
},
// 登录页
{
path: '/Login2',
name: 'Login2',
meta: {
index: 1
},
component: () => import(/* webpackChunkName: "SaveWorkbench" */ '../views/Login2.vue'),
},
// 消息中心
{
path: '/MessageCenter',
name: 'MessageCenter',
meta: {
index: 1
},
component: () => import(/* webpackChunkName: "SaveWorkbench" */ '../views/MessageCenter/MessageCenter.vue'),
},
// 安全工作台页面
{
path: '/SaveWorkbench',
name: 'SaveWorkbench',
meta: {
index: 1
},
component: () => import(/* webpackChunkName: "SaveWorkbench" */ '../views/SaveWorkbench.vue'),
},
// 我的地盘页面
{
path: '/My',
name: 'My',
meta: {
index: 1
},
component: () => import(/* webpackChunkName: "SaveWorkbench" */ '../views/My.vue'),
},
]
const router = new VueRouter({
mode: 'hash',
base: process.env.BASE_URL,
routes
})
export default router
/**
* 严肃声明:
* 开源版本请务必保留此注释头信息,若删除我方将保留所有法律责任追究!
* 本系统已申请软件著作权,受国家版权局知识产权以及国家计算机软件著作权保护!
* 可正常分享和学习源码,不得用于违法犯罪活动,违者必究!
* Copyright (c) 2020 陈尼克 all rights reserved.
* 版权所有,侵权必究!
*/
import axios from '../utils/axios'
export function addAddress(params) {
return axios.post('/address', params);
}
export function EditAddress(params) {
return axios.put('/address', params);
}
export function DeleteAddress(id) {
return axios.delete(`/address/${id}`);
}
export function getDefaultAddress() {
return axios.get('/address/default');
}
export function getAddressList() {
return axios.get('/address', { pageNumber: 1, pageSize: 1000 })
}
export function getAddressDetail(id) {
return axios.get(`/address/${id}`)
}
/**
* 严肃声明:
* 开源版本请务必保留此注释头信息,若删除我方将保留所有法律责任追究!
* 本系统已申请软件著作权,受国家版权局知识产权以及国家计算机软件著作权保护!
* 可正常分享和学习源码,不得用于违法犯罪活动,违者必究!
* Copyright (c) 2020 陈尼克 all rights reserved.
* 版权所有,侵权必究!
*/
import axios from '../utils/axios'
export function addCart(params) {
return axios.post('/shop-cart', params);
}
export function modifyCart(params) {
return axios.put('/shop-cart', params);
}
export function getCart(params) {
return axios.get('/shop-cart', { params });
}
export function deleteCartItem(id) {
return axios.delete(`/shop-cart/${id}`);
}
export function getByCartItemIds(params) {
return axios.get('/shop-cart/settle', { params });
}
/**
* 严肃声明:
* 开源版本请务必保留此注释头信息,若删除我方将保留所有法律责任追究!
* 本系统已申请软件著作权,受国家版权局知识产权以及国家计算机软件著作权保护!
* 可正常分享和学习源码,不得用于违法犯罪活动,违者必究!
* Copyright (c) 2020 陈尼克 all rights reserved.
* 版权所有,侵权必究!
*/
import axios from '../utils/axios'
export function getDetail(id) {
return axios.get(`/goods/detail/${id}`);
}
export function getCategory() {
return axios.get('/categories');
}
export function search(params) {
return axios.get('/search', { params });
}
/**
* 严肃声明:
* 开源版本请务必保留此注释头信息,若删除我方将保留所有法律责任追究!
* 本系统已申请软件著作权,受国家版权局知识产权以及国家计算机软件著作权保护!
* 可正常分享和学习源码,不得用于违法犯罪活动,违者必究!
* Copyright (c) 2020 陈尼克 all rights reserved.
* 版权所有,侵权必究!
*/
import axios from '../utils/axios'
export function getHome(params) {
return axios.get('/index-infos');
}
/**
* 严肃声明:
* 开源版本请务必保留此注释头信息,若删除我方将保留所有法律责任追究!
* 本系统已申请软件著作权,受国家版权局知识产权以及国家计算机软件著作权保护!
* 可正常分享和学习源码,不得用于违法犯罪活动,违者必究!
* Copyright (c) 2020 陈尼克 all rights reserved.
* 版权所有,侵权必究!
*/
import axios from '../utils/axios'
export function createOrder(params) {
return axios.post('/saveOrder', params);
}
export function getOrderList(params) {
return axios.get('/order', { params });
}
export function getOrderDetail(id) {
return axios.get(`/order/${id}`);
}
export function cancelOrder(id) {
return axios.put(`/order/${id}/cancel`);
}
export function confirmOrder(id) {
return axios.put(`/order/${id}/finish`)
}
export function payOrder(params) {
return axios.get('/paySuccess', { params })
}
/**
* 严肃声明:
* 开源版本请务必保留此注释头信息,若删除我方将保留所有法律责任追究!
* 本系统已申请软件著作权,受国家版权局知识产权以及国家计算机软件著作权保护!
* 可正常分享和学习源码,不得用于违法犯罪活动,违者必究!
* Copyright (c) 2020 陈尼克 all rights reserved.
* 版权所有,侵权必究!
*/
import axios from '../utils/axios'
export function getUserInfo() {
return axios.get('/user/info');
}
export function EditUserInfo(params) {
return axios.put('/user/info', params);
}
export function login(params) {
return axios.post('/user/login', params);
}
export function logout() {
return axios.post('/user/logout')
}
export function register(params) {
return axios.post('/user/register', params);
}
/**
* 严肃声明:
* 开源版本请务必保留此注释头信息,若删除我方将保留所有法律责任追究!
* 本系统已申请软件著作权,受国家版权局知识产权以及国家计算机软件著作权保护!
* 可正常分享和学习源码,不得用于违法犯罪活动,违者必究!
* Copyright (c) 2020 陈尼克 all rights reserved.
* 版权所有,侵权必究!
*/
import { getCart } from '../service/cart'
export default {
async updateCart(ctx) {
const { data } = await getCart()
ctx.commit('addCart', {
count: data.length || 0
})
}
}
/**
* 严肃声明:
* 开源版本请务必保留此注释头信息,若删除我方将保留所有法律责任追究!
* 本系统已申请软件著作权,受国家版权局知识产权以及国家计算机软件著作权保护!
* 可正常分享和学习源码,不得用于违法犯罪活动,违者必究!
* Copyright (c) 2020 陈尼克 all rights reserved.
* 版权所有,侵权必究!
*/
import Vue from 'vue'
import Vuex from 'vuex'
import state from './state'
import actions from './actions'
import mutations from './mutations'
Vue.use(Vuex)
export default new Vuex.Store({
state,
mutations,
actions,
modules: {}
})
/**
* 严肃声明:
* 开源版本请务必保留此注释头信息,若删除我方将保留所有法律责任追究!
* 本系统已申请软件著作权,受国家版权局知识产权以及国家计算机软件著作权保护!
* 可正常分享和学习源码,不得用于违法犯罪活动,违者必究!
* Copyright (c) 2020 陈尼克 all rights reserved.
* 版权所有,侵权必究!
*/
export default {
addCart (state, payload) {
state.cartCount = payload.count
}
}
/**
* 严肃声明:
* 开源版本请务必保留此注释头信息,若删除我方将保留所有法律责任追究!
* 本系统已申请软件著作权,受国家版权局知识产权以及国家计算机软件著作权保护!
* 可正常分享和学习源码,不得用于违法犯罪活动,违者必究!
* Copyright (c) 2020 陈尼克 all rights reserved.
* 版权所有,侵权必究!
*/
export default {
cartCount: 0
}
/**
* 严肃声明:
* 开源版本请务必保留此注释头信息,若删除我方将保留所有法律责任追究!
* 本系统已申请软件著作权,受国家版权局知识产权以及国家计算机软件著作权保护!
* 可正常分享和学习源码,不得用于违法犯罪活动,违者必究!
* Copyright (c) 2020 陈尼克 all rights reserved.
* 版权所有,侵权必究!
*/
import axios from 'axios'
import { Toast } from 'vant'
import router from '../router'
axios.defaults.baseURL = process.env.NODE_ENV == 'development' ? 'http://backend-api-01.newbee.ltd/api/v1' : 'http://backend-api-01.newbee.ltd/api/v1'
axios.defaults.withCredentials = true
axios.defaults.headers['X-Requested-With'] = 'XMLHttpRequest'
axios.defaults.headers['token'] = localStorage.getItem('token') || ''
axios.defaults.headers.post['Content-Type'] = 'application/json'
axios.interceptors.response.use(res => {
if (typeof res.data !== 'object') {
Toast.fail('服务端异常!')
return Promise.reject(res)
}
if (res.data.resultCode != 200) {
if (res.data.message) Toast.fail(res.data.message)
if (res.data.resultCode == 416) {
router.push({ path: '/login' })
}
return Promise.reject(res.data)
}
return res.data
})
export default axios
<!--
* 严肃声明:
* 开源版本请务必保留此注释头信息,若删除我方将保留所有法律责任追究!
* 本系统已申请软件著作权,受国家版权局知识产权以及国家计算机软件著作权保护!
* 可正常分享和学习源码,不得用于违法犯罪活动,违者必究!
* Copyright (c) 2020 陈尼克 all rights reserved.
* 版权所有,侵权必究!
*-->
<template>
<div class="about">
<s-header :name="'关于我们'"></s-header>
<div class="about-body">
<van-divider :style="{ color: '#1baeae', borderColor: '#1baeae', fontSize: '20px', fontWeight: 500 }">简介</van-divider>
<div>newbee-mall 项目是一套电商系统,包括 newbee-mall 商城系统及 newbee-mall-admin 商城后台管理系统,基于 Spring Boot 2.X 及相关技术栈开发。 前台商城系统包含首页门户、商品分类、新品上线、首页轮播、商品推荐、商品搜索、商品展示、购物车、订单结算、订单流程、个人订单管理、会员中心、帮助中心等模块。 后台管理系统包含数据面板、轮播图管理、商品管理、订单管理、会员管理、分类管理、设置等模块。</div>
<van-divider :style="{ color: '#1baeae', borderColor: '#1baeae', fontSize: '20px', fontWeight: 500 }">开源地址</van-divider>
<div>
<div>掘金小册配套学习文档:<a target="_blank" href="https://juejin.im/book/6844733826191589390">《Vue 商城项目开发实战》</a></div>
<br/>
<div>后端 API 地址:<a target="_blank" href="https://github.com/newbee-ltd/newbee-mall-api">https://github.com/newbee-ltd/newbee-mall-api</a></div>
<br/>
<div>前端 Vue 开源地址:<a target="_blank" href="https://github.com/newbee-ltd/newbee-mall-vue-app">https://github.com/newbee-ltd/newbee-mall-vue-app</a></div>
<br/>
<div>线上预览地址:<a target="_blank" href="http://47.99.134.126:5000/">http://vue-app.newbee.ltd</a></div>
</div>
</div>
</div>
</template>
<script>
import sHeader from '@/components/SimpleHeader'
export default {
components: {
sHeader
},
}
</script>
<style lang="less" scoped>
.about {
box-sizing: border-box;
padding: 20px;
.about-body {
margin-top: 44px;
font-size: 16px;
a {
color: #007fff;
}
}
}
</style>
<!--
* 严肃声明:
* 开源版本请务必保留此注释头信息,若删除我方将保留所有法律责任追究!
* 本系统已申请软件著作权,受国家版权局知识产权以及国家计算机软件著作权保护!
* 可正常分享和学习源码,不得用于违法犯罪活动,违者必究!
* Copyright (c) 2020 陈尼克 all rights reserved.
* 版权所有,侵权必究!
*
-->
<template>
<div class="address-box">
<s-header :name="'地址管理'" :back="'/user'"></s-header>
<div class="address-item">
<van-address-list
v-if="from != 'mine'"
v-model="chosenAddressId"
:list="list"
default-tag-text="默认"
@add="onAdd"
@edit="onEdit"
@select="select"
/>
<van-address-list
v-else
v-model="chosenAddressId"
:list="list"
default-tag-text="默认"
@add="onAdd"
@edit="onEdit"
/>
</div>
</div>
</template>
<script>
import { Toast } from 'vant';
import sHeader from '@/components/SimpleHeader'
import { getAddressList } from '../service/address'
export default {
components: {
sHeader
},
data() {
return {
chosenAddressId: '1',
list: [],
from: this.$route.query.from,
}
},
async mounted() {
const { data } = await getAddressList()
this.list = data.map(item => {
return {
id: item.addressId,
name: item.userName,
tel: item.userPhone,
address: `${item.provinceName} ${item.cityName} ${item.regionName} ${item.detailAddress}`,
isDefault: !!item.defaultFlag
}
})
},
methods: {
onAdd() {
this.$router.push({ path: `address-edit?type=add&from=${this.from}` })
},
onEdit(item, index) {
this.$router.push({ path: `address-edit?type=edit&addressId=${item.id}&from=${this.from}` })
},
select(item, index) {
this.$router.push({ path: `create-order?addressId=${item.id}&from=${this.from}` })
}
}
}
</script>
<style lang="less">
@import '../common/style/mixin';
.address-box {
.van-radio__icon {
display: none;
}
.address-item {
margin-top: 44px;
.van-button {
background: @primary;
border-color: @primary;
}
}
}
</style>
<!--
* 严肃声明:
* 开源版本请务必保留此注释头信息,若删除我方将保留所有法律责任追究!
* 本系统已申请软件著作权,受国家版权局知识产权以及国家计算机软件著作权保护!
* 可正常分享和学习源码,不得用于违法犯罪活动,违者必究!
* Copyright (c) 2020 陈尼克 all rights reserved.
* 版权所有,侵权必究!
*
-->
<template>
<div class="address-edit-box">
<s-header :name="`${type == 'add' ? '新增地址' : '编辑地址'}`"></s-header>
<van-address-edit
class="edit"
:area-list="areaList"
:address-info="addressInfo"
:show-delete="type == 'edit'"
show-set-default
show-search-result
:search-result="searchResult"
:area-columns-placeholder="['请选择', '请选择', '请选择']"
@save="onSave"
@delete="onDelete"
/>
</div>
</template>
<script>
import { Toast } from 'vant'
import sHeader from '@/components/SimpleHeader'
import { addAddress, EditAddress, DeleteAddress, getAddressDetail } from '../service/address'
import { tdist } from '@/common/js/utils'
export default {
components: {
sHeader
},
data() {
return {
areaList: {
province_list: {},
city_list: {},
county_list: {}
},
searchResult: [],
type: 'add',
addressId: '',
addressInfo: {},
from: ''
}
},
async mounted() {
// 省市区列表构造
let _province_list = {}
let _city_list = {}
let _county_list = {}
tdist.getLev1().forEach(p => {
_province_list[p.id] = p.text
tdist.getLev2(p.id).forEach(c => {
_city_list[c.id] = c.text
tdist.getLev3(c.id).forEach(q => _county_list[q.id] = q.text)
})
})
this.areaList.province_list = _province_list
this.areaList.city_list = _city_list
this.areaList.county_list = _county_list
const { addressId, type, from } = this.$route.query
this.addressId = addressId
this.type = type
this.from = from || ''
if (type == 'edit') {
const { data: addressDetail } = await getAddressDetail(addressId)
let _areaCode = ''
const province = tdist.getLev1()
Object.entries(this.areaList.county_list).forEach(([id, text]) => {
// 先找出当前对应的区
if (text == addressDetail.regionName) {
// 找到区对应的几个省份
const provinceIndex = province.findIndex(item => item.id.substr(0, 2) == id.substr(0, 2))
// 找到区对应的几个市区
const cityItem = Object.entries(this.areaList.city_list).filter(([cityId, cityName]) => cityId.substr(0, 4) == id.substr(0, 4))[0]
// 对比找到的省份和接口返回的省份是否相等,因为有一些区会重名
if (province[provinceIndex].text == addressDetail.provinceName && cityItem[1] == addressDetail.cityName) {
_areaCode = id
}
}
})
this.addressInfo = {
id: addressDetail.addressId,
name: addressDetail.userName,
tel: addressDetail.userPhone,
province: addressDetail.provinceName,
city: addressDetail.cityName,
county: addressDetail.regionName,
addressDetail: addressDetail.detailAddress,
areaCode: _areaCode,
isDefault: !!addressDetail.defaultFlag
}
}
},
methods: {
async onSave(content) {
const params = {
userName: content.name,
userPhone: content.tel,
provinceName: content.province,
cityName: content.city,
regionName: content.county,
detailAddress: content.addressDetail,
defaultFlag: content.isDefault ? 1 : 0,
}
if (this.type == 'edit') {
params['addressId'] = this.addressId
}
const { message } = await this.type == 'add' ? addAddress(params) : EditAddress(params)
Toast('保存成功')
setTimeout(() => {
this.$router.push({ path: `address?from=${this.from}` })
}, 1000)
},
async onDelete() {
const { data } = await DeleteAddress(this.addressId)
Toast('删除成功')
setTimeout(() => {
this.$router.push({ path: 'address' })
}, 1000)
}
}
}
</script>
<style lang="less">
@import '../common/style/mixin';
.address-edit-box {
margin-top: 44px;
.van-address-edit {
.van-button--danger {
background: @primary;
border-color: @primary;
}
.van-switch--on {
background: @primary;
}
}
}
</style>
<!--
* 严肃声明:
* 开源版本请务必保留此注释头信息,若删除我方将保留所有法律责任追究!
* 本系统已申请软件著作权,受国家版权局知识产权以及国家计算机软件著作权保护!
* 可正常分享和学习源码,不得用于违法犯罪活动,违者必究!
* Copyright (c) 2020 陈尼克 all rights reserved.
* 版权所有,侵权必究!
*
-->
<template>
<div class="cart-box">
<s-header :name="'购物车'"></s-header>
<div class="cart-body">
<van-checkbox-group @change="groupChange" v-model="result" ref="checkboxGroup">
<van-swipe-cell :right-width="50" v-for="(item, index) in list" :key="index">
<div class="good-item">
<van-checkbox :name="item.cartItemId" />
<div class="good-img"><img :src="prefix(item.goodsCoverImg)" alt=""></div>
<div class="good-desc">
<div class="good-title">
<span>{{ item.goodsName }}</span>
<span>x{{ item.goodsCount }}</span>
</div>
<div class="good-btn">
<div class="price">¥{{ item.sellingPrice }}</div>
<van-stepper
integer
:min="1"
:value="item.goodsCount"
:name="item.cartItemId"
async-change
@change="onChange"
/>
</div>
</div>
</div>
<van-button
slot="right"
square
icon="delete"
type="danger"
class="delete-button"
@click="deleteGood(item.cartItemId)"
/>
</van-swipe-cell>
</van-checkbox-group>
</div>
<van-submit-bar
v-if="list.length > 0"
class="submit-all"
:price="total * 100"
button-text="结算"
@submit="onSubmit"
>
<van-checkbox @click="allCheck" v-model="checkAll">全选</van-checkbox>
</van-submit-bar>
<div class="empty" v-if="!list.length">
<van-icon name="smile-o" />
<div class="title">购物车空空空如也</div>
<van-button color="#1baeae" type="primary" @click="goTo" block>前往首页</van-button>
</div>
<nav-bar></nav-bar>
</div>
</template>
<script>
import { Toast } from 'vant'
import navBar from '@/components/NavBar'
import sHeader from '@/components/SimpleHeader'
import { getCart, deleteCartItem, modifyCart } from '../service/cart'
export default {
data() {
return {
checked: false,
list: [],
all: false,
result: [],
checkAll: true
}
},
components: {
navBar,
sHeader
},
mounted() {
this.init()
},
computed: {
total: function() {
let sum = 0
let _list = this.list.filter(item => this.result.includes(item.cartItemId))
_list.forEach(item => {
sum += item.goodsCount * item.sellingPrice
})
return sum
}
},
methods: {
async init() {
Toast.loading({ message: '加载中...', forbidClick: true });
const { data } = await getCart({ pageNumber: 1 })
this.list = data
this.result = data.map(item => item.cartItemId)
Toast.clear()
},
goBack() {
this.$router.go(-1)
},
goTo() {
this.$router.push({ path: 'home' })
},
async onChange(value, detail) {
if (this.list.filter(item => item.cartItemId == detail.name)[0].goodsCount == value) return
Toast.loading({ message: '修改中...', forbidClick: true });
const params = {
cartItemId: detail.name,
goodsCount: value
}
const { data } = await modifyCart(params)
this.list.forEach(item => {
if (item.cartItemId == detail.name) {
item.goodsCount = value
}
})
Toast.clear();
},
async onSubmit() {
if (this.result.length == 0) {
Toast.fail('请选择商品进行结算')
return
}
const params = JSON.stringify(this.result)
// for(let i = 0; i < this.result.length; i++) {
// await deleteCartItem(this.result[i])
// }
this.$router.push({ path: `create-order?cartItemIds=${params}` })
},
async deleteGood(id) {
const { data } = await deleteCartItem(id)
this.$store.dispatch('updateCart')
this.init()
},
groupChange(result) {
if (result.length == this.list.length) {
this.checkAll = true
} else {
this.checkAll = false
}
this.result = result
},
allCheck(value) {
if (!this.checkAll) {
this.result = this.list.map(item => item.cartItemId)
} else {
this.result = []
}
}
}
}
</script>
<style lang="less">
@import '../common/style/mixin';
.cart-box {
.cart-header {
position: fixed;
top: 0;
left: 0;
z-index: 10000;
.fj();
.wh(100%, 44px);
line-height: 44px;
padding: 0 10px;
.boxSizing();
color: #252525;
background: #fff;
border-bottom: 1px solid #dcdcdc;
.cart-name {
font-size: 14px;
}
}
.cart-body {
margin: 60px 0 100px 0;
padding-left: 10px;
.good-item {
display: flex;
.good-img {
img {
.wh(100px, 100px)
}
}
.good-desc {
display: flex;
flex-direction: column;
justify-content: space-between;
flex: 1;
padding: 20px;
.good-title {
display: flex;
justify-content: space-between;
}
.good-btn {
display: flex;
justify-content: space-between;
.price {
font-size: 16px;
color: red;
line-height: 28px;
}
.van-icon-delete {
font-size: 20px;
margin-top: 4px;
}
}
}
}
.delete-button {
width: 50px;
height: 100%;
}
}
.empty {
width: 50%;
margin: 0 auto;
text-align: center;
margin-top: 200px;
.van-icon-smile-o {
font-size: 50px;
}
.title {
font-size: 16px;
margin-bottom: 20px;
}
}
.submit-all {
margin-bottom: 50px;
.van-checkbox {
margin-left: 10px
}
.van-submit-bar__text {
margin-right: 10px
}
.van-submit-bar__button {
background: @primary;
}
}
.van-checkbox__icon--checked .van-icon {
background-color: @primary;
border-color: @primary;
}
}
</style>
<!--
* 严肃声明:
* 开源版本请务必保留此注释头信息,若删除我方将保留所有法律责任追究!
* 本系统已申请软件著作权,受国家版权局知识产权以及国家计算机软件著作权保护!
* 可正常分享和学习源码,不得用于违法犯罪活动,违者必究!
* Copyright (c) 2020 陈尼克 all rights reserved.
* 版权所有,侵权必究!
*
-->
<template>
<div class="categray">
<div>
<header class="category-header wrap">
<i class="nbicon nbfanhui" @click="goHome"></i>
<div class="header-search">
<i class="nbicon nbSearch"></i>
<router-link tag="span" class="search-title" to="./product-list?from=category">全场50元起步</router-link>
</div>
<i class="iconfont icon-More"></i>
</header>
<nav-bar></nav-bar>
<div class="search-wrap" ref="searchWrap">
<list-scroll :scroll-data="categoryData" class="nav-side-wrapper">
<ul class="nav-side">
<li
v-for="item in categoryData"
:key="item.categoryId"
v-text="item.categoryName"
:class="{'active' : currentIndex == item.categoryId}"
@click="selectMenu(item.categoryId)"
></li>
</ul>
</list-scroll>
<div class="search-content">
<list-scroll :scroll-data="categoryData" >
<div class="swiper-container">
<div class="swiper-wrapper">
<template v-for="(category, index) in categoryData">
<div class="swiper-slide" v-if="currentIndex == category.categoryId" :key="index">
<!-- <img class="category-main-img" :src="category.mainImgUrl" v-if="category.mainImgUrl"/> -->
<div class="category-list" v-for="(products, index) in category.secondLevelCategoryVOS" :key="index">
<p class="catogory-title">{{products.categoryName}}</p>
<div class="product-item" v-for="(product, index) in products.thirdLevelCategoryVOS" :key="index" @click="selectProduct(product)">
<img src="//s.weituibao.com/1583591077131/%E5%88%86%E7%B1%BB.png" class="product-img"/>
<p v-text="product.categoryName" class="product-title"></p>
</div>
</div>
</div>
</template>
</div>
</div>
</list-scroll>
</div>
</div>
</div>
</div>
</template>
<script>
import navBar from '@/components/NavBar'
import listScroll from '@/components/ListScroll'
import { getCategory } from "../service/good";
export default {
components: {
navBar,
listScroll
},
data() {
return {
categoryData: [],
currentIndex: 15
}
},
async mounted() {
this.setWrapHeight()
const { data } = await getCategory()
this.categoryData = data
},
methods: {
goHome () {
this.$router.push({ path: 'home' })
},
setWrapHeight() {
// 设置视口高度
let $screenHeight = document.documentElement.clientHeight
this.$refs.searchWrap.style.height = $screenHeight - 100 + 'px'
},
selectMenu(index) {
this.currentIndex = index
},
selectProduct(item){
this.$router.push({ path: `product-list?categoryId=${item.categoryId}` })
},
}
}
</script>
<style lang="less" scoped>
@import '../common/style/mixin';
.categray {
.category-header {
background: #fff;
position: fixed;
left: 0;
top: 0;
.fj();
.wh(100%, 50px);
line-height: 50px;
padding: 0 15px;
box-sizing: border-box;
font-size: 15px;
color: #656771;
z-index: 10000;
&.active {
background: @primary;
}
.icon-left {
font-size: 25px;
font-weight: bold;
}
.header-search {
display: flex;
width: 80%;
height: 20px;
line-height: 20px;
margin: 10px 0;
padding: 5px 0;
color: #232326;
background: #F7F7F7;
border-radius: 20px;
.nbSearch {
padding: 0 10px 0 20px;
font-size: 17px;
}
.search-title {
font-size: 12px;
color: #666;
}
}
.icon-More {
font-size: 20px;
}
}
}
.search-wrap {
.fj();
width: 100%;
margin-top: 50px;
background: #F8F8F8;
border-top: 1px solid #999;
.nav-side-wrapper {
width: 28%;
height: 100%;
overflow: hidden;
.nav-side {
width: 100%;
.boxSizing();
background: #F8F8F8;
li {
width: 100%;
height: 56px;
text-align: center;
line-height: 56px;
font-size: 14px;
&.active {
color: @primary;
background: #fff;
}
}
}
}
.search-content {
width: 72%;
height: 100%;
padding: 0 10px;
background: #fff;
.boxSizing();
.swiper-container {
width: 100%;
.swiper-slide {
width: 100%;
.category-main-img {
width: 100%;
}
.category-list {
display: flex;
flex-wrap: wrap;
flex-shrink: 0;
width: 100%;
.catogory-title {
width: 100%;
font-size: 17px;
font-weight: 500;
padding: 20px 0;
}
.product-item {
width: 33.3333%;
margin-bottom: 10px;
text-align: center;
font-size: 15px;
.product-img {
.wh(30px, 30px);
}
}
}
}
}
}
}
.fade-out-enter-active, .fade-out-leave-active {
// transition: opacity 0.5s;
}
.fade-out-enter, .fade-out-leave-to {
// opacity: 0;
}
</style>
<!--
* 严肃声明:
* 开源版本请务必保留此注释头信息,若删除我方将保留所有法律责任追究!
* 本系统已申请软件著作权,受国家版权局知识产权以及国家计算机软件著作权保护!
* 可正常分享和学习源码,不得用于违法犯罪活动,违者必究!
* Copyright (c) 2020 陈尼克 all rights reserved.
* 版权所有,侵权必究!
*
-->
<template>
<div class="create-order">
<s-header :name="'生成订单'" @callback="deleteLocal"></s-header>
<div class="address-wrap">
<div class="name" @click="goTo">
<span>{{ address.userName }} </span>
<span>{{ address.userPhone }}</span>
</div>
<div class="address">
{{ address.provinceName }} {{ address.cityName }} {{ address.regionName }} {{ address.detailAddress }}
</div>
<van-icon class="arrow" name="arrow" />
</div>
<div class="good">
<div class="good-item" v-for="(item, index) in cartList" :key="index">
<div class="good-img"><img :src="prefix(item.goodsCoverImg)" alt=""></div>
<div class="good-desc">
<div class="good-title">
<span>{{ item.goodsName }}</span>
<span>x{{ item.goodsCount }}</span>
</div>
<div class="good-btn">
<div class="price">¥{{ item.sellingPrice }}</div>
</div>
</div>
</div>
</div>
<div class="pay-wrap">
<div class="price">
<span>商品金额</span>
<span>¥{{ total }}</span>
</div>
<van-button @click="createOrder" class="pay-btn" color="#1baeae" type="primary" block>生成订单</van-button>
</div>
<van-popup
closeable
:close-on-click-overlay="false"
v-model="showPay"
position="bottom"
:style="{ height: '30%' }"
@close="close"
>
<div :style="{ width: '90%', margin: '0 auto', padding: '50px 0' }">
<van-button :style="{ marginBottom: '10px' }" color="#1989fa" block @click="payOrder(1)">支付宝支付</van-button>
<van-button color="#4fc08d" block @click="payOrder(2)">微信支付</van-button>
</div>
</van-popup>
</div>
</template>
<script>
import sHeader from '@/components/SimpleHeader'
import { getCart, getByCartItemIds } from '../service/cart'
import { getDefaultAddress, getAddressDetail } from '../service/address'
import { createOrder, payOrder } from '../service/order'
import { setLocal, getLocal } from '@/common/js/utils'
import { Toast } from 'vant'
export default {
components: {
sHeader
},
data() {
return {
cartList: [],
address: {},
showPay: false,
orderNo: '',
cartItemIds: []
}
},
mounted() {
this.init()
},
methods: {
async init() {
Toast.loading({ message: '加载中...', forbidClick: true });
const { addressId, cartItemIds } = this.$route.query
const _cartItemIds = cartItemIds ? JSON.parse(cartItemIds) : JSON.parse(getLocal('cartItemIds'))
setLocal('cartItemIds', JSON.stringify(_cartItemIds))
const { data: list } = await getByCartItemIds({ cartItemIds: _cartItemIds.join(',') })
const { data: address } = addressId ? await getAddressDetail(addressId) : await getDefaultAddress()
if (!address) {
this.$router.push({ path: 'address' })
return
}
this.cartList = list
this.address = address
Toast.clear()
},
goTo() {
this.$router.push({ path: `address?cartItemIds=${JSON.stringify(this.cartItemIds)}` })
},
deleteLocal() {
setLocal('cartItemIds', '')
},
async createOrder() {
const params = {
addressId: this.address.addressId,
cartItemIds: this.cartList.map(item => item.cartItemId)
}
const { data, resultCode } = await createOrder(params)
setLocal('cartItemIds', '')
this.orderNo = data
this.showPay = true
},
close() {
this.$router.push({ path: 'order' })
},
async payOrder(type) {
Toast.loading
await payOrder({ orderNo: this.orderNo, payType: type })
this.$router.push({ path: 'order' })
}
},
computed: {
total: function() {
let sum = 0
this.cartList.forEach(item => {
sum += item.goodsCount * item.sellingPrice
})
return sum
}
}
}
</script>
<style lang="less" scoped>
@import '../common/style/mixin';
.create-order {
background: #f9f9f9;
.address-wrap {
margin-bottom: 20px;
background: #fff;
position: relative;
margin-top: 44px;
font-size: 14px;
padding: 15px;
color: #222333;
.name, .address {
margin: 10px 0;
}
.arrow {
position: absolute;
right: 10px;
top: 50%;
transform: translateY(-50%);
font-size: 20px;
}
&::before {
position: absolute;
right: 0;
bottom: 0;
left: 0;
height: 2px;
background: -webkit-repeating-linear-gradient(135deg, #ff6c6c 0, #ff6c6c 20%, transparent 0, transparent 25%, #1989fa 0, #1989fa 45%, transparent 0, transparent 50%);
background: repeating-linear-gradient(-45deg, #ff6c6c 0, #ff6c6c 20%, transparent 0, transparent 25%, #1989fa 0, #1989fa 45%, transparent 0, transparent 50%);
background-size: 80px;
content: '';
}
}
.good {
margin-bottom: 120px;
}
.good-item {
padding: 10px;
background: #fff;
display: flex;
.good-img {
img {
.wh(100px, 100px)
}
}
.good-desc {
display: flex;
flex-direction: column;
justify-content: space-between;
flex: 1;
padding: 20px;
.good-title {
display: flex;
justify-content: space-between;
}
.good-btn {
display: flex;
justify-content: space-between;
.price {
font-size: 16px;
color: red;
line-height: 28px;
}
.van-icon-delete {
font-size: 20px;
margin-top: 4px;
}
}
}
}
.pay-wrap {
position: fixed;
bottom: 0;
left: 0;
width: 100%;
background: #fff;
padding: 10px 0;
padding-bottom: 50px;
border-top: 1px solid #e9e9e9;
>div {
display: flex;
justify-content: space-between;
padding: 0 5%;
margin: 10px 0;
font-size: 14px;
span:nth-child(2) {
color: red;
font-size: 18px;
}
}
.pay-btn {
position: fixed;
bottom: 7px;
right: 0;
left: 0;
width: 90%;
margin: 0 auto;
}
}
}
</style>
This diff is collapsed.
<!--
* 严肃声明:
* 开源版本请务必保留此注释头信息,若删除我方将保留所有法律责任追究!
* 本系统已申请软件著作权,受国家版权局知识产权以及国家计算机软件著作权保护!
* 可正常分享和学习源码,不得用于违法犯罪活动,违者必究!
* Copyright (c) 2020 陈尼克 all rights reserved.
* 版权所有,侵权必究!
*
-->
<template>
<div class="login">
<s-header :name="type == 'login' ? '登录' : '注册'" :back="'/home'"></s-header>
<img class="logo" src="//s.weituibao.com/1582958061265/mlogo.png" alt="">
<div v-if="type == 'login'" class="login-body login">
<van-form @submit="onSubmit">
<van-field
v-model="username"
name="username"
label="用户名"
placeholder="用户名"
:rules="[{ required: true, message: '请填写用户名' }]"
/>
<van-field
v-model="password"
type="password"
name="password"
label="密码"
placeholder="密码"
:rules="[{ required: true, message: '请填写密码' }]"
/>
<div class="verify">
<Verify ref="loginVerifyRef" @error="error" :showButton="false" @success="success" :width="'100%'" :height="'40px'" :fontSize="'16px'" :type="2"></Verify>
</div>
<div style="margin: 16px;">
<div class="link-register" @click="toggle('register')">立即注册</div>
<van-button round block type="info" color="#1baeae" native-type="submit">登录</van-button>
</div>
</van-form>
</div>
<div v-else class="login-body register">
<van-form @submit="onSubmit">
<van-field
v-model="username1"
name="username1"
label="用户名"
placeholder="用户名"
:rules="[{ required: true, message: '请填写用户名' }]"
/>
<van-field
v-model="password1"
type="password"
name="password1"
label="密码"
placeholder="密码"
:rules="[{ required: true, message: '请填写密码' }]"
/>
<div class="verify">
<Verify ref="loginVerifyRef" @error="error" :showButton="false" @success="success" :width="'100%'" :height="'40px'" :fontSize="'16px'" :type="2"></Verify>
</div>
<div style="margin: 16px;">
<div class="link-login" @click="toggle('login')">已有登录账号</div>
<van-button round block type="info" color="#1baeae" native-type="submit">注册</van-button>
</div>
</van-form>
</div>
</div>
</template>
<script>
import sHeader from '@/components/SimpleHeader'
import { login, register, getUserInfo } from '../service/user'
import { setLocal, getLocal } from '@/common/js/utils'
import { Toast } from 'vant'
import Verify from 'vue2-verify'
export default {
data() {
return {
username: '',
password: '',
username1: '',
password1: '',
type: 'login',
verify: false
}
},
components: {
sHeader,
Verify
},
methods: {
dealTriVer() {
// 执行验证码的验证,通过 this.verify 知道验证码是否填写正确
this.$refs.loginVerifyRef.$refs.instance.checkCode()
},
toggle(v) {
this.verify = false
this.type = v
},
async onSubmit(values) {
this.dealTriVer()
if (!this.verify) {
Toast.fail('验证码未填或填写错误!')
return
}
if (this.type == 'login') {
const { data, resultCode } = await login({
"loginName": values.username,
"passwordMd5": this.$md5(values.password)
})
setLocal('token', data)
window.location.href = '/'
} else {
const { data } = await register({
"loginName": values.username1,
"password": values.password1
})
Toast.success('注册成功')
this.type = 'login'
}
},
success(obj) {
this.verify = true
// 回调之后,刷新验证码
obj.refresh()
},
error(obj) {
this.verify = false
// 回调之后,刷新验证码
obj.refresh()
}
},
}
</script>
<style lang="less">
.login {
.logo {
width: 120px;
height: 120px;
display: block;
margin: 80px auto 0px;
}
.login-body {
padding: 0 20px;
}
.login {
.link-register {
font-size: 14px;
margin-bottom: 20px;
color: #1989fa;
display: inline-block;
}
}
.register {
.link-login {
font-size: 14px;
margin-bottom: 20px;
color: #1989fa;
display: inline-block;
}
}
.verify-bar-area {
margin-top: 24px;
.verify-left-bar {
border-color: #1baeae;
}
.verify-move-block {
background-color: #1baeae;
color: #fff;
}
}
.verify {
>div {
width: 100%;
}
display: flex;
justify-content: center;
.cerify-code-panel {
margin-top: 16px;
}
.verify-code {
width: 40%!important;
float: left!important;
}
.verify-code-area {
float: left!important;
width: 54%!important;
margin-left: 14px!important;
.varify-input-code {
width: 90px;
height: 38px!important;
border: 1px solid #e9e9e9;
padding-left: 10px;
font-size: 16px;
}
.verify-change-area {
line-height: 44px;
}
}
}
}
</style>
<template>
<div class="login" :style="{ backgroundImage: `url(${bg})` }">
<div class="title">
<div class="login-logo">
<van-image :src="require('@/assets/login/login-logo.png')" />
</div>
<div class="login-name">首开集团安全隐患排查治理体系</div>
</div>
<div class="con" :style="{ backgroundImage: `url(${conBg})` }">
<div class="hello">Hello!</div>
<div class="welcome">
欢迎登录<span>首开集团安全隐患排查治理体系</span>!
</div>
<div class="login-form">
<van-form @submit="onSubmit">
<div class="username-wrap">
<div class="username-icon">
<van-image :src="require('@/assets/login/login-username.png')" />
</div>
<van-field
v-model="username"
name="username"
label=""
placeholder="账号"
:rules="[{ required: true, message: '请填写用户名' }]"
/>
</div>
<div class="passworld-wrap">
<div class="passworld-icon">
<van-image :src="require('@/assets/login/login-passworld.png')" />
</div>
<van-field
v-model="password"
name="password"
placeholder="密码"
:rules="[{ required: true, message: '请填写密码' }]"
/>
</div>
<div style="margin: 16px;">
<van-button round block type="info" native-type="submit"
>登录</van-button
>
</div>
</van-form>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
bg: require("@/assets/login/login-bg.png"),
conBg: require("@/assets/login/login-center.png"),
username: "",
password: ""
};
},
mounted() {},
methods: {
onSubmit(values) {
if(values.username=='admin'&&values.password=='123456'){
this.$notify({
message:'成功',
background:'green',
duration: 1000
})
localStorage.setItem('admin_token','2dsfewr')
this.$router.push('/MessageCenter')
location.reload();
}else{
this.$notify({
message:'账号或密码不正确',
background:'red',
duration: 1000
})
}
}
}
};
</script>
<style lang="less" scoped>
/* @import url(); 引入css类 */
.login {
background-size: cover;
background-repeat: no-repeat;
background-position: center;
background-attachment: fixed;
.login-logo {
width: 120px;
margin: 22% auto 0px;
}
.login-name {
width: 100%;
text-align: center;
margin-top: 20px;
color: #fafbfe;
font-size: 18px;
font-weight: bold;
}
.con {
width: 345px;
height: 340px;
margin: 62px auto 0;
padding: 35px 25px;
box-sizing: border-box;
background-size: cover;
background-repeat: no-repeat;
.hello {
color: #004fb1;
font-size: 20px;
font-weight: bold;
}
.welcome {
margin: 15px 0;
color: #7795e0;
span {
color: #71aaf2;
}
}
.login-form {
.username-wrap {
position: relative;
border-bottom: 1px solid #d2dcf5;
.username-icon {
width: 20px;
position: absolute;
left: 5px;
top: 9px;
z-index: 100;
}
/deep/ .van-field__body {
padding-left: 20px;
box-sizing: border-box;
}
/deep/ .van-field__error-message{
padding-left: 20px;
}
}
.passworld-wrap {
position: relative;
border-bottom: 1px solid #d2dcf5;
.passworld-icon {
width: 20px;
position: absolute;
left: 5px;
top: 9px;
z-index: 100;
}
/deep/ .van-field__body {
padding-left: 20px;
box-sizing: border-box;
}
/deep/ .van-field__error-message{
padding-left: 20px;
}
}
}
}
}
</style>
<template>
<div>
<!-- 头部标签 -->
<van-sticky>
<header class="header-wrap">
消息中心
</header>
</van-sticky>
<!-- 内容 -->
<div class="con">
<van-tabs
v-model="activeName"
color="#247df7"
title-inactive-colo="#d0d1d1"
title-active-color="#000000"
sticky
offset-top="50"
>
<van-tab title="消息信息" name="消息信息" badge="5">
<message-news></message-news>
</van-tab>
<van-tab title="待办事项" name="待办事项" badge="2">待办事项</van-tab>
<van-tab title="通知公告" name="通知公告" badge="6">通知公告</van-tab>
</van-tabs>
</div>
<!-- tanBar -->
<tab-bar :index="0"></tab-bar>
</div>
</template>
<script>
import MessageNews from "./MessageNews.vue";
import tabBar from "@/components/TabBar";
export default {
components: {
MessageNews,
tabBar
},
data() {
return {
activeName: "消息信息"
};
},
mounted() {},
methods: {}
};
</script>
<style lang="less" scoped>
/* @import url(); 引入css类 */
.header-wrap {
width: 100%;
height: 1.333333rem;
background-color: #2980f7;
font-size: 17px;
line-height: 1.333333rem;
color: white;
font-weight: 600;
text-align: center;
}
.con {
// height: calc(100% - 110px);
// height: 100%;
padding: 0 0 50px 0;
background-color: #f0f1f5;
position: relative;
/deep/ .van-info {
right: -6px;
background-color: #fa4c4c;
}
}
</style>
<template>
<div>
<div class="message-wrap">
<!-- 标签 -->
<div class="category-wrap">
<!-- <span class="my-tag-style active">全部</span>
<span class="my-tag-style">已读</span>
<span class="my-tag-style">未读</span> -->
<span
class="my-tag-style"
:class="index == activeIndex ? 'active' : ''"
v-for="(item, index) in messageCategory"
:key="item.key"
@click="selectCategory(index, item.category)"
>{{ item.category }}</span
>
</div>
<!-- 搜索 -->
<div class="search-wrap">
<van-search v-model="searchVal" placeholder="搜索" @search="onSearch" />
</div>
<!-- 内容列表 -->
<div class="con-list">
<!-- <van-pull-refresh v-model="refreshing" @refresh="onRefresh">
<van-list
v-model="loading"
:finished="finished"
finished-text="没有更多了"
@load="onLoad"
> -->
<van-cell-group inset>
<div class="messgae-title">隐患确认信息</div>
<div class="message-content">
张大海已确认一般隐患B类,右万宝宝负责整改。
</div>
</van-cell-group>
<!-- </van-list>
</van-pull-refresh> -->
</div>
</div>
</div>
</template>
<script>
import { Toast } from "vant";
export default {
data() {
return {
messageCategory: [
{
key: "0",
category: "全部"
},
{
key: "1",
category: "已读"
},
{
key: "2",
category: "未读"
}
],
activeIndex: 0,
searchVal: "",
// refreshing: false, // 下拉刷新开关
// loading: false, // 列表滚动到底部会触发load事件
// finished: false // 列表数据全部加载完成
};
},
mounted() {},
methods: {
// 点击类别
selectCategory(index, data) {
this.activeIndex = index;
console.log(data);
},
// 搜索事件
onSearch(val) {
if (val !== "") {
console.log(val);
}
},
// // 下拉刷新事件
// onRefresh() {
// // 清空列表数据
// this.finished = false;
// // 重新加载数据
// // 将 loading 设置为 true,表示处于加载状态
// this.loading = true;
// this.onLoad();
// },
// // 列表初始化函数
// onLoad() {
// setTimeout(() => {
// if (this.refreshing) {
// this.refreshing = false;
// }
// // 加载完成后将loading改成 false
// this.loading = false;
// // 为什么会连续触发 load 事件? 先加上这句 this.finished = true; 以后再删
// // this.finished = true;
// // 如果列表数据全部加载完成 则将finished改为true
// // if (this.list.length >= 40) {
// // this.finished = true;
// // }
// }, 5000);
// }
}
};
</script>
<style lang="less" scoped>
/* @import url(); 引入css类 */
.message-wrap {
padding: 10px 10px 0;
background-color: #f0f1f5;
// 标签
.category-wrap {
.my-tag-style {
width: 75px;
height: 21px;
font-size: 13px;
border: 1px solid #1989fa;
border-radius: 4px;
color: #1989fa;
display: inline-block;
text-align: center;
line-height: 21px;
margin-right: 10px;
}
.active {
color: white;
background-color: #1989fa;
}
}
// 搜索
.search-wrap {
margin: 10px 0;
.van-search {
border-radius: 5px;
padding: 5px 12px;
}
.van-search__content {
background-color: #ffffff;
}
}
// 内容
.con-list {
.van-cell-group--inset {
margin: 0;
margin-bottom: 10px;
padding: 10px;
font-size: 13px;
.messgae-title {
}
.message-content {
margin-top: 10px;
}
}
}
}
</style>
<template>
<div>
<!-- 头部标签 -->
<van-sticky>
<header class="header-wrap">
首开集团安全管理平台
</header>
</van-sticky>
<!-- 内容 -->
<div class="con">
<!-- 个人信息 -->
<van-cell-group inset>
<van-row gutter="20">
<van-col span="6">
<div>
<van-image
width="2rem"
height="2rem"
fit="fill"
:src="userInfo.portrait"
/>
</div>
</van-col>
<van-col span="18">
<div class="user-info-wrap">
<div class="user-name">{{ userInfo.name }}</div>
<p>{{ userInfo.position }}</p>
<div class="tag-wrap">
<van-tag color="#cbcdfb">隐患上报人</van-tag>
<van-tag color="#b5e2f1">隐患整改人</van-tag>
<van-tag color="#bed9fd">检查专员</van-tag>
</div>
</div>
</van-col>
</van-row>
</van-cell-group>
<!-- 设置 -->
<van-cell-group inset class="my-cell-group">
<div class="set-wrap">
<van-image
width="0.613rem"
height="0.613rem"
fit="fill"
:src="require('@/assets/myTerritory/set.png')"
/>
<span>设置</span>
</div>
</van-cell-group>
<!-- 退出系统 -->
<footer class="sign-out">
<van-button type="info" block @click="logout">退出系统</van-button>
</footer>
</div>
<!-- tanBar -->
<tab-bar :index="2"></tab-bar>
</div>
</template>
<script>
import tabBar from "@/components/TabBar";
export default {
components: {
tabBar
},
data() {
return {
userInfo: {
portrait: require("@/assets/myTerritory/touxiang.png"),
name: "刘华强",
position: "技术安全部"
// jurisdiction: [
// '隐患上报人',
// '隐患整改人',
// '检查专员'
// ]
}
};
},
mounted() {},
methods: {
logout() {
localStorage.removeItem('admin_token');
this.$router.push("/Login2");
location.reload();
}
}
};
</script>
<style lang="less" scoped>
/* @import url(); 引入css类 */
.header-wrap {
width: 100%;
height: 50px;
background-color: #2980f7;
font-size: 17px;
line-height: 50px;
color: white;
font-weight: 600;
text-align: center;
}
.con {
height: calc(100% - 110px);
padding: 10px 0 50px 0;
background-color: #f0f1f5;
position: relative;
.user-info-wrap {
display: flex;
flex-direction: column;
justify-content: space-between;
.user-name {
font-size: 17px;
font-weight: bold;
}
.tag-wrap {
.van-tag {
margin-right: 10px;
margin-top: 3px;
padding: 2px 4px;
}
}
}
.my-cell-group {
padding: 10px 10px !important;
.set-wrap {
height: 0.8rem;
display: flex;
align-items: center;
span {
margin-left: 0.2666rem;
font-size: 15px;
font-weight: bold;
}
}
}
}
.sign-out {
width: 96%;
position: absolute;
bottom: 1.86667rem;
left: 0px;
right: 0;
margin: auto;
overflow: hidden;
border-radius: 5px;
button {
font-size: 15px;
font-weight: bold;
}
}
.van-cell-group--inset {
margin: 0 10px 10px;
padding: 10px 10px 15px;
}
</style>
<!--
* 严肃声明:
* 开源版本请务必保留此注释头信息,若删除我方将保留所有法律责任追究!
* 本系统已申请软件著作权,受国家版权局知识产权以及国家计算机软件著作权保护!
* 可正常分享和学习源码,不得用于违法犯罪活动,违者必究!
* Copyright (c) 2020 陈尼克 all rights reserved.
* 版权所有,侵权必究!
*
-->
<template>
<div class="order-box">
<s-header :name="'我的订单'" :back="'/user'"></s-header>
<van-tabs @change="onChangeTab" :color="'#1baeae'" :title-active-color="'#1baeae'" class="order-tab" v-model="status">
<van-tab title="全部" name=''></van-tab>
<van-tab title="待付款" name="0"></van-tab>
<van-tab title="待确认" name="1"></van-tab>
<van-tab title="待发货" name="2"></van-tab>
<van-tab title="已发货" name="3"></van-tab>
<van-tab title="交易完成" name="4"></van-tab>
</van-tabs>
<van-pull-refresh v-model="refreshing" @refresh="onRefresh" class="order-list-refresh">
<van-list
v-model="loading"
:finished="finished"
finished-text="没有更多了"
@load="onLoad"
@offset="300"
>
<div v-for="(item, index) in list" :key="index" class="order-item-box" @click="goTo(item.orderNo)">
<div class="order-item-header">
<span>订单时间:{{ item.createTime }}</span>
<span>{{ item.orderStatusString }}</span>
</div>
<van-card
v-for="one in item.newBeeMallOrderItemVOS"
:key="one.orderId"
:num="one.goodsCount"
:price="one.sellingPrice"
desc="全场包邮"
:title="one.goodsName"
:thumb="prefix(one.goodsCoverImg)"
/>
</div>
</van-list>
</van-pull-refresh>
</div>
</template>
<script>
import sHeader from '@/components/SimpleHeader'
import { getOrderList } from '../service/order'
import { prefix } from '@/common/js/utils'
export default {
data() {
return {
status: '',
loading: false,
finished: false,
refreshing: false,
list: [],
page: 1
}
},
components: {
sHeader
},
async mounted() {
// this.loadData()
},
methods: {
async loadData() {
const { data, data: { list } } = await getOrderList({ pageNumber: this.page, status: this.status })
this.list = this.list.concat(list)
this.totalPage = data.totalPage
this.loading = false;
if (this.page >= data.totalPage) this.finished = true
},
onChangeTab(name, title) {
this.status = name
this.onRefresh()
},
goTo(id) {
this.$router.push({ path: `order-detail?id=${id}` })
},
goBack() {
this.$router.go(-1)
},
onLoad() {
if (!this.refreshing && this.page < this.totalPage) {
this.page = this.page + 1
}
if (this.refreshing) {
this.list = [];
this.refreshing = false;
}
this.loadData()
},
onRefresh() {
this.refreshing = true
this.finished = false
this.loading = true
this.page = 1
this.onLoad()
},
}
}
</script>
<style lang="less" scoped>
@import '../common/style/mixin';
.order-box {
.order-header {
position: fixed;
top: 0;
left: 0;
z-index: 10000;
.fj();
.wh(100%, 44px);
line-height: 44px;
padding: 0 10px;
.boxSizing();
color: #252525;
background: #fff;
border-bottom: 1px solid #dcdcdc;
.order-name {
font-size: 14px;
}
}
.order-tab {
margin-top: 44px;
position: fixed;
left: 0;
z-index: 1000;
width: 100%;
}
.order-list-refresh {
margin-top: 68px;
.van-card__content {
display: flex;
flex-direction: column;
justify-content: center;
}
.van-pull-refresh__head {
background: #f9f9f9;
}
.van-list {
min-height: calc(100vh - 88px);
background: #f9f9f9;
margin-top: 20px;
}
.order-item-box {
margin: 20px 10px;
background-color: #fff;
.order-item-header {
padding: 10px 20px 0 20px;
display: flex;
justify-content: space-between;
}
.van-card {
background-color: #fff;
margin-top: 0;
}
}
}
}
</style>
<!--
* 严肃声明:
* 开源版本请务必保留此注释头信息,若删除我方将保留所有法律责任追究!
* 本系统已申请软件著作权,受国家版权局知识产权以及国家计算机软件著作权保护!
* 可正常分享和学习源码,不得用于违法犯罪活动,违者必究!
* Copyright (c) 2020 陈尼克 all rights reserved.
* 版权所有,侵权必究!
*
-->
<template>
<div class="order-detail-box">
<s-header :name="'订单详情'" @callback="close"></s-header>
<div class="order-status">
<div class="status-item">
<label>订单状态:</label>
<span>{{ detail.orderStatusString }}</span>
</div>
<div class="status-item">
<label>订单编号:</label>
<span>{{ detail.orderNo }}</span>
</div>
<div class="status-item">
<label>下单时间:</label>
<span>{{ detail.createTime }}</span>
</div>
<!-- <van-button v-if="[1,2,3].includes(detail.orderStatus)" style="margin-bottom: 10px" color="#1baeae" block @click="confirmOrder(detail.orderNo)">确认订单</van-button> -->
<van-button v-if="detail.orderStatus == 0" style="margin-bottom: 10px" color="#1baeae" block @click="showPayFn">去支付</van-button>
<van-button v-if="!(detail.orderStatus < 0 || detail.orderStatus == 4)" block @click="cancelOrder(detail.orderNo)">取消订单</van-button>
</div>
<div class="order-price">
<div class="price-item">
<label>商品金额:</label>
<span>¥ {{ detail.totalPrice }}</span>
</div>
<div class="price-item">
<label>配送方式:</label>
<span>普通快递</span>
</div>
</div>
<van-card
v-for="item in detail.newBeeMallOrderItemVOS"
:key="item.goodsId"
style="background: #fff"
:num="item.goodsCount"
:price="item.sellingPrice"
desc="全场包邮"
:title="item.goodsName"
:thumb="prefix(item.goodsCoverImg)"
/>
<van-popup
v-model="showPay"
position="bottom"
:style="{ height: '24%' }"
>
<div :style="{ width: '90%', margin: '0 auto', padding: '20px 0' }">
<van-button :style="{ marginBottom: '10px' }" color="#1989fa" block @click="payOrder(detail.orderNo, 1)">支付宝支付</van-button>
<van-button color="#4fc08d" block @click="payOrder(detail.orderNo, 2)">微信支付</van-button>
</div>
</van-popup>
</div>
</template>
<script>
import sHeader from '@/components/SimpleHeader'
import { getOrderDetail, cancelOrder, confirmOrder, payOrder } from '../service/order'
import { Dialog, Toast } from 'vant'
export default {
components: {
sHeader
},
data() {
return {
detail: {},
showPay: false
}
},
mounted() {
this.init()
},
methods: {
async init() {
Toast.loading({
message: '加载中...',
forbidClick: true
});
const { id } = this.$route.query
const { data } = await getOrderDetail(id)
this.detail = data
Toast.clear()
},
cancelOrder(id) {
Dialog.confirm({
title: '确认取消订单?',
}).then(() => {
cancelOrder(id).then(res => {
if (res.resultCode == 200) {
Toast('删除成功')
this.init()
}
})
}).catch(() => {
// on cancel
});
},
confirmOrder(id) {
Dialog.confirm({
title: '是否确认订单?',
}).then(() => {
confirmOrder(id).then(res => {
if (res.resultCode == 200) {
Toast('确认成功')
this.init()
}
})
}).catch(() => {
// on cancel
});
},
showPayFn() {
this.showPay = true
},
async payOrder(id, type) {
Toast.loading
await payOrder({ orderNo: id, payType: type })
this.showPay = false
this.init()
},
close() {
Dialog.close()
}
}
}
</script>
<style lang="less" scoped>
.order-detail-box {
background: #f7f7f7;
.order-status {
background: #fff;
margin-top: 44px;
padding: 20px;
font-size: 15px;
.status-item {
margin-bottom: 10px;
label {
color: #999;
}
span {
}
}
}
.order-price {
background: #fff;
margin: 20px 0;
padding: 20px;
font-size: 15px;
.price-item {
margin-bottom: 10px;
label {
color: #999;
}
span {
}
}
}
.van-card {
margin-top: 0;
}
.van-card__content {
display: flex;
flex-direction: column;
justify-content: center;
}
}
</style>
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
<!--
* 严肃声明:
* 开源版本请务必保留此注释头信息,若删除我方将保留所有法律责任追究!
* 本系统已申请软件著作权,受国家版权局知识产权以及国家计算机软件著作权保护!
* 可正常分享和学习源码,不得用于违法犯罪活动,违者必究!
* Copyright (c) 2020 陈尼克 all rights reserved.
* 版权所有,侵权必究!
*
-->
<template>
<div class="seting-box">
<s-header :name="'账号管理'"></s-header>
<div class="input-item">
<van-field v-model="nickName" label="昵称" />
<van-field v-model="introduceSign" label="个性签名" />
<van-field v-model="password" type='password' label="修改密码" />
</div>
<van-button class="save-btn" color="#1baeae" type="primary" @click="save" block>保存</van-button>
<van-button class="save-btn" color="#1baeae" type="primary" @click="logout" block>退出登录</van-button>
</div>
</template>
<script>
import sHeader from '@/components/SimpleHeader'
import { getUserInfo, EditUserInfo, logout } from '../service/user'
import { setLocal } from '@/common/js/utils'
import { Toast } from 'vant'
export default {
components: {
sHeader
},
data() {
return {
nickName: '',
introduceSign: '',
password: ''
}
},
async mounted() {
const { data } = await getUserInfo()
this.nickName = data.nickName
this.introduceSign = data.introduceSign
},
methods: {
async save() {
const params = {
introduceSign: this.introduceSign,
nickName: this.nickName,
passwordMd5: this.$md5(this.password)
}
const { data } = await EditUserInfo(params)
Toast.success('保存成功')
},
async logout() {
const { resultCode } = await logout()
if (resultCode == 200) {
setLocal('token', '')
window.location.href = '/'
}
}
}
}
</script>
<style lang="less" scoped>
.seting-box {
.input-item {
margin-top: 44px;
}
.save-btn {
width: 80%;
margin: 20px auto ;
}
}
</style>
This diff is collapsed.
<!--
* 严肃声明:
* 开源版本请务必保留此注释头信息,若删除我方将保留所有法律责任追究!
* 本系统已申请软件著作权,受国家版权局知识产权以及国家计算机软件著作权保护!
* 可正常分享和学习源码,不得用于违法犯罪活动,违者必究!
* Copyright (c) 2020 陈尼克 all rights reserved.
* 版权所有,侵权必究!
*
-->
<template>
<div>
<LHeader v-bind:text="text"></LHeader>
<van-search
v-model="value"
show-action
placeholder="请输入关键字"
@search="onSearch"
>
<template #action>
<div @click="onSearch">搜索</div>
</template>
</van-search>
<div class="card" @click="cardLocation">
<div>检查名称:昌平区回迁房改造项目安全检查</div>
<div>检查名称:专项检查</div>
<div>检查名称:2021-12-15</div>
<div>检查名称:昌平区回迁房改造工程</div>
</div>
<div class="card">
<div>检查名称:昌平区回迁房改造项目安全检查</div>
<div>检查名称:专项检查</div>
<div>检查名称:2021-12-31</div>
<div>检查名称:昌平区回迁房改造工程</div>
</div>
</div>
</template>
<script>
import LHeader from '@/components/header.vue'
export default {
name: 'checked',
components: {
"LHeader":LHeader
},
data() {
return {
value:'',
text:'检查执行'
}
},
mounted() {
},
methods: {
onSearch(){
this.$toast('提示内容')
},
cardLocation(){
this.$router.push('/problem')
}
}
}
</script>
<style lang="less" scoped>
.card{
width:90%;
box-shadow: 0px 0px 10px 2px #F3F3F3;
padding: 0.25rem;
margin:0.4rem auto;
background: white;
}
.card div{
font-size: 0.4rem;
}
</style>
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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