Add: add font,admin,service

main
muyue 1 year ago
parent b5da8b29ff
commit f68b69f69c

13
admin/.gitignore vendored

@ -0,0 +1,13 @@
.DS_Store
dist/electron/
dist/web/*
build/*
!build/icons
node_modules/
npm-debug.log
npm-debug.log.*
thumbs.db
!.gitkeep
.idea/*
/dist
/tests

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2023 Shengliang
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

@ -0,0 +1,14 @@
module.exports = {
presets: [
// https://github.com/vuejs/vue-cli/tree/master/packages/@vue/babel-preset-app
'@vue/cli-plugin-babel/preset'
],
'env': {
'development': {
// babel-plugin-dynamic-import-node plugin only does one thing by converting all import() to require().
// This plugin can significantly increase the speed of hot updates, when you have a large number of pages.
// https://panjiachen.github.io/vue-element-admin-site/guide/advanced/lazy-loading.html
'plugins': ['dynamic-import-node']
}
}
}

@ -0,0 +1,24 @@
module.exports = {
moduleFileExtensions: ['js', 'jsx', 'json', 'vue'],
transform: {
'^.+\\.vue$': 'vue-jest',
'.+\\.(css|styl|less|sass|scss|svg|png|jpg|ttf|woff|woff2)$':
'jest-transform-stub',
'^.+\\.jsx?$': 'babel-jest'
},
moduleNameMapper: {
'^@/(.*)$': '<rootDir>/src/$1'
},
snapshotSerializers: ['jest-serializer-vue'],
testMatch: [
'**/tests/unit/**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)'
],
collectCoverageFrom: ['src/utils/**/*.{js,vue}', '!src/utils/auth.js', '!src/utils/request.js', 'src/components/**/*.{js,vue}'],
coverageDirectory: '<rootDir>/tests/unit/coverage',
// 'collectCoverage': true,
'coverageReporters': [
'lcov',
'text-summary'
],
testURL: 'http://localhost/'
}

@ -0,0 +1,9 @@
{
"compilerOptions": {
"baseUrl": "./",
"paths": {
"@/*": ["src/*"]
}
},
"exclude": ["node_modules", "dist"]
}

@ -0,0 +1,57 @@
const Mock = require('mockjs')
const { param2Obj } = require('./utils')
const user = require('./user')
const table = require('./table')
const mocks = [
...user,
...table
]
// for front mock
// please use it cautiously, it will redefine XMLHttpRequest,
// which will cause many of your third-party libraries to be invalidated(like progress event).
function mockXHR() {
// mock patch
// https://github.com/nuysoft/Mock/issues/300
Mock.XHR.prototype.proxy_send = Mock.XHR.prototype.send
Mock.XHR.prototype.send = function() {
if (this.custom.xhr) {
this.custom.xhr.withCredentials = this.withCredentials || false
if (this.responseType) {
this.custom.xhr.responseType = this.responseType
}
}
this.proxy_send(...arguments)
}
function XHR2ExpressReqWrap(respond) {
return function(options) {
let result = null
if (respond instanceof Function) {
const { body, type, url } = options
// https://expressjs.com/en/4x/api.html#req
result = respond({
method: type,
body: JSON.parse(body),
query: param2Obj(url)
})
} else {
result = respond
}
return Mock.mock(result)
}
}
for (const i of mocks) {
Mock.mock(new RegExp(i.url), i.type || 'get', XHR2ExpressReqWrap(i.response))
}
}
module.exports = {
mocks,
mockXHR
}

@ -0,0 +1,81 @@
const chokidar = require('chokidar')
const bodyParser = require('body-parser')
const chalk = require('chalk')
const path = require('path')
const Mock = require('mockjs')
const mockDir = path.join(process.cwd(), 'mock')
function registerRoutes(app) {
let mockLastIndex
const { mocks } = require('./index.js')
const mocksForServer = mocks.map(route => {
return responseFake(route.url, route.type, route.response)
})
for (const mock of mocksForServer) {
app[mock.type](mock.url, mock.response)
mockLastIndex = app._router.stack.length
}
const mockRoutesLength = Object.keys(mocksForServer).length
return {
mockRoutesLength: mockRoutesLength,
mockStartIndex: mockLastIndex - mockRoutesLength
}
}
function unregisterRoutes() {
Object.keys(require.cache).forEach(i => {
if (i.includes(mockDir)) {
delete require.cache[require.resolve(i)]
}
})
}
// for mock server
const responseFake = (url, type, respond) => {
return {
url: new RegExp(`${process.env.VUE_APP_BASE_API}${url}`),
type: type || 'get',
response(req, res) {
console.log('request invoke:' + req.path)
res.json(Mock.mock(respond instanceof Function ? respond(req, res) : respond))
}
}
}
module.exports = app => {
// parse app.body
// https://expressjs.com/en/4x/api.html#req.body
app.use(bodyParser.json())
app.use(bodyParser.urlencoded({
extended: true
}))
const mockRoutes = registerRoutes(app)
var mockRoutesLength = mockRoutes.mockRoutesLength
var mockStartIndex = mockRoutes.mockStartIndex
// watch files, hot reload mock server
chokidar.watch(mockDir, {
ignored: /mock-server/,
ignoreInitial: true
}).on('all', (event, path) => {
if (event === 'change' || event === 'add') {
try {
// remove mock routes stack
app._router.stack.splice(mockStartIndex, mockRoutesLength)
// clear routes cache
unregisterRoutes()
const mockRoutes = registerRoutes(app)
mockRoutesLength = mockRoutes.mockRoutesLength
mockStartIndex = mockRoutes.mockStartIndex
console.log(chalk.magentaBright(`\n > Mock Server hot reload success! changed ${path}`))
} catch (error) {
console.log(chalk.redBright(error))
}
}
})
}

@ -0,0 +1,29 @@
const Mock = require('mockjs')
const data = Mock.mock({
'items|30': [{
id: '@id',
title: '@sentence(10, 20)',
'status|1': ['published', 'draft', 'deleted'],
author: 'name',
display_time: '@datetime',
pageviews: '@integer(300, 5000)'
}]
})
module.exports = [
{
url: '/vue-admin-template/table/list',
type: 'get',
response: config => {
const items = data.items
return {
code: 20000,
data: {
total: items.length,
items: items
}
}
}
}
]

@ -0,0 +1,84 @@
const tokens = {
admin: {
token: 'admin-token'
},
editor: {
token: 'editor-token'
}
}
const users = {
'admin-token': {
roles: ['admin'],
introduction: 'I am a super administrator',
avatar: 'https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif',
name: 'Super Admin'
},
'editor-token': {
roles: ['editor'],
introduction: 'I am an editor',
avatar: 'https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif',
name: 'Normal Editor'
}
}
module.exports = [
// user login
{
url: '/vue-admin-template/user/login',
type: 'post',
response: config => {
const { username } = config.body
const token = tokens[username]
// mock error
if (!token) {
return {
code: 60204,
message: 'Account and password are incorrect.'
}
}
return {
code: 20000,
data: token
}
}
},
// get user info
{
url: '/vue-admin-template/user/info\.*',
type: 'get',
response: config => {
const { token } = config.query
const info = users[token]
// mock error
if (!info) {
return {
code: 50008,
message: 'Login failed, unable to get user details.'
}
}
return {
code: 20000,
data: info
}
}
},
// user logout
{
url: '/vue-admin-template/user/logout',
type: 'post',
response: _ => {
return {
code: 20000,
data: 'success'
}
}
}
]

@ -0,0 +1,25 @@
/**
* @param {string} url
* @returns {Object}
*/
function param2Obj(url) {
const search = decodeURIComponent(url.split('?')[1]).replace(/\+/g, ' ')
if (!search) {
return {}
}
const obj = {}
const searchArr = search.split('&')
searchArr.forEach(v => {
const index = v.indexOf('=')
if (index !== -1) {
const name = v.substring(0, index)
const val = v.substring(index + 1, v.length)
obj[name] = val
}
})
return obj
}
module.exports = {
param2Obj
}

38301
admin/package-lock.json generated

File diff suppressed because it is too large Load Diff

@ -0,0 +1,67 @@
{
"name": "vue-admin-template",
"version": "4.4.0",
"description": "A vue admin template with Element UI & axios & iconfont & permission control & lint",
"author": "Pan <panfree23@gmail.com>",
"scripts": {
"dev": "vue-cli-service serve",
"build:prod": "vue-cli-service build",
"build:stage": "vue-cli-service build --mode staging",
"preview": "node build/index.js --preview",
"svgo": "svgo -f src/icons/svg --config=src/icons/svgo.yml",
"lint": "eslint --ext .js,.vue src",
"test:unit": "jest --clearCache && vue-cli-service test:unit",
"test:ci": "npm run lint && npm run test:unit"
},
"dependencies": {
"axios": "0.18.1",
"clipboard": "^2.0.11",
"core-js": "^3.30.1",
"element-ui": "2.13.2",
"jquery": "^3.6.3",
"js-cookie": "2.2.0",
"lrz": "^4.9.41",
"moment": "^2.29.4",
"normalize.css": "7.0.0",
"nprogress": "0.2.0",
"path-to-regexp": "2.4.0",
"quill": "^2.0.2",
"vue": "2.6.10",
"vue-axios": "^3.5.2",
"vue-barcode": "^1.3.0",
"vue-quill-editor": "^3.0.6",
"vue-router": "3.0.6",
"vuedraggable": "^2.24.3",
"vuex": "3.1.0"
},
"devDependencies": {
"@vue/cli-plugin-babel": "4.4.4",
"@vue/cli-plugin-unit-jest": "4.4.4",
"@vue/cli-service": "4.4.4",
"@vue/test-utils": "1.0.0-beta.29",
"autoprefixer": "9.5.1",
"babel-jest": "23.6.0",
"babel-plugin-dynamic-import-node": "2.3.3",
"chalk": "2.4.2",
"connect": "3.6.6",
"html-webpack-plugin": "3.2.0",
"mockjs": "1.0.1-beta3",
"runjs": "4.3.2",
"sass": "1.26.8",
"sass-loader": "8.0.2",
"script-ext-html-webpack-plugin": "2.1.3",
"serve-static": "1.13.2",
"svg-sprite-loader": "4.1.3",
"svgo": "1.2.2",
"vue-template-compiler": "2.6.10"
},
"browserslist": [
"> 1%",
"last 2 versions"
],
"engines": {
"node": ">=8.9",
"npm": ">= 3.0.0"
},
"license": "MIT"
}

@ -0,0 +1,8 @@
// https://github.com/michael-ciniawsky/postcss-load-config
module.exports = {
'plugins': {
// to edit target browsers: use "browserslist" field in package.json
'autoprefixer': {}
}
}

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

@ -0,0 +1,19 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<!-- <link href="https://cdn.bootcss.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet"> -->
<link href="/admin/css/font-awesome.min.css" rel="stylesheet">
<title><%= webpackConfig.name %></title>
</head>
<body>
<noscript>
<strong>We're sorry but <%= webpackConfig.name %> 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>

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 301 KiB

@ -0,0 +1,97 @@
<template>
<div id="app">
<transition name="router-fade" mode="out-in">
<router-view></router-view>
</transition>
</div>
</template>
<script>
export default {
name: "admin",
};
</script>
<style>
* {
margin: 0;
padding: 0;
}
html,
body,
#app {
height: 100%;
width: 100%;
background: #f5f7f9;
font-family: Lato, Helvetica, sans-serif;
}
a,
a:hover {
text-decoration: none;
}
.content-nav {
height: 40px;
background: #f5f7fa;
margin: 0 0 10px 0;
display: flex;
}
.content-nav .breadcrumb {
height: 40px;
line-height: 40px;
flex: 1;
color: #8492a6;
}
.content-nav .operation-nav {
width: auto;
display: flex;
align-items: center;
}
.content-main {
padding: 20px;
background: #fff;
}
.filter-box {
height: auto;
overflow: hidden;
}
.page-box {
margin-top: 20px;
text-align: right;
}
.form-table-box .el-input__inner {
max-width: 240px;
}
.form-table-box .el-textarea {
width: 400px;
}
.router-fade-enter-active,
.router-fade-leave-active {
transition: opacity 0.3s;
}
.router-fade-enter,
.router-fade-leave-active {
opacity: 0;
}
.form-table-box .el-form {
margin-top: 40px;
}
.form-tip {
color: #888;
font-size: 12px;
line-height: 30px;
}
</style>

@ -0,0 +1,9 @@
import request from '@/utils/request'
export function getList(params) {
return request({
url: '/vue-admin-template/table/list',
method: 'get',
params
})
}

@ -0,0 +1,24 @@
import request from '@/utils/request'
export function login(data) {
return request({
url: '/vue-admin-template/user/login',
method: 'post',
data
})
}
export function getInfo(token) {
return request({
url: '/vue-admin-template/user/info',
method: 'get',
params: { token }
})
}
export function logout() {
return request({
url: '/vue-admin-template/user/logout',
method: 'post'
})
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 96 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

@ -0,0 +1,336 @@
<template>
<div class="content-page">
<div class="content-nav">
<el-breadcrumb class="breadcrumb" separator="/">
<el-breadcrumb-item :to="{ name: 'ad' }">广告列表</el-breadcrumb-item>
<el-breadcrumb-item>{{infoForm.id ? '编辑广告' : '添加广告'}}</el-breadcrumb-item>
</el-breadcrumb>
<div class="operation-nav">
<!--<el-button type="primary" @click="test" icon="arrow-left">test</el-button>-->
<el-button type="primary" @click="goBackPage" icon="arrow-left">返回列表</el-button>
</div>
</div>
<div class="content-main">
<div class="form-table-box">
<el-form ref="infoForm" :rules="infoRules" :model="infoForm" label-width="120px">
<el-form-item label="广告图片" prop="image_url" v-if="infoForm.image_url" class="image-uploader-diy new-height">
<div class="index-image">
<el-image :preview-src-list="previewList" v-if="infoForm.image_url" :src="infoForm.image_url" @click="previewIndexImg"
class="image-show" fit="cover"></el-image>
<div class="o-shadow" @click="delePicList">
<i class="el-icon-delete"></i>
</div>
</div>
</el-form-item>
<el-form-item label="广告图片" prop="image_url" v-if="!infoForm.image_url">
<el-upload name="file" ref="upload" class="upload-demo" :action="qiniuZone" :on-success="handleSuccess"
:before-upload="getQiniuToken" :auto-upload="true" list-type="picture-card" :data="picData" :http-request="uploadIndexImg">
<el-button size="small" type="primary">点击上传</el-button>
<div slot="tip" class="el-upload__tip">只能上传jpg/png文件</div>
</el-upload>
</el-form-item>
<el-form-item label="商品类型">
<el-radio-group v-model="infoForm.link_type">
<el-radio :label="0">商品id</el-radio>
<el-radio :label="1">链接</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="广告链接" prop="link" v-if="infoForm.link_type == 1">
<el-input class="link-input" v-model="infoForm.link"></el-input>
</el-form-item>
<el-form-item label="商品id" prop="link" v-if="infoForm.link_type == 0">
<el-input class="id-input" v-model="infoForm.goods_id"></el-input>
<el-popover
placement="right"
v-model="related_pop"
>
<el-table :data="chooseRelateGoods" stripe style="width: 100%">
<el-table-column prop="id" label="id" width="100"></el-table-column>
<el-table-column prop="list_pic_url" label="商品图片" width="120">
<template slot-scope="scope">
<img :src="scope.row.list_pic_url" alt="" style="width: 40px;height: 40px">
</template>
</el-table-column>
<el-table-column prop="name" label="商品名称" width="300px"></el-table-column>
<el-table-column label="操作">
<template slot-scope="scope">
<el-button
size="small"
type="danger"
@click="relateSelect(scope.row.id)">选择
</el-button>
</template>
</el-table-column>
</el-table>
<el-button slot="reference" type="primary" @click="relateGoodsClick"></el-button>
</el-popover>
</el-form-item>
<el-form-item label="结束时间" prop="end_time">
<el-date-picker
v-model="infoForm.end_time"
type="datetime"
placeholder="选择日期"
default-time="23:59:59">
>
</el-date-picker>
</el-form-item>
<el-form-item label="排序" prop="sort_order">
<el-input-number v-model="infoForm.sort_order" :min="1" :max="999"></el-input-number>
</el-form-item>
<el-form-item label="广告启用">
<el-switch active-value="1" inactive-value="0" v-model="infoForm.enabled"></el-switch>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="onSubmitInfo"></el-button>
<el-button @click="goBackPage"></el-button>
</el-form-item>
</el-form>
</div>
</div>
</div>
</template>
<script>
import api from '@/config/api';
import lrz from 'lrz'
import moment from 'moment'
export default {
data() {
return {
qiniuZone:'',
root: '',
fileList: [],
infoForm: {
id: 0,
image_url: '',
link_type: 0,
enabled: 0,
end_time: '',
goods_id:0,
link:''
},
infoRules: {
image_url: [
{required: true, message: '请输入广告图片', trigger: 'blur'},
],
end_time: [
{required: true, message: '请选择时间', trigger: 'blur'},
],
},
picData: {
token: ''
},
url: '',
chooseRelateGoods: [],
related_pop: false,
previewList: [],
}
},
methods: {
handleSuccess(){},
previewIndexImg() {
let that = this;
that.previewList = [];
that.previewList.push(that.infoForm.image_url);
},
delePicList() {
let that = this;
that.$confirm('确定删除该图片?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
})
.then(() => {
that.infoForm.image_url = '';
})
.catch(() => {})
},
uploadIndexImg(request) {
const file = request.file;
lrz(file).then((rst) => {
const config = {
headers: {
'Content-Type': 'multipart/form-data'
},
};
const fileName = moment().format('YYYYMMDDHHmmssSSS') + Math.floor(Math.random() * 100) + file.name; //
const formData = new FormData();
formData.append('file', rst.file);
formData.append('token', this.picData.token);
formData.append('key', fileName);
this.$http.post(this.qiniuZone, formData, config).then((res) => {
this.handleUploadImageSuccess(res.data)
})
}).catch(function(err){
console.log(err)
})
},
handleUploadImageSuccess(res, file) {
let url = this.url;
this.infoForm.image_url = url + res.key;
},
relateSelect(id) {
console.log(id);
this.infoForm.goods_id = id;
this.related_pop = false;
},
relateGoodsClick() {
this.axios.post('ad/getallrelate', {id: this.infoForm.id}).then((response) => {
if (response.data.errno === 0) {
this.chooseRelateGoods = response.data.data
}
});
},
test() {
console.log(this.infoForm.end_time);
},
beforeAdRemove() {
return this.$confirm(`确定移除?`);
},
adRemove(file, fileList) {
this.infoForm.image_url = '';
},
getQiniuToken() {
let that = this
this.axios.post('index/getQiniuToken').then((response) => {
let resInfo = response.data.data;
console.log(resInfo);
that.picData.token = resInfo.token;
that.url = resInfo.url;
})
},
goBackPage() {
this.$router.go(-1);
},
onSubmitInfo() {
console.log(this.infoForm);
// return false;
let time = this.infoForm.end_time
if (time == 0) {
this.$message({
type: 'error',
message: '请选择时间'
});
return false;
}
if (this.infoForm.link_type == 0) {
if(this.infoForm.goods_id == 0 ){
this.$message({
type: 'error',
message: '请选择商品'
});
return false;
}
}
if (this.infoForm.link_type == 1) {
if(this.infoForm.link == '' ){
this.$message({
type: 'error',
message: '请输入链接'
});
return false;
}
}
this.$refs['infoForm'].validate((valid) => {
if (valid) {
this.axios.post('ad/store', this.infoForm).then((response) => {
if (response.data.errno === 0) {
this.$message({
type: 'success',
message: '保存成功'
});
this.$router.go(-1);
} else if (response.data.errno === 100) {
this.$message({
type: 'error',
message: '该商品已经有广告关联'
})
}
else {
this.$message({
type: 'error',
message: '保存失败'
})
}
})
} else {
return false;
}
});
},
getInfo() {
if (this.infoForm.id <= 0) {
return false
}
//广
let that = this
this.axios.get('ad/info', {
params: {
id: that.infoForm.id
}
}).then((response) => {
let resInfo = response.data.data;
resInfo.enabled = resInfo.enabled ? "1" : "0";
that.infoForm = resInfo;
that.infoForm.end_time = resInfo.end_time * 1000;
let info = {
name: resInfo.name,
url: resInfo.image_url
};
this.fileList.push(info);
console.log(this.infoForm);
})
}
},
components: {},
mounted() {
this.infoForm.id = this.$route.query.id || 0;
this.getInfo();
this.root = api.rootUrl;
this.getQiniuToken();
this.qiniuZone = api.qiniu;
}
}
</script>
<style scoped>
.image-show {
width: 375px;
height: 220px;
background-color: #f9f9f9;
display: block;
}
.id-input {
margin-bottom: 20px;
}
.link-input .el-input__inner {
width: 400px !important;
}
.o-shadow {
position: absolute;
bottom: 10px;
right: 10px;
background-color: rgba(0, 0, 0, .5);
opacity: 0;
transition: opacity .3s;
color: #fff;
font-size: 20px;
line-height: 20px;
padding: 10px;
cursor: pointer;
}
.index-image {
width: 375px;
height: 220px;
position: relative;
}
.index-image:hover .o-shadow {
opacity: 1;
}
</style>

@ -0,0 +1,153 @@
<template>
<div class="content-page">
<div class="content-nav">
<el-breadcrumb class="breadcrumb" separator="/">
<el-breadcrumb-item>广告列表</el-breadcrumb-item>
</el-breadcrumb>
<div class="operation-nav">
<router-link to="/dashboard/ad/add">
<el-button type="primary" icon="plus">添加广告</el-button>
</router-link>
</div>
</div>
<div class="content-main">
<div class="form-table-box">
<el-table :data="tableData" style="width: 100%" border stripe>
<el-table-column prop="id" label="ID" width="70px"></el-table-column>
<el-table-column prop="image_url" label="广告">
<template slot-scope="scope">
<img :src="scope.row.image_url" alt="" style="width: 90px;height: 50px">
</template>
</el-table-column>
<el-table-column prop="goods_id" label="关联商品"></el-table-column>
<el-table-column prop="end_time" label="结束时间"></el-table-column>
<el-table-column prop="sort_order" label="排序" width="100" sortable>
<template slot-scope="scope">
<el-input v-model="scope.row.sort_order" placeholder="排序" @blur="submitSort(scope.$index, scope.row)"></el-input>
</template>
</el-table-column>
<el-table-column prop="enabled" label="状态" width="80px">
<template slot-scope="scope">
{{ scope.row.enabled == 1 ? '启用' : '禁用' }}
</template>
</el-table-column>
<el-table-column label="开启状态" width="80">
<template slot-scope="scope">
<el-switch
v-model="scope.row.enabled"
active-text=""
inactive-text=""
@change='changeStatus($event,scope.row.id)'>
</el-switch>
</template>
</el-table-column>
<el-table-column label="操作" width="170">
<template slot-scope="scope">
<el-button size="small" @click="handleRowEdit(scope.$index, scope.row)">编辑</el-button>
<el-button size="small" type="danger" @click="handleRowDelete(scope.$index, scope.row)">删除</el-button>
</template>
</el-table-column>
</el-table>
</div>
<div class="page-box">
<el-pagination @current-change="handlePageChange" :current-page="page" :page-size="10" layout="total, prev, pager, next, jumper" :total="total">
</el-pagination>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
page: 1,
total: 0,
filterForm: {
name: ''
},
tableData: []
}
},
methods: {
test(){
console.log(this.tableData);
},
submitSort(index, row){
this.axios.post('ad/updateSort', { id: row.id,sort:row.sort_order }).then((response) => {
})
},
changeStatus($event, para) {
this.axios.get('ad/saleStatus', {
params: {
status: $event,
id: para
}
}).then((response) => {
})
},
handlePageChange(val) {
this.page = val;
//localStorage
localStorage.setItem('adPage', this.page)
localStorage.setItem('adFilterForm', JSON.stringify(this.filterForm));
this.getList()
},
handleRowEdit(index, row) {
this.$router.push({ name: 'ad_add', query: { id: row.id } })
},
handleRowDelete(index, row) {
this.$confirm('确定要删除?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
this.axios.post('ad/destory', { id: row.id }).then((response) => {
console.log(response.data)
if (response.data.errno === 0) {
this.$message({
type: 'success',
message: '删除成功!'
});
this.getList();
}
})
});
},
onSubmitFilter() {
this.page = 1
this.getList()
},
getList() {
this.axios.get('ad', {
params: {
page: this.page,
}
}).then((response) => {
this.tableData = response.data.data.data
this.page = response.data.data.currentPage
this.total = response.data.data.count
})
console.log(this.tableData);
}
},
components: {
},
mounted() {
this.getList();
}
}
</script>
<style scoped>
</style>

@ -0,0 +1,231 @@
<template>
<div class="content-page">
<div class="content-nav">
<el-breadcrumb class="breadcrumb" separator="/">
<el-breadcrumb-item :to="{ name: 'admin' }">管理员</el-breadcrumb-item>
<el-breadcrumb-item>{{infoForm.id ? '编辑管理员' : '添加管理员'}}</el-breadcrumb-item>
</el-breadcrumb>
<div class="operation-nav">
<el-button type="primary" @click="goBackPage" icon="arrow-left">返回列表</el-button>
<!--<el-button type="primary" @click="testa" icon="arrow-left">测试</el-button>-->
</div>
</div>
<div class="content-main">
<div class="form-table-box">
<el-form ref="infoForm" :rules="infoRules" :model="infoForm" label-width="120px">
<el-form-item label="管理员用户名" prop="username">
<el-input v-model="infoForm.username"></el-input>
</el-form-item>
<el-form-item label="新密码" v-if="infoForm.id" prop="newpassword">
<el-switch
v-model="change"
active-color="#13ce66">
</el-switch>
</el-form-item>
<el-form-item label="" v-if="change" prop="newpassword">
<el-input type="password" v-model="infoForm.newpassword" placeholder="输入新的密码"></el-input>
</el-form-item>
<el-form-item label="密码" v-if="!infoForm.id" prop="password">
<el-input type="password" v-model="infoForm.password"></el-input>
</el-form-item>
<el-form-item>
<el-button v-if="infoForm.id > 0" type="primary" @click="saveAdminInfo"></el-button>
<el-button v-else type="primary" @click="addAdminInfo"></el-button>
<el-button @click="goBackPage"></el-button>
</el-form-item>
</el-form>
</div>
</div>
</div>
</template>
<script>
import api from '@/config/api';
export default {
data() {
return {
change:false,
infoForm: {
id: 0,
username: "",
newpassword: '',
password: ''
},
infoRules: {
username: [
{required: true, message: '请输入昵称', trigger: 'blur'},
],
password: [
{required: true, message: '请输入密码', trigger: 'blur'},
],
},
}
},
methods: {
testa() {
console.log(this.tableData);
console.log(this.infoForm);
},
goBackPage() {
this.$router.go(-1);
},
saveAdminInfo() {
let user = this.infoForm;
if(this.change == true){
let password = user.newpassword;
if(password == undefined){
user.newpassword = ''
}
if(password != undefined && password.replace(/(^\s*)|(\s*$)/g, "").length < 6){
this.$message({
type: 'error',
message: '密码请大于6个字符'
})
return false;
}
}
this.$refs['infoForm'].validate((valid) => {
if (valid) {
this.axios.post('admin/adminSave', {
user: user,
change:this.change,
}).then((response) => {
if (response.data.errno === 0) {
this.$message({
type: 'success',
message: '保存成功'
});
}
else if (response.data.errno === 400) {
this.$message({
type: 'error',
message: response.data.errmsg
});
}
else {
this.$message({
type: 'error',
message: '保存失败'
})
}
})
} else {
return false;
}
});
},
addAdminInfo() {
let user = this.infoForm;
let password = user.password;
if(password == undefined){
user.password = ''
}
if(password != undefined && password.replace(/(^\s*)|(\s*$)/g, "").length < 6){
this.$message({
type: 'error',
message: '密码请大于6个字符'
})
return false;
}
this.$refs['infoForm'].validate((valid) => {
if (valid) {
this.axios.post('admin/adminAdd', {
user: user,
}).then((response) => {
if (response.data.errno === 0) {
this.$message({
type: 'success',
message: '添加成功'
});
this.$router.push({ name: 'admin'} )
} else {
this.$message({
type: 'error',
message: '添加失败'
})
}
})
} else {
return false;
}
});
},
getInfo() {
//
let that = this
this.axios.post('admin/adminDetail', {
id: that.infoForm.id
}).then((response) => {
if (response.data.errno === 0) {
let resInfo = response.data.data;
that.infoForm = resInfo;
}
})
}
},
components: {},
mounted() {
this.infoForm.id = this.$route.query.id || 0;
console.log(this.infoForm.id);
this.getInfo();
}
}
</script>
<style>
.image-uploader {
height: 105px;
}
.image-uploader .el-upload {
border: 1px solid #d9d9d9;
cursor: pointer;
position: relative;
overflow: hidden;
}
.image-uploader .el-upload:hover {
border-color: #20a0ff;
}
.image-uploader .image-uploader-icon {
font-size: 28px;
color: #8c939d;
width: 187px;
height: 105px;
line-height: 105px;
text-align: center;
}
.image-uploader .image-show {
width: 187px;
height: 105px;
display: block;
}
.image-uploader.new-image-uploader {
font-size: 28px;
color: #8c939d;
width: 165px;
height: 105px;
line-height: 105px;
text-align: center;
}
.image-uploader.new-image-uploader .image-uploader-icon {
font-size: 28px;
color: #8c939d;
width: 165px;
height: 105px;
line-height: 105px;
text-align: center;
}
.image-uploader.new-image-uploader .image-show {
width: 165px;
height: 105px;
display: block;
}
</style>

@ -0,0 +1,95 @@
<template>
<div class="content-page">
<div class="content-nav">
<el-breadcrumb class="breadcrumb" separator="/">
<el-breadcrumb-item>管理员</el-breadcrumb-item>
</el-breadcrumb>
<!-- <div class="operation-nav">
<router-link to="/dashboard/user">
<el-button type="primary" icon="plus">添加管理员</el-button>
</router-link>
</div> -->
</div>
<div class="content-main">
<div class="form-table-box">
<el-table :data="tableData" style="width: 100%" border stripe>
<el-table-column prop="id" label="ID" width="60"></el-table-column>
<el-table-column prop="username" label="会员名称"></el-table-column>
<el-table-column prop="last_login_time" label="最近登录" width="200"></el-table-column>
<el-table-column prop="last_login_ip" label="登录IP" width="200"></el-table-column>
<el-table-column label="操作" width="180">
<template slot-scope="scope">
<el-button size="small" @click="handleRowEdit(scope.$index, scope.row)">编辑</el-button>
<el-button v-if="scope.row.id != loginInfo.id" plain size="small" type="danger" @click="handleRowDelete(scope.$index, scope.row)"></el-button>
</template>
</el-table-column>
</el-table>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
page: 1,
total: 0,
filterForm: {
username: ''
},
tableData: [],
loginInfo:null,
}
},
methods: {
handleRowEdit(index, row) {
this.$router.push({ name: 'admin_add', query: { id: row.id } })
},
handleRowDelete(index, row) {
console.log(row);
this.$confirm('确定要删除?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
this.axios.post('admin/deleAdmin', { id: row.id }).then((response) => {
console.log(response.data);
if (response.data.errno === 0) {
this.$message({
type: 'success',
message: '删除成功!'
});
this.getList();
}
})
});
},
onSubmitFilter() {
this.page = 1
this.getList()
},
getList() {
this.axios.get('admin').then((response) => {
this.tableData = response.data.data;
console.log(this.tableData);
})
}
},
components: {
},
mounted() {
this.getList();
if(!this.loginInfo){
this.loginInfo = JSON.parse(window.localStorage.getItem('userInfo') || null);
}
}
}
</script>
<style scoped>
</style>

@ -0,0 +1,320 @@
<template>
<div class="content-page">
<div class="content-nav">
<el-breadcrumb class="breadcrumb" separator="/">
<el-breadcrumb-item :to="{ name: 'nature' }"
>商品设置</el-breadcrumb-item
>
<el-breadcrumb-item>{{
infoForm.id ? "编辑分类" : "添加分类"
}}</el-breadcrumb-item>
</el-breadcrumb>
<div class="operation-nav">
<el-button type="primary" @click="goBackPage" icon="arrow-left"
>返回列表</el-button
>
</div>
</div>
<div class="content-main">
<div class="form-table-box">
<el-form
ref="infoForm"
:rules="infoRules"
:model="infoForm"
label-width="120px"
>
<!-- <el-form-item label="上级分类" prop="name">
<el-select v-model="infoForm.parent_id" placeholder="请选择上级分类">
<el-option v-for="item in parentCategory" :key="item.id" :label="item.name"
:value="item.id"></el-option>
</el-select>
</el-form-item> -->
<el-form-item label="分类名称" prop="name">
<el-input v-model="infoForm.name"></el-input>
</el-form-item>
<el-form-item label="简短介绍">
<el-input
type="textarea"
v-model="infoForm.front_name"
:rows="1"
></el-input>
<div class="form-tip"></div>
</el-form-item>
<el-form-item
label="分类图片"
prop="img_url"
v-if="infoForm.parent_id == 0"
>
<img
v-if="infoForm.img_url"
:src="infoForm.img_url"
class="image-show"
/>
<el-upload
class="upload-demo"
name="file"
:action="qiniuZone"
:on-remove="bannerRemove"
:before-remove="beforeBannerRemove"
:file-list="fileList"
:on-success="handleUploadBannerSuccess"
:data="picData"
:before-upload="getQiniuToken"
>
<el-button v-if="!infoForm.img_url" size="small" type="primary"
>点击上传</el-button
>
</el-upload>
<div class="form-tip">
图片尺寸顶级分类为690*自定义, 只能上传jpg/png文件
</div>
</el-form-item>
<el-form-item
label="分类图片高度"
prop="name"
v-if="infoForm.parent_id == 0"
>
<el-input v-model="infoForm.p_height"></el-input>
</el-form-item>
<el-form-item
label="图标"
prop="icon_url"
v-if="infoForm.parent_id == 0"
>
<img
v-if="infoForm.icon_url"
:src="infoForm.icon_url"
class="image-show"
/>
<el-upload
class="upload-demo"
name="file"
:action="qiniuZone"
:on-remove="iconRemove"
:before-remove="beforeIconRemove"
:file-list="fileList2"
:data="picData"
:on-success="handleUploadIconSuccess"
:before-upload="getQiniuToken"
>
<el-button v-if="!infoForm.icon_url" size="small" type="primary"
>点击上传</el-button
>
</el-upload>
<div class="form-tip">
图片尺寸图标250*250, 只能上传jpg/png文件
</div>
</el-form-item>
<el-form-item label="排序">
<el-input-number
v-model="infoForm.sort_order"
:min="1"
:max="1000"
></el-input-number>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="onSubmitInfo"></el-button>
<el-button @click="goBackPage"></el-button>
</el-form-item>
</el-form>
</div>
</div>
</div>
</template>
<script>
import api from "@/config/api";
export default {
data() {
return {
root: "",
qiniuZone: "",
fileList: [],
fileList2: [],
parentCategory: [
{
id: 0,
name: "顶级分类",
},
],
infoForm: {
id: 0,
name: "",
parent_id: 0,
front_name: "",
img_url: "",
sort_order: 100,
icon_url: "",
// is_show: true,
},
infoRules: {
name: [{ required: true, message: "请输入名称", trigger: "blur" }],
front_name: [
{ required: true, message: "请输入简介", trigger: "blur" },
],
img_url: [
{ required: true, message: "请选择分类图片", trigger: "blur" },
],
icon_url: [
{ required: true, message: "请选择分类图标", trigger: "blur" },
],
},
picData: {
token: "",
},
url: "",
};
},
methods: {
getQiniuToken() {
let that = this;
this.axios.post("index/getQiniuToken").then((response) => {
let resInfo = response.data.data;
console.log(resInfo);
that.picData.token = resInfo.token;
that.url = resInfo.url;
});
},
beforeBannerRemove(file, fileList) {
return this.$confirm(`确定移除该图?删除后将无法找回`);
},
beforeIconRemove(file, fileList) {
return this.$confirm(`确定移除图标?删除后将无法找回`);
},
bannerRemove(file, fileList) {
this.infoForm.img_url = "";
let id = this.infoForm.id;
this.axios
.post("category/deleteBannerImage", { id: id })
.then((response) => {
this.$message({
type: "success",
message: "删除成功",
});
});
},
iconRemove(file, fileList) {
this.infoForm.icon_url = "";
let id = this.infoForm.id;
this.axios
.post("category/deleteIconImage", { id: id })
.then((response) => {
this.$message({
type: "success",
message: "删除成功",
});
});
},
goBackPage() {
this.$router.go(-1);
},
onSubmitInfo() {
this.infoForm.level = this.infoForm.parent_id == 0 ? "L1" : "L2";
console.log(this.infoForm.level);
this.$refs["infoForm"].validate((valid) => {
if (valid) {
this.axios.post("category/store", this.infoForm).then((response) => {
if (response.data.errno === 0) {
this.$message({
type: "success",
message: "保存成功",
});
this.$router.go(-1);
} else {
this.$message({
type: "error",
message: "保存失败",
});
}
});
} else {
return false;
}
});
},
handleUploadBannerSuccess(res, file) {
let url = this.url;
this.infoForm.img_url = url + res.key;
},
handleUploadIconSuccess(res, file) {
let url = this.url;
this.infoForm.icon_url = url + res.key;
},
getTopCategory() {
this.axios.get("category/topCategory").then((response) => {
this.parentCategory = this.parentCategory.concat(response.data.data);
});
},
getInfo() {
if (this.infoForm.id <= 0) {
return false;
}
//
let that = this;
this.axios
.get("category/info", {
params: {
id: that.infoForm.id,
},
})
.then((response) => {
let resInfo = response.data.data;
console.log(resInfo);
let data = {
name: "分类图",
url: resInfo.img_url,
};
this.fileList.push(data);
let iconData = {
name: "图标",
url: resInfo.icon_url,
};
this.fileList2.push(iconData);
that.infoForm = resInfo;
});
},
},
mounted() {
this.getTopCategory();
this.infoForm.id = this.$route.query.id || 0;
this.getInfo();
this.root = api.rootUrl;
this.qiniuZone = api.qiniu;
this.getQiniuToken();
},
};
</script>
<style scoped>
.image-uploader {
height: 105px;
}
.image-uploader .el-upload {
border: 1px solid #d9d9d9;
cursor: pointer;
position: relative;
overflow: hidden;
}
.image-uploader .el-upload:hover {
border-color: #20a0ff;
}
.image-uploader .image-uploader-icon {
font-size: 28px;
color: #8c939d;
min-width: 105px;
height: 105px;
line-height: 105px;
text-align: center;
}
.image-show {
background-color: #f8f8f8;
min-width: 105px;
height: 105px;
display: block;
}
</style>

@ -0,0 +1,189 @@
<template>
<div class="content-page">
<div class="content-nav">
<el-breadcrumb class="breadcrumb" separator="/">
<el-breadcrumb-item :to="{ path: '/dashboard/nature' }">商品设置</el-breadcrumb-item>
<el-breadcrumb-item>商品分类</el-breadcrumb-item>
</el-breadcrumb>
<div class="operation-nav">
<router-link to="/dashboard/category/add">
<el-button type="primary" icon="plus">添加分类</el-button>
</router-link>
</div>
</div>
<div class="content-main">
<div class="form-table-box">
<el-table :data="tableData" style="width: 100%" border stripe>
<el-table-column prop="name" label="分类名称">
<template slot-scope="scope">
<div v-if="scope.row.level==1" class="bg-gray">{{scope.row.name}}</div>
<div v-if="scope.row.level==2" class="bg-left">{{scope.row.name}}</div>
<!-- {{ scope.row.level == 2 ? ' ' : '' }} {{scope.row.name}} -->
</template>
</el-table-column>
<el-table-column label="图标显示" width="80">
<template slot-scope="scope">
<el-switch
v-model="scope.row.is_channel"
active-text=""
inactive-text=""
@change='changeChannelStatus($event,scope.row.id)'>
</el-switch>
</template>
</el-table-column>
<el-table-column label="首页显示" width="80">
<template slot-scope="scope">
<el-switch
v-model="scope.row.is_show"
active-text=""
inactive-text=""
@change='changeShowStatus($event,scope.row.id)'>
</el-switch>
</template>
</el-table-column>
<el-table-column label="全部产品页面显示" width="140">
<template slot-scope="scope">
<el-switch
v-model="scope.row.is_category"
active-text=""
inactive-text=""
@change='changeCategoryStatus($event,scope.row.id)'>
</el-switch>
</template>
</el-table-column>
<el-table-column prop="sort_order" label="排序" width="100" sortable>
<template slot-scope="scope">
<el-input v-model="scope.row.sort_order" placeholder="排序" @blur="submitSort(scope.$index, scope.row)"></el-input>
</template>
</el-table-column>
<el-table-column label="操作" width="300">
<template slot-scope="scope">
<el-button size="small" @click="handleRowEdit(scope.$index, scope.row)">编辑</el-button>
<el-button size="small" type="danger" @click="handleRowDelete(scope.$index, scope.row)">删除
</el-button>
</template>
</el-table-column>
</el-table>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
page: 1,
total: 0,
filterForm: {
name: ''
},
tableData: []
}
},
methods: {
changeShowStatus($event, para) {
this.axios.get('category/showStatus', {
params: {
status: $event,
id: para
}
}).then((response) => {
})
},
changeChannelStatus($event, para) {
this.axios.get('category/channelStatus', {
params: {
status: $event,
id: para
}
}).then((response) => {
})
},
changeCategoryStatus($event, para) {
this.axios.get('category/categoryStatus', {
params: {
status: $event,
id: para
}
}).then((response) => {
})
},
submitSort(index, row){
this.axios.post('category/updateSort', { id: row.id,sort:row.sort_order }).then((response) => {
})
},
handleRowEdit(index, row) {
this.$router.push({name: 'category_add', query: {id: row.id}})
},
handleRowDelete(index, row) {
this.$confirm('确定要删除?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
this.axios.post('category/destory', {id: row.id}).then((response) => {
console.log(response.data)
if (response.data.errno === 0) {
this.$message({
type: 'success',
message: '删除成功!'
});
this.getList();
}
else {
this.$message({
type: 'error',
message: '删除失败,该分类有子分类!'
});
}
})
});
},
onSubmitFilter() {
this.page = 1
this.getList()
},
getList() {
this.axios.get('category', {
params: {
page: this.page,
name: this.filterForm.name
}
}).then((response) => {
this.tableData = response.data.data
})
}
},
components: {},
mounted() {
this.getList();
}
}
</script>
<style scoped>
.sub-category .el-table__expanded-cell {
padding: 0;
}
.bg-gray {
/* background:gray; */
color: red;
font-weight: bold;
}
.bg-left {
margin-left: 30px;
}
</style>

@ -0,0 +1,83 @@
<template>
<span :endTime="endTime" :callback="callback" :endText="endText">
<slot>
{{content}}
</slot>
</span>
</template>
<script>
export default {
data() {
return {
content: '',
endTime:'',
}
},
props: {
// endTime: {
// type: String,
// default: ''
// },
endText: {
type: String,
default: '已结束'
},
callback: {
type: Function,
default: ''
}
},
mounted() {
this.getInfo();
},
methods: {
getInfo() {
this.axios.get('index',).then((response) => {
console.log(response);
this.infoData = response.data.data;
let time = response.data.data.timestamp;
this.endTime = time.toString();
this.countdowm(this.endTime)
})
},
countdowm(timestamp) {
let self = this;
let timer = setInterval(function () {
let nowTime = new Date();
let endTime = new Date(timestamp * 1000);
let t = endTime.getTime() - nowTime.getTime() - 10;
if (t > 0) {
let day = Math.floor(t / 86400000);
let hour = Math.floor((t / 3600000) % 24);
let min = Math.floor((t / 60000) % 60);
let sec = Math.floor((t / 1000) % 60);
hour = hour < 10 ? "0" + hour : hour;
min = min < 10 ? "0" + min : min;
sec = sec < 10 ? "0" + sec : sec;
let format = '';
if (day > 0) {
format = `${day}${hour}小时${min}${sec}`;
}
if (day <= 0 && hour > 0) {
format = `${hour}小时${min}${sec}`;
}
if (day <= 0 && hour <= 0) {
format = `${min}${sec}`;
}
self.content = format;
} else {
clearInterval(timer);
self.content = self.endText;
self._callback();
}
}, 1000);
},
_callback() {
if (this.callback && this.callback instanceof Function) {
this.callback();
}
}
}
}
</script>

@ -0,0 +1,84 @@
<template>
<div class="right-box">
<div class="navbar">
<div class="menu">
<div class="menu-item">
<i class="fa fa-sign-out" @click="logout"></i>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {}
},
methods: {
logout() {
this.$confirm('是否要退出?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
localStorage.clear();
this.$router.replace({name: 'login'});
});
}
}
}
</script>
<style scoped>
.right-box {
background: #112233;
height: 60px;
display: block;
position: fixed;
top: 0;
left: 200px;
z-index: 5;
float: left;
width: calc(100% - 200px);
overflow: hidden;
-webkit-box-shadow: 0 1px 8px rgba(0,21,41,.08);
box-shadow: 2px 6px 8px rgba(0,21,41,.08);
}
.fa:hover{
cursor:pointer
}
/*.fa-sign-out{*/
/*color:#000000;*/
/*}*/
/*.fa-user{*/
/*color:#000000;*/
/*}*/
.navbar {
height: 60px;
/*background: #fff;*/
display: flex;
width: 100%;
justify-content: center;
flex-direction: row;
}
.navbar .menu {
flex: 1;
margin-top: 15px;
height: 40px;
display: flex;
justify-content: flex-end;
}
.navbar .menu-item {
margin: 0 15px;
height: 30px;
line-height: 30px;
text-align: center;
font-size: 20px;
color: #fff;
}
</style>

@ -0,0 +1,187 @@
<template>
<div class="left-box">
<div class="logo">
<img src="static/images/loading.gif" />
</div>
<div class="a" style="overflow-x: hidden; overflow-y: auto; height: 100%">
<el-menu
class="sidebar"
:unique-opened="true"
:default-active="currentPagePath"
@open="handleOpen"
:router="true"
@close="handleClose"
>
<el-menu-item index="/dashboard/welcome">
<i class="fa fa-tachometer"></i>
<span>后台主页</span>
</el-menu-item>
<el-menu-item index="/dashboard/order">
<i class="fa fa-large fa-reorder"></i>
<span>订单列表</span>
</el-menu-item>
<el-submenu index="goods">
<template slot="title">
<i class="fa fa-shopping-bag"></i>
<span>商品管理</span>
</template>
<el-menu-item index="/dashboard/goods">
<i class="fa fa-circle"></i>
<span>商品列表</span>
</el-menu-item>
<el-menu-item index="/dashboard/nature">
<i class="fa fa-circle"></i>
<span>商品设置</span>
</el-menu-item>
</el-submenu>
<el-menu-item index="/dashboard/shopcart">
<i class="fa fa-large fa-shopping-cart"></i>
<span>购物车</span>
</el-menu-item>
<el-menu-item index="/dashboard/user">
<i class="fa fa-large fa-users"></i>
<span>用户列表</span>
</el-menu-item>
<el-submenu index="settings">
<template slot="title">
<i class="fa fa-large fa-wrench"></i>
<span>店铺设置</span>
</template>
<el-menu-item index="/dashboard/settings/showset">
<i class="fa fa-circle"></i>
<span>显示设置</span>
</el-menu-item>
<el-menu-item index="/dashboard/ad">
<i class="fa fa-circle"></i>
<span>广告列表</span>
</el-menu-item>
<el-menu-item index="/dashboard/notice">
<i class="fa fa-circle"></i>
<span>公告管理</span>
</el-menu-item>
<el-menu-item index="/dashboard/freight">
<i class="fa fa-circle"></i>
<span>运费模板</span>
</el-menu-item>
<el-menu-item index="/dashboard/shipper">
<i class="fa fa-circle"></i>
<span>快递设置</span>
</el-menu-item>
<el-menu-item index="/dashboard/admin">
<i class="fa fa-circle"></i>
<span>管理员</span>
</el-menu-item>
</el-submenu>
<el-menu-item @click="logout">
<i class="fa fa-large fa-sign-out"></i>
<span>退出</span>
</el-menu-item>
</el-menu>
</div>
</div>
</template>
<script>
export default {
data() {
return {
currentPagePath: "/dashboard",
loginInfo: null,
};
},
methods: {
handleOpen(key, keyPath) {
console.log(key, keyPath);
},
handleClose(key, keyPath) {
console.log(key, keyPath);
},
logout() {
this.$confirm("是否要退出?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning",
}).then(() => {
localStorage.clear();
this.$router.replace({ name: "login" });
});
},
checkLogin() {
this.axios.get("index/checkLogin").then((response) => {
console.log(response.data);
if (response.data.errno === 401) {
localStorage.clear();
this.$router.replace({ name: "login" });
}
});
},
},
mounted() {
console.log(this.$route.path);
this.checkLogin();
if (!this.loginInfo) {
this.loginInfo = JSON.parse(
window.localStorage.getItem("userInfo") || null
);
}
},
};
</script>
<style>
.left-box {
width: 200px;
display: flex;
position: fixed;
top: 0;
left: 0;
z-index: 5;
height: 100%;
float: left;
flex-direction: column;
background: #fff;
}
.left-box .sidebar {
width: 200px;
flex: 1;
border-radius: 0;
/*background: #233445;*/
}
.left-box .fa {
margin-right: 10px;
font-size: 18px;
/*color: #ccc;*/
}
.left-box span {
/*color: #ccc;*/
}
.left-box .el-submenu .el-menu-item .fa {
margin-right: 10px;
font-size: 10px;
}
/*渐变背景*/
.back {
background: -webkit-linear-gradient(138deg, #8731e8 0%, #4528dc 100%);
background: -o-linear-gradient(138deg, #8731e8 0%, #4528dc 100%);
background: linear-gradient(-48deg, #8731e8 0%, #4528dc 100%);
opacity: 0.7;
}
.left-box .logo {
display: flex;
justify-content: center;
align-items: center;
height: 120px;
width: 200px;
border-right: solid 1px #e6e6e6;
/*box-shadow: 0 1px 1px rgba(0, 0, 0, .5);*/
}
.left-box .logo img {
height: 60px;
}
</style>

@ -0,0 +1,61 @@
<style scoped>
body {
background: #f5f7fa;
display: block;
}
.container {
height: 100%;
width: 100%;
}
.content {
box-sizing: border-box;
padding: 20px 20px 20px 220px;
min-height: 700px;
overflow: auto;
}
.footer {
margin-top: 10px;
text-align: center;
line-height: 30px;
color: #999;
display: block;
}
</style>
<template>
<div class="container">
<sidebar></sidebar>
<!-- <navbar></navbar> -->
<div class="content">
<transition name="router-fade" mode="out-in">
<router-view></router-view>
</transition>
</div>
</div>
</template>
<script>
import Sidebar from './Common/Sidebar';
import Navbar from './Common/Navbar';
export default {
data() {
return {
}
},
components: {
Sidebar,
Navbar
},
methods: {
handleOpen(key, keyPath) {
console.log(key, keyPath);
},
handleClose(key, keyPath) {
console.log(key, keyPath);
}
},
}
</script>

@ -0,0 +1,309 @@
<template>
<div class="content-page">
<div class="content-nav">
<el-breadcrumb class="breadcrumb" separator="/">
<el-breadcrumb-item :to="{ name: 'freight' }">运费模板</el-breadcrumb-item>
<el-breadcrumb-item>{{infoForm.id ? '编辑偏远地区' : '添加偏远地区'}}</el-breadcrumb-item>
</el-breadcrumb>
<div class="operation-nav">
<el-button type="primary" @click="goBackPage" icon="arrow-left">返回列表</el-button>
</div>
</div>
<div class="content-main">
<div class="form-table-box">
<el-form ref="infoForm" :rules="infoRules" :model="infoForm" label-width="120px">
<el-form-item label="名称" prop="content">
<el-input v-model="infoForm.content" placeholder="请输入名称" autofocus></el-input>
</el-form-item>
<el-form-item class="special-freight">
<div class="form-table-box">
<el-table :data="tableData" style="width: 100%" border stripe>
<el-table-column prop="areaName" label="偏远地区"></el-table-column>
<el-table-column label="操作" width="160">
<template slot-scope="scope">
<el-button size="small" type="primary" plain
@click="handleRowEdit(scope.$index, scope.row)">编辑地区
</el-button>
</template>
</el-table-column>
</el-table>
</div>
<!--<div class="add-btn" v-if="tableData.length == 0">-->
<!--<el-button type="text" @click="add_template">+</el-button>-->
<!--</div>-->
</el-form-item>
<el-form-item>
<el-button v-if="infoForm.id" type="primary" @click="onSaveTemplate"></el-button>
<el-button v-else type="primary" @click="onAddTemplate"></el-button>
<el-button @click="goBackPage"></el-button>
<!--<el-button @click="testCallBack"></el-button>-->
</el-form-item>
</el-form>
</div>
</div>
<el-dialog size="tiny" title="设置偏远地区" :visible.sync="specEditVisible">
<el-form ref="specForm" class="specFormDialig">
<el-form-item label="" label-width="100px">
<el-transfer v-model="selectedArea" :props="{key: 'id',label: 'name'}"
:data="areaData" :titles="['可选', '已选']"></el-transfer>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="specEditVisible = false"> </el-button>
<el-button type="primary" @click="updateArea"></el-button>
<!--<el-button type="primary" @click="updateSpec" v-if="!is_spec_add"></el-button>-->
</div>
</el-dialog>
</div>
</template>
<script>
import api from '@/config/api';
export default {
data() {
return {
areaData: [],
selectedArea: [],
specEditVisible: false,
infoForm: {
id: 0,
content: ''
},
infoRules: {
content: [
{required: true, message: '请输入名称', trigger: 'blur'},
],
},
tableData: [{
area: '',
ghost: 0
}],
}
},
methods: {
testCallBack() {
console.log(this.tableData);
},
updateArea() {
let all = this.areaData;
let selected = this.selectedArea;
selected = selected.join(',')
this.tableData[0].area = selected;
let areaName = this.selectedArea;
let newName = [];
for (const item in areaName) {
all.map((ele) => ele.id == areaName[item] ? newName.push(ele.name) : '')
}
let that = this;
let name = newName.join(',');
that.tableData = [];
that.tableData.push({
area: selected,
areaName: name
})
// console.log(this.tableData[index].areaName);
that.specEditVisible = false;
},
onSaveTemplate() {
this.$refs['infoForm'].validate((valid) => {
if (valid) {
let data = this.tableData[0];
if (data.area == '') {
this.$message({
type: 'error',
message: '地区不能为空'
})
return false;
}
let that = this;
this.axios.post('shipper/saveExceptArea', {
table: that.tableData,
info: that.infoForm
}).then((response) => {
if (response.data.errno === 0) {
this.$message({
type: 'success',
message: '保存成功'
});
that.getInfo();
} else {
this.$message({
type: 'error',
message: '保存失败'
})
}
})
} else {
return false;
}
});
},
onAddTemplate() {
console.log('哈哈哈');
this.$refs['infoForm'].validate((valid) => {
if (valid) {
let data = this.tableData[0];
if (data.area == '') {
this.$message({
type: 'error',
message: '地区不能为空'
})
return false;
}
let that = this;
this.axios.post('shipper/addExceptArea', {
table: that.tableData,
info: that.infoForm
}).then((response) => {
if (response.data.errno === 0) {
this.$message({
type: 'success',
message: '添加成功'
});
this.$router.go(-1);
} else {
this.$message({
type: 'error',
message: '添加失败'
})
}
})
} else {
return false;
}
});
},
test() {
console.log(this.defaultData);
},
goBackPage() {
this.$router.go(-1);
},
getAllAreaData() {
let that = this;
this.axios.post('shipper/getareadata').then((response) => {
if (response.data.errno === 0) {
that.areaData = response.data.data;
}
})
},
handleRowEdit(index, row) {
let nowArea = this.tableData[0].area;
this.selectedArea = nowArea.split(',').map(Number);
let area = nowArea;
area = area.split(',');
let all = this.areaData;
this.specEditVisible = true;
},
getInfo() {
if (this.infoForm.id <= 0) {
return false
}
//
let that = this
this.axios.post('shipper/exceptAreaDetail', {
id: that.infoForm.id
}).then((response) => {
// console.log(response.data.data);
let info = response.data.data;
that.infoForm = info;
that.tableData = [{
area: info.area,
areaName: info.areaName
}]
// that.tableData = response.data.data.data;
})
}
},
components: {},
mounted() {
this.infoForm.id = this.$route.query.id || 0;
// console.log(this.infoForm.id);
this.getInfo();
this.getAllAreaData();
}
}
</script>
<style scoped>
.number_input {
width: 90px;
}
.money_input {
width: 100px;
}
.el-form-item__content {
display: flex;
justify-content: flex-start;
}
.line-wrap {
display: flex;
justify-content: flex-start;
}
.default-freight .el-input {
width: 130px;
float: left;
}
.default-freight .el-input .el-input__inner {
width: 100px;
}
.default-freight .line {
display: flex;
justify-content: flex-start;
border-right: 1px solid #f1f1f1;
/*padding-right: 40px;*/
margin-right: 40px;
}
.default-freight .line2 {
display: flex;
justify-content: flex-start;
}
.default-freight .text {
width: 60px;
float: left;
margin-left: 10px;
}
.default-freight .text2 {
width: 50px;
float: left;
/*margin: 10px;*/
}
.float-right {
float: right;
}
.add-btn {
color: #3a8ee6;
font-size: 14px;
padding: 20px;
border: 1px solid #f1f1f1;
border-top: none;
display: flex;
justify-content: space-between;
}
</style>

@ -0,0 +1,165 @@
<template>
<div class="content-page">
<div class="content-nav">
<el-breadcrumb class="breadcrumb" separator="/">
<el-breadcrumb-item :to="{ name: 'freight' }">运费模板</el-breadcrumb-item>
<el-breadcrumb-item>偏远地区</el-breadcrumb-item>
</el-breadcrumb>
<div class="operation-nav">
<el-button type="primary" plain @click="addExceptArea" icon="arrow-left">添加偏远地区</el-button>
<el-button type="primary" @click="goBackPage" icon="arrow-left">返回</el-button>
</div>
</div>
<div class="content-main">
<div class="form-table-box">
<div class="form-table-box">
<el-table :data="tableData" style="width: 100%" border stripe>
<el-table-column prop="id" label="ID" width="100px"></el-table-column>
<el-table-column prop="content" label="名称" width="200px"></el-table-column>
<el-table-column prop="areaName" label="偏远地区"></el-table-column>
<el-table-column label="操作" width="200">
<template slot-scope="scope">
<el-button type="primary" size="small" plain
@click="handleRowEdit(scope.$index, scope.row)">编辑
</el-button>
<el-button size="small"
@click="handleRowDelete(scope.$index, scope.row)"
type="danger" plain>
删除
</el-button>
</template>
</el-table-column>
</el-table>
</div>
</div>
</div>
</div>
</template>
<script>
import api from '@/config/api';
export default {
data() {
return {
value: true,
nowTableIndex: 0,
areaData: [],
selectedArea: [],
hiddenSelectedArea: [],
specEditVisible: false,
tableData: [],
}
},
methods: {
goBackPage() {
this.$router.go(-1);
},
addExceptArea(){
this.$router.push({name: 'except_area_add'});
},
handleRowEdit(index, row) {
this.$router.push({ name: 'except_area_add', query: { id: row.id } })
},
handleRowDelete(index, row) {
this.$confirm('确定要删除?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
this.axios.post('shipper/exceptAreaDelete', {id: row.id}).then((response) => {
console.log(response.data)
if (response.data.errno === 0) {
this.$message({
type: 'success',
message: '删除成功!'
});
this.getInfo();
}
})
});
},
getInfo() {
let that = this;
this.axios.get('shipper/exceptarea').then((response) => {
that.tableData = response.data.data;
})
}
},
components: {},
mounted() {
this.getInfo();
}
}
</script>
<style scoped>
.number_input {
width: 90px;
}
.money_input {
width: 100px;
}
.el-form-item__content {
display: flex;
justify-content: flex-start;
}
.line-wrap {
display: flex;
justify-content: flex-start;
}
.default-freight .el-input {
width: 130px;
float: left;
}
.default-freight .el-input .el-input__inner {
width: 100px;
}
.default-freight .line {
display: flex;
justify-content: flex-start;
border-right: 1px solid #f1f1f1;
/*padding-right: 40px;*/
margin-right: 40px;
}
.default-freight .line2 {
display: flex;
justify-content: flex-start;
}
.default-freight .text {
width: 60px;
float: left;
margin-left: 10px;
}
.default-freight .text2 {
width: 50px;
float: left;
/*margin: 10px;*/
}
.float-right {
float: right;
}
.add-btn {
color: #3a8ee6;
font-size: 14px;
padding: 20px;
border: 1px solid #f1f1f1;
border-top: none;
display: flex;
justify-content: space-between;
}
</style>

@ -0,0 +1,691 @@
<template>
<div class="content-page">
<div class="content-nav">
<el-breadcrumb class="breadcrumb" separator="/">
<el-breadcrumb-item :to="{ name: 'freight' }">运费模板</el-breadcrumb-item>
<el-breadcrumb-item>{{infoForm.id ? '编辑模板' : '添加模板'}}</el-breadcrumb-item>
</el-breadcrumb>
<div class="operation-nav">
<el-button type="primary" @click="goBackPage" icon="arrow-left">返回列表</el-button>
<!--<el-button type="primary" @click="test" icon="arrow-left">测试</el-button>-->
</div>
</div>
<div class="content-main">
<div class="form-table-box">
<el-form ref="infoForm" :rules="infoRules" :model="infoForm" label-width="120px">
<el-form-item label="模板名字" prop="name">
<el-input v-model="infoForm.name" placeholder="请输入模板名称" autofocus></el-input>
</el-form-item>
<el-form-item label="包装费用">
<el-input v-model="infoForm.package_price"></el-input>
</el-form-item>
<el-form-item label="快递收费方式">
<el-radio-group v-model="infoForm.freight_type">
<el-radio :label="0">按件计费</el-radio>
<el-radio :label="1">按重量计费</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="默认运费" class="default-freight">
<!--<div class="line-wrap">-->
<!--<div class="line">-->
<!--<el-input v-model="defaultData.start"></el-input>-->
<!--<div class="text">{{infoForm.freight_type == 0?'件内':'KG内'}}</div>-->
<!--<el-input v-model="defaultData.start_fee"></el-input>-->
<!--<div class="text"></div>-->
<!--</div>-->
<!--<div class="line2">-->
<!--<div class="text2">每增加</div>-->
<!--<el-input v-model="defaultData.add"></el-input>-->
<!--<div class="text">{{infoForm.freight_type == 0?'件':'KG'}}</div>-->
<!--<div class="text2">增加</div>-->
<!--<el-input v-model="defaultData.add_fee"></el-input>-->
<!--<div class="text"></div>-->
<!--</div>-->
<!--</div>-->
<div class="form-table-box">
<el-table :data="defaultData" style="width: 100%" border stripe>
<el-table-column prop="start" :label="infoForm.freight_type == 0?'首件(个)':'首重(KG)'"
>
<template slot-scope="scope">
<el-input size="mini" v-model="scope.row.start" placeholder="个"
@blur="submitValue(scope.$index, scope.row.start)"
autofocus></el-input>
</template>
</el-table-column>
<el-table-column prop="start_fee" label="运费(元)">
<template slot-scope="scope">
<el-input size="mini" v-model="scope.row.start_fee" placeholder="运费"
@blur="submitValue(scope.$index, scope.row.start_fee)"></el-input>
</template>
</el-table-column>
<el-table-column prop="add" :label="infoForm.freight_type == 0?'续件(个)':'续重(KG)'"
>
<template slot-scope="scope">
<el-input size="mini" v-model="scope.row.add" placeholder="个"
@blur="submitValue(scope.$index, scope.row.add)"></el-input>
</template>
</el-table-column>
<el-table-column prop="add_fee" label="运费(元)">
<template slot-scope="scope">
<el-input size="mini" v-model="scope.row.add_fee" placeholder="运费"
@blur="submitValue(scope.$index, scope.row.add_fee)"></el-input>
</template>
</el-table-column>
<el-table-column prop="free_by_number" label="按件包邮" width="140">
<template slot-scope="scope">
<el-switch v-if="scope.row.free_by_number == 0"
v-model="scope.row.freeByNumber"
active-color="#13ce66"
@change="changeDefaultNumberSwitch(scope.$index, scope.row)">
</el-switch>
<el-input-number v-if="scope.row.free_by_number > 0" class="number_input"
:min="0" :max="99999" controls-position="right" size="mini"
v-model="scope.row.free_by_number" placeholder="件"
@blur="changeDefaultNumberInput(scope.$index, scope.row.free_by_number)"
@change="changeDefaultNumberInput(scope.$index, scope.row.free_by_number)"
></el-input-number>
</template>
</el-table-column>
<el-table-column prop="free_by_money" label="按金额包邮" width="140">
<template slot-scope="scope">
<el-switch v-if="scope.row.free_by_money == 0"
v-model="scope.row.freeByMoney"
active-color="#13ce66"
@change="changeDefaultMoneySwitch(scope.$index, scope.row)">
</el-switch>
<el-input-number v-if="scope.row.free_by_money > 0" class="money_input" :min="0"
:max="99999"
controls-position="right" size="mini"
v-model="scope.row.free_by_money" placeholder="金额"
@blur="changeDefaultMoneyInput(scope.$index, scope.row.free_by_money)"
@change="changeDefaultMoneyInput(scope.$index, scope.row.free_by_money)"
></el-input-number>
</template>
</el-table-column>
</el-table>
</div>
</el-form-item>
<el-form-item label="指定区域运费" class="special-freight">
<div class="form-table-box">
<el-table :data="tableData" style="width: 100%" border stripe>
<el-table-column prop="areaName" label="运送到"></el-table-column>
<el-table-column prop="start" :label="infoForm.freight_type == 0?'首件(个)':'首重(KG)'"
width="90">
<template slot-scope="scope">
<el-input size="mini" v-model="scope.row.start" placeholder="个"
@blur="submitValue(scope.$index, scope.row.start)"
autofocus></el-input>
</template>
</el-table-column>
<el-table-column prop="start_fee" label="运费(元)" width="90">
<template slot-scope="scope">
<el-input size="mini" v-model="scope.row.start_fee" placeholder="运费"
@blur="submitValue(scope.$index, scope.row.start_fee)"></el-input>
</template>
</el-table-column>
<el-table-column prop="add" :label="infoForm.freight_type == 0?'续件(个)':'续重(KG)'"
width="90">
<template slot-scope="scope">
<el-input size="mini" v-model="scope.row.add" placeholder="个"
@blur="submitValue(scope.$index, scope.row.add)"></el-input>
</template>
</el-table-column>
<el-table-column prop="add_fee" label="运费(元)" width="90">
<template slot-scope="scope">
<el-input size="mini" v-model="scope.row.add_fee" placeholder="运费"
@blur="submitValue(scope.$index, scope.row.add_fee)"></el-input>
</template>
</el-table-column>
<el-table-column prop="free_by_number" label="按件包邮" width="120">
<template slot-scope="scope">
<el-switch v-if="scope.row.free_by_number == 0"
v-model="scope.row.freeByNumber"
active-color="#13ce66"
@change="changeNumberSwitch(scope.$index, scope.row)">
</el-switch>
<el-input-number v-if="scope.row.free_by_number > 0" class="number_input"
:min="0" :max="99999" controls-position="right" size="mini"
v-model="scope.row.free_by_number" placeholder="件"
@blur="changeNumberInput(scope.$index, scope.row.free_by_number)"
@change="changeNumberInput(scope.$index, scope.row.free_by_number)"
></el-input-number>
</template>
</el-table-column>
<el-table-column prop="free_by_money" label="按金额包邮" width="120">
<template slot-scope="scope">
<el-switch v-if="scope.row.free_by_money == 0"
v-model="scope.row.freeByMoney"
active-color="#13ce66"
@change="changeMoneySwitch(scope.$index, scope.row)">
</el-switch>
<el-input-number v-if="scope.row.free_by_money > 0" class="money_input" :min="0"
:max="99999"
controls-position="right" size="mini"
v-model="scope.row.free_by_money" placeholder="金额"
@blur="changeMoneyInput(scope.$index, scope.row.free_by_money)"
@change="changeMoneyInput(scope.$index, scope.row.free_by_money)"
></el-input-number>
</template>
</el-table-column>
<el-table-column label="操作" width="160">
<template slot-scope="scope">
<el-button size="mini" type="primary" plain
@click="handleRowEdit(scope.$index, scope.row)">编辑地区
</el-button>
<el-button
@click.native.prevent="deleteRow(scope.$index, tableData)"
type="text"
size="small">
移除
</el-button>
</template>
</el-table-column>
</el-table>
</div>
<div class="add-btn">
<el-button type="text" @click="add_template">+</el-button>
<el-form-item>
<el-button v-if="infoForm.id" type="danger" class="float-right" @click="onSaveTemplate">
保存模板
</el-button>
<el-button v-else type="danger" class="float-right" @click="onAddTemplate">2
</el-button>
</el-form-item>
</div>
</el-form-item>
</el-form>
</div>
</div>
<el-dialog size="tiny" title="设置运送到到区域" :visible.sync="specEditVisible">
<el-form ref="specForm" class="specFormDialig">
<el-form-item label="" prop="value" label-width="100px">
<el-transfer v-model="selectedArea" :props="{key: 'id',label: 'name'}"
:data="areaData" :titles="['可选', '已选']"></el-transfer>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="specEditVisible = false"> </el-button>
<el-button type="primary" @click="updateArea"></el-button>
<!--<el-button type="primary" @click="updateSpec" v-if="!is_spec_add"></el-button>-->
</div>
</el-dialog>
</div>
</template>
<script>
import api from '@/config/api';
export default {
data() {
return {
value: true,
nowTableIndex: 0,
areaData: [],
selectedArea: [],
hiddenSelectedArea: [],
specEditVisible: false,
infoForm: {
id: 0,
freight_type: 0,
package_price: 0,
name: ''
},
infoRules: {
name: [
{required: true, message: '请输入模板名称', trigger: 'blur'},
],
},
tableData: [],
defaultData: [{
start: 1,
start_fee: 0,
add: 1,
add_fee: 0,
freeByMoney: false,
freeByNumber: false,
free_by_money: 0,
free_by_number: 0,
}]
}
},
methods: {
changeDefaultNumberSwitch(index, row) {
if (row.freeByNumber == true) {
this.defaultData[index].free_by_number = 1;
}
},
changeDefaultMoneySwitch(index, row) {
if (row.freeByMoney == true) {
this.defaultData[index].free_by_money = 1;
}
},
changeDefaultNumberInput(index, row) {
if (row == 0) {
this.defaultData[index].freeByNumber = false;
}
},
changeDefaultMoneyInput(index, row) {
if (row == 0) {
this.defaultData[index].freeByMoney = false;
}
},
changeNumberSwitch(index, row) {
if (row.freeByNumber == true) {
this.tableData[index].free_by_number = 1;
}
},
changeMoneySwitch(index, row) {
if (row.freeByMoney == true) {
this.tableData[index].free_by_money = 1;
}
},
changeNumberInput(index, row) {
if (row == 0) {
this.tableData[index].freeByNumber = false;
}
},
changeMoneyInput(index, row) {
if (row == 0) {
this.tableData[index].freeByMoney = false;
}
},
submitValue(index, row) {
// console.log(row);
if (row == '' || row < 0) {
this.$message({
type: 'error',
message: '值不能为空或小于零'
})
return false;
}
},
updateArea() {
let index = this.nowTableIndex;
let all = this.areaData;
let selected = this.selectedArea;
// console.log(all);
selected = selected.join(',')
// console.log(selected);
// area selected
this.tableData[index].area = selected;
let areaName = this.selectedArea;
// let i = 0;
// for (const item of areaName) {
// all.map((ele) => ele.id == item ? areaName[i] = ele.name : '')
// i++;
// }
// for (const item in areaName) {
// all.map((ele) => ele.id == areaName[item] ? areaName[item] = ele.name : '')
// }
let newName = [];
for (const item in areaName) {
all.map((ele) => ele.id == areaName[item] ? newName.push(ele.name) : '')
}
// areaName selectedareaName;
let that = this;
that.tableData[index].areaName = newName.join(',');
that.tableData[index].start = 1;
that.tableData[index].add = 1;
// console.log(this.tableData[index].areaName);
console.log('--------');
console.log(that.tableData[index].area);
console.log('--------');
that.specEditVisible = false;
},
onSaveTemplate() {
let name = this.infoForm.name;
let defa = this.defaultData;
// console.log(this.tableData);
if (name == '') {
this.$message({
type: 'error',
message: '名称不能为空'
})
return false;
}
for (const ele of defa) {
if (ele.start == 0 || ele.add == 0 || ele.start_fee < 0 || ele.add_fee < 0) {
this.$message({
type: 'error',
message: '值不能为空'
})
return false;
}
if (ele.area == '') {
this.$message({
type: 'error',
message: '地区不能为空'
})
return false;
}
}
let data = this.tableData;
for (const ele of data) {
if (ele.start == 0 || ele.add == 0 || ele.start_fee < 0 || ele.add_fee < 0) {
this.$message({
type: 'error',
message: '值不能为空'
})
return false;
}
if (ele.area == '') {
this.$message({
type: 'error',
message: '地区不能为空'
})
return false;
}
}
let that = this;
this.axios.post('shipper/saveTable', {
table: that.tableData,
defaultData: that.defaultData,
info: that.infoForm
}).then((response) => {
if (response.data.errno === 0) {
this.$message({
type: 'success',
message: '保存成功'
});
that.getInfo();
} else {
this.$message({
type: 'error',
message: '保存失败'
})
}
})
},
onAddTemplate() {
let name = this.infoForm.name;
let freight_type = this.infoForm.freight_type;
let defa = this.defaultData;
// console.log(this.tableData);
if (name == '') {
this.$message({
type: 'error',
message: '名称不能为空'
})
return false;
}
for (const ele of defa) {
if (ele.start == 0 || ele.add == 0 || ele.start_fee < 0 || ele.add_fee < 0) {
this.$message({
type: 'error',
message: '值不能为空'
})
return false;
}
if (ele.area == '') {
this.$message({
type: 'error',
message: '地区不能为空'
})
return false;
}
}
let data = this.tableData;
for (const ele of data) {
if (ele.start == 0 || ele.add == 0 || ele.start_fee < 0 || ele.add_fee < 0) {
this.$message({
type: 'error',
message: '值不能为空'
})
return false;
}
if (ele.area == '') {
this.$message({
type: 'error',
message: '地区不能为空'
})
return false;
}
}
let that = this;
this.axios.post('shipper/addTable', {
table: that.tableData,
defaultData: that.defaultData,
info: that.infoForm
}).then((response) => {
if (response.data.errno === 0) {
that.$message({
type: 'success',
message: '添加成功'
});
that.$router.go(-1);
} else {
that.$message({
type: 'error',
message: '添加失败'
})
}
})
},
deleteRow(index, rows) {
this.$confirm('确定要删除?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
rows.splice(index, 1);
// this.axios.post('ad/destory', { id: row.id }).then((response) => {
// console.log(response.data)
// if (response.data.errno === 0) {
// this.$message({
// type: 'success',
// message: '!'
// });
//
// this.getList();
// }
// })
});
},
test() {
console.log(this.tableData[0]);
},
add_template() {
let ele = {
template_id: '',
area: '',
start: '',
start_fee: '',
add: '',
add_fee: '',
free_by_money: false,
free_by_number: false,
}
this.tableData.push(ele)
},
goBackPage() {
this.$router.go(-1);
},
getAllAreaData() {
let that = this;
this.axios.post('shipper/getareadata').then((response) => {
if (response.data.errno === 0) {
that.areaData = response.data.data;
// console.log(that.areaData);
// let otherArea =
//
// tableDataarea
// areaalldisable
// all
}
})
},
handleRowEdit(index, row) {
// console.log(row.id);
this.nowTableIndex = index;
let nowArea = this.tableData[index].area;
// console.log(nowArea);
// console.log(typeof(nowArea));
this.selectedArea = nowArea.split(',').map(Number);
let table = this.tableData;
let area = '';
for (const ele in table) {
if (ele != index) {
area = table[ele].area + ',' + area;
}
}
// console.log(area.split(','));
area = area.split(',');
let all = this.areaData;
// tableDataarea
// areaalldisabled
for (const item of all) {
item.disabled = false;
for (const ele of area) {
if (item.id == ele) {
item.disabled = true;
}
}
}
this.specEditVisible = true;
},
getAreaData() {
let that = this
this.axios.post('shipper/freightdetail', {
id: that.infoForm.id
}).then((response) => {
that.infoForm = response.data.data.freight;
that.tableData = response.data.data.data;
// console.log(this.tableData);
// that.defaultData = response.data.data.defaultData;
})
},
getInfo() {
if (this.infoForm.id <= 0) {
return false
}
//
let that = this
this.axios.post('shipper/freightdetail', {
id: that.infoForm.id
}).then((response) => {
that.infoForm = response.data.data.freight;
that.tableData = response.data.data.data;
that.defaultData = response.data.data.defaultData;
console.log(that.defaultData);
})
}
},
components: {},
mounted() {
this.infoForm.id = this.$route.query.id || 0;
// console.log(this.infoForm.id);
this.getInfo();
this.getAllAreaData();
}
}
</script>
<style scoped>
.number_input {
width: 90px;
}
.money_input {
width: 100px;
}
.el-form-item__content {
display: flex;
justify-content: flex-start;
}
.line-wrap {
display: flex;
justify-content: flex-start;
}
.default-freight .el-input {
width: 130px;
float: left;
}
.default-freight .el-input .el-input__inner {
width: 100px;
}
.default-freight .line {
display: flex;
justify-content: flex-start;
border-right: 1px solid #f1f1f1;
/*padding-right: 40px;*/
margin-right: 40px;
}
.default-freight .line2 {
display: flex;
justify-content: flex-start;
}
.default-freight .text {
width: 60px;
float: left;
margin-left: 10px;
}
.default-freight .text2 {
width: 50px;
float: left;
/*margin: 10px;*/
}
.float-right {
float: right;
}
.add-btn {
color: #3a8ee6;
font-size: 14px;
padding: 20px;
border: 1px solid #f1f1f1;
border-top: none;
display: flex;
justify-content: space-between;
}
</style>

@ -0,0 +1,95 @@
<template>
<div class="content-page">
<div class="content-nav">
<el-breadcrumb class="breadcrumb" separator="/">
<el-breadcrumb-item>快递模板</el-breadcrumb-item>
</el-breadcrumb>
<div class="operation-nav">
<!--<el-button icon="plus" @click="expressList"></el-button>-->
<el-button icon="plus" @click="exceptareaList"></el-button>
<el-button type="primary" icon="plus" @click="addFreightTemplate"></el-button>
</div>
</div>
<div class="content-main">
<div class="form-table-box">
<el-table :data="tableData" style="width: 100%" border stripe>
<el-table-column prop="id" label="ID" width="100px"></el-table-column>
<el-table-column prop="name" label="名字"></el-table-column>
<el-table-column prop="package_price" label="包装费"></el-table-column>
<el-table-column prop="freight_type" label="按件/按重" width="200">
<template slot-scope="scope">
{{ scope.row.freight_type == 0 ? '按件' : '按重' }}
</template>
</el-table-column>
<el-table-column label="操作" width="170">
<template slot-scope="scope">
<el-button size="small" @click="handleRowEdit(scope.$index, scope.row)">编辑</el-button>
<el-button size="small" type="danger" @click="handleRowDelete(scope.$index, scope.row)">删除
</el-button>
</template>
</el-table-column>
</el-table>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
tableData: []
}
},
methods: {
expressList(){
this.$router.push({name: 'shipper'});
},
exceptareaList(){
this.$router.push({name: 'except_area'});
},
addFreightTemplate(){
this.$router.push({name: 'freight_add'});
},
handleRowEdit(index, row) {
this.$router.push({name: 'freight_add', query: {id: row.id}})
},
handleRowDelete(index, row) {
this.$confirm('确定要删除?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
this.axios.post('shipper/destory', {id: row.id}).then((response) => {
console.log(response.data)
if (response.data.errno === 0) {
this.$message({
type: 'success',
message: '删除成功!'
});
this.getList();
}
})
});
},
getList() {
this.axios.get('shipper/freight').then((response) => {
console.log(response);
this.tableData = response.data.data
})
}
},
components: {},
mounted() {
this.getList();
}
}
</script>
<style scoped>
</style>

File diff suppressed because it is too large Load Diff

@ -0,0 +1,529 @@
<template>
<div class="content-page">
<div class="content-nav">
<el-breadcrumb class="breadcrumb" separator="/">
<el-breadcrumb-item>商品列表</el-breadcrumb-item>
</el-breadcrumb>
<div class="operation-nav">
<router-link to="/dashboard/goods/add">
<el-button type="primary" icon="plus" size="small">添加商品</el-button>
</router-link>
</div>
</div>
<div class="content-main">
<div class="block">
<span class="wrapper">
<el-button :plain="true" type="primary" :class="activeClass == 1 ? 'active' : '' "
@click="sortOrder(1)" size="small">按销量排序</el-button>
<el-button :plain="true" type="primary" :class="activeClass == 2 ? 'active' : '' "
@click="sortOrder(2)" size="small">按售价排序</el-button>
<el-button :plain="true" type="primary" :class="activeClass == 3 ? 'active' : '' "
@click="sortOrder(3)" size="small">按库存排序</el-button>
</span>
</div>
<el-tabs v-model="activeName" @tab-click="handleClick">
<el-tab-pane label="全部商品" name="first">
</el-tab-pane>
<el-tab-pane label="出售中" name="second"></el-tab-pane>
<el-tab-pane label="已售完" name="third"></el-tab-pane>
<el-tab-pane label="已下架" name="fourth"></el-tab-pane>
</el-tabs>
<div class="filter-box">
<el-form :inline="true" :model="filterForm" class="form-inline">
<el-form-item label="商品名称">
<el-input size="small" v-model="filterForm.name" placeholder="商品名称"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" size="small" @click="onSubmitFilter"></el-button>
<el-button size="small" @click="clear"></el-button>
</el-form-item>
</el-form>
<!--<el-button @click="expandToggle" type="primary" icon="plus" size="small">{{expand == false?'全部展开':'全部收起'}}</el-button>-->
</div>
<div class="form-table-box">
<el-table :data="tableData" style="width: 100%" stripe>
<el-table-column type="expand">
<template slot-scope="props">
<el-table :data="props.row.product" style="width: 100%" stripe>
<el-table-column prop="id" label="id" width="60"></el-table-column>
<el-table-column prop="goods_sn" label="商品SKU" width="140">
<template slot-scope="scope">
<el-input @blur="checkSkuOnly(scope.$index, scope.row)" size="mini"
v-model="scope.row.goods_sn" placeholder="商品SKU"></el-input>
</template>
</el-table-column>
<el-table-column prop="goods_aka" label="快递单上的简称" width="160">
<template slot-scope="scope">
<el-input size="mini" v-model="scope.row.goods_name"
placeholder="简称"></el-input>
</template>
</el-table-column>
<el-table-column prop="value" label="型号/规格" width="140">
<template slot-scope="scope">
<el-input size="mini" v-model="scope.row.value" placeholder="如1斤/条"></el-input>
</template>
</el-table-column>
<el-table-column prop="cost" label="成本(元)" width="90">
<template slot-scope="scope">
<el-input size="mini" v-model="scope.row.cost" placeholder="成本"></el-input>
</template>
</el-table-column>
<el-table-column prop="retail_price" label="零售(元)" width="90">
<template slot-scope="scope">
<el-input size="mini" v-model="scope.row.retail_price"
placeholder="零售"></el-input>
</template>
</el-table-column>
<el-table-column prop="goods_weight" label="重量(KG)" width="90">
<template slot-scope="scope">
<el-input size="mini" v-model="scope.row.goods_weight"
placeholder="重量"></el-input>
</template>
</el-table-column>
<el-table-column prop="goods_number" label="库存" width="90">
<template slot-scope="scope">
<el-input size="mini" v-model="scope.row.goods_number"
placeholder="库存"></el-input>
</template>
</el-table-column>
<el-table-column label="操作" width="140">
<template slot-scope="scope">
<el-button
size="mini"
type="danger"
icon="el-icon-check" circle
@click="specSave(scope.$index, scope.row)">
</el-button>
<el-switch
size="mini"
v-model="scope.row.is_on_sale"
active-text=""
inactive-text=""
active-value="1"
inactive-value="0"
@change='changeProductStatus($event,scope.row.id)'>
</el-switch>
</template>
</el-table-column>
</el-table>
</template>
</el-table-column>
<el-table-column prop="id" label="ID" width="120"></el-table-column>
<el-table-column prop="list_pic_url" label="商品图片" width="80">
<template slot-scope="scope">
<img :src="scope.row.list_pic_url" alt="" style="width: 40px;height: 40px">
</template>
</el-table-column>
<el-table-column prop="name" label="商品名称"></el-table-column>
<el-table-column prop="sort_order" label="排序" width="140" sortable>
<template slot-scope="scope">
<el-input-number class="sort-width" size="mini" :min="1" :max="100" controls-position="right" v-model="scope.row.sort_order" placeholder="排序" @blur="submitSort(scope.$index, scope.row)" @change="submitSort(scope.$index, scope.row)"></el-input-number>
</template>
</el-table-column>
<el-table-column prop="sell_volume" label="销量" width="80" sortable></el-table-column>
<el-table-column prop="goods_number" label="库存" width="80" sortable>
</el-table-column>
<el-table-column label="首页显示" width="80">
<template slot-scope="scope">
<el-switch
v-model="scope.row.is_index"
active-text=""
inactive-text=""
@change='changeShowStatus($event,scope.row.id)'>
</el-switch>
</template>
</el-table-column>
<el-table-column label="上架" width="80">
<template slot-scope="scope">
<el-switch
v-model="scope.row.is_on_sale"
active-text=""
inactive-text=""
@change='changeStatus($event,scope.row.id)'>
</el-switch>
</template>
</el-table-column>
<el-table-column label="操作">
<template slot-scope="scope">
<el-button size="small" @click="handleRowEdit(scope.$index, scope.row)">编辑</el-button>
<el-button size="small" plain type="danger" @click="handleRowDelete(scope.$index, scope.row)">删除
</el-button>
</template>
</el-table-column>
</el-table>
</div>
<div class="page-box">
<el-pagination @current-change="handlePageChange" :current-page="page" :page-size="size"
layout="total, prev, pager, next, jumper" :total="total">
</el-pagination>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
page: 1,
size:10,
total: 0,
filterForm: {
name: ''
},
tableData: [],
activeName: 'second',
pIndex: 0,
num: 0,
activeClass: 0,
expand:true,
tableDa:[{
date: '2016-05-02',
name: '王小虎',
address: '上海市普陀区金沙江路 1518 弄'
}, {
date: '2016-05-04',
name: '王小虎',
address: '上海市普陀区金沙江路 1517 弄'
}, {
date: '2016-05-01',
name: '王小虎',
address: '上海市普陀区金沙江路 1519 弄'
}, {
date: '2016-05-03',
name: '王小虎',
address: '上海市普陀区金沙江路 1516 弄'
}],
}
},
methods: {
stockSyc(){
this.$confirm('确定要同步库存?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
this.axios.post('crontab/updateStockByHand').then((response) => {
if (response.data.errno === 0) {
this.$message({
type: 'success',
message: '同步成功'
});
this.getOnSaleList();
}
})
}).catch(() => {
});
},
updateGoodsNumber(){
this.axios.post('goods/updateGoodsNumber').then((response) => {
if (response.data.errno === 0) {
this.$message({
type: 'success',
message: '同步成功2/2完成'
});
}
})
},
specSave(index,row){
if(row.goods_name == '' || row.value == '' || row.cost == '' || row.retail_price == '' || row.goods_weight == ''){
this.$message({
type: 'error',
message: '值不能为空!'
});
return false;
}
this.axios.post('goods/updatePrice', row).then((response) => {
if (response.data.errno === 0) {
this.$message({
type: 'success',
message: '修改成功!'
});
}
else if (response.data.errno === 100) {
this.$message({
type: 'error',
message: response.data.errmsg
});
}
})
},
checkSkuOnly(index,row){
console.log(index);
console.log(row);
if(row.goods_sn == ''){
this.$message({
type: 'error',
message: 'SKU不能为空'
})
return false;
}
this.axios.post('goods/checkSku', {info: row}).then((response) => {
if (response.data.errno === 100) {
this.$message({
type: 'error',
message: '该SKU已存在'
})
}
else{
this.$message({
type: 'success',
message: '该SKU可以用'
})
}
})
},
expandToggle(){
this.expand = !this.expand;
},
test(){
console.log(this.tableData);
},
submitName(index, row){
this.axios.post('goods/updateShortName', { id: row.id,short_name:row.short_name }).then((response) => {
if (response.data.errno === 0) {
this.$message({
type: 'success',
message: '修改成功!'
});
}
})
},
submitSort(index, row){
this.axios.post('goods/updateSort', { id: row.id,sort:row.sort_order }).then((response) => {})
},
handleClick(tab, event) {
let pindex = tab._data.index;
this.page = 1;
this.activeClass = 0;
if (pindex == 0) {
this.getList();
this.pIndex = 0;
}
else if (pindex == 1) {
this.getOnSaleList();
this.pIndex = 1;
}
else if (pindex == 2) {
this.getOutList();
this.pIndex = 2;
}
else if (pindex == 3) {
this.getDropList();
this.pIndex = 3;
}
},
handlePageChange(val) {
this.page = val;
let nIndex = this.pIndex;
if (nIndex == 0) {
this.getList();
}
else if (nIndex == 1) {
this.getOnSaleList();
}
else if (nIndex == 2) {
this.getOutList();
}
else if (nIndex == 3) {
this.getDropList();
}
else if (nIndex == 4) {
this.sortOrder(this.num);
}
},
handleRowEdit(index, row) {
this.$router.push({name: 'goods_add', query: {id: row.id}})
},
handleRowDelete(index, row) {
this.$confirm('确定要删除?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
let that = this;
that.axios.post('goods/destory', {id: row.id}).then((response) => {
if (response.data.errno === 0) {
that.$message({
type: 'success',
message: '删除成功!'
});
let pIndex = localStorage.getItem('pIndex');
console.log(pIndex);
if (pIndex == 0) {
that.getList();
}
else if (pIndex == 1) {
that.getOnSaleList();
}
else if (pIndex == 2) {
that.getOutList();
}
else if (pIndex == 3) {
that.getDropList();
}
}
})
}).catch(() => {
// this.$message({
// type: 'info',
// message: ''
// });
});
},
onSubmitFilter() {
this.page = 1;
this.getList();
},
clear(){
this.axios.get('goods', {
params: {
page: this.page,
name: ''
}
}).then((response) => {
this.tableData = response.data.data.data
this.page = response.data.data.currentPage
this.total = response.data.data.count
})
},
getList() {
this.axios.get('goods', {
params: {
page: this.page,
size: this.size,
name: this.filterForm.name
}
}).then((response) => {
this.tableData = response.data.data.data
this.page = response.data.data.currentPage
this.total = response.data.data.count
})
},
getOnSaleList() {
this.axios.get('goods/onsale', {
params: {
page: this.page,
size: this.size
}
}).then((response) => {
this.tableData = response.data.data.data
this.page = response.data.data.currentPage
this.total = response.data.data.count
})
},
getOutList() {
this.axios.get('goods/out', {
params: {
page: this.page,
size: this.size
}
}).then((response) => {
this.tableData = response.data.data.data;
this.page = response.data.data.currentPage;
this.total = response.data.data.count;
})
},
getDropList() {
this.axios.get('goods/drop', {
params: {
page: this.page,
size: this.size
}
}).then((response) => {
this.tableData = response.data.data.data;
this.page = response.data.data.currentPage;
this.total = response.data.data.count;
})
},
sortOrder(num) {
this.num = num;
this.pIndex = 4;
this.activeClass = num;
this.axios.get('goods/sort', {
params: {
page: this.page,
size: this.size,
index: num
}
}).then((response) => {
this.tableData = response.data.data.data;
this.page = response.data.data.currentPage;
this.total = response.data.data.count;
})
},
changeStatus($event, para) {
this.axios.get('goods/saleStatus', {
params: {
status: $event,
id: para
}
}).then((response) => {
})
},
changeProductStatus($event, para) {
this.axios.get('goods/productStatus', {
params: {
status: $event,
id: para
}
}).then((response) => {
})
},
changeShowStatus($event, para) {
this.axios.get('goods/indexShowStatus', {
params: {
status: $event,
id: para
}
}).then((response) => {
})
}
},
components: {},
mounted() {
this.getOnSaleList();
}
}
</script>
<style scoped>
.sort-width{
width: 90px;
}
.right{
float: right;
}
.form-inline {
margin-top: 2px;
height: 40px;
margin-right: 20px;
}
.block {
margin-bottom: 10px;
height:42px;
display: flex;
align-items: center;
justify-content:space-between;
}
.active {
border-color: #ff4949;
color: #ff4949;
}
.marginRight{
margin-right: 20px;
}
</style>

@ -0,0 +1,979 @@
<template>
<div class="content-page">
<div class="content-nav">
<el-breadcrumb class="breadcrumb" separator="/">
<el-breadcrumb-item :to="{ name: 'goods' }">商品管理</el-breadcrumb-item>
<el-breadcrumb-item>{{infoForm.id ? '编辑商品' : '添加商品'}}</el-breadcrumb-item>
</el-breadcrumb>
<div class="operation-nav">
<!-- <el-button type="primary" @click="test"></el-button> -->
<el-button type="primary" @click="onSubmitInfo"></el-button>
<el-button @click="goBackPage" icon="arrow-left">返回列表</el-button>
</div>
</div>
<div class="content-main">
<div class="form-table-box">
<el-form ref="infoForm" :rules="infoRules" :model="infoForm" label-width="120px">
<el-form-item label="商品分类">
<el-select class="el-select-class" v-model="cateId" placeholder="选择型号分类">
<el-option v-for="item in cateOptions" :key="item.value" :label="item.label" :value="item.value">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="商品图片" prop="list_pic_url" v-if="infoForm.list_pic_url" class="image-uploader-diy new-height">
<div class="index-image">
<el-image :preview-src-list="previewList" v-if="infoForm.list_pic_url" :src="infoForm.list_pic_url" @click="previewIndexImg"
class="image-show" fit="cover"></el-image>
<div class="o-shadow" @click="delePicList">
<i class="el-icon-delete"></i>
</div>
</div>
</el-form-item>
<el-form-item label="商品图片" prop="list_pic_url" v-if="!infoForm.list_pic_url">
<el-upload name="file" ref="upload" class="upload-demo" :action="qiniuZone" :on-success="handleSuccess"
:before-upload="indexImgBefore" :auto-upload="true" list-type="picture-card" :data="picData" :http-request="uploadIndexImg">
<el-button size="small" type="primary">点击上传</el-button>
<div slot="tip" class="el-upload__tip">只能上传jpg/png文件</div>
</el-upload>
</el-form-item>
<el-form-item label="商品轮播图" prop="goods_sn">
<draggable v-model="gallery_list" draggable=".gallery-item" class="drag-wrap">
<div v-for="(element, index) in gallery_list" class="gallery-item" v-if="element.is_delete == 0">
<el-image :preview-src-list="previewList" @click="previewImg(index)" style="width: 148px; height: 148px;margin:0 10px 10px 0;"
:src="element.url" fit="cover"></el-image>
<div class="shadow" @click="onRemoveHandler(index)">
<i class="el-icon-delete"></i>
</div>
</div>
<el-upload name="file" ref="upload" :on-remove="galleryRemove" class="upload-demo" :action="qiniuZone"
:on-preview="galleryPreview" :show-file-list="false" :data="picData" :before-upload="galleryBefore" :on-error="hasErrorAct"
:on-success="handleSuccess" :auto-upload="true" multiple list-type="picture-card" :http-request="uploadGalleryImg">
<i class="el-icon-plus"></i>
</el-upload>
</draggable>
</el-form-item>
<el-form-item label="商品名称" prop="name">
<el-input v-model="infoForm.name"></el-input>
</el-form-item>
<el-form-item label="商品简介" prop="goods_brief">
<el-input type="textarea" v-model="infoForm.goods_brief" :rows="3"></el-input>
<div class="form-tip"></div>
</el-form-item>
<el-form-item label="商品单位" prop="goods_unit">
<el-input v-model="infoForm.goods_unit"></el-input>
<div class="form-tip"></div>
</el-form-item>
<el-form-item label="销量" prop="sell_volume">
<el-input v-model="infoForm.sell_volume"></el-input>
</el-form-item>
<el-form-item label="型号和价格">
<div>
<el-select class="el-select-class" v-model="specValue" placeholder="选择型号分类">
<el-option v-for="item in specOptionsList" :key="item.value" :label="item.label" :value="item.value">
</el-option>
</el-select>
</div>
<div class="spec-wrap">
<el-table :data="specData" stripe style="width: 100%">
<el-table-column prop="goods_sn" label="商品SKU" width="140">
<template slot-scope="scope">
<el-input @blur="checkSkuOnly(scope.$index, scope.row)" size="mini" v-model="scope.row.goods_sn" placeholder="商品SKU"></el-input>
</template>
</el-table-column>
<el-table-column prop="goods_aka" label="快递单上的简称" width="160">
<template slot-scope="scope">
<el-input size="mini" v-model="scope.row.goods_name" placeholder="简称"></el-input>
</template>
</el-table-column>
<el-table-column prop="value" label="型号/规格" width="130">
<template slot-scope="scope">
<el-input size="mini" v-model="scope.row.value" placeholder="如1斤/条"></el-input>
</template>
</el-table-column>
<el-table-column prop="cost" label="成本(元)" width="100">
<template slot-scope="scope">
<el-input size="mini" v-model="scope.row.cost" placeholder="成本"></el-input>
</template>
</el-table-column>
<el-table-column prop="retail_price" label="零售(元)" width="100">
<template slot-scope="scope">
<el-input size="mini" v-model="scope.row.retail_price" placeholder="零售"></el-input>
</template>
</el-table-column>
<el-table-column prop="goods_weight" label="重量(KG)" width="100">
<template slot-scope="scope">
<el-input size="mini" v-model="scope.row.goods_weight" placeholder="重量"></el-input>
</template>
</el-table-column>
<el-table-column prop="goods_number" label="库存" width="100">
<template slot-scope="scope">
<el-input size="mini" v-model="scope.row.goods_number" placeholder="库存"></el-input>
</template>
</el-table-column>
<el-table-column label="操作" width="70">
<template slot-scope="scope">
<el-button size="mini" type="danger" icon="el-icon-delete" circle @click="specDelete(scope.$index, scope.row)">
</el-button>
</template>
</el-table-column>
</el-table>
<el-button class="marginTop20" type="primary" @click="addSpecData"></el-button>
</div>
</el-form-item>
<el-form-item label="属性设置" class="checkbox-wrap">
<el-checkbox-group v-model="infoForm.is_new" class="checkbox-list">
<el-checkbox label="新品" name="is_new"></el-checkbox>
</el-checkbox-group>
</el-form-item>
<el-form-item label="选择快递模板">
<el-select v-model="kdValue" placeholder="请选择快递" @change="kdChange">
<el-option v-for="item in kdOptions" :key="item.value" :label="item.label" :value="item.value">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="排序" prop="sort_order">
<el-input-number :mini="1" :max="100" v-model="infoForm.sort_order"></el-input-number>
</el-form-item>
<el-form-item label=" ">
<el-switch active-text="" inactive-text="" active-value="1" inactive-value="0" v-model="infoForm.is_on_sale"></el-switch>
</el-form-item>
<el-form-item label="商品详情" prop="goods_desc">
<div class="edit_container">
<quill-editor v-model="infoForm.goods_desc" ref="myTextEditor" class="editer" :options="editorOption" @blur="onEditorBlur($event)"
@ready="onEditorReady($event)">
</quill-editor>
</div>
</el-form-item>
<!-- 图片上传组件辅助-->
<el-form-item class="upload_ad">
<el-upload ref="upload" name="file" class="avatar-uploader" :action="qiniuZone" list-type="picture-card"
:file-list="detail_list" :before-upload="beforeUpload" :on-success="handleSuccess" :data="picData" multiple
:http-request="uploadDetailsImg">
</el-upload>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="onSubmitInfo"></el-button>
<el-button @click="goBackPage"></el-button>
<el-button type="danger" class="float-right" @click="onCopyGood" v-if="infoForm.id > 0"></el-button>
</el-form-item>
</el-form>
</div>
</div>
<el-dialog :visible.sync="dialogVisible" size="tiny">
<img width="100%" :src="dialogImageUrl" alt="">
</el-dialog>
</div>
</template>
<script>
import api from '@/config/api';
import lrz from 'lrz'
import moment from 'moment'
import draggable from 'vuedraggable'
import $ from 'jquery'
import {
quillEditor
} from 'vue-quill-editor'
const toolbarOptions = [
['bold', 'italic', 'underline', 'strike'],
['blockquote'],
[{
'list': 'ordered'
}, {
'list': 'bullet'
}],
[{
'indent': '-1'
}, {
'indent': '+1'
}],
[{
'size': ['small', false, 'large', 'huge']
}],
[{
'header': [1, 2, 3, 4, 5, 6, false]
}],
['link', 'image', 'video']
]
export default {
data() {
return {
root: '',
qiniuZone: '',
picData: {
token: ''
},
url: '',
kdOptions: [],
kdValue: '',
cateId: '',
detail_list: [],
dialogImageUrl: '',
dialogVisible: false,
options: [],
cateOptions: [],
editorOption: {
modules: {
toolbar: {
container: toolbarOptions, //
handlers: {
'image': function(value) {
if (value) {
document.querySelector('.avatar-uploader input').click()
} else {
this.quill.format('image', false);
}
}
}
},
syntax: {
highlight: text => hljs.highlightAuto(text).value
}
}
},
category: [],
infoForm: {
name: "",
list_pic_url: '',
goods_brief: '',
goods_desc: '',
is_on_sale: 0,
is_new: false,
// is_index: false,
},
infoRules: {
name: [{
required: true,
message: '请输入名称',
trigger: 'blur'
}, ],
goods_brief: [{
required: true,
message: '请输入简介',
trigger: 'blur'
}, ],
list_pic_url: [{
required: true,
message: '请选择商品图片',
trigger: 'blur'
}, ],
},
specRules: {
value: [{
required: true,
message: '请输入型号名',
trigger: 'blur'
}, ],
},
specData: [{
goods_sn: '',
value: '',
cost: '',
retail_price: '',
goods_weight: '',
goods_number: ''
}],
specOptionsList: [],
specValue: 1,
selectedSpec: '规格',
is_has_spec: false,
gallery: {
goods_id: 0,
},
gallery_list: [],
visible: false,
hasPost: 0,
previewList: [],
autoFocus: false,
}
},
methods: {
handleSuccess() {},
uploadIndexImg(request) {
const file = request.file;
lrz(file).then((rst) => {
const config = {
headers: {
'Content-Type': 'multipart/form-data'
},
};
const fileName = moment().format('YYYYMMDDHHmmssSSS') + Math.floor(Math.random() * 100) + file.name; //
const formData = new FormData();
formData.append('file', rst.file);
formData.append('token', this.picData.token);
formData.append('key', fileName);
this.$http.post(this.qiniuZone, formData, config).then((res) => {
this.handleUploadListSuccess(res.data)
})
}).catch(function(err) {
console.log(err)
})
},
handleUploadListSuccess(res) {
let url = this.url;
this.infoForm.list_pic_url = url + res.key;
console.log(this.infoForm.list_pic_url);
this.axios.post('goods/uploadHttpsImage', {
url: this.infoForm.list_pic_url
}).then((response) => {
let lastUrl = response.data.data;
this.infoForm.https_pic_url = lastUrl;
})
},
onRemoveHandler(index) {
let that = this;
that.$confirm('确定删除该图片?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
})
.then(() => {
let arr = that.gallery_list;
arr[index].is_delete = 1;
})
.catch(() => {})
},
uploadGalleryImg(request) {
const file = request.file;
lrz(file).then((rst) => {
const config = {
headers: {
'Content-Type': 'multipart/form-data'
},
};
const fileName = moment().format('YYYYMMDDHHmmssSSS') + Math.floor(Math.random() * 100) + file.name; //
const formData = new FormData();
formData.append('file', rst.file);
formData.append('token', this.picData.token);
formData.append('key', fileName);
this.$http.post(this.qiniuZone, formData, config).then((res) => {
this.handleUploadGallerySuccess(res.data)
})
}).catch(function(err) {
console.log(err)
})
},
handleUploadGallerySuccess(res) {
let url = this.url;
let urlData = url + res.key;
let data = {
id: 0,
url: urlData,
is_delete: 0,
}
this.gallery_list.push(data);
},
test() {
console.log(this.gallery_list);
},
previewIndexImg() {
let that = this;
that.previewList = [];
that.previewList.push(that.infoForm.list_pic_url);
},
previewImg(index) {
let that = this;
that.previewList = [];
let arr = that.gallery_list;
that.previewList.push(arr[index].url);
},
beforeRemove(file, fileList) {
return this.$confirm(`确定移除 ${ file.name }`);
},
checkSkuOnly(index, row) {
console.log(index);
console.log(row);
if (row.goods_sn == '') {
this.$message({
type: 'error',
message: 'SKU不能为空'
})
return false;
}
this.axios.post('goods/checkSku', {
info: row
}).then((response) => {
if (response.data.errno === 100) {
this.$message({
type: 'error',
message: '该SKU已存在'
})
} else {
this.$message({
type: 'success',
message: '该SKU可以用'
})
}
})
},
getSpecData() {
let id = this.infoForm.id;
this.axios.post('specification/getGoodsSpec', {
id: id
}).then((response) => {
if (response.data.errno === 0) {
let info = response.data.data;
this.specData = info.specData;
this.specValue = info.specValue;
}
})
},
addSpecData() {
let ele = {
goods_sn: '',
value: '',
cost: '',
retail_price: '',
goods_weight: '',
goods_number: ''
}
this.specData.push(ele)
},
specDelete(index, row) {
this.specData.splice(index, 1);
},
testCallBack() {
console.log(this.specValue);
},
hasErrorAct(err) {
console.log(err);
},
getQiniuToken() {
let that = this
this.axios.post('index/getQiniuToken').then((response) => {
let resInfo = response.data.data;
that.picData.token = resInfo.token;
that.url = resInfo.url;
})
},
specChange(value) {
this.specForm.id = value;
},
addPrimarySpec() {
this.is_has_spec = true;
},
getImgUrl() {
let str = this.infoForm.goods_desc;
//gi
let imgReg = /<img [^>]*src=['"]([^'"]+)[^>]*>/gi;
//src
let srcReg = /src=[\'\"]?([^\'\"]*)[\'\"]?/i;
let arr = str.match(imgReg);
if (arr == null) {
return false;
}
let data = [];
for (let i = 0; i < arr.length; i++) {
let src = arr[i].match(srcReg);
let jsonData = {};
jsonData.url = src[1];
data[i] = jsonData;
}
this.detail_list = data;
},
submitUpload() {
this.$refs.upload.submit();
},
delePicList() {
let that = this;
that.$confirm('确定删除该图片?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
})
.then(() => {
that.infoForm.list_pic_url = '';
})
.catch(() => {})
},
indexImgBefore(file) {
this.getQiniuToken();
},
galleryBefore(file) {
this.picData.key = new Date().getTime() + Math.floor(Math.random() * 100) + file.name; //
this.getQiniuToken();
},
galleryRemove(file, fileList) {
console.log(file);
console.log(fileList);
},
galleryPreview(file) {
console.log(file);
this.dialogImageUrl = file.url;
this.dialogVisible = true;
},
getGalleryList() {
let goodsId = this.infoForm.id;
this.axios.post('goods/getGalleryList', {
goodsId: goodsId
}).then((response) => {
this.gallery_list = response.data.data.galleryData;
})
},
kdChange(kdValue) {
this.infoForm.freight_template_id = kdValue;
},
timeChange(val) {
console.log(val);
// this.infoForm.freight_template_id = kdValue;
},
onEditorReady(editor) {
console.log('editor ready!', editor)
},
onEditorFocus(editor) {
console.log('editor focus!', editor)
},
onEditorBlur(editor) {
console.log('editor blur!', editor)
},
beforeUpload(file) {
this.getQiniuToken();
this.quillUpdateImg = true
},
uploadError() {
// loading
this.quillUpdateImg = false
this.$message.error('图片插入失败')
},
goBackPage() {
this.$router.go(-1);
},
//
onLinkImageUrl() {
var imageurl = document.querySelector('.url-image-fuzhu input').value
let quill = this.$refs.myTextEditor.quill
let length = quill.getSelection().index;
quill.insertEmbed(length, 'image', imageurl)
quill.setSelection(length + 1)
},
onCopyGood() {
this.$confirm('确定复制该商品?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
this.axios.post('goods/copygoods', {
id: this.infoForm.id
}).then((response) => {
if (response.data.errno === 0) {
this.$message({
type: 'success',
message: '复制成功!'
});
// this.is_has_spec = false;
// this.specData = [];
}
})
});
},
onSubmitInfo() {
this.$refs['infoForm'].validate((valid) => {
if (valid) {
if (this.infoForm.list_pic_url == '' || this.infoForm.list_pic_url == null) {
this.$message({
type: 'error',
message: '请上传商品首图!'
})
return false;
}
if (this.gallery_list.length == 0) {
this.$message({
type: 'error',
message: '请至少上传一张轮播图!'
})
return false;
}
if (this.specData.length == 0) {
this.$message({
type: 'error',
message: '请添加一个规格型号'
})
return false;
}
for (const ele of this.specData) {
if (ele.cost == '' || ele.goods_sn == '' || ele.goods_weight == '' || ele.retail_price == '' || ele.value ==
'') {
this.$message({
type: 'error',
message: '型号和价格的值不能为空'
})
return false;
}
}
this.infoForm.gallery = this.gallery_list;
// return false;
this.axios.post('goods/store', {
info: this.infoForm,
specData: this.specData,
specValue: this.specValue,
cateId: this.cateId,
}).then((response) => {
if (response.data.errno === 0) {
this.$message({
type: 'success',
message: '保存成功'
});
this.infoForm.id = response.data.data;
this.getGalleryList();
// this.$router.go(-1);
} else {
this.$message({
type: 'error',
message: '保存失败'
})
}
})
} else {
return false;
}
});
},
uploadDetailsImg(request) {
const file = request.file;
lrz(file).then((rst) => {
const config = {
headers: {
'Content-Type': 'multipart/form-data'
},
};
const fileName = moment().format('YYYYMMDDHHmmssSSS') + Math.floor(Math.random() * 100) + file.name; //
const formData = new FormData();
formData.append('file', rst.file);
formData.append('token', this.picData.token);
formData.append('key', fileName);
this.$http.post(this.qiniuZone, formData, config).then((res) => {
this.handleUploadDetailSuccess(res.data)
})
}).catch(function(err) {
console.log(err)
})
},
handleUploadDetailSuccess(res) {
let url = this.url;
let data = url + res.key;
let quill = this.$refs.myTextEditor.quill
//
//
let length = quill.getSelection().index;
// res.info
quill.insertEmbed(length, 'image', data)
//
quill.setSelection(length + 1)
// this.$message.error('')
// loading
this.quillUpdateImg = false
},
getInfo() {
if (this.infoForm.id <= 0) {
return false
}
//
let that = this
this.axios.get('goods/info', {
params: {
id: that.infoForm.id
}
}).then((response) => {
let resInfo = response.data.data;
let goodsInfo = resInfo.info;
// goodsInfo.is_index = goodsInfo.is_index ? true : false;
goodsInfo.is_new = goodsInfo.is_new ? true : false;
goodsInfo.is_on_sale = goodsInfo.is_on_sale ? "1" : "0";
that.infoForm = goodsInfo;
that.kdValue = goodsInfo.freight_template_id;
that.cateId = resInfo.category_id;
that.getImgUrl();
})
},
//
getAllCategory() {
let that = this;
this.axios.get('goods/getAllCategory', {
params: {}
}).then((response) => {
that.options = response.data.data;
})
},
getAllSpecification() {
let that = this;
this.axios.get('goods/getAllSpecification').then((response) => {
let resInfo = response.data.data;
console.log(resInfo);
that.specOptionsList = resInfo;
})
},
getExpressData() {
let that = this
this.axios.get('goods/getExpressData', {
params: {}
}).then((response) => {
let options = response.data.data;
that.kdOptions = options.kd;
that.cateOptions = options.cate;
})
},
// summernote
sendFile(file) {},
// summernote
initSummerNote() {
let that = this;
$('#summernote').summernote({
lang: 'zh-CN',
placeholder: '请输入商品描述',
height: 300,
minHeight: 300,
maxHeight: 400,
focus: true,
callbacks: {
onBlur: function(e) {
console.log(" on blur ");
console.log($('#summernote').summernote('code'));
that.infoForm.goods_desc = $('#summernote').summernote('code');
},
onImageUpload: function(files) {
console.log("onImageUpLoad...");
that.sendFile(files[0]);
}
}
}),
// console.error(that.infoForm.goods_desc);
$('#summernote').summernote('code', that.infoForm.goods_desc)
},
},
components: {
quillEditor,
draggable
},
computed: {
editor() {
return this.$refs.myTextEditor.quillEditor
}
},
mounted() {
this.infoForm.id = this.$route.query.id || 0;
this.getInfo();
this.getAllCategory();
this.getExpressData();
this.getQiniuToken();
this.getAllSpecification();
if (this.infoForm.id > 0) {
this.getSpecData();
this.getGalleryList();
}
this.root = api.rootUrl;
this.qiniuZone = api.qiniu;
},
}
</script>
<style scoped>
.shadow,
.o-shadow {
position: absolute;
bottom: 10px;
right: 10px;
background-color: rgba(0, 0, 0, .5);
opacity: 0;
transition: opacity .3s;
color: #fff;
font-size: 20px;
line-height: 20px;
padding: 10px;
cursor: pointer;
}
.gallery-item {
display: flex;
justify-content: center;
align-items: center;
float: left;
position: relative;
}
.gallery-item:hover .shadow {
opacity: 1;
}
.video-wrap {
width: 300px;
}
.dialog-header {
display: flex;
justify-content: flex-start;
margin-bottom: 10px;
}
.dialog-header .value {
width: 150px;
margin-right: 14px;
}
.input-wrap .el-input {
width: 200px;
float: left;
margin: 0 20px 20px 0;
}
.input-wrap .el-input input {
background-color: #fff !important;
color: #233445 !important;
}
.specFormDialig .el-input {
width: 150px;
margin-right: 10px;
}
.el-select-class {
width: 200px;
margin-right: 20px;
}
.sepc-form {
display: flex;
justify-content: flex-start;
margin-bottom: 10px;
}
.spec-form-wrap {
margin-top: 0 !important;
}
.add-spec {
margin-top: 10px;
}
.spec-form-wrap .header {
display: flex;
justify-content: flex-start;
}
.spec-form-wrap .header .l {
width: 200px;
margin-right: 20px;
}
.spec-form-wrap .header .m {
width: 200px;
margin-right: 20px;
}
.spec-form-wrap .header .m {
width: 200px;
margin-right: 20px;
}
/*.sepc-form div{*/
/*margin-left: 0;*/
/*}*/
.float-right {
float: right;
}
.sepc-form .el-input {
width: 200px;
margin-right: 20px;
}
.marginTop20 {
margin-top: 20px;
}
.checkbox-wrap .checkbox-list {
float: left;
margin-right: 20px;
}
.upload_ad {
display: none;
}
.upload_ad .el-upload--picture-card {
display: none;
}
.ql-container {
min-height: 200px;
max-height: 400px;
overflow-y: auto;
}
.image-uploader-diy {
/*height: 200px;*/
position: relative;
}
.image-uploader-diy .el-upload {
border: 1px solid #d9d9d9;
cursor: pointer;
position: relative;
overflow: hidden;
}
.image-uploader-diy .el-upload:hover {
border-color: #20a0ff;
}
.image-uploader-diy .image-uploader-icon {
font-size: 28px;
color: #8c939d;
width: 200px;
height: 200px;
line-height: 200px;
text-align: center;
}
.image-uploader-diy .image-show {
min-width: 148px;
height: 148px;
background-color: #f9f9f9;
display: block;
}
.index-image {
width: 148px;
height: 148px;
position: relative;
}
.index-image:hover .o-shadow {
opacity: 1;
}
.image-uploader-diy .new-image-uploader {
font-size: 28px;
color: #8c939d;
width: 165px;
height: 105px;
line-height: 105px;
text-align: center;
}
.image-uploader-diy .new-image-uploader .image-uploader-icon {
font-size: 28px;
color: #8c939d;
width: 165px;
height: 105px;
line-height: 105px;
text-align: center;
}
.image-uploader-diy .new-image-uploader .image-show {
width: 165px;
height: 105px;
display: block;
}
.item-url-image-fuzhu .el-input {
width: 260px;
}
.hidden {
display: none;
}
</style>

@ -0,0 +1,218 @@
<!-- <template>
<div class="content-page">
<div class="content-nav">
<el-breadcrumb class="breadcrumb" separator="/">
<el-breadcrumb-item>编辑商品</el-breadcrumb-item>
<el-breadcrumb-item>轮播图顺序</el-breadcrumb-item>
</el-breadcrumb>
<div class="operation-nav">
<el-button size="small" type="primary" @click="onSubmitInfo"></el-button>
<el-button size="small" @click="goBackPage" icon="arrow-left">返回列表</el-button>
</div>
</div>
<div class="content-main">
<el-form ref="infoForm" :model="infoForm">
<el-form-item class="in-wrap" label="图片" v-for="item in infoForm.data">
<img class="img-wrap" :src="item.img_url" />
<el-input class="input-wrap" type="number" size="small" v-model="item.sort_order"
placeholder=""></el-input>
</el-form-item>
</el-form>
</div>
</div>
</template> -->
<template>
<div class="com-image-drag">
<div class="button-list">
<el-button @click="openDrag" v-if="!drag_open" :disabled="banner_list.length <= 1" type="text" size="small" class="operation-success"></el-button>
<el-button @click="save" v-if="drag_open" type="text" size="small" class="operation-success"></el-button>
<el-button @click="cancle" v-if="drag_open" type="text" size="small" class="operation-error"></el-button>
</div>
<div class="image-list">
<!-- 拖拽层 -->
<div class="list-wrap">
<draggable v-model="banner_list" :options="{
animation: 150,
ghostClass: 'sortable-ghost',
chosenClass: 'chosenClass',
scroll: true,
scrollSensitivity: 200
}">
<div class="image-item" v-for="($item, $index) in banner_list" :key="$index" :style="{ backgroundImage: `url(${$item.url})` }"></div>
</draggable>
</div>
<!-- 展示层 -->
<div class="list-wrap" v-show="!drag_open">
<div class="image-item" v-for="($item, $index) in banner_list" :key="$index" :style="{ backgroundImage: `url(${$item.url})` }"
@mouseover.prevent="$item.is_hover = true" @mouseleave.prevent="$item.is_hover = false">
<div class="label" v-show="!$item.is_hover">
<i class="el-icon-upload-success el-icon-check icon-success"></i>
</div>
</div>
<el-upload list-type="picture-card" name="file" class="upload-machine" :disabled="drag_open" action="https://up.qiniu.com/"
:on-success="onSuccess" :before-upload="beforeUpload" :show-file-list="false" :multiple="multiple" enctype="multipart/form-data"></el-upload>
</div>
</div>
</div>
</template>
<script>
import api from '@/config/api';
import draggable from "vuedraggable";
export default {
props: {
list: {
type: Array
},
limit: {
type: Number,
default: 0
},
multiple: {
type: Boolean,
default: false
},
action: {
type: Function,
default: () => {}
},
beforeUpload: {
type: Function,
default: () => {}
},
onError: {
type: Function,
default: () => {}
},
onSuccess: {
type: Function,
default: () => {}
}
},
data() {
return {
banner_list: [], //
file_list: [], //
drag_open: false, //,
infoForm: {}
}
},
methods: {
// goBack(){
// this.$router.push({name: 'goods_add', query: {id: infoForm.id}})
// },
// test() {
// console.log(this.infoForm);
// },
// onSubmitInfo() {
// this.axios.post('goods/galleryEdit', this.infoForm).then((response) => {
// if (response.data.errno === 0) {
// this.$message({
// type: 'success',
// message: ''
// });
// } else {
// this.$message({
// type: 'error',
// message: ''
// })
// }
// })
// },
// goBackPage() {
// this.$router.go(-1);
// },
// getInfo() {
// console.log(this.infoForm.id)
// if (this.infoForm.id <= 0) {
// return false
// }
// let that = this
// this.axios.get('goods/galleryList', {
// params: {
// id: that.infoForm.id
// }
// }).then((response) => {
// console.log(response.data);
// that.infoForm = response.data;
// })
// }
getInfo() {
console.log(this.infoForm.id)
if (this.infoForm.id <= 0) {
return false
}
let that = this
this.axios.get('goods/galleryList', {
params: {
id: that.infoForm.id
}
}).then((response) => {
console.log(response.data);
that.infoForm = response.data;
// console.log(api)
that.banner_list = that.infoForm.data.map(function(v) {
let obj = {
url: v.img_url,
is_hover: false
};
return obj;
});
})
},
//
openDrag() {
this.file_list = JSON.parse(JSON.stringify(this.banner_list)); //
this.drag_open = true;
},
//
cancle() {
this.banner_list = this.file_list;
this.drag_open = false;
},
//
save() {
this.drag_open = false;
}
},
components: {
draggable
},
mounted() {
this.infoForm.id = this.$route.query.id || 0;
this.getInfo();
}
}
</script>
<style scoped>
.image-item{
width: 200px;
height: 200px;
}
.in-wrap {
display: flex;
justify-content: flex-start;
align-items: center;
margin-left: 0;
}
.img-wrap {
float: left;
width: 100px;
height: 100px;
}
.input-wrap {
width: 100px;
float: left;
margin-left: 30px;
margin-top: 30px;
}
</style>

@ -0,0 +1,106 @@
<template>
<div class="content-page">
<div class="content-nav">
<el-breadcrumb class="breadcrumb" separator="/">
<el-breadcrumb-item :to="{ name: 'dashboard' }">首页</el-breadcrumb-item>
<el-breadcrumb-item>数据管理</el-breadcrumb-item>
<el-breadcrumb-item>{{infoForm.id ? '编辑热门搜索' : '添加热门搜索'}}</el-breadcrumb-item>
</el-breadcrumb>
<div class="operation-nav">
<el-button type="primary" @click="goBackPage" icon="arrow-left">返回列表</el-button>
</div>
</div>
<div class="content-main">
<div class="form-table-box">
<el-form ref="infoForm" :rules="infoRules" :model="infoForm" label-width="120px">
<el-form-item label="商品ID" prop="id">
<el-input v-model="infoForm.id"></el-input>
</el-form-item>
<el-form-item label="关键词" prop="keyword">
<el-input v-model="infoForm.keyword"></el-input>
</el-form-item>
<el-form-item label="排序">
<el-input-number v-model="infoForm.sort_order" :min="1" :max="1000"></el-input-number>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="onSubmitInfo"></el-button>
<el-button @click="goBackPage"></el-button>
</el-form-item>
</el-form>
</div>
</div>
</div>
</template>
<script>
import api from '@/config/api';
export default {
data() {
return {
infoForm: {
id: 0,
keyword: '',
},
infoRules: {
keyword: [
{ required: true, message: '请输入关键词', trigger: 'blur' },
],
},
}
},
methods: {
goBackPage() {
this.$router.go(-1);
},
onSubmitInfo() {
this.$refs['infoForm'].validate((valid) => {
if (valid) {
this.axios.post('keywords/store', this.infoForm).then((response) => {
if (response.data.errno === 0) {
this.$message({
type: 'success',
message: '保存成功'
});
this.$router.go(-1)
} else {
this.$message({
type: 'error',
message: '保存失败'
})
}
})
} else {
return false;
}
});
},
getInfo() {
if (this.infoForm.id <= 0) {
return false
}
//
let that = this
this.axios.get('keywords/info', {
params: {
id: that.infoForm.id
}
}).then((response) => {
let resInfo = response.data.data;
that.infoForm = resInfo;
})
}
},
components: {
},
mounted() {
this.infoForm.id = this.$route.query.id || 0;
this.getInfo();
console.log(api)
}
}
</script>

@ -0,0 +1,132 @@
<template>
<div class="content-page">
<div class="content-nav">
<el-breadcrumb class="breadcrumb" separator="/">
<el-breadcrumb-item :to="{ path: '/dashboard' }">首页</el-breadcrumb-item>
<el-breadcrumb-item>数据管理</el-breadcrumb-item>
<el-breadcrumb-item>热门搜索</el-breadcrumb-item>
</el-breadcrumb>
<div class="operation-nav">
<router-link to="/dashboard/keywords/add">
<el-button type="primary" icon="plus">添加热门搜索</el-button>
</router-link>
</div>
</div>
<div class="content-main">
<div class="filter-box">
<el-form :inline="true" :model="filterForm" class="demo-form-inline">
<el-form-item label="关键词">
<el-input v-model="filterForm.name" placeholder="搜索关键词"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="onSubmitFilter"></el-button>
</el-form-item>
</el-form>
</div>
<div class="form-table-box">
<el-table :data="tableData" style="width: 100%" border stripe>
<el-table-column prop="id" label="ID" width="100px">
</el-table-column>
<el-table-column prop="keyword" label="关键词">
</el-table-column>
<el-table-column prop="is_hot" label="is_hot">
</el-table-column>
<el-table-column prop="is_default" label="is_default">
</el-table-column>
<el-table-column prop="is_show" label="is_show">
</el-table-column>
<el-table-column prop="sort_order" label="排序" width="80">
</el-table-column>
<el-table-column label="操作" width="140">
<template slot-scope="scope">
<el-button size="small" @click="handleRowEdit(scope.$index, scope.row)">编辑</el-button>
<el-button size="small" type="danger" @click="handleRowDelete(scope.$index, scope.row)">删除</el-button>
</template>
</el-table-column>
</el-table>
</div>
<div class="page-box">
<el-pagination @current-change="handlePageChange" :current-page="page" :page-size="10" layout="total, prev, pager, next, jumper" :total="total">
</el-pagination>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
page: 1,
total: 0,
filterForm: {
name: ''
},
tableData: []
}
},
methods: {
handlePageChange(val) {
this.page = val;
//localStorage
localStorage.setItem('keywordsPage', this.page)
localStorage.setItem('keywordsFilterForm', JSON.stringify(this.filterForm));
this.getList()
},
handleRowEdit(index, row) {
this.$router.push({ name: 'keywords_add', query: { id: row.id } })
},
handleRowDelete(index, row) {
this.$confirm('确定要删除?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
this.axios.post('keywords/destory', { id: row.id }).then((response) => {
console.log(response.data)
if (response.data.errno === 0) {
this.$message({
type: 'success',
message: '删除成功!'
});
this.getList();
}
})
});
},
onSubmitFilter() {
this.page = 1
this.getList()
},
getList() {
this.axios.get('keywords', {
params: {
page: this.page,
name: this.filterForm.name
}
}).then((response) => {
this.tableData = response.data.data.data
this.page = response.data.data.currentPage
this.total = response.data.data.count
})
}
},
components: {
},
mounted() {
this.getList();
}
}
</script>
<style scoped>
</style>

@ -0,0 +1,195 @@
<template>
<div class="login">
<div class="login-box">
<div class="logo">
<img src="static/images/loading.gif" />
</div>
<div class="body">
<p class="tips">海风小店</p>
<el-form ref="form" :model="form" :rules="rules" label-position="top">
<el-form-item label="" prop="username">
<el-input v-model="form.username" placeholder="用户名"></el-input>
</el-form-item>
<el-form-item label="" prop="password">
<el-input
type="password"
v-model="form.password"
placeholder="密码"
@keyup.enter.native="startLogin"
></el-input>
</el-form-item>
<el-form-item>
<el-button
type="primary"
@click="startLogin"
:loading="loading"
style="width: 100%"
>
{{ loading ? "登录中..." : "登录" }}
</el-button>
</el-form-item>
</el-form>
</div>
</div>
</div>
</template>
<script>
import api from "@/config/api";
export default {
data() {
return {
root: "",
form: {
username: "",
password: "",
},
rules: {
username: [
{ required: true, message: "请输入用户名", trigger: "blur" },
],
password: [
{ required: true, message: "请输入密码", trigger: "blur" },
{ min: 6, message: "密码不得低于6个字符", trigger: "blur" },
],
},
loading: false,
};
},
components: {},
methods: {
startLogin() {
console.log("<<<<<<<<==================>>>>>>>>");
console.log(123123);
console.log("<<<<<<<<==================>>>>>>>>");
this.$refs["form"].validate((valid) => {
if (!valid) {
return false;
}
this.loading = true;
let root = this.root;
this.axios
.post(root + "auth/login", {
username: this.form.username,
password: this.form.password,
})
.then((res) => {
let call = res.data;
console.log(call);
this.loading = false;
if (res.data.errno === 0) {
console.log(res.data.data);
localStorage.setItem("token", res.data.data.token);
localStorage.setItem(
"userInfo",
JSON.stringify(res.data.data.userInfo)
);
console.log(JSON.stringify(res.data.data.token));
console.log(JSON.stringify(res.data.data.userInfo));
this.$router.push({ name: "welcome" });
let sUserAgent = navigator.userAgent;
// todo
let mobileAgents = [
"Android",
"iPhone",
"Symbian",
"WindowsPhone",
"iPod",
"BlackBerry",
"Windows CE",
];
let goUrl = 0;
for (var i = 0; i < mobileAgents.length; i++) {
if (sUserAgent.indexOf(mobileAgents[i]) > -1) {
goUrl = 1;
break;
}
}
console.log(goUrl);
if (goUrl == 1) {
this.$router.push({ name: "wap" });
}
} else {
this.$message({
type: "error",
message: call.errmsg,
});
return false;
}
})
.catch((err) => {
this.loading = false;
});
});
},
},
mounted() {
this.root = api.rootUrl;
},
};
</script>
<style>
.login {
align-items: center;
background: url("https://www.qile.club/img/back.jpg");
/* 以上为登录背景,可以自己更换成自己喜欢的 */
background-size: 100%;
background-repeat: no-repeat;
display: flex;
font-family: Lato, Helvetica, sans-serif;
justify-content: center;
text-align: center;
height: 100%;
width: 100%;
color: #656565;
}
.login-box {
width: 320px;
background: #fff;
-webkit-border-radius: 10px;
-moz-border-radius: 10px;
border-radius: 10px;
box-shadow: 2px 2px 12px #ccc;
}
.login-box .logo {
height: 100px;
padding-top: 30px;
/*background: #324157;*/
display: flex;
align-items: center;
justify-content: center;
}
.login-box .logo img {
width: 80px;
height: 80px;
}
.login-box .body {
padding: 10px 30px 30px 30px;
}
.login-box .body .tips {
font-size: 14px;
height: 40px;
line-height: 40px;
text-align: center;
margin-bottom: 30px;
}
.login-box .body .author {
display: block;
font-size: 14px;
height: 40px;
line-height: 40px;
text-align: center;
color: #656565;
margin-bottom: 10px;
text-decoration: none;
}
.login-box .body .author a {
text-decoration: none;
}
</style>

@ -0,0 +1,264 @@
<template>
<div class="content-page">
<div class="content-nav">
<el-breadcrumb class="breadcrumb" separator="/">
<el-breadcrumb-item>商品设置</el-breadcrumb-item>
</el-breadcrumb>
</div>
<div class="content-main">
<el-tabs v-model="activeName" @tab-click="handleClick">
<el-tab-pane label="商品分类" name="first"></el-tab-pane>
<el-tab-pane label="商品型号" name="second"></el-tab-pane>
</el-tabs>
<div class="form-table-box">
<div class="btn-wrap">
<router-link v-if="pIndex == 0" to="/dashboard/category/add">
<el-button plain type="primary" icon="plus">添加分类</el-button>
</router-link>
<router-link v-if="pIndex == 1" to="/dashboard/specification/detail">
<el-button plain type="primary" icon="plus">添加型号</el-button>
</router-link>
</div>
<el-table v-if="pIndex == 0" :data="categoryData" style="width: 100%" border stripe>
<el-table-column prop="name" label="分类名称">
<template slot-scope="scope">
<div v-if="scope.row.level==1" class="bg-gray">{{scope.row.name}}</div>
<div v-if="scope.row.level==2" class="bg-left">{{scope.row.name}}</div>
<!-- {{ scope.row.level == 2 ? ' ' : '' }} {{scope.row.name}} -->
</template>
</el-table-column>
<el-table-column label="图标显示" width="80">
<template slot-scope="scope">
<el-switch
v-model="scope.row.is_channel"
active-text=""
inactive-text=""
@change='changeChannelStatus($event,scope.row.id)'>
</el-switch>
</template>
</el-table-column>
<el-table-column label="首页显示" width="80">
<template slot-scope="scope">
<el-switch
v-model="scope.row.is_show"
active-text=""
inactive-text=""
@change='changeShowStatus($event,scope.row.id)'>
</el-switch>
</template>
</el-table-column>
<el-table-column label="全部产品页面显示" width="140">
<template slot-scope="scope">
<el-switch
v-model="scope.row.is_category"
active-text=""
inactive-text=""
@change='changeCategoryStatus($event,scope.row.id)'>
</el-switch>
</template>
</el-table-column>
<el-table-column prop="sort_order" label="排序" width="100" sortable>
<template slot-scope="scope">
<el-input v-model="scope.row.sort_order" placeholder="排序" @blur="submitSort(scope.$index, scope.row)"></el-input>
</template>
</el-table-column>
<el-table-column label="操作" width="300">
<template slot-scope="scope">
<el-button size="small" @click="handleRowEdit(scope.$index, scope.row)">编辑</el-button>
<el-button size="small" type="danger" @click="handleRowDelete(scope.$index, scope.row)">删除
</el-button>
</template>
</el-table-column>
</el-table>
<el-table v-if="pIndex == 1" :data="specData" style="width: 100%" border stripe>
<el-table-column prop="id" label="ID" width="100">
</el-table-column>
<el-table-column prop="name" label="型号名">
</el-table-column>
<el-table-column prop="sort_order" label="排序" width="200">
</el-table-column>
<el-table-column label="操作" width="160">
<template slot-scope="scope">
<el-button size="small" @click="specEdit(scope.$index, scope.row)">编辑</el-button>
<el-button size="small" type="danger" @click="specDelete(scope.$index, scope.row)">删除
</el-button>
</template>
</el-table-column>
</el-table>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
activeName: 'first',
pIndex: 0,
categoryData:[],
is_spec_add: false,
dialogFormVisible:false,
specData: [],
form:{},
formLabelWidth: '120px'
}
},
methods: {
handleClick(tab, event) {
let pindex = tab._data.index;
this.activeClass = 0;
if (pindex == 0) {
this.getList();
this.pIndex = 0;
}
else if (pindex == 1) {
this.getSpecList();
this.pIndex = 1;
}
},
changeShowStatus($event, para) {
this.axios.get('category/showStatus', {
params: {
status: $event,
id: para
}
}).then((response) => {
})
},
changeChannelStatus($event, para) {
this.axios.get('category/channelStatus', {
params: {
status: $event,
id: para
}
}).then((response) => {
})
},
changeCategoryStatus($event, para) {
this.axios.get('category/categoryStatus', {
params: {
status: $event,
id: para
}
}).then((response) => {
})
},
submitSort(index, row){
this.axios.post('category/updateSort', { id: row.id,sort:row.sort_order }).then((response) => {
})
},
handleRowEdit(index, row) {
this.$router.push({name: 'category_add', query: {id: row.id}})
},
specEdit(index, row) {
console.log(row.id);
this.$router.push({name: 'specification_detail', query: {id: row.id}})
},
specDelete(index, row) {
this.$confirm('确定要删除?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
this.axios.post('specification/delete', {id: row.id}).then((response) => {
console.log(response.data)
if (response.data.errno === 0) {
this.$message({
type: 'success',
message: '删除成功!'
});
this.getSpecList();
}
else {
this.$message({
type: 'error',
message: '删除失败,该型号下有商品!'
});
}
})
});
},
handleRowDelete(index, row) {
this.$confirm('确定要删除?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
this.axios.post('category/destory', {id: row.id}).then((response) => {
console.log(response.data)
if (response.data.errno === 0) {
this.$message({
type: 'success',
message: '删除成功!'
});
this.getList();
}
else {
this.$message({
type: 'error',
message: '删除失败,该分类有子分类!'
});
}
})
});
},
getList() {
this.axios.get('category', {
params: {
page: this.page,
}
}).then((response) => {
this.categoryData = response.data.data
})
},
getSpecList() {
this.axios.get('specification').then((response) => {
this.specData = response.data.data
})
}
},
components: {},
mounted() {
this.getList();
}
}
</script>
<style scoped>
.sort-width{
width: 90px;
}
.right{
float: right;
}
.form-inline {
margin-top: 2px;
height: 40px;
margin-right: 20px;
}
.block {
margin-bottom: 10px;
height:42px;
display: flex;
align-items: center;
justify-content:space-between;
}
.active {
border-color: #ff4949;
color: #ff4949;
}
.marginRight{
margin-right: 20px;
}
.btn-wrap{
margin-bottom: 10px;
}
</style>

@ -0,0 +1,765 @@
<template>
<div class="content-page">
<div class="content-nav">
<el-breadcrumb class="breadcrumb" separator="/">
<!--<el-breadcrumb-item :to="{ name: 'dashboard' }">首页</el-breadcrumb-item>-->
<el-breadcrumb-item :to="{ name: 'order' }"
>订单管理</el-breadcrumb-item
>
<el-breadcrumb-item>{{
infoForm.order_sn ? "订单详情" : "添加订单"
}}</el-breadcrumb-item>
</el-breadcrumb>
<div class="operation-nav">
<el-button
type="primary"
@click="goBackPage"
size="small"
icon="arrow-left"
>返回列表</el-button
>
<!--<el-button type="primary" @click="test" size="small" icon="arrow-left">test</el-button>-->
</div>
</div>
<div class="order-status-text">
<label>{{ infoForm.order_status_text }}</label>
<div>
<el-button type="danger" plain @click="changeStatus"
>变更状态</el-button
>
<!--<el-button v-if="infoForm.order_status == 201" type="danger" @click="goPackage"></el-button>-->
<!--<el-button v-if="infoForm.order_status == 300" type="primary" @click="goPackage"></el-button>-->
</div>
</div>
<div class="content-main">
<div class="form-table-box">
<el-tabs v-model="activeName" @tab-click="handleClick">
<el-tab-pane label="订单信息" name="first">
<div class="content-title marginTop">买家信息</div>
<el-table :data="addressData" style="width: 100%" border stripe>
<el-table-column
prop="user_id"
label="用户id"
width="70"
></el-table-column>
<el-table-column
prop="nickname"
label="昵称"
width="100"
></el-table-column>
<el-table-column prop="avatar" label="头像" width="80">
<template slot-scope="scope">
<img
:src="scope.row.avatar"
alt=""
style="width: 60px; height: 60px"
/>
</template>
</el-table-column>
<el-table-column
prop="name"
label="客户名"
width="100"
></el-table-column>
<el-table-column
prop="mobile"
label="客户手机"
width="120"
></el-table-column>
<el-table-column
prop="address"
label="客户地址"
></el-table-column>
<el-table-column
prop="postscript"
label="买家备注"
width="300"
></el-table-column>
<el-table-column label="操作">
<template slot-scope="scope">
<el-button
size="small"
@click="addressEdit(scope.$index, scope.row)"
>编辑
</el-button>
</template>
</el-table-column>
</el-table>
<div class="content-title marginTop">货物信息</div>
<el-table
:data="infoForm.goodsList"
style="width: 100%"
border
stripe
>
<el-table-column
prop="goods_sn"
label="商品SKU"
width="120"
></el-table-column>
<el-table-column prop="list_pic_url" label="商品图" width="120"
>list_pic_url
<template slot-scope="scope">
<img
:src="scope.row.list_pic_url"
alt=""
style="width: 60px; height: 60px"
/>
</template>
</el-table-column>
<el-table-column
prop="goods_name"
label="商品名"
></el-table-column>
<el-table-column
prop="goods_specifition_name_value"
label="型号"
width="100"
></el-table-column>
<el-table-column
prop="retail_price"
label="售价"
width="100"
></el-table-column>
<el-table-column
prop="number"
label="购买数量"
width="100"
></el-table-column>
<el-table-column label="小计" width="100">
<template slot-scope="scope">
<label>{{ scope.row.retail_price * scope.row.number }}</label>
</template>
</el-table-column>
<el-table-column label="操作">
<template slot-scope="scope">
<el-button
size="small"
@click="goodsListEdit(scope.$index, scope.row)"
>编辑
</el-button>
<el-button
size="small"
type="danger"
@click="handleRowDelete(scope.$index, scope.row)"
>删除
</el-button>
</template>
</el-table-column>
</el-table>
<div class="detail-wrap">
<div class="total-price">
优惠¥{{ infoForm.promotions_price }}
</div>
<div class="total-price">
合计¥{{ infoForm.actual_price }}含运费¥{{
infoForm.freight_price
}}
</div>
<div class="total-price">
改价前¥{{ infoForm.change_price }}含运费¥{{
infoForm.freight_price
}}
</div>
<div class="total-price">
{{
infoForm.change_price - infoForm.actual_price > 0
? "优惠金额:" +
(infoForm.change_price - infoForm.actual_price).toFixed(2)
: "涨价金额:" +
(infoForm.actual_price - infoForm.change_price).toFixed(2)
}}
</div>
</div>
<div class="memo-wrap">
<div class="content-title">卖家备注</div>
<el-input
class="memo-input"
type="textarea"
autosize
placeholder="请输入内容"
v-model="infoForm.admin_memo"
>
</el-input>
<el-button size="small" type="primary" @click="saveAdminMemo"
>保存
</el-button>
</div>
<div class="footer">
<div class="item">
<div class="t">订单ID</div>
<div class="c">{{ infoForm.id }}</div>
</div>
<div class="item">
<div class="t">订单号</div>
<div class="c">{{ infoForm.order_sn }}</div>
</div>
<div class="item">
<div class="t">加入时间</div>
<div class="c">{{ infoForm.add_time }}</div>
</div>
<div class="item" v-if="infoForm.pay_time">
<div class="t">付款时间</div>
<div class="c">{{ infoForm.pay_time }}</div>
</div>
<div class="item" v-if="infoForm.shipping_time">
<div class="t">发货时间</div>
<div class="c">{{ infoForm.shipping_time }}</div>
</div>
<div class="item" v-if="infoForm.confirm_time">
<div class="t">确认时间</div>
<div class="c">{{ infoForm.confirm_time }}</div>
</div>
<div class="item" v-if="infoForm.dealdone_time">
<div class="t">完成时间</div>
<div class="c">{{ infoForm.dealdone_time }}</div>
</div>
</div>
</el-tab-pane>
<el-tab-pane label="物流信息" name="second">
<div class="no-traces" v-if="expressData.logistic_code == ''">
暂无物流信息
</div>
<div class="has-traces" v-else>
<p>
<label>快递公司</label>
<span>{{ expressData.shipper_name }}</span>
</p>
<p>
<label>快递单号</label>
<span>{{ expressData.logistic_code }}</span>
</p>
<p>
<label>快递轨迹</label>
</p>
<div v-if="on_posting == 1" class="posting">
正在查询请稍候...
</div>
<ul class="traces-wrap">
<li class="traces-list" v-for="item in expressData.traces">
<div class="traces-time">{{ item.time }}</div>
<div class="traces-content">{{ item.status }}</div>
</li>
</ul>
</div>
</el-tab-pane>
</el-tabs>
<!--<div class="content-title">买家信息</div>-->
</div>
</div>
<el-dialog title="修改地址" :visible.sync="dialogAddressVisible">
<el-form :model="nowAddressData">
<el-form-item label="所在地区:" label-width="120px">
<el-cascader
:options="options"
placeholder="请选择"
v-model="addOptions"
>
</el-cascader>
</el-form-item>
<el-form-item label="详细地址:" label-width="120px">
<el-input
class="el-input"
v-model="nowAddressData.cAddress"
auto-complete="off"
placeholder="请输入详细地"
></el-input>
</el-form-item>
<el-form-item label="收货人:" label-width="120px">
<el-input
class="el-input"
v-model="nowAddressData.name"
auto-complete="off"
placeholder="请输入收货人"
></el-input>
</el-form-item>
<el-form-item label="手机:" label-width="120px">
<el-input
class="el-input"
v-model="nowAddressData.mobile"
auto-complete="off"
placeholder="请输入收货人手机"
></el-input>
</el-form-item>
<el-form-item label="留言:" label-width="120px">
<el-input
class="el-input"
v-model="nowAddressData.postscript"
auto-complete="off"
placeholder=""
:disabled="true"
></el-input>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="dialogAddressVisible = false"> </el-button>
<el-button type="primary" @click="saveAddress"> </el-button>
</div>
</el-dialog>
<el-dialog title="修改商品" :visible.sync="dialogGoodsListVisible">
<el-form :model="goodsData">
<el-form-item label="id:" label-width="120px">
<label>{{ goodsData.goods_id }}</label>
</el-form-item>
<el-form-item label="商品图:" label-width="120px">
<template slot-scope="scope">
<img
:src="goodsData.list_pic_url"
alt=""
style="width: 60px; height: 60px"
/>
</template>
</el-form-item>
<el-form-item label="商品名:" label-width="120px">
<label>{{ goodsData.goods_name }}</label>
</el-form-item>
<el-form-item label="商品型号:" label-width="120px">
<label>{{ goodsData.goods_specifition_name_value }}</label>
</el-form-item>
<el-form-item label="售价:" label-width="120px">
<label>{{ goodsData.retail_price }}</label>
</el-form-item>
<el-form-item label="购买数量:" label-width="120px">
<el-input-number
v-model="goodsData.number"
:min="1"
label="购买的数量"
></el-input-number>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="dialogGoodsListVisible = false"> </el-button>
<el-button type="primary" @click="saveGoodsList"></el-button>
</div>
</el-dialog>
<el-dialog title="提示" :visible.sync="dialogVisible" width="30%">
<span>确定打包备货</span>
<span slot="footer" class="dialog-footer">
<el-button @click="dialogVisible = false"> </el-button>
<el-button type="primary" @click="PackageConfirm"> </el-button>
</span>
</el-dialog>
<el-dialog title="变更状态" :visible.sync="statusVisible" width="30%">
<el-form :model="statusData">
<el-form-item label="状态:" label-width="120px">
<el-select
class="el-select-class"
v-model="statusValue"
placeholder="选择状态"
>
<!---->
<el-option
v-for="item in statusList"
:key="item.value"
:label="item.label"
:value="item.value"
>
</el-option>
</el-select>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="statusVisible = false"> </el-button>
<el-button type="primary" @click="statusConfirm"> </el-button>
</span>
</el-dialog>
</div>
</template>
<script>
// import ElButton from "../../../../node_modules/element-ui/packages/button/src/button.vue";
import ElButton from "../../../node_modules/element-ui/packages/button/src/button.vue";
export default {
data() {
return {
statusList: [
{
value: "101",
label: "待付款",
},
{
value: "102",
label: "交易关闭",
},
{
value: "300",
label: "待发货",
},
{
value: "301",
label: "已发货",
},
{
value: "401",
label: "交易成功",
},
],
statusVisible: false,
statusValue: "",
statusData: {},
activeName: "first",
dialogVisible: false,
dialogAddressVisible: false,
dialogGoodsListVisible: false,
addressData: [],
infoForm: {
order_sn: 0,
},
infoRules: {
// goods_sn: [
// {required: true, message: '', trigger: 'blur'},
// ],
user_id: [{ required: true, message: "请输入名称", trigger: "blur" }],
order_sn: [{ required: true, message: "请输入简介", trigger: "blur" }],
order_status: [
{ required: true, message: "请选择商品图片", trigger: "blur" },
],
},
options: [],
addOptions: [],
nowAddressData: {},
goodsData: {},
oldGoodsNumber: 0,
expressData: {},
is_finish: 0,
on_posting: 0,
};
},
methods: {
changeStatus() {
this.statusVisible = true;
},
statusConfirm() {
this.axios
.post("order/changeStatus", {
status: this.statusValue,
orderSn: this.infoForm.order_sn,
})
.then((response) => {
// console.log(response.data);
this.getInfo();
this.statusVisible = false;
});
},
handleClick(tab, event) {
let pindex = tab._data.index;
if (pindex == 1) {
if (this.is_finish == 0) {
this.on_posting = 1;
this.axios
.post("order/getOrderExpress", { orderId: this.infoForm.id })
.then((response) => {
this.expressData = response.data.data;
this.expressData.traces = JSON.parse(this.expressData.traces);
this.is_finish = response.data.data.is_finish;
this.on_posting = 0;
});
}
}
},
PackageConfirm() {
this.axios
.get("order/orderpack", {
params: {
orderSn: this.infoForm.order_sn,
},
})
.then((response) => {
this.dialogVisible = false;
this.addressData = [];
this.getInfo();
});
},
goPackage() {
this.dialogVisible = true;
},
test() {
console.log(this.addressData);
console.log(this.infoForm);
},
handleRowDelete(index, row) {
this.goodsData = row;
this.goodsData.order_id = this.infoForm.id;
this.$confirm("确定要删除?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning",
})
.then(() => {
this.axios
.post("order/goodsListDelete", this.goodsData)
.then((response) => {
if (response.data.errno === 0) {
this.$message({
type: "success",
message: "删除成功!",
});
this.$router.go(-1);
}
});
})
.catch(() => {
// this.$message({
// type: 'info',
// message: ''
// });
});
},
saveGoodsList() {
this.goodsData.order_id = this.infoForm.id;
let old = this.oldGoodsNumber;
let now = this.goodsData.number;
console.log(old);
console.log(now);
if (old != now) {
let number = 0;
let addOrMinus = 0;
if (old > now) {
number = old - now;
} else {
number = now - old;
addOrMinus = 1;
}
this.goodsData.number = number;
this.goodsData.addOrMinus = addOrMinus;
this.axios
.post("order/saveGoodsList", this.goodsData)
.then((response) => {
// console.log(response.data);
// this.dialogGoodsListVisible = false;
// this.infoForm.order_sn = response.data.data;
//
// this.addressData = [];
// this.getInfo();
this.$router.go(-1);
});
} else {
this.dialogGoodsListVisible = false;
}
},
saveAdminMemo() {
this.axios
.post("order/saveAdminMemo", {
text: this.infoForm.admin_memo,
id: this.infoForm.id,
})
.then((response) => {
console.log("++---------------------------++");
console.log(response);
console.log("++---------------------------++");
if (response.data.errno === 0) {
this.$message({
type: "success",
message: "保存成功!",
});
} else {
this.$message({
type: "error",
message: "保存失败",
});
}
});
},
saveAddress() {
this.nowAddressData.order_sn = this.infoForm.order_sn;
this.nowAddressData.addOptions = this.addOptions;
this.axios
.post("order/saveAddress", this.nowAddressData)
.then((response) => {
console.log("++---------------------------++");
console.log(response);
console.log("++---------------------------++");
if (response.data.errno === 0) {
this.$message({
type: "success",
message: "修改成功!",
});
this.addressData = [];
this.getInfo();
this.dialogAddressVisible = false;
} else {
this.$message({
type: "error",
message: "修改失败",
});
}
});
},
onSubmitInfo() {},
goBackPage() {
this.$router.go(-1);
},
addressEdit() {
this.dialogAddressVisible = true;
},
goodsListEdit(index, info) {
console.log(info);
this.goodsData = info;
this.oldGoodsNumber = info.number;
this.dialogGoodsListVisible = true;
},
getAllRegion() {
let that = this;
this.axios.get("order/getAllRegion").then((response) => {
this.options = response.data.data;
});
},
getInfo() {
if (this.infoForm.id <= 0) {
return false;
}
this.axios
.get("order/detail", {
params: {
orderId: this.infoForm.id,
},
})
.then((response) => {
console.log("++---------------------------++");
console.log(response.data.data);
console.log("++---------------------------++");
this.infoForm = response.data.data.orderInfo;
let data = {
user_id: this.infoForm.user_id,
name: this.infoForm.consignee,
nickname: this.infoForm.user_name,
avatar: this.infoForm.avatar,
mobile: this.infoForm.mobile,
postscript: this.infoForm.postscript,
address: this.infoForm.full_region + this.infoForm.address,
cAddress: this.infoForm.address,
};
this.addressData = [];
this.addressData.push(data);
this.nowAddressData = data;
this.addOptions.push(
this.infoForm.province,
this.infoForm.city,
this.infoForm.district
);
console.log(this.infoForm);
});
},
},
components: { ElButton },
mounted() {
// console.log(this.$route.query);
this.infoForm.id = this.$route.query.id || 0;
this.getInfo();
this.getAllRegion();
},
};
</script>
<style scoped>
.no-traces {
width: 100%;
line-height: 100px;
font-size: 15px;
}
.has-traces {
width: 100%;
}
.has-traces p {
height: 30px;
line-height: 30px;
}
.has-traces p label {
font-size: 15px;
color: #6f6f6f;
width: 100px;
}
.has-traces .traces-wrap {
margin-bottom: 20px;
margin-left: 80px;
}
.traces-wrap li {
display: flex;
justify-content: flex-start;
align-items: center;
height: 30px;
}
.traces-wrap .traces-time {
font-size: 15px;
width: 160px;
}
.traces-wrap .traces-content {
font-size: 15px;
}
.memo-wrap {
display: flex;
justify-content: flex-start;
align-items: center;
}
.memo-input {
margin-right: 10px;
}
.order-status-text {
width: 100%;
height: 100px;
line-height: 100px;
background: #fff;
padding: 0 30px;
box-sizing: border-box;
margin-bottom: 10px;
display: flex;
justify-content: space-between;
align-items: center;
}
.content-title {
margin-bottom: 8px;
font-size: 14px;
}
.marginTop {
margin-top: 20px;
}
.footer {
width: 100%;
margin: 30px 0;
padding: 20px 0;
border-top: 1px solid #d1dbe5;
}
.footer .item {
font-size: 14px;
color: #5e7382;
display: flex;
justify-content: flex-start;
align-items: center;
margin-bottom: 10px;
}
.detail-wrap {
display: flex;
flex-direction: column;
padding: 20px;
border: 1px solid #f1f1f1;
margin: 20px 0;
}
.total-price {
width: 100%;
font-size: 14px;
margin: 6px 0;
}
.item .t {
width: 80px;
}
</style>

File diff suppressed because it is too large Load Diff

@ -0,0 +1,195 @@
<template>
<div class="content-page">
<div class="content-nav">
<el-breadcrumb class="breadcrumb" separator="/">
<el-breadcrumb-item>公告管理</el-breadcrumb-item>
</el-breadcrumb>
<div class="operation-nav">
<div style="margin-left:10px;"></div>
<el-button type="primary" icon="plus" @click="addNotice"></el-button>
</div>
</div>
<div class="content-main">
<div class="form-table-box">
<el-table :data="tableData" style="width: 100%" border stripe>
<el-table-column prop="id" label="ID" width="60"></el-table-column>
<el-table-column prop="content" label="内容"></el-table-column>
<el-table-column prop="end_time" label="结束时间" width="180"></el-table-column>
<el-table-column prop="enabled" label="状态" width="110px">
<template slot-scope="scope">
{{ scope.row.is_delete == 0 ? '启用中' : '已到期下线' }}
</template>
</el-table-column>
<el-table-column label="操作" width="220px">
<template slot-scope="scope">
<el-button size="small" @click="handleRowEdit(scope.$index, scope.row)">编辑</el-button>
<el-button plain size="small" type="danger"
@click="handleRowDelete(scope.$index, scope.row)">删除
</el-button>
</template>
</el-table-column>
</el-table>
</div>
</div>
<el-dialog :title="is_add? '添加':'编辑'" :visible.sync="dialog">
<el-form :model="noticeData">
<el-form-item label="内容:" label-width="120px">
<el-input class="el-input" v-model="noticeData.content" auto-complete="off"
placeholder="请输入内容"></el-input>
</el-form-item>
<el-form-item label="到期时间:" label-width="120px">
<el-date-picker
v-model="noticeData.time"
type="datetime"
placeholder="选择日期时间"
default-time="23:59:59">
</el-date-picker>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="dialog = false"> </el-button>
<!--<el-button @click="test"> </el-button>-->
<el-button type="primary" @click="goNotice" v-if="is_add"></el-button>
<el-button type="primary" @click="updateNotice" v-if="!is_add"></el-button>
</div>
</el-dialog>
</div>
</template>
<script>
export default {
data() {
return {
tableData: [],
noticeData: {
time:'',
content:''
},
dialog: false,
is_add: false,
}
},
methods: {
test(){
console.log(this.noticeData);
},
updateNotice() {
console.log(this.noticeData);
if(this.noticeData.content == ''){
this.$message({
type: 'error',
message: '内容不能为空'
})
return false;
}
else if(this.noticeData.time == null){
this.$message({
type: 'error',
message: '过期时间不能为空'
})
return false;
}
this.axios.post('notice/update', this.noticeData).then((response) => {
if (response.data.errno === 0) {
this.$message({
type: 'success',
message: '添加成功!'
});
this.getList();
} else {
this.$message({
type: 'error',
message: '添加失败'
})
}
})
this.dialog = false;
},
goNotice() {
console.log(this.noticeData);
if(this.noticeData.content == ''){
this.$message({
type: 'error',
message: '内容不能为空'
})
return false;
}
else if(this.noticeData.time == null){
this.$message({
type: 'error',
message: '过期时间不能为空'
})
return false;
}
this.axios.post('notice/add', this.noticeData).then((response) => {
if (response.data.errno === 0) {
this.$message({
type: 'success',
message: '添加成功!'
});
this.getList();
} else {
this.$message({
type: 'error',
message: '添加失败'
})
}
})
this.dialog = false;
},
addNotice() {
this.dialog = true;
this.is_add = true;
},
handleRowEdit(index, row) {
this.noticeData.time = row.end_time;
this.noticeData.content = row.content;
this.noticeData.id = row.id;
this.dialog = true;
this.is_add = false;
},
submitContent(index, row) {
this.axios.post('notice/updateContent', {id: row.id, content: row.content}).then((response) => {
})
},
handleRowDelete(index, row) {
this.$confirm('确定要删除?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
this.axios.post('notice/destory', {id: row.id}).then((response) => {
console.log(response.data)
if (response.data.errno === 0) {
this.$message({
type: 'success',
message: '删除成功!'
});
this.getList();
}
})
});
},
getList() {
this.axios.get('notice').then((response) => {
this.tableData = response.data.data;
})
}
},
components: {},
mounted() {
this.getList();
}
}
</script>
<style scoped>
</style>

@ -0,0 +1,119 @@
<template>
<div class="content-page">
<div class="content-nav">
<el-breadcrumb class="breadcrumb" separator="/">
<el-breadcrumb-item :to="{ name: 'shipper_list'}">快递公司</el-breadcrumb-item>
<el-breadcrumb-item>{{infoForm.id ? '编辑快递公司' : '添加快递公司'}}</el-breadcrumb-item>
</el-breadcrumb>
<div class="operation-nav">
<el-button type="primary" @click="goBackPage" icon="arrow-left">返回列表</el-button>
</div>
</div>
<div class="content-main">
<div class="form-table-box">
<el-form ref="infoForm" :rules="infoRules" :model="infoForm" label-width="120px">
<el-form-item label="名字" prop="name">
<el-input v-model="infoForm.name"></el-input>
</el-form-item>
<el-form-item label="代号" prop="code">
<el-input v-model="infoForm.code"></el-input>
</el-form-item>
<el-form-item label="客户编号">
<el-input v-model="infoForm.CustomerName"></el-input>
<div class="form-tips">打印电子面单需要填写</div>
</el-form-item>
<el-form-item label="月结账号">
<el-input v-model="infoForm.MonthCode"></el-input>
<div class="form-tips">打印电子面单需要填写</div>
</el-form-item>
<el-form-item label="排序" prop="sort_order">
<el-input-number v-model="infoForm.sort_order" :min="1" :max="1000"></el-input-number>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="onSubmitInfo"></el-button>
<el-button @click="goBackPage"></el-button>
</el-form-item>
</el-form>
</div>
</div>
</div>
</template>
<script>
import api from '@/config/api';
export default {
data() {
return {
infoForm: {
id: 0,
name: '',
code: '',
sort_order: 0
},
infoRules: {
name: [
{required: true, message: '请输入快递公司名字', trigger: 'blur'},
],
code: [
{required: true, message: '请输入快递公司代号', trigger: 'blur'},
],
MonthCode: [
{required: true, message: '请输入快递公司月结账号', trigger: 'blur'},
],
},
}
},
methods: {
goBackPage() {
this.$router.go(-1);
},
onSubmitInfo() {
this.$refs['infoForm'].validate((valid) => {
if (valid) {
this.axios.post('shipper/store', this.infoForm).then((response) => {
if (response.data.errno === 0) {
this.$message({
type: 'success',
message: '保存成功'
});
this.$router.go(-1)
} else {
this.$message({
type: 'error',
message: '保存失败'
})
}
})
} else {
return false;
}
});
},
getInfo() {
if (this.infoForm.id <= 0) {
return false
}
//
let that = this
this.axios.get('shipper/info', {
params: {
id: that.infoForm.id
}
}).then((response) => {
let resInfo = response.data.data;
that.infoForm = resInfo;
})
}
},
components: {},
mounted() {
this.infoForm.id = this.$route.query.id || 0;
this.getInfo();
console.log(api)
}
}
</script>

@ -0,0 +1,160 @@
<template>
<div class="content-page">
<div class="content-nav">
<el-breadcrumb class="breadcrumb" separator="/">
<el-breadcrumb-item :to="{ name: 'shipper' }">快递设置</el-breadcrumb-item>
<el-breadcrumb-item>快递列表</el-breadcrumb-item>
</el-breadcrumb>
<div class="operation-nav">
<el-button plain type="primary" @click="addShipper" icon="arrow-left">添加快递</el-button>
<el-button @click="goBackPage" icon="arrow-left">返回</el-button>
</div>
</div>
<div class="content-main">
<div class="filter-box">
<el-form :inline="true" :model="filterForm" class="demo-form-inline">
<el-form-item label="快递公司">
<el-input v-model="filterForm.name" placeholder="搜索快递公司"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="onSubmitFilter"></el-button>
</el-form-item>
</el-form>
</div>
<div class="form-table-box">
<el-table :data="tableData" style="width: 100%" border stripe>
<el-table-column prop="id" label="ID" width="100px">
</el-table-column>
<el-table-column prop="name" label="名字" width="220">
</el-table-column>
<el-table-column prop="code" label="代号" width="220">
</el-table-column>
<el-table-column prop="sort_order" label="排序" width="220">
<template slot-scope="scope">
<el-input-number class="sort-width" size="mini" :min="1" :max="100" controls-position="right" v-model="scope.row.sort_order" placeholder="排序" @blur="submitSort(scope.$index, scope.row)" @change="submitSort(scope.$index, scope.row)"></el-input-number>
</template>
</el-table-column>
<el-table-column label="使用" width="80">
<template slot-scope="scope">
<el-switch
v-model="scope.row.enabled"
active-text=""
inactive-text=""
@change='changeStatus($event,scope.row.id)'>
</el-switch>
</template>
</el-table-column>
<el-table-column label="操作">
<template slot-scope="scope">
<el-button size="small" @click="handleRowEdit(scope.$index, scope.row)">编辑</el-button>
<el-button size="small" type="danger" @click="handleRowDelete(scope.$index, scope.row)">删除</el-button>
</template>
</el-table-column>
</el-table>
</div>
<div class="page-box">
<el-pagination @current-change="handlePageChange" :current-page="page" :page-size="10" layout="total, prev, pager, next, jumper" :total="total">
</el-pagination>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
page: 1,
total: 0,
filterForm: {
name: ''
},
tableData: []
}
},
methods: {
submitSort(index, row){
this.axios.post('shipper/updateSort', { id: row.id,sort:row.sort_order }).then((response) => {})
},
goBackPage() {
this.$router.go(-1);
},
handlePageChange(val) {
this.page = val;
//localStorage
localStorage.setItem('shipperPage', this.page)
localStorage.setItem('shipperFilterForm', JSON.stringify(this.filterForm));
this.getList()
},
addShipper() {
this.$router.push({ name: 'shipper_add', query: { id: 0 } })
},
handleRowEdit(index, row) {
this.$router.push({ name: 'shipper_add', query: { id: row.id } })
},
handleRowDelete(index, row) {
this.$confirm('确定要删除?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
this.axios.post('shipper/destory', { id: row.id }).then((response) => {
console.log(response.data)
if (response.data.errno === 0) {
this.$message({
type: 'success',
message: '删除成功!'
});
this.getList();
}
})
});
},
onSubmitFilter() {
this.page = 1
this.getList()
},
getList() {
this.axios.get('shipper/list', {
params: {
page: this.page,
name: this.filterForm.name
}
}).then((response) => {
this.tableData = response.data.data.data
this.page = response.data.data.currentPage
this.total = response.data.data.count
console.log(this.tableData)
for(const item of this.tableData){
item.enabled = item.enabled?true:false
}
})
},
changeStatus($event, para) {
this.axios.get('shipper/enabledStatus', {
params: {
status: $event,
id: para
}
}).then((response) => {
this.$message({
type: 'success',
message: '更新成功!'
});
})
},
},
components: {
},
mounted() {
this.getList();
}
}
</script>
<style scoped>
</style>

@ -0,0 +1,193 @@
<template>
<div class="content-page">
<div class="content-nav">
<el-breadcrumb class="breadcrumb" separator="/">
<el-breadcrumb-item>快递设置</el-breadcrumb-item>
</el-breadcrumb>
<div class="operation-nav">
<router-link to="/dashboard/shipper/list">
<el-button type="primary" icon="plus">快递公司列表</el-button>
</router-link>
</div>
</div>
<div class="content-main">
<div class="form-table-box">
<el-form ref="infoForm" :model="infoForm" :rules="infoRules" label-width="120px">
<el-form-item label="打印后自动发货">
<el-switch v-model="infoForm.autoDelivery"
@change='changeStatus(infoForm.autoDelivery)'></el-switch>
</el-form-item>
<el-form-item label="寄件人" prop="Name">
<el-input v-model="infoForm.Name" placeholder="请输入非代理发货时的寄件人"></el-input>
</el-form-item>
<el-form-item label="电话" prop="Tel">
<el-input v-model="infoForm.Tel" placeholder="请输入电话"></el-input>
</el-form-item>
<el-form-item label="省份" prop="ProvinceName">
<el-cascader
:options="options"
placeholder="请选择地区"
v-model="senderOptions">
</el-cascader>
</el-form-item>
<!---->
<!--<el-form-item label="省份" prop="ProvinceName">-->
<!--<el-input v-model="infoForm.ProvinceName" placeholder="请输入省份"></el-input>-->
<!--</el-form-item>-->
<!--<el-form-item label="城市" prop="CityName">-->
<!--<el-input v-model="infoForm.CityName" placeholder="请输入城市"></el-input>-->
<!--</el-form-item>-->
<!--<el-form-item label="区/县" prop="ExpAreaName">-->
<!--<el-input v-model="infoForm.ExpAreaName" placeholder="请输入区/县"></el-input>-->
<!--</el-form-item>-->
<el-form-item label="地址" prop="Address">
<el-input v-model="infoForm.Address" placeholder="请输入具体地址"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="onSaveSubmit"></el-button>
</el-form-item>
</el-form>
</div>
<div class="form-table-box">
<el-form label-width="120px">
<el-form-item label="使用中的快递">
<el-table :data="tableData" style="width: 100%" border stripe>
<el-table-column prop="name" label="名字"></el-table-column>
<el-table-column prop="code" label="代号"></el-table-column>
<el-table-column prop="CustomerName" label="客户编号"></el-table-column>
<el-table-column prop="MonthCode" label="月结账号"></el-table-column>
<el-table-column label="操作" width="170">
<template slot-scope="scope">
<el-button size="small" @click="handleRowEdit(scope.$index, scope.row)">编辑
</el-button>
</template>
</el-table-column>
</el-table>
</el-form-item>
</el-form>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
infoForm: {},
page: 1,
total: 0,
filterForm: {
name: ''
},
tableData: [],
options: [],
senderOptions:[],
infoRules: {
Name: [
{required: true, message: '请输入寄件人姓名', trigger: 'blur'},
],
Tel: [
{required: true, message: '请输入寄件人电话', trigger: 'blur'},
],
ProvinceName: [
{required: true, message: '请输入寄件省份', trigger: 'blur'},
],
CityName: [
{required: true, message: '请输入寄件城市', trigger: 'blur'},
],
ExpAreaName: [
{required: true, message: '请输入寄件区县', trigger: 'blur'},
],
Address: [
{required: true, message: '请输入寄件人具体地址', trigger: 'blur'},
],
}
}
},
methods: {
getAllRegion() {
let that = this;
this.axios.get('order/getAllRegion').then((response) => {
this.options = response.data.data;
})
},
changeStatus() {
this.infoForm.autoDelivery == true ? this.infoForm.autoDelivery = 1 : this.infoForm.autoDelivery = 0;
this.axios.post('admin/changeAutoStatus', {status:this.infoForm.autoDelivery}).then((response) => {
if (response.data.errno === 0) {
this.$message({
type: 'success',
message: '更改成功'
});
this.infoForm.autoDelivery == 1 ? this.infoForm.autoDelivery = true : this.infoForm.autoDelivery = false
}
else {
this.$message({
type: 'error',
message: '更改失败'
})
}
})
},
handleRowEdit(index, row) {
this.$router.push({name: 'shipper_add', query: {id: row.id}})
},
onSaveSubmit() {
this.infoForm.province_id = this.senderOptions[0];
this.infoForm.city_id = this.senderOptions[1];
this.infoForm.district_id = this.senderOptions[2];
this.infoForm.autoDelivery == true ? this.infoForm.autoDelivery = 1 : this.infoForm.autoDelivery = 0;
this.$refs['infoForm'].validate((valid) => {
if (valid) {
this.axios.post('admin/storeShipperSettings', this.infoForm).then((response) => {
if (response.data.errno === 0) {
this.$message({
type: 'success',
message: '保存成功'
});
this.infoForm.autoDelivery == 1 ? this.infoForm.autoDelivery = true : this.infoForm.autoDelivery = false
}
else {
this.$message({
type: 'error',
message: '保存失败'
})
}
})
} else {
return false;
}
});
},
getList() {
this.axios.get('shipper').then((response) => {
this.infoForm = response.data.data.set;
this.tableData = response.data.data.info;
this.infoForm.autoDelivery == 1 ? this.infoForm.autoDelivery = true : this.infoForm.autoDelivery = false
this.senderOptions.push(
this.infoForm.province_id,
this.infoForm.city_id,
this.infoForm.district_id
)
})
}
},
components: {},
mounted() {
this.getList();
this.getAllRegion();
}
}
</script>
<style scoped>
.form-table-box {
border: 1px solid #f1f1f1;
margin-bottom: 20px;
}
</style>

@ -0,0 +1,104 @@
<template>
<div class="content-page">
<div class="content-nav">
<el-breadcrumb class="breadcrumb" separator="/">
<el-breadcrumb-item>购物车列表</el-breadcrumb-item>
</el-breadcrumb>
</div>
<div class="content-main">
<div class="filter-box">
<el-form :inline="true" :model="filterForm" class="demo-form-inline">
<el-form-item label="商品名称">
<el-input v-model="filterForm.name" placeholder="商品名称"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="onSubmitFilter"></el-button>
</el-form-item>
</el-form>
</div>
<div class="form-table-box">
<el-table :data="tableData" style="width: 100%" border stripe>
<el-table-column prop="id" label="ID" width="60px">
</el-table-column>
<el-table-column prop="user_id" label="用户ID" width="80px"></el-table-column>
<el-table-column prop="nickname" label="用户昵称" width="100px"></el-table-column>
<el-table-column prop="goods_id" label="商品ID" width="100px"></el-table-column>
<el-table-column prop="list_pic_url" label="图片" width="70px">
<template slot-scope="scope">
<img :src="scope.row.list_pic_url" alt="" style="width: 50px;height: 50px">
</template>
</el-table-column>
<el-table-column prop="goods_name" label="商品名称"></el-table-column>
<el-table-column prop="goods_specifition_name_value" label="型号"></el-table-column>
<el-table-column prop="number" label="数量" width="70px"></el-table-column>
<el-table-column prop="retail_price" label="成交价"></el-table-column>
<el-table-column prop="add_time" label="加入时间"></el-table-column>
<el-table-column prop="is_delete" label="是否删除">
<template slot-scope="scope">
<label>{{scope.row.is_delete == 1? '已删':''}}</label>
</template>
</el-table-column>
</el-table>
</div>
<div class="page-box">
<el-pagination @current-change="handlePageChange" :current-page="page" :page-size="10" layout="total, prev, pager, next, jumper" :total="total">
</el-pagination>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
page: 1,
total: 0,
filterForm: {
name: ''
},
tableData: []
}
},
methods: {
handlePageChange(val) {
this.page = val;
//localStorage
localStorage.setItem('shopCartPage', this.page)
localStorage.setItem('shopCartFilterForm', JSON.stringify(this.filterForm));
this.getList()
},
onSubmitFilter() {
this.page = 1
this.getList()
},
getList() {
this.axios.get('shopcart', {
params: {
page: this.page,
name: this.filterForm.name
}
}).then((response) => {
this.tableData = response.data.data.data
this.page = response.data.data.currentPage
this.total = response.data.data.count
})
}
},
components: {
},
mounted() {
this.getList();
}
}
</script>
<style scoped>
</style>

@ -0,0 +1,124 @@
<template>
<div class="content-page">
<div class="content-nav">
<el-breadcrumb class="breadcrumb" separator="/">
<el-breadcrumb-item>显示设置</el-breadcrumb-item>
</el-breadcrumb>
<div class="operation-nav">
<el-button type="primary" @click="onSubmitInfo"></el-button>
</div>
</div>
<div class="content-main">
<div class="form-table-box">
<el-form ref="infoForm" :model="infoForm" label-width="120px">
<el-form-item label="广告" prop="type">
<el-radio-group v-model="infoForm.banner">
<el-radio :label="1">显示</el-radio>
<el-radio :label="0">不显示</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="公告">
<el-radio-group v-model="infoForm.notice">
<el-radio :label="1">显示</el-radio>
<el-radio :label="0">不显示</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="广告下的图标">
<el-radio-group v-model="infoForm.channel">
<el-radio :label="1">显示</el-radio>
<el-radio :label="0">不显示</el-radio>
</el-radio-group>
<div class="form-tip">那几个图标</div>
</el-form-item>
<el-form-item label="首页分类图片或文字">
<el-radio-group v-model="infoForm.index_banner_img">
<el-radio :label="1">图片</el-radio>
<el-radio :label="0">文字</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="onSubmitInfo"></el-button>
<el-button @click="goBackPage"></el-button>
</el-form-item>
</el-form>
</div>
</div>
</div>
</template>
<script>
import api from '@/config/api';
export default {
data() {
return {
value: [],
infoForm: {
},
}
},
methods: {
test(){
console.log(this.value);
},
goBackPage() {
this.$router.go(-1);
},
onSubmitInfo() {
this.$refs['infoForm'].validate((valid) => {
if (valid) {
this.axios.post('admin/showsetStore', this.infoForm).then((response) => {
if (response.data.errno === 0) {
this.$message({
type: 'success',
message: '保存成功'
});
// this.$router.go(-1)
} else {
this.$message({
type: 'error',
message: '保存失败'
})
}
})
} else {
return false;
}
});
},
getInfo() {
if (this.infoForm.id <= 0) {
return false
}
//
let that = this
this.axios.get('admin/showset').then((response) => {
let resInfo = response.data.data;
that.infoForm = resInfo;
})
}
},
components: {},
mounted() {
this.getInfo();
}
}
</script>
<style scoped>
.el-form-item .date-picker {
width: 450px!important;
max-width: 410px!important;
}
.el-form-item .date-picker input {
width: 410px!important;
max-width: 410px!important;
}
.margin-left{
margin-left:20px;
}
</style>

@ -0,0 +1,190 @@
<template>
<div class="content-page">
<div class="content-nav">
<el-breadcrumb class="breadcrumb" separator="/">
<el-breadcrumb-item :to="{ name: 'nature' }">商品设置</el-breadcrumb-item>
<el-breadcrumb-item>{{infoForm.id ? '编辑型号' : '添加型号'}}</el-breadcrumb-item>
</el-breadcrumb>
<div class="operation-nav">
<el-button type="primary" @click="goBackPage" icon="arrow-left">返回列表</el-button>
</div>
</div>
<div class="content-main">
<div class="form-table-box">
<el-form ref="infoForm" :rules="infoRules" :model="infoForm" label-width="120px">
<el-form-item label="分类名称" prop="name">
<el-input v-model="infoForm.name"></el-input>
</el-form-item>
<el-form-item label="排序">
<el-input-number v-model="infoForm.sort_order" :min="1" :max="1000"></el-input-number>
</el-form-item>
<el-form-item>
<el-button v-if="infoForm.id > 0" type="primary" @click="updateSpec"></el-button>
<el-button v-else type="primary" @click="addSpec"></el-button>
<el-button v-if="infoForm.id > 0" type="danger" @click="specDelete"></el-button>
<el-button @click="goBackPage"></el-button>
</el-form-item>
</el-form>
</div>
</div>
</div>
</template>
<script>
import api from '@/config/api';
export default {
data() {
return {
infoForm: {
id: 0,
name: "",
sort_order: 1,
},
infoRules:{
name: [
{required: true, message: '请输入名称', trigger: 'blur'},
]
}
}
},
methods: {
addSpec(){
let info = {
name:this.infoForm.name,
sort_order:this.infoForm.sort_order
}
this.$refs['infoForm'].validate((valid) => {
if (valid) {
this.axios.post('specification/add', info).then((response) => {
if (response.data.errno === 0) {
this.$message({
type: 'success',
message: '添加成功!'
});
this.$router.go(-1);
} else {
this.$message({
type: 'error',
message: '添加失败'
})
}
})
} else {
return false;
}
});
},
updateSpec(){
let info = {
id:this.infoForm.id,
name:this.infoForm.name,
sort_order:this.infoForm.sort_order
}
this.$refs['infoForm'].validate((valid) => {
if (valid) {
this.axios.post('specification/update', info).then((response) => {
if (response.data.errno === 0) {
this.$message({
type: 'success',
message: '保存成功!'
});
this.$router.go(-1);
} else {
this.$message({
type: 'error',
message: '保存失败'
})
}
})
} else {
return false;
}
});
},
specDelete(index, row) {
this.$confirm('确定要删除?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
this.axios.post('specification/delete', {id: row.id}).then((response) => {
console.log(response.data)
if (response.data.errno === 0) {
this.$message({
type: 'success',
message: '删除成功!'
});
this.$router.go(-1);
}
else {
this.$message({
type: 'error',
message: '删除失败,该型号下有商品!'
});
}
})
});
},
goBackPage() {
this.$router.go(-1);
},
getInfo() {
console.log(this.infoForm.id);
console.log(this.infoForm.id);
console.log(this.infoForm.id);
if (this.infoForm.id <= 0) {
return false
}
let that = this
this.axios.post('specification/detail', {
id: that.infoForm.id
}).then((response) => {
let resInfo = response.data.data;
console.log(resInfo);
that.infoForm = resInfo;
})
}
},
components: {},
mounted() {
this.infoForm.id = this.$route.query.id || 0;
this.getInfo();
}
}
</script>
<style scoped>
.image-uploader {
height: 105px;
}
.image-uploader .el-upload {
border: 1px solid #d9d9d9;
cursor: pointer;
position: relative;
overflow: hidden;
}
.image-uploader .el-upload:hover {
border-color: #20a0ff;
}
.image-uploader .image-uploader-icon {
font-size: 28px;
color: #8c939d;
min-width: 105px;
height: 105px;
line-height: 105px;
text-align: center;
}
.image-show {
background-color: #f8f8f8;
min-width: 105px;
height: 105px;
display: block;
}
</style>

@ -0,0 +1,736 @@
<template>
<div class="content-page">
<div class="content-nav">
<el-breadcrumb class="breadcrumb" separator="/">
<el-breadcrumb-item :to="{ name: 'user' }">会员管理</el-breadcrumb-item>
<el-breadcrumb-item>会员详情</el-breadcrumb-item>
</el-breadcrumb>
<div class="operation-nav">
<el-button type="primary" @click="goBackPage" icon="arrow-left">返回列表</el-button>
</div>
</div>
<div class="content-main">
<div class="form-table-box">
<el-table :data="userData" style="width: 100%" border stripe>
<el-table-column prop="id" label="ID" width="60">
</el-table-column>
<el-table-column label="头像" width="80">
<template slot-scope="scope">
<img :src="scope.row.avatar" alt="" style="width: 50px;height: 50px">
</template>
</el-table-column>
<el-table-column prop="nickname" width="80" label="昵称"></el-table-column>
<el-table-column prop="name" width="110" label="姓名">
<template slot-scope="scope">
<el-input size="mini" v-model="scope.row.name" placeholder="姓名"
@blur="submitName(scope.$index, scope.row)"></el-input>
</template>
</el-table-column>
<el-table-column prop="name" width="160" label="手机">
<template slot-scope="scope">
<el-input size="mini" v-model="scope.row.mobile" placeholder="手机"
@blur="submitMobile(scope.$index, scope.row)"></el-input>
</template>
</el-table-column>
<el-table-column prop="gender" label="性别" width="60">
<template slot-scope="scope">
{{ scope.row.gender == 2 ? '女' : '男' }}
</template>
</el-table-column>
<el-table-column prop="register_time" label="注册时间" width="180"></el-table-column>
<el-table-column prop="last_login_time" label="最近登录" width="180"></el-table-column>
</el-table>
</div>
<div class="block-box">
<div class="block">
<div class="text">提交订单数:</div>
<div class="num">{{this.dataInfo.orderSum}}</div>
</div>
<div class="block">
<div class="text">成交订单:</div>
<div class="num">{{this.dataInfo.orderDone}}</div>
</div>
<div class="block">
<div class="text">消费金额:</div>
<div class="num" v-if="this.dataInfo.orderMoney == null">0</div>
<div class="num" v-else>{{this.dataInfo.orderMoney}}</div>
</div>
<div class="block">
<div class="text">加入购物车:</div>
<div class="num" v-if="this.dataInfo.cartSum == null">0</div>
<div class="num" v-else>{{this.dataInfo.cartSum}}</div>
</div>
</div>
<el-tabs v-model="activeName" @tab-click="handleClick">
<el-tab-pane label="订单" name="first"></el-tab-pane>
<el-tab-pane label="地址管理" name="second"></el-tab-pane>
<el-tab-pane label="购物车" name="third"></el-tab-pane>
<el-tab-pane label="足迹" name="fourth"></el-tab-pane>
</el-tabs>
<div class="form-table-box" v-if="this.pIndex == 0">
<div v-for="item in orderData" class="list-wrap clearfix">
<div class="header clearfix">
<div class="status-text">{{item.order_status_text}}</div>
<div class="add-time">{{item.add_time}}</div>
<div class="order-id">订单号{{item.order_sn}}</div>
<div class="price-wrap">当前合计{{item.actual_price}}含运费{{item.freight_price}}</div>
<div v-if="item.change_price!= item.actual_price" class="price-change">
改价前{{item.change_price}}
</div>
<div class="goods-num">{{item.goodsCount}}件商品</div>
</div>
<div class="content-wrap clearfix">
<div class="left">
<div class="goods-list" v-for="iitem in item.goodsList">
<img :src="iitem.list_pic_url" class="goods-img">
<div class="goods-name">{{iitem.goods_name}}</div>
<div class="goods-spec">{{iitem.goods_specifition_name_value}}</div>
<div class="goods-number">数量{{iitem.number}}</div>
<div class="goods-number">¥{{iitem.retail_price}}</div>
</div>
</div>
<div class="main">
<div class="m1">
<div class="user-name">{{item.consignee}}</div>
<div class="user-mobile">{{item.mobile}}</div>
</div>
<div class="user-address">{{item.full_region}}{{item.address}}</div>
<div class="user-post">{{item.postscript}}</div>
</div>
<div class="right">
<el-button class="right-detail" type="text" @click="viewDetail(item.order_sn)"
size="mini">
查看详情
</el-button>
</div>
</div>
</div>
</div>
<div class="address-wrap" v-if="this.pIndex == 1">
<div class="coupon-w">
<div class="top">
<div class="l">
<div class="f1" style="width: 100px;">收件人</div>
<div class="f1" style="width: 100px;">手机</div>
<div class="f1" style="width: 600px;">详细地址</div>
</div>
<div class="r">操作</div>
</div>
<div class="bottom" v-for="item in addressData">
<div class="l">
<div class="f1" style="width: 100px;">{{item.name}}</div>
<div class="f1" style="width: 100px;">{{item.mobile}}</div>
<div class="f1" style="width: 600px;">{{item.full_region}}</div>
</div>
<div class="r">
<el-button size="small" @click="addressEdit(item)"></el-button>
</div>
</div>
</div>
</div>
<div class="form-table-box" v-if="this.pIndex == 2">
<el-table :data="cartData" style="width: 100%" border stripe>
<el-table-column prop="goods_id" label="商品ID" width="100px"></el-table-column>
<el-table-column prop="list_pic_url" label="图片" width="70px">
<template slot-scope="scope">
<img :src="scope.row.list_pic_url" alt="" style="width: 50px;height: 50px">
</template>
</el-table-column>
<el-table-column prop="goods_name" label="商品名称"></el-table-column>
<el-table-column prop="goods_specifition_name_value" label="型号"></el-table-column>
<el-table-column prop="number" label="数量" width="70px"></el-table-column>
<el-table-column prop="retail_price" label="成交价"></el-table-column>
<el-table-column prop="add_time" label="加入时间"></el-table-column>
<el-table-column prop="is_delete" label="是否删除">
<template slot-scope="scope">
<label>{{scope.row.is_delete == 1? '已删':''}}</label>
</template>
</el-table-column>
</el-table>
</div>
<div class="form-table-box" v-if="this.pIndex == 3">
<el-table :data="footData" style="width: 100%" stripe>
<el-table-column prop="id" label="商品ID" width="100px"></el-table-column>
<el-table-column prop="list_pic_url" label="图片" width="70px">
<template slot-scope="scope">
<img :src="scope.row.list_pic_url" alt="" style="width: 50px;height: 50px">
</template>
</el-table-column>
<el-table-column prop="name" label="商品名称"></el-table-column>
</el-table>
</div>
<div class="page-box">
<el-pagination @current-change="handlePageChange" :current-page="page" :page-size="10"
layout="total, prev, pager, next, jumper" :total="total">
</el-pagination>
</div>
</div>
<el-dialog title="修改地址" :visible.sync="dialogAddressVisible">
<el-form :model="nowAddressData">
<el-form-item label="所在地区:" label-width="120px">
<el-cascader
:options="options"
placeholder="请选择"
v-model="addOptions">
</el-cascader>
</el-form-item>
<el-form-item label="详细地址:" label-width="120px">
<el-input class="el-input" v-model="nowAddressData.address" auto-complete="off"
placeholder="请输入详细地"></el-input>
</el-form-item>
<el-form-item label="收货人:" label-width="120px">
<el-input class="el-input" v-model="nowAddressData.name" auto-complete="off"
placeholder="请输入收货人"></el-input>
</el-form-item>
<el-form-item label="手机:" label-width="120px">
<el-input class="el-input" v-model="nowAddressData.mobile" auto-complete="off"
placeholder="请输入收货人手机"></el-input>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="dialogAddressVisible = false"> </el-button>
<el-button type="primary" @click="saveAddress"> </el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import api from '@/config/api';
export default {
data() {
return {
loginInfo: null,
page: 1,
total: 0,
filterForm: {
name: ''
},
tableData: [],
activeName: 'first',
pIndex: 0,
num: 0,
infoForm: {
id: 0
},
userData: [],
addressData: [],
cartData: [],
footData: [],
orderData: [],
dialogAddressVisible: false,
nowAddressData: {},
addOptions: [],
options: [],
addValue: {},
dataInfo: {},
data_money: [],
data_sum: [],
forlist: [11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0],
}
},
methods: {
saveAddress() {
this.nowAddressData.addOptions = this.addOptions;
this.axios.post('user/saveaddress', this.nowAddressData).then((response) => {
if (response.data.errno === 0) {
this.$message({
type: 'success',
message: '修改成功!'
});
this.addressData = [];
this.getAddress();
this.dialogAddressVisible = false;
} else {
this.$message({
type: 'error',
message: '修改失败'
})
}
})
},
addressEdit(item) {
this.nowAddressData = item;
this.addOptions.push(
item.province_id,
item.city_id,
item.district_id,
)
this.dialogAddressVisible = true
},
viewDetail(index) {
this.$router.push({name: 'order_detail', query: {order_sn: index}})
},
handleClick(tab, event) {
let pindex = tab._data.index;
this.page = 1;
this.total = 0
if (pindex == 0) {
this.pIndex = 0;
this.getOrder();
}
else if (pindex == 1) {
this.pIndex = 1;
this.getAddress();
}
else if (pindex == 2) {
this.pIndex = 2;
this.getCartData();
}
else if (pindex == 3) {
this.pIndex = 3;
this.getFootData();
}
},
submitNick(index, row) {
this.axios.post('user/updateInfo', {id: row.id, nickname: row.nickname}).then((response) => {
})
},
submitName(index, row) {
this.axios.post('user/updateName', {id: row.id, name: row.name}).then((response) => {
if (response.data.errno === 0) {
this.$message({
type: 'success',
message: '修改成功!'
});
} else {
this.$message({
type: 'error',
message: '修改失败'
})
}
})
},
submitMobile(index, row) {
this.axios.post('user/updateMobile', {id: row.id, mobile: row.mobile}).then((response) => {
if (response.data.errno === 0) {
this.$message({
type: 'success',
message: '修改成功!'
});
} else {
this.$message({
type: 'error',
message: '修改失败'
})
}
})
},
handlePageChange(val) {
this.page = val;
//localStorage
localStorage.setItem('thisPage', this.page)
let pindex = this.pIndex;
if (pindex == 0) {
this.getOrder();
}
else if (pindex == 1) {
this.getAddress();
}
else if (pindex == 2) {
this.getCartData();
}
else if (pindex == 3) {
this.getFootData();
}
},
goBackPage() {
this.$router.go(-1);
},
datainfo() {
if (this.infoForm.id <= 0) {
return false
}
let that = this;
this.axios.get('user/datainfo', {
params: {
id: that.infoForm.id
}
}).then((response) => {
let info = response.data.data;
this.dataInfo = info;
})
},
getInfo() {
if (this.infoForm.id <= 0) {
return false
}
let that = this;
this.axios.get('user/info', {
params: {
id: that.infoForm.id
}
}).then((response) => {
let info = response.data.data;
this.userData.push(info);
})
},
getOrder() {
if (this.infoForm.id <= 0) {
return false
}
let that = this;
this.axios.get('user/order', {
params: {
id: that.infoForm.id,
page: this.page,
}
}).then((response) => {
this.orderData = response.data.data.data;
this.page = response.data.data.currentPage;
this.total = response.data.data.count
})
},
getAddress() {
if (this.infoForm.id <= 0) {
return false
}
let that = this;
this.axios.get('user/address', {
params: {
id: that.infoForm.id,
page: this.page,
}
}).then((response) => {
this.addressData = response.data.data.data;
this.page = response.data.data.currentPage;
this.total = response.data.data.count;
})
},
getCartData() {
if (this.infoForm.id <= 0) {
return false
}
let that = this;
this.axios.get('user/cartdata', {
params: {
id: that.infoForm.id,
page: this.page,
}
}).then((response) => {
this.cartData = response.data.data.data;
this.page = response.data.data.currentPage;
this.total = response.data.data.count
})
},
getFootData() {
if (this.infoForm.id <= 0) {
return false
}
let that = this
this.axios.get('user/foot', {
params: {
id: that.infoForm.id,
page: this.page,
}
}).then((response) => {
this.footData = response.data.data.data
this.page = response.data.data.currentPage
this.total = response.data.data.count
})
},
getAllRegion() {
let that = this;
this.axios.get('order/getAllRegion').then((response) => {
this.options = response.data.data;
})
},
},
components: {},
mounted() {
this.infoForm.id = this.$route.query.id || 0;
this.getInfo();
this.getOrder();
this.datainfo();
this.getAllRegion();
// this.root = api.rootUrl;
if (!this.loginInfo) {
this.loginInfo = JSON.parse(window.localStorage.getItem('userInfo') || null);
}
}
}
</script>
<style>
.form-table-box {
margin-bottom: 20px;
}
.addr-w {
display: flex;
justify-content: space-between;
border-bottom: 1px solid #f1f1f1;
}
.addr-w .l {
display: flex;
justify-content: flex-start;
}
.addr-w .l .f1 {
min-width: 100px;
height: 50px;
line-height: 50px;
font-size: 14px;
margin-right: 20px;
}
.addr-w .r {
min-width: 100px;
height: 50px;
line-height: 50px;
font-size: 14px;
text-align: center;
}
.coupon-w {
display: flex;
flex-direction: column;
}
.coupon-w .top {
display: flex;
justify-content: space-between;
border-bottom: 1px solid #f1f1f1;
color: #888;
}
.coupon-w .bottom {
display: flex;
justify-content: space-between;
border-bottom: 1px solid #f1f1f1;
}
.coupon-w .l {
display: flex;
justify-content: flex-start;
}
.coupon-w .l .f1 {
min-width: 100px;
height: 50px;
line-height: 50px;
font-size: 14px;
margin-right: 20px;
}
.coupon-w .r {
min-width: 100px;
height: 50px;
line-height: 50px;
font-size: 14px;
text-align: center;
}
.list-wrap {
width: 100%;
border: 1px solid #dfe5ed;
margin-bottom: 10px;
}
.goods-img {
width: 40px;
height: 40px;
}
.list-wrap .header {
width: 100%;
height: 40px;
background-color: rgba(236, 245, 255, 0.51);
line-height: 40px;
color: #1f2d3d;
font-size: 13px;
padding: 0 10px;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
.status-text {
float: left;
color: #f0797f;
margin-right: 10px;
}
.add-time {
float: left;
margin-right: 20px;
}
.order-id {
float: left;
}
.goods-num {
float: right;
margin-right: 20px;
}
.price-wrap {
float: right;
margin-right: 20px;
}
.edit-wrap {
float: right;
margin-top: 5px;
}
.price-change {
float: right;
margin-right: 10px;
color: #e64242;
}
.content-wrap {
width: 100%;
display: flex;
justify-content: flex-start;
}
.content-wrap .left {
width: 50%;
border-right: 1px solid #d1dbe5;
padding: 10px;
}
.content-wrap .main {
width: 40%;
border-right: 1px solid #d1dbe5;
padding: 20px 10px;
}
.content-wrap .right {
width: 10%;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
}
.right .right-detail {
margin-left: 0;
margin-top: 6px;
}
.goods-list {
display: flex;
justify-content: flex-start;
align-items: center;
}
.goods-name {
color: #5e7382;
font-size: 14px;
margin-right: 20px;
width: 200px;
}
.goods-spec {
color: #0066cc;
font-size: 14px;
margin-right: 30px;
}
.goods-number {
color: #000000;
font-size: 14px;
margin-right: 20px;
}
.m1 {
display: flex;
justify-content: flex-start;
}
.user-name {
color: #000000;
font-size: 14px;
margin-right: 10px;
line-height: 20px;
}
.user-mobile {
color: #000000;
font-size: 14px;
line-height: 20px;
margin-right: 20px;
}
.user-address {
color: #333;
font-size: 13px;
line-height: 20px;
}
.user-post {
color: #333;
font-size: 14px;
line-height: 20px;
margin-top: 4px;
background-color: #e6e3b8;
}
.block-box {
display: flex;
justify-content: space-between;
margin-bottom: 20px;
}
.block-box .block {
display: flex;
justify-content: flex-start;
background: #fafafa;
align-items: center;
border: 1px solid #f1f1f1;
padding: 40px;
width: 24%;
box-sizing: border-box;
box-shadow: 1px 4px 4px #f1f1f1;
}
.block-box .a-block {
display: flex;
background: #fdf6ec;
flex-direction: column;
border: 1px solid #f1f1f1;
padding: 20px;
width: 160px;
}
.a-block .text {
font-size: 20px;
}
.a-block .time .label1 {
margin-right: 10px;
}
.a-block .time {
font-size: 12px;
display: flex;
justify-content: flex-start;
align-items: center;
}
.block .text {
font-size: 14px;
color: #888;
margin-right: 10px;
}
.block .num {
color: #222;
font-size: 18px;
}
</style>

@ -0,0 +1,155 @@
<template>
<div class="content-page">
<div class="content-nav">
<el-breadcrumb class="breadcrumb" separator="/">
<el-breadcrumb-item>用户列表</el-breadcrumb-item>
</el-breadcrumb>
</div>
<div class="content-main">
<div class="filter-box">
<el-form :inline="true" :model="filterForm" class="demo-form-inline">
<el-form-item label="用户昵称">
<el-input v-model="filterForm.nickname" placeholder="用户昵称"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="onSubmitFilter"></el-button>
</el-form-item>
</el-form>
</div>
<div class="form-table-box">
<el-table :data="tableData" style="width: 100%" border stripe>
<el-table-column prop="id" label="ID" width="60">
</el-table-column>
<el-table-column label="头像" width="80">
<template slot-scope="scope">
<img :src="scope.row.avatar" alt="" style="width: 50px;height: 50px">
</template>
</el-table-column>
<!--<el-table-column prop="username" label="会员名称">-->
<!--</el-table-column>-->
<el-table-column prop="nickname" label="昵称">
<template slot-scope="scope">
<el-input v-model="scope.row.nickname" placeholder="昵称" @blur="submitNick(scope.$index, scope.row)"></el-input>
</template>
</el-table-column>
<el-table-column prop="gender" label="性别" width="120">
<template slot-scope="scope">
{{ scope.row.gender == 2 ? '女' : '男' }}
</template>
</el-table-column>
<!--<el-table-column prop="mobile" label="手机号"></el-table-column>-->
<el-table-column prop="register_time" label="注册时间" width="180">
</el-table-column>
<el-table-column prop="last_login_time" label="最近登录" width="180">
</el-table-column>
<el-table-column label="操作">
<template slot-scope="scope">
<el-button size="small" @click="handleRowEdit(scope.$index, scope.row)">编辑</el-button>
<!-- <el-button plain size="small" type="danger" @click="handleRowDelete(scope.$index, scope.row)">删除</el-button> -->
</template>
</el-table-column>
</el-table>
</div>
<div class="page-box">
<el-pagination background @current-change="handlePageChange" :current-page.sync="page" :page-size="10" layout="total, prev, pager, next, jumper" :total="total">
</el-pagination>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
page: 1,
total: 0,
filterForm: {
name: ''
},
tableData: [],
loginInfo:null,
username:''
}
},
methods: {
submitNick(index, row){
this.axios.post('user/updateInfo', { id: row.id,nickname:row.nickname }).then((response) => {
})
},
handlePageChange(val) {
this.page = val;
//localStorage
localStorage.setItem('userPage', this.page)
this.getList()
},
handleRowEdit(index, row) {
this.$router.push({ name: 'user_add', query: { id: row.id } })
},
handleRowDelete(index, row) {
this.$confirm('确定要删除?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
this.axios.post('user/destory', { id: row.id }).then((response) => {
console.log(response.data)
if (response.data.errno === 0) {
this.$message({
type: 'success',
message: '删除成功!'
});
this.getList();
}
})
});
},
onSubmitFilter() {
this.page = 1
this.getList()
},
getList() {
this.axios.get('user', {
params: {
page: this.page,
nickname: this.filterForm.nickname
}
}).then((response) => {
console.log(response.data);
console.log(response);
this.tableData = response.data.data.userData.data;
this.page = response.data.data.userData.currentPage;
this.total = response.data.data.userData.count;
})
if(!this.loginInfo){
this.loginInfo = JSON.parse(window.localStorage.getItem('userInfo') || null);
this.username = this.loginInfo.username;
}
}
},
components: {
},
mounted() {
let thePage = localStorage.getItem('userPage');
if(thePage == null){
thePage = 1;
}
this.page = Number(thePage);
console.log(this.page);
this.getList();
}
}
</script>
<style scoped>
</style>

@ -0,0 +1,95 @@
<template>
<div class="wrap">
<div class="top">
<img src="http://lucky-icon.meiweiyuxian.com/hio/pinwheel.jpg"/>
<div class="menu">
<div class="menu-item">
<router-link to="/dashboard">
<i class="fa fa-user"></i>
</router-link>
</div>
<div class="menu-item">
<i class="fa fa-sign-out" @click="logout"></i>
</div>
</div>
</div>
<div class="header clearfix">
<el-card class="box-card card-red">
<div class="text item">商品</div>
</el-card>
<el-card class="box-card card-green">
<h1></h1>
<div class="text item">订单</div>
</el-card>
</div>
<div class="main">
<div></div>
<div class="form-table-box">
<el-table :data="tableData" style="width: 100%" stripe>
<el-table-column prop="list_pic_url" label="图片" width="80">
<template slot-scope="scope">
<img :src="scope.row.list_pic_url" alt="" style="width: 60px;height: 60px">
</template>
</el-table-column>
<el-table-column prop="name" label="商品名称">
</el-table-column>
<el-table-column prop="retail_price" label="售价" width="90" sortable>
<template slot-scope="scope">
<el-input v-model="scope.row.retail_price" placeholder="售价"
@blur="submit(scope.$index, scope.row)"></el-input>
</template>
</el-table-column>
<el-table-column label="上架" width="60">
<template slot-scope="scope">
<el-switch
v-model="tableData[scope.$index].is_on_sale"
active-text=""
inactive-text=""
@change='changeStatus($event,tableData[scope.$index].goods_id)'>
</el-switch>
</template>
</el-table-column>
</el-table>
</div>
</div>
</div>
</template>
<script scoped>
import api from '@/config/api';
export default {
data() {
return {
}
},
components: {},
methods: {
logout() {
this.$confirm('是否要退出?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
center: true
}).then(() => {
localStorage.clear();
this.$router.replace({name: 'login'});
});
},
},
mounted() {
this.getList();
this.root = api.rootUrl;
}
}
</script>
<style>
</style>

@ -0,0 +1,104 @@
<template>
<div class="footer-box">
<el-menu class="foot-wrap" :unique-opened="true" :default-active="currentPagePath"
:router="true">
<el-menu-item class="btn-footer" index="/wap">
<i class="fa fa-cube"></i>
<span>商品</span>
</el-menu-item>
<el-menu-item class="btn-footer" index="/wap/order">
<i class="fa fa-inbox"></i>
<span>订单</span>
</el-menu-item>
<el-menu-item class="btn-footer" index="" @click="logout">
<i class="fa fa-sign-out"></i>
<span>退出</span>
</el-menu-item>
</el-menu>
</div>
</template>
<script>
export default {
data() {
return {
currentPagePath: '/wap',
loginInfo:null,
username:''
}
},
methods: {
logout() {
this.$confirm('是否要退出?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
center: true
}).then(() => {
localStorage.clear();
this.$router.replace({name: 'login'});
});
},
},
mounted() {
console.log(this.$route.path);
if(!this.loginInfo){
this.loginInfo = JSON.parse(window.localStorage.getItem('userInfo') || null);
this.username = this.loginInfo.username;
}
}
}
</script>
<style>
.footer-box{
position: fixed;
bottom: 0;
width:100%;
height:50px;
background: #fff;
z-index:999;
border-top:1px solid #f1f1f1;
}
.foot-wrap{
width:100%;
height:50px;
display: flex;;
justify-content: space-around;
}
.btn-footer{
display: flex;
flex-direction: column;
padding-top:6px;
padding-left: 0 !important;
padding-right: 0 !important;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
.btn-footer span{
height:30px;
line-height:30px;
font-size:12px;
}
.btn-footer .fa{
width:16px;
height:16px;
font-size:16px;
margin:0 auto;
}
.btn-footer:focus,.btn-footer .is-active {
background: none;
}
.el-message-box {
width: 300px !important;
}
</style>

@ -0,0 +1,196 @@
<template>
<div class="wrap">
<div class="main">
<el-tabs class="tabs-wrap" v-model="activeName" @tab-click="handleClick">
<!--<el-tab-pane label="全部商品" name="first">-->
<!--</el-tab-pane>-->
<el-tab-pane label="出售中" name="second"></el-tab-pane>
<!--<el-tab-pane label="已售完" name="third"></el-tab-pane>-->
<el-tab-pane label="已下架" name="fourth"></el-tab-pane>
</el-tabs>
<div class="form-table-box">
<el-table :data="tableData" style="width: 100%" stripe>
<el-table-column prop="list_pic_url" label="图片" width="80">
<template slot-scope="scope">
<img :src="scope.row.list_pic_url" alt="" style="width: 60px;height: 60px">
</template>
</el-table-column>
<el-table-column prop="name" label="商品名称">
</el-table-column>
<el-table-column prop="retail_price" label="售价" width="90" sortable>
<template slot-scope="scope">
<el-input v-model="scope.row.retail_price" placeholder="售价"
@blur="submit(scope.$index, scope.row)"></el-input>
</template>
</el-table-column>
<el-table-column label="上架" width="60">
<template slot-scope="scope">
<el-switch
v-model="tableData[scope.$index].is_on_sale"
active-text=""
inactive-text=""
@change='changeStatus($event,tableData[scope.$index].goods_id)'>
</el-switch>
</template>
</el-table-column>
</el-table>
</div>
</div>
</div>
</template>
<script>
import api from '@/config/api';
export default {
data() {
return {
page: 1,
total: 0,
filterForm: {
name: ''
},
tableData: [],
activeName: 'second',
pIndex: 0,
num: 0,
activeClass: 0,
}
},
components: {},
methods: {
submit(index, row) {
this.axios.post('wap/updatePrice', {
id: row.goods_id,
sn: row.goods_sn,
price: row.retail_price
}).then((response) => {
})
},
changeStatus($event, para) {
this.axios.get('goods/saleStatus', {
params: {
status: $event,
id: para
}
}).then((response) => {
this.getList();
})
},
logout() {
this.$confirm('是否要退出?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
center: true
}).then(() => {
localStorage.clear();
this.$router.replace({name: 'login'});
});
},
handleClick(tab, event) {
let pindex = tab._data.index;
this.activeClass = 0;
if (pindex == 0) {
this.getOnSaleList();
this.pIndex = 0;
}
else if (pindex == 1) {
this.getOutSaleList();
this.pIndex = 1;
}
},
// getList() {
// this.axios.get('wap').then((response) => {
// console.log(response.data)
// this.tableData = response.data.data
// })
// },
getOnSaleList() {
this.axios.get('wap/onsale').then((response) => {
console.log(response.data)
this.tableData = response.data.data
})
},
getOutSaleList() {
this.axios.get('wap/drop').then((response) => {
console.log(response.data)
this.tableData = response.data.data
})
},
},
mounted() {
this.getOnSaleList();
this.root = api.rootUrl;
}
}
</script>
<style scoped>
.tabs-wrap {
padding: 0 10px;
}
.main {
padding: 50px 0;
}
.top {
width: 100%;
background: #233445;
height: 60px;
display: flex;
justify-content: space-between;
align-items: center;
padding: 10px;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
.top img {
width: 40px;
height: 40px;
}
.top .menu {
width: 100px;
display: flex;
justify-content: flex-end;
}
.menu .menu-item {
margin: 0 15px;
height: 30px;
line-height: 30px;
text-align: center;
font-size: 20px;
color: #fff;
}
.menu-item a {
color: #fff;
}
.wrap {
background: #fff;
}
.header {
width: 100%;
display: flex;
justify-content: space-between;
padding: 10px;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
.el-card {
width: 46%;
box-shadow: none !important;
}
</style>

@ -0,0 +1,542 @@
<template>
<div class="wrap">
<div class="main">
<!--<div class="filter-box">-->
<!--<el-form :inline="true" :model="filterForm" class="filter-wrap">-->
<!--<el-form-item label="收货人">-->
<!--<el-input v-model="filterForm.consignee" placeholder="请输入收货人"></el-input>-->
<!--</el-form-item>-->
<!--<el-form-item>-->
<!--<el-button type="primary" @click="onSubmitFilter"></el-button>-->
<!--</el-form-item>-->
<!--</el-form>-->
<!--</div>-->
<div class="top-wrap">
<el-tabs v-model="activeName" @tab-click="handleClick">
<el-tab-pane label="待备货" name="first"></el-tab-pane>
<el-tab-pane label="待发货" name="second"></el-tab-pane>
<el-tab-pane label="待付款" name="third"></el-tab-pane>
</el-tabs>
</div>
<div class="form-table-box">
<el-input v-show="0" style="opacity: 0" id="foo" v-model="copyText" value="" >{{copyText}}
</el-input>
<div v-for="item in tableData" class="list-wrap clearfix">
<div class="header clearfix">
<div class="h1">
<div class="in1">
<div class="status-text">{{item.order_status_text}}{{item.is_fake ? '--假的订单' : ''}}
</div>
<div class="goods-num">{{item.goodsCount}}件商品</div>
</div>
<div class="add-time">{{item.add_time}}</div>
</div>
<!--<div class="order-id">订单号{{item.order_sn}}</div>-->
<div class="h2">
<div class="price-wrap">当前合计{{item.actual_price}}含运费{{item.freight_price}}</div>
<div v-if="item.change_price!= item.actual_price" class="price-change">
改价前{{item.change_price}}
</div>
</div>
</div>
<div class="content-wrap clearfix">
<div class="goods-list" v-for="iitem in item.goodsList">
<img :src="iitem.list_pic_url" style="width: 40px;height: 40px" class="goods-img">
<div class="content">
<div class="c1">
<div class="goods-name">{{iitem.goods_name}}</div>
<div class="goods-spec">{{iitem.goods_specifition_name_value}}</div>
</div>
<div class="c2">
<div class="goods-number">数量{{iitem.number}}</div>
<div class="goods-number">¥{{iitem.retail_price}}</div>
</div>
</div>
</div>
<div class="goods-main">
<div class="to">
<div class="t">收件人信息</div>
<!--<el-button :class="'c'+item.id" data-clipboard-target="#foo" size="mini" type="primary" round-->
<!--plain @click="copyit(item)">点击复制-->
<!--</el-button>-->
</div>
<div class="m1">
<div class="user-name">{{item.consignee}} {{item.mobile}}</div>
</div>
<div class="m2">
<div class="user-address">{{item.full_region}}{{item.address}}</div>
<div class="user-post">{{item.postscript}}</div>
</div>
</div>
<div class="right">
<el-button round plain v-if="item.button_text !=''" size="small" type="danger"
@click="orderEdit(item.order_sn,item.button_text)">
{{item.button_text}}
</el-button>
</div>
</div>
</div>
<div class="page-box">
<el-pagination @current-change="handlePageChange" :current-page="page" :page-size="10"
layout="total, prev, pager, next, jumper" :total="total">
</el-pagination>
</div>
</div>
</div>
<el-dialog
title="提示"
:visible.sync="dialogVisible"
width="70%">
<span>确定打包备货</span>
<span slot="footer" class="dialog-footer">
<el-button @click="dialogVisible = false"> </el-button>
<el-button type="primary" @click="confirm"> </el-button>
</span>
</el-dialog>
<el-dialog title="发货" :visible.sync="dialogFormVisible" width="94%">
<el-form :model="dform">
<div class="dialog-wrap">
<div class="d-list-wrap">
<div class="d-goods-list" v-for="ditem in orderInfo.goodsList">
<img :src="ditem.list_pic_url" style="width: 40px;height: 40px;margin-right: 8px;" class="d-goods-img">
<div class="goods-name">{{ditem.goods_name}}</div>
<div class="goods-spec">{{ditem.goods_specifition_name_value}}</div>
<div class="goods-number">× {{ditem.number}}</div>
</div>
</div>
<div class="d-main">
<div class="m1">
<div class="user-name">{{orderInfo.consignee}}</div>
<div class="user-mobile">{{orderInfo.mobile}}</div>
</div>
<div class="user-address">{{orderInfo.full_region}}{{orderInfo.address}}</div>
<div class="user-post">{{orderInfo.postscript}}</div>
</div>
</div>
<el-form-item class="d-hoho" label="发货方式">
<el-radio-group v-model="dform.method" @change="deliveryMethodChange(dform.method)">
<el-radio :label="1">快递</el-radio>
<el-radio :label="2">无需快递</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item class="d-hoho" label="选择快递" v-if="isShow">
<el-select v-model="nowDeliveryId" value-key="id" placeholder="请选择快递">
<el-option
v-for="item in deliveryCom"
:key="item.id"
:label="item.name"
:value="item.id">
</el-option>
</el-select>
<!--@change="deliveryChange(deliveryCom.id)"-->
</el-form-item>
<el-form-item class="d-haha" label="快递单号" v-if="isShow">
<el-input v-model="dform.logistic_code"></el-input>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="dialogFormVisible = false"> </el-button>
<el-button type="primary" @click="deliveyGoConfirm"> </el-button>
</div>
</el-dialog>
<el-dialog title="修改价格" :visible.sync="dialogPriceVisible" width="90%">
<el-form :model="orderInfo">
<el-form-item label="改价前总价:">
<h2>¥{{orderInfo.change_price}}</h2>
</el-form-item>
<el-form-item label="货款总价:">
<el-input v-model="orderInfo.goods_price" auto-complete="off" placeholder="请输入修改后的价格"></el-input>
</el-form-item>
<el-form-item label="快递费用:">
<el-input v-model="orderInfo.freight_price" auto-complete="off"
placeholder="请输入修改后的快递价格"></el-input>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="dialogPriceVisible = false"> </el-button>
<el-button type="primary" @click="priceChangeConfirm"> </el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import api from '@/config/api';
import Clipboard from 'clipboard';
export default {
data() {
return {
page: 1,
total: 0,
filterForm: {
name: ''
},
order_status: 201,
tableData: [],
activeName: 'first',
pIndex: 0,
num: 0,
activeClass: 0,
copyBtn: '',
copyText: '',
order_sn: 0,
dialogVisible:false,
dialogFormVisible:false,
dialogPriceVisible:false,
dform: {
method: 1,
},
orderInfo: {},
isShow:true,
nowDeliveryId: 0,
deliveryCom: [],
}
},
components: {},
methods: {
deliveryMethodChange(val) {
if (val == 1) {
this.isShow = true
}
else {
this.isShow = false
}
},
priceChangeConfirm() {
this.axios.get('order/orderPrice', {
params: {
orderSn: this.order_sn,
goodsPrice: this.orderInfo.goods_price,
kdPrice: this.orderInfo.freight_price,
}
}).then((response) => {
this.dialogPriceVisible = false;
this.getList();
});
},
getOrderInfo(sn) {
this.axios.get('order/detail', {
params: {
orderSn: this.order_sn,
}
}).then((response) => {
this.orderInfo = response.data.data;
console.log(this.orderInfo);
})
},
copyit(item) {
console.log(item);
let val = item.consignee +'|'+ item.mobile +'|'+ item.full_region +item.address+item.postscript;
this.copyText = val;
let classo = "c"+item.id;
console.log(classo);
var clipboard = new Clipboard('.'+classo);
clipboard.on('success', function (e) {
console.info('Text:', e.text);
console.log('复制成功');
clipboard.destroy();
e.clearSelection();
});
clipboard.on('error', function (e) {
console.error('Action:', e.action);
console.error('Trigger:', e.trigger);
});
},
handlePageChange(val) {
this.page = val;
//localStorage
localStorage.setItem('orderPage', this.page)
localStorage.setItem('orderFilterForm', JSON.stringify(this.filterForm));
this.getList()
},
onSubmitFilter() {
this.page = 1
this.getList()
},
handleClick(tab, event) {
let pindex = tab._data.index;
if (pindex == 0) {
this.order_status = 201
}
else if (pindex == 1) {
this.order_status = 300
}
else if (pindex == 2) {
this.order_status = '101'
}
this.getList();
},
orderEdit(sn, para) {
this.order_sn = sn;
console.log(this.order_sn);
if (para == '备货') {
console.log(para);
this.dialogVisible = true;
}
else if (para == '发货') {
this.deliveryCom.id = 0;
this.dform.logistic_code = '';
this.getOrderInfo(this.order_sn);
this.dialogFormVisible = true;
}
else if (para == '修改价格') {
this.getOrderInfo(this.order_sn);
this.dialogPriceVisible = true;
}
},
getDeliveyInfo() {
this.axios.get('delivery').then((response) => {
this.deliveryCom = response.data.data;
console.log(this.deliveryCom);
})
},
confirm() {
this.axios.get('order/orderpack', {
params: {
orderSn: this.order_sn,
}
}).then((response) => {
this.dialogVisible = false;
this.getList();
})
},
deliveyGoConfirm() {
let method = this.method;
console.log(this.order_sn);
console.log(this.nowDeliveryId);
console.log(this.dform.method);
this.axios.get('order/orderDelivery', {
params: {
orderSn: this.order_sn,
shipper: this.nowDeliveryId,
method: this.dform.method,
logistic_code: this.dform.logistic_code
}
}).then((response) => {
this.dialogFormVisible = false;
this.getList();
});
this.dialogFormVisible = false;
},
getList() {
console.log(this.order_status);
this.axios.get('order', {
params: {
page: this.page,
orderSn: this.filterForm.order_sn,
consignee: this.filterForm.consignee,
status: this.order_status,
}
}).then((response) => {
this.tableData = response.data.data.data;
console.log();
this.page = response.data.data.currentPage;
this.total = response.data.data.count;
})
},
},
mounted() {
this.getList();
this.getDeliveyInfo();
this.root = api.rootUrl;
}
}
</script>
<style scoped>
.el-pagination {
padding-right: 30px;
margin-bottom: 40px;
}
.top-wrap {
padding: 0 12px;
}
.tabs-wrap {
padding: 0 10px;
}
.filter-wrap {
height: 42px;
padding: 12px;
}
.main {
padding: 50px 0;
}
.el-message-box {
width: 300px !important;
}
.wrap {
background: #fff;
}
.list-wrap {
/*width: 100%;*/
border: 1px solid #dfe5ed;
margin: 12px;
padding: 10px;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
-webkit-border-radius: 4px;
-moz-border-radius: 4px;
border-radius: 4px;
}
.header .h1 {
height: 40px;
display: flex;
justify-content: space-between;
align-items: center;
font-size: 14px;
border-bottom: 1px solid #f1f1f1;
}
.h1 .in1 {
display: flex;
justify-content: flex-start;
align-items: center;
}
.in1 .goods-num {
margin-left: 4px;
color: #ff3456;
}
.header .h2 {
height: 40px;
display: flex;
justify-content: flex-start;
align-items: center;
font-size: 13px;
border-bottom: 1px solid #f1f1f1;
}
.price-change {
float: right;
margin-right: 10px;
color: #e64242;
}
.content-wrap .goods-list {
border-bottom: 1px solid #f1f1f1;
padding: 12px 0;
display: flex;
justify-content: flex-start;
}
.goods-list .goods-img {
width: 80px !important;
height: 80px !important;
}
.content-wrap .content {
margin-left: 10px;
width: 100%;
display: flex;
flex-direction: column;
font-size: 14px;
}
.content .c1 {
width: 100%;
height: 40px;
line-height: 40px;
display: flex;
justify-content: space-between;
}
.content .c2 {
width: 100%;
line-height: 40px;
display: flex;
justify-content: space-between;
}
.content-wrap .goods-main {
padding: 12px 0;
border-bottom: 1px solid #f1f1f1;
}
.goods-main .to {
display: flex;
justify-content: space-between;
align-items: center;
font-size: 13px;
color: #999;
margin-bottom: 10px;
}
.goods-main .m1 {
display: flex;
flex-direction: column;
font-size: 15px;
line-height: 30px;
}
.goods-main .m2 {
font-size: 15px;
line-height: 30px;
}
.content-wrap .right {
margin-top: 10px;
display: flex;
justify-content: flex-end;
}
.dialog-wrap .d-list-wrap {
margin-bottom: 10px;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
.dialog-wrap .d-goods-list {
display: flex;
justify-content: flex-start;
align-items: center;
font-size:14px;
/*margin-bottom:20px;*/
/*border-bottom:1px solid #d1dbe5;*/
}
.dialog-wrap .d-main {
padding: 10px;
margin-bottom: 10px;
border: 1px solid #d1dbe5;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
.dialog-wrap .d-main div {
font-size: 14px;
}
.d-hoho{
margin-bottom:10px;
}
.d-haha{
margin: 0;
}
.fahuo .el-dialog__body{
padding:0 20px !important;
}
</style>

@ -0,0 +1,58 @@
<template>
<div class="top-box">
<div class="top-wrap">
<!--<img class="logo" src="static/images/logo.png"/>-->
汇鲜
</div>
</div>
</template>
<script>
export default {
data() {
return {
currentPagePath: '/wap',
loginInfo:null,
username:''
}
},
methods: {
},
mounted() {
console.log(this.$route.path);
if(!this.loginInfo){
this.loginInfo = JSON.parse(window.localStorage.getItem('userInfo') || null);
this.username = this.loginInfo.username;
}
}
}
</script>
<style scoped>
.top-box{
position: fixed;
top:0;
width:100%;
height:50px;
background: #233445;
z-index:999;
}
.top-wrap{
width:100%;
height:50px;
display: flex;;
justify-content: center;
align-items: center;
font-size:14px;
color: #fff;
}
.top-wrap .logo{
width:30px;
height:30px;
}
</style>

@ -0,0 +1,53 @@
<style>
body {
background: #f5f7fa;
display: block;
}
.container {
height: 100%;
width: 100%;
}
.content {
box-sizing: border-box;
}
</style>
<template>
<div class="container">
<sidebar></sidebar>
<navbar></navbar>
<div class="content">
<transition name="router-fade" mode="out-in">
<router-view></router-view>
</transition>
</div>
</div>
</template>
<script>
import Sidebar from 'Common/Sidebar';
import Navbar from 'Common/Navbar';
export default {
data() {
return {
dialogVisible: false,
}
},
components: {
Sidebar,
Navbar
},
methods: {
handleOpen(key, keyPath) {
console.log(key, keyPath);
},
handleClose(key, keyPath) {
console.log(key, keyPath);
},
},
}
</script>

@ -0,0 +1,53 @@
<style scoped>
body {
background: #f5f7fa;
display: block;
}
.container {
height: 100%;
width: 100%;
}
.content {
box-sizing: border-box;
}
</style>
<template>
<div class="container">
<topbar></topbar>
<footerbar></footerbar>
<div class="content">
<transition name="router-fade" mode="out-in">
<router-view></router-view>
</transition>
</div>
</div>
</template>
<script>
import Topbar from './Wap/Topbar';
import Footerbar from './Wap/Footerbar';
export default {
data() {
return {
dialogVisible: false,
}
},
components: {
Topbar,
Footerbar
},
methods: {
handleOpen(key, keyPath) {
console.log(key, keyPath);
},
handleClose(key, keyPath) {
console.log(key, keyPath);
},
},
}
</script>

@ -0,0 +1,392 @@
<template>
<div class="content-page">
<div class="content-nav">
<el-breadcrumb class="breadcrumb" separator="/">
<el-breadcrumb-item>后台主页</el-breadcrumb-item>
</el-breadcrumb>
</div>
<div class="content-main clearfix">
<!-- <div class="notice">-->
<!-- <div class="l">本演示后台数据为演示数据可以随意操作系统每5分钟重置一次</div>-->
<!-- <div class="r" v-if="resetVision">-->
<!-- <label>重置倒计时</label>-->
<!-- <countdown class="count" endTime="" :callback="callback" endText="已经结束了"></countdown>-->
<!-- </div>-->
<!-- </div>-->
<!-- <div class="github">-->
<!-- <a target="_blank" href="https://github.com/iamdarcy">github地址</a>-->
<!-- <div class="l">请您在github给个star 技术交流QQ群824781955</div>-->
<!-- </div>-->
<div class="header clearfix">
<el-card class="box-card card-red">
<router-link class="link-color" :to="{ path: '/dashboard/order' }">
<h1>{{infoData.orderToDelivery}}</h1>
<div class="text item">待发货订单</div>
</router-link>
</el-card>
<el-card class="box-card card-green">
<router-link class="link-color" :to="{ path: '/dashboard/goods' }">
<h1>{{infoData.goodsOnsale}}</h1>
<div class="text item">上架中的商品</div>
</router-link>
</el-card>
<el-card class="box-card card-black">
<router-link class="link-color" :to="{ path: '/dashboard/user' }">
<h1>{{infoData.user}}</h1>
<div class="text item">总用户数</div>
</router-link>
</el-card>
</div>
<div class="main">
<el-tabs class="o-tab" v-model="activeName2" type="card" @tab-click="handleClick">
<el-tab-pane label="今天" name="first"></el-tab-pane>
<el-tab-pane label="昨天" name="second"></el-tab-pane>
<el-tab-pane label="最近7天" name="third"></el-tab-pane>
<el-tab-pane label="最近30天" name="fourth"></el-tab-pane>
</el-tabs>
<div class="tab-content clearfix">
<el-card class="box-card2">
<div slot="header" class="clearfix">
<span style="line-height: 36px;">顾客</span>
<el-popover
placement="right"
v-model="related_pop"
>
<el-tabs class="user-tab" v-model="userTab" type="card" @tab-click="userTabClick">
<el-tab-pane label="新增" name="first"></el-tab-pane>
<el-tab-pane label="老客户" name="second"></el-tab-pane>
</el-tabs>
<el-table :data="userData" style="width: 100%" height="550" border stripe>
<el-table-column label="头像" width="80">
<template slot-scope="scope">
<img :src="scope.row.avatar" alt="" style="width: 50px;height: 50px">
</template>
</el-table-column>
<el-table-column prop="nickname" label="昵称" width="140"></el-table-column>
<el-table-column prop="gender" label="性别" width="50">
<template slot-scope="scope">
{{ scope.row.gender == 2 ? '女' : '男' }}
</template>
</el-table-column>
<el-table-column prop="register_time" label="注册时间" width="170">
</el-table-column>
<el-table-column prop="last_login_time" label="最近登录" width="170">
</el-table-column>
</el-table>
<el-button class="float-right" slot="reference" size="mini" type="primary" @click="seeClick"></el-button>
</el-popover>
</div>
<div class="text item">
<span>新增</span>
<h3 style="float: right;">{{mainInfo.newUser}}</h3>
</div>
<div class="text item">
<span>老顾客</span>
<h3 style="float: right;">{{mainInfo.oldUser}}</h3>
</div>
</el-card>
<el-card class="box-card2">
<div slot="header" class="clearfix">
<span style="line-height: 36px;">下单</span>
</div>
<div class="text item">
<span>加入购物车</span>
<h3 style="float: right;">{{mainInfo.addCart}}</h3>
</div>
<div class="text item">
<span>提交订单数/金额</span>
<h3 style="float: right;">{{mainInfo.addOrderNum}} / {{mainInfo.addOrderSum}}</h3>
</div>
</el-card>
<el-card class="box-card2">
<div slot="header" class="clearfix">
<span style="line-height: 36px;">支付</span>
</div>
<div class="text item">
<span>成交订单数</span>
<h3 style="float: right;">{{mainInfo.payOrderNum}}</h3>
</div>
<div class="text item">
<span>成交金额</span>
<h3 style="float: right;">{{mainInfo.payOrderSum}}</h3>
</div>
</el-card>
</div>
<div class="line clearfix"></div>
<div class="block-4 clearfix">
<el-card class="box-card">
<div class="text item">
<span>客单价</span>
<p style="float: right;">{{mainInfo.payOrderSum / mainInfo.payOrderNum | numFilter}}</p>
</div>
<p class="tips">成交金额/成交订单数</p>
</el-card>
<el-card class="box-card">
<div class="text item">
<span>下单转化率</span>
<p style="float: right;">
{{mainInfo.addOrderNum / (mainInfo.newUser + mainInfo.oldUser) | numFilter}}</p>
</div>
<p class="tips">下单人数/访问人数</p>
</el-card>
<el-card class="box-card">
<div class="text item">
<span>下单-支付转化率</span>
<p style="float: right;">{{mainInfo.payOrderNum / mainInfo.addOrderNum | numFilter}}</p>
</div>
<p class="tips">支付人数/下单人数</p>
</el-card>
<el-card class="box-card">
<div class="text item">
<span>支付转化率</span>
<p style="float: right;">
{{mainInfo.payOrderNum / (mainInfo.newUser + mainInfo.oldUser) | numFilter}}</p>
</div>
<p class="tips">支付人数/访问人数</p>
</el-card>
</div>
</div>
</div>
</div>
</template>
<script>
import Countdown from './Common/Countdown';
export default {
data() {
return {
dialogVisible: false,
infoData: {},
activeName2: 'first',
userTab:'first',
mainInfo: {},
loginInfo: null,
username: '',
label:'',
userData:[],
newData:[],
oldData:[],
related_pop:false,
resetVision:true,
}
},
methods: {
callback(){
this.resetVision = false;
},
seeClick(){
console.log('????');
},
getInfo() {
this.axios.get('index',).then((response) => {
this.infoData = response.data.data;
})
},
handleClick(tab, event) {
this.related_pop = false;
this.userTab = 'first';
console.log(tab._data.index);
let pindex = tab._data.index;
console.log('pindex:' + pindex);
this.getMainInfo(pindex);
},
userTabClick(tab, event){
let pindex = tab._data.index;
console.log(pindex);
if(pindex == 0){
this.userData = this.newData;
console.log(this.userData);
}
else{
this.userData = this.oldData;
console.log(this.userData);
}
},
getMainInfo(index) {
this.axios.get('index/main', {
params: {
pindex: index
}
}).then((response) => {
this.mainInfo = response.data.data;
this.newData = response.data.data.newData;
this.oldData = response.data.data.oldData;
this.userData = this.newData;
console.log(this.mainInfo);
})
},
},
components: {
Countdown
},
mounted() {
this.getInfo();
this.getMainInfo(0);
if(!this.loginInfo){
this.loginInfo = JSON.parse(window.localStorage.getItem('userInfo') || null);
this.username = this.loginInfo.username;
}
},
filters: {
numFilter(value) {
let realVal = Number(value).toFixed(2);
return Number(realVal);
}
}
}
</script>
<style scoped>
.notice{
width: 100%;
height: 60px;
padding: 30px;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
background: #ffecd5;
margin-bottom: 20px;
font-size: 16px;
border-radius: 6px;
display: flex;
justify-content: space-between;
align-items: center;
}
.github{
width: 100%;
height: 60px;
padding: 30px;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
background: #f8f8f8;
margin-bottom: 20px;
font-size: 16px;
border-radius: 6px;
display: flex;
justify-content: flex-start;
align-items: center;
}
.notice .r{
display: flex;
justify-content: space-between;
align-items: center;
}
.github a{
margin-right: 20px;
}
.count{
background: #fff;
padding: 10px;
}
.float-right{
float:right;
}
.tips {
color: #8c939d;
font-size: 13px;
}
.text {
font-size: 14px;
}
.item {
padding: 10px 0;
}
.clearfix:before,
.clearfix:after {
display: table;
content: "";
}
.clearfix:after {
clear: both
}
.tab-content{
margin-bottom: 20px;
}
.box-card {
width: 32%;
float: left;
margin:0 20px 14px 0;
}
.box-card:last-child {
margin-right: 0px;
}
.box-card .link-color{
color: #fff;
}
.box-card:last-child {
margin-right: 0;
}
.box-card2 {
width: 32%;
float: left;
margin-right: 17px;
}
.box-card2:last-child {
margin-right: 0;
}
.header {
margin-bottom: 30px;
}
.line {
margin: 20px 0;
border-top: 1px solid #d1dbe5;
}
.card-red {
background: #e64242;
border: none;
color: #fff;
}
.card-blue {
background: #4db3ff;
border: none;
color: #fff;
}
.card-green{
background: #11b95c;
border:none;
color: #fff;
}
.card-black{
background: #1f2d3d;
border:none;
color: #fff;
}
.card-gray{
background: #d1dbe5;
border:none;
}
.card-gray a{
color: #1f2d3d;
}
.card-yellow{
background: #f8dd66;
border:none;
color: #111111;
}
.card-yellow .link-color{
color: #111111;
}
</style>

@ -0,0 +1,20 @@
const rootUrl = 'http://192.168.212.36:8360/admin/';
const api = {
rootUrl : rootUrl,
qiniu: 'http://up-z2.qiniup.com',
// 请根据自己创建的七牛的区域进行设置:
// https://developer.qiniu.com/kodo/manual/1671/region-endpoint
// 华东 http(s)://up.qiniup.com
// 华北 http(s)://up-z1.qiniup.com
// 华南 http(s)://up-z2.qiniup.com
// 北美 http(s)://up-na0.qiniup.com
// 东南亚 http(s)://up-as0.qiniup.com
};
// import api from './config/api'
// Axios.defaults.baseURL = api.rootUrl;
export default api

@ -0,0 +1,68 @@
import Vue from 'vue'
import 'normalize.css/normalize.css' // A modern alternative to CSS resets
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'
import locale from 'element-ui/lib/locale/lang/en' // lang i18n
import VueAxios from 'vue-axios'
import Axios from 'axios'
import api from './config/api'
import '@/styles/index.scss' // global css
import App from './App'
import store from './store'
import router from './router'
// import '@/icons' // icon
// import '@/permission' // permission control
/**
* If you don't want to use mock-server
* you want to use MockJs for mock api
* you can execute: mockXHR()
*
* Currently MockJs will be used in the production environment,
* please remove it before going online ! ! !
*/
if (process.env.NODE_ENV === 'production') {
const { mockXHR } = require('../mock')
mockXHR()
}
// set ElementUI lang to EN
Vue.use(ElementUI, { locale })
// 如果想要中文版 element-ui按如下方式声明
// Vue.use(ElementUI)
Vue.use(VueAxios, Axios);
Vue.config.productionTip = false
router.beforeEach((to, from, next) => {
let token = localStorage.getItem('token') || '';
//配置接口信息
// Axios.defaults.baseURL = 'http://www.地址.com:8360/admin/';
Axios.defaults.baseURL = api.rootUrl;
Axios.defaults.headers.common['X-Hioshop-Token'] = token;
if (!token && to.name !== 'login') {
next({
path: '/login',
query: { redirect: to.fullPath }
})
} else {
next()
}
});
new Vue({
el: '#app',
router,
store,
render: h => h(App)
})

@ -0,0 +1,64 @@
import router from './router'
import store from './store'
import { Message } from 'element-ui'
import NProgress from 'nprogress' // progress bar
import 'nprogress/nprogress.css' // progress bar style
import { getToken } from '@/utils/auth' // get token from cookie
import getPageTitle from '@/utils/get-page-title'
NProgress.configure({ showSpinner: false }) // NProgress Configuration
const whiteList = ['/login'] // no redirect whitelist
router.beforeEach(async(to, from, next) => {
// start progress bar
NProgress.start()
// set page title
document.title = getPageTitle(to.meta.title)
// determine whether the user has logged in
const hasToken = getToken()
if (hasToken) {
if (to.path === '/login') {
// if is logged in, redirect to the home page
next({ path: '/' })
NProgress.done()
} else {
const hasGetUserInfo = store.getters.name
if (hasGetUserInfo) {
next()
} else {
try {
// get user info
await store.dispatch('user/getInfo')
next()
} catch (error) {
// remove token and go to login page to re-login
await store.dispatch('user/resetToken')
Message.error(error || 'Has Error')
next(`/login?redirect=${to.path}`)
NProgress.done()
}
}
}
} else {
/* has no token*/
if (whiteList.indexOf(to.path) !== -1) {
// in the free login whitelist, go directly
next()
} else {
// other pages that do not have permission to access are redirected to the login page.
next(`/login?redirect=${to.path}`)
NProgress.done()
}
}
})
router.afterEach(() => {
// finish progress bar
NProgress.done()
})

@ -0,0 +1,342 @@
import Vue from "vue";
import Router from "vue-router";
Vue.use(Router);
/* Layout */
/**
* Note: sub-menu only appear when route children.length >= 1
* Detail see: https://panjiachen.github.io/vue-element-admin-site/guide/essentials/router-and-nav.html
*
* hidden: true if set true, item will not show in the sidebar(default is false)
* alwaysShow: true if set true, will always show the root menu
* if not set alwaysShow, when item has more than one children route,
* it will becomes nested mode, otherwise not show the root menu
* redirect: noRedirect if set noRedirect will no redirect in the breadcrumb
* name:'router-name' the name is used by <keep-alive> (must set!!!)
* meta : {
roles: ['admin','editor'] control the page roles (you can set multiple roles)
title: 'title' the name show in sidebar and breadcrumb (recommend set)
icon: 'svg-name'/'el-icon-x' the icon show in the sidebar
breadcrumb: false if set false, the item will hidden in breadcrumb(default is true)
activeMenu: '/example/list' if set path, the sidebar will highlight the path you set
}
*/
/**
* constantRoutes
* a base page that does not have permission () =>importments
* all roles can be accessed
*/
// export const constantRoutes = [
// {
// path: '/login',
// component: () => import('@/views/login/index'),
// hidden: true
// },
// {
// path: '/404',
// component: () => import('@/views/404'),
// hidden: true
// },
// {
// path: '/',
// component: Layout,
// redirect: '/dashboard',
// children: [{
// path: 'dashboard',
// name: 'Dashboard',
// component: () => import('@/views/dashboard/index'),
// meta: { title: 'Dashboard', icon: 'dashboard' }
// }]
// },
// {
// path: '/example',
// component: Layout,
// redirect: '/example/table',
// name: 'Example',
// meta: { title: 'Example', icon: 'el-icon-s-help' },
// children: [
// {
// path: 'table',
// name: 'Table',
// component: () => import('@/views/table/index'),
// meta: { title: 'Table', icon: 'table' }
// },
// {
// path: 'tree',
// name: 'Tree',
// component: () => import('@/views/tree/index'),
// meta: { title: 'Tree', icon: 'tree' }
// }
// ]
// },
// {
// path: '/form',
// component: Layout,
// children: [
// {
// path: 'index',
// name: 'Form',
// component: () => import('@/views/form/index'),
// meta: { title: 'Form', icon: 'form' }
// }
// ]
// },
// {
// path: '/nested',
// component: Layout,
// redirect: '/nested/menu1',
// name: 'Nested',
// meta: {
// title: 'Nested',
// icon: 'nested'
// },
// children: [
// {
// path: 'menu1',
// component: () => import('@/views/nested/menu1/index'), // Parent router-view
// name: 'Menu1',
// meta: { title: 'Menu1' },
// children: [
// {
// path: 'menu1-1',
// component: () => import('@/views/nested/menu1/menu1-1'),
// name: 'Menu1-1',
// meta: { title: 'Menu1-1' }
// },
// {
// path: 'menu1-2',
// component: () => import('@/views/nested/menu1/menu1-2'),
// name: 'Menu1-2',
// meta: { title: 'Menu1-2' },
// children: [
// {
// path: 'menu1-2-1',
// component: () => import('@/views/nested/menu1/menu1-2/menu1-2-1'),
// name: 'Menu1-2-1',
// meta: { title: 'Menu1-2-1' }
// },
// {
// path: 'menu1-2-2',
// component: () => import('@/views/nested/menu1/menu1-2/menu1-2-2'),
// name: 'Menu1-2-2',
// meta: { title: 'Menu1-2-2' }
// }
// ]
// },
// {
// path: 'menu1-3',
// component: () => import('@/views/nested/menu1/menu1-3'),
// name: 'Menu1-3',
// meta: { title: 'Menu1-3' }
// }
// ]
// },
// {
// path: 'menu2',
// component: () => import('@/views/nested/menu2/index'),
// name: 'Menu2',
// meta: { title: 'menu2' }
// }
// ]
// },
// {
// path: 'external-link',
// component: Layout,
// children: [
// {
// path: 'https://panjiachen.github.io/vue-element-admin-site/#/',
// meta: { title: 'External Link', icon: 'link' }
// }
// ]
// },
// // 404 page must be placed at the end !!!
// { path: '*', redirect: '/404', hidden: true }
// ]
export const constantRoutes = [
{
path: "/dashboard",
name: "dashboard",
component: () => import("@/components/DashboardPage"),
children: [
{
path: "welcome",
name: "welcome",
component: () => import("@/components/WelcomePage"),
},
{
path: "goods",
name: "goods",
component: () => import("@/components/Goods/GoodsPage"),
},
{
path: "goods/add",
name: "goods_add",
component: () => import("@/components/Goods/GoodsAddPage"),
},
{
path: "nature",
name: "nature",
component: () => import("@/components/Nature/NaturePage"),
},
{
path: "specification/detail",
name: "specification_detail",
component: () =>
import("@/components/Specification/SpecificationAddPage"),
},
{
path: "category",
name: "category",
component: () => import("@/components/Category/CategoryPage"),
},
{
path: "category/add",
name: "category_add",
component: () => import("@/components/Category/CategoryAddPage"),
},
{
path: "order",
name: "order",
component: () => import("@/components/Order/OrderPage"),
},
{
path: "order/detail",
name: "order_detail",
component: () => import("@/components/Order/OrderDetailPage"),
},
{
path: "user",
name: "user",
component: () => import("@/components/User/UserPage"),
},
{
path: "user/add",
name: "user_add",
component: () => import("@/components/User/UserAddPage"),
},
{
path: "shipper",
name: "shipper",
component: () => import("@/components/Shipper/ShipperPage"),
},
{
path: "shipper/list",
name: "shipper_list",
component: () => import("@/components/Shipper/ShipperListPage"),
},
{
path: "shipper/add",
name: "shipper_add",
component: () => import("@/components/Shipper/ShipperAddPage"),
},
{
path: "freight",
name: "freight",
component: () => import("@/components/Freight/FreightPage"),
},
{
path: "except_area",
name: "except_area",
component: () => import("@/components/Freight/ExceptAreaPage"),
},
{
path: "except_area/add",
name: "except_area_add",
component: () => import("@/components/Freight/ExceptAreaAddPage"),
},
{
path: "freight/add",
name: "freight_add",
component: () => import("@/components/Freight/FreightAddPage"),
},
{
path: "notice",
name: "notice",
component: () => import("@/components/Settings/NoticePage"),
},
{
path: "ad",
name: "ad",
component: () => import("@/components/Ad/AdPage"),
},
{
path: "ad/add",
name: "ad_add",
component: () => import("@/components/Ad/AdAddPage"),
},
{
path: "shopcart",
name: "shopcart",
component: () => import("@/components/ShopCart/ShopCartPage"),
},
{
path: "keywords",
name: "keywords",
component: () => import("@/components/Keywords/KeywordsPage"),
},
{
path: "keywords/add",
name: "keywords_add",
component: () => import("@/components/Keywords/KeywordsAddPage"),
},
{
path: "goodsgalleryedit",
name: "goodsgalleryedit",
component: () =>
import("@/components/GoodsGallery/GoodsGalleryEditPage"),
},
{
path: "admin",
name: "admin",
component: () => import("@/components/Admin/AdminPage"),
},
{
path: "admin/add",
name: "admin_add",
component: () => import("@/components/Admin/AdminAddPage"),
},
{
path: "settings/showset",
name: "showset",
component: () => import("@/components/Showset/ShowSetPage"),
},
],
},
{
path: "/login",
name: "login",
component: () => import("@/components/LoginPage"),
},
{
path: "*",
redirect: "/dashboard",
},
];
const createRouter = () =>
new Router({
// mode: 'history', // () =>import service support
scrollBehavior: () => ({ y: 0 }),
routes: constantRoutes,
});
const router = createRouter();
// Detail see: https://github.com/vuejs/vue-router/issues/1234#issuecomment-357941465
export function resetRouter() {
const newRouter = createRouter();
router.matcher = newRouter.matcher; // reset router
}
export default router;

@ -0,0 +1,16 @@
module.exports = {
title: '海风小店',
/**
* @type {boolean} true | false
* @description Whether fix the header
*/
fixedHeader: false,
/**
* @type {boolean} true | false
* @description Whether show the logo in sidebar
*/
sidebarLogo: false
}

@ -0,0 +1,30 @@
// import Vue from 'vue'
// import getters from './getters'
// import app from './modules/app'
// import settings from './modules/settings'
// import user from './modules/user'
// Vue.use(Vuex)
// const store = new Vuex.Store({
// modules: {
// app,
// settings,
// user
// },
// getters
// })
// export default store
import Vuex from 'vuex'
import Vue from 'vue'
import modules from './modules'
Vue.use(Vuex)
export default new Vuex.Store({
modules,
strict: process.env.NODE_ENV !== 'production'
})

@ -0,0 +1,14 @@
/**
* The file enables `@/store/index.js` to import all vuex modules
* in a one-shot manner. There should not be any reason to edit this file.
*/
const files = require.context('.', false, /\.js$/)
const modules = {}
files.keys().forEach(key => {
if (key === './index.js') return
modules[key.replace(/(\.\/|\.js)/g, '')] = files(key).default
})
export default modules

@ -0,0 +1,49 @@
// cover some element-ui styles
.el-breadcrumb__inner,
.el-breadcrumb__inner a {
font-weight: 400 !important;
}
.el-upload {
input[type="file"] {
display: none !important;
}
}
.el-upload__input {
display: none;
}
// to fixed https://github.com/ElemeFE/element/issues/2461
.el-dialog {
transform: none;
left: 0;
position: relative;
margin: 0 auto;
}
// refine element ui upload
.upload-container {
.el-upload {
width: 100%;
.el-upload-dragger {
width: 100%;
height: 200px;
}
}
}
// dropdown
.el-dropdown-menu {
a {
display: block
}
}
// to fix el-date-picker css style
.el-range-separator {
box-sizing: content-box;
}

@ -0,0 +1,65 @@
@import './variables.scss';
@import './mixin.scss';
@import './transition.scss';
@import './element-ui.scss';
@import './sidebar.scss';
body {
height: 100%;
-moz-osx-font-smoothing: grayscale;
-webkit-font-smoothing: antialiased;
text-rendering: optimizeLegibility;
font-family: Helvetica Neue, Helvetica, PingFang SC, Hiragino Sans GB, Microsoft YaHei, Arial, sans-serif;
}
label {
font-weight: 700;
}
html {
height: 100%;
box-sizing: border-box;
}
#app {
height: 100%;
}
*,
*:before,
*:after {
box-sizing: inherit;
}
a:focus,
a:active {
outline: none;
}
a,
a:focus,
a:hover {
cursor: pointer;
color: inherit;
text-decoration: none;
}
div:focus {
outline: none;
}
.clearfix {
&:after {
visibility: hidden;
display: block;
font-size: 0;
content: " ";
clear: both;
height: 0;
}
}
// main-container global css
.app-container {
padding: 20px;
}

@ -0,0 +1,28 @@
@mixin clearfix {
&:after {
content: "";
display: table;
clear: both;
}
}
@mixin scrollBar {
&::-webkit-scrollbar-track-piece {
background: #d3dce6;
}
&::-webkit-scrollbar {
width: 6px;
}
&::-webkit-scrollbar-thumb {
background: #99a9bf;
border-radius: 20px;
}
}
@mixin relative {
position: relative;
width: 100%;
height: 100%;
}

@ -0,0 +1,226 @@
#app {
.main-container {
min-height: 100%;
transition: margin-left .28s;
margin-left: $sideBarWidth;
position: relative;
}
.sidebar-container {
transition: width 0.28s;
width: $sideBarWidth !important;
background-color: $menuBg;
height: 100%;
position: fixed;
font-size: 0px;
top: 0;
bottom: 0;
left: 0;
z-index: 1001;
overflow: hidden;
// reset element-ui css
.horizontal-collapse-transition {
transition: 0s width ease-in-out, 0s padding-left ease-in-out, 0s padding-right ease-in-out;
}
.scrollbar-wrapper {
overflow-x: hidden !important;
}
.el-scrollbar__bar.is-vertical {
right: 0px;
}
.el-scrollbar {
height: 100%;
}
&.has-logo {
.el-scrollbar {
height: calc(100% - 50px);
}
}
.is-horizontal {
display: none;
}
a {
display: inline-block;
width: 100%;
overflow: hidden;
}
.svg-icon {
margin-right: 16px;
}
.sub-el-icon {
margin-right: 12px;
margin-left: -2px;
}
.el-menu {
border: none;
height: 100%;
width: 100% !important;
}
// menu hover
.submenu-title-noDropdown,
.el-submenu__title {
&:hover {
background-color: $menuHover !important;
}
}
.is-active>.el-submenu__title {
color: $subMenuActiveText !important;
}
& .nest-menu .el-submenu>.el-submenu__title,
& .el-submenu .el-menu-item {
min-width: $sideBarWidth !important;
background-color: $subMenuBg !important;
&:hover {
background-color: $subMenuHover !important;
}
}
}
.hideSidebar {
.sidebar-container {
width: 54px !important;
}
.main-container {
margin-left: 54px;
}
.submenu-title-noDropdown {
padding: 0 !important;
position: relative;
.el-tooltip {
padding: 0 !important;
.svg-icon {
margin-left: 20px;
}
.sub-el-icon {
margin-left: 19px;
}
}
}
.el-submenu {
overflow: hidden;
&>.el-submenu__title {
padding: 0 !important;
.svg-icon {
margin-left: 20px;
}
.sub-el-icon {
margin-left: 19px;
}
.el-submenu__icon-arrow {
display: none;
}
}
}
.el-menu--collapse {
.el-submenu {
&>.el-submenu__title {
&>span {
height: 0;
width: 0;
overflow: hidden;
visibility: hidden;
display: inline-block;
}
}
}
}
}
.el-menu--collapse .el-menu .el-submenu {
min-width: $sideBarWidth !important;
}
// mobile responsive
.mobile {
.main-container {
margin-left: 0px;
}
.sidebar-container {
transition: transform .28s;
width: $sideBarWidth !important;
}
&.hideSidebar {
.sidebar-container {
pointer-events: none;
transition-duration: 0.3s;
transform: translate3d(-$sideBarWidth, 0, 0);
}
}
}
.withoutAnimation {
.main-container,
.sidebar-container {
transition: none;
}
}
}
// when menu collapsed
.el-menu--vertical {
&>.el-menu {
.svg-icon {
margin-right: 16px;
}
.sub-el-icon {
margin-right: 12px;
margin-left: -2px;
}
}
.nest-menu .el-submenu>.el-submenu__title,
.el-menu-item {
&:hover {
// you can use $subMenuHover
background-color: $menuHover !important;
}
}
// the scroll bar appears when the subMenu is too long
>.el-menu--popup {
max-height: 100vh;
overflow-y: auto;
&::-webkit-scrollbar-track-piece {
background: #d3dce6;
}
&::-webkit-scrollbar {
width: 6px;
}
&::-webkit-scrollbar-thumb {
background: #99a9bf;
border-radius: 20px;
}
}
}

@ -0,0 +1,48 @@
// global transition css
/* fade */
.fade-enter-active,
.fade-leave-active {
transition: opacity 0.28s;
}
.fade-enter,
.fade-leave-active {
opacity: 0;
}
/* fade-transform */
.fade-transform-leave-active,
.fade-transform-enter-active {
transition: all .5s;
}
.fade-transform-enter {
opacity: 0;
transform: translateX(-30px);
}
.fade-transform-leave-to {
opacity: 0;
transform: translateX(30px);
}
/* breadcrumb transition */
.breadcrumb-enter-active,
.breadcrumb-leave-active {
transition: all .5s;
}
.breadcrumb-enter,
.breadcrumb-leave-active {
opacity: 0;
transform: translateX(20px);
}
.breadcrumb-move {
transition: all .5s;
}
.breadcrumb-leave-active {
position: absolute;
}

@ -0,0 +1,25 @@
// sidebar
$menuText:#bfcbd9;
$menuActiveText:#409EFF;
$subMenuActiveText:#f4f4f5; //https://github.com/ElemeFE/element/issues/12951
$menuBg:#304156;
$menuHover:#263445;
$subMenuBg:#1f2d3d;
$subMenuHover:#001528;
$sideBarWidth: 210px;
// the :export directive is the magic sauce for webpack
// https://www.bluematador.com/blog/how-to-share-variables-between-js-and-sass
:export {
menuText: $menuText;
menuActiveText: $menuActiveText;
subMenuActiveText: $subMenuActiveText;
menuBg: $menuBg;
menuHover: $menuHover;
subMenuBg: $subMenuBg;
subMenuHover: $subMenuHover;
sideBarWidth: $sideBarWidth;
}

@ -0,0 +1,119 @@
"use strict";
const path = require("path");
const defaultSettings = require("./src/settings.js");
function resolve(dir) {
return path.join(__dirname, dir);
}
const name = defaultSettings.title || "vue Admin Template"; // page title
// If your port is set to 80,
// use administrator privileges to execute the command line.
// For example, Mac: sudo npm run
// You can change the port by the following methods:
// port = 9528 npm run dev OR npm run dev --port = 9528
const port = process.env.port || process.env.npm_config_port || 9528; // dev port
// All configuration item explanations can be find in https://cli.vuejs.org/config/
module.exports = {
/**
* You will need to set publicPath if you plan to deploy your site under a sub path,
* for example GitHub Pages. If you plan to deploy your site to https://foo.github.io/bar/,
* then publicPath should be set to "/bar/".
* In most cases please use '/' !!!
* Detail: https://cli.vuejs.org/config/#publicpath
*/
publicPath: "./",
outputDir: "dist",
assetsDir: "static",
lintOnSave: process.env.NODE_ENV === "development",
productionSourceMap: false,
devServer: {
port: port,
open: true,
overlay: {
warnings: false,
errors: true,
},
// lintOnSave: false,
// before: require("./mock/mock-server.js"),
},
configureWebpack: {
// provide the app's title in webpack's name field, so that
// it can be accessed in index.html to inject the correct title.
name: name,
resolve: {
alias: {
"@": resolve("src"),
},
},
},
chainWebpack(config) {
// it can improve the speed of the first screen, it is recommended to turn on preload
config.plugin("preload").tap(() => [
{
rel: "preload",
// to ignore runtime.js
// https://github.com/vuejs/vue-cli/blob/dev/packages/@vue/cli-service/lib/config/app.js#L171
fileBlacklist: [/\.map$/, /hot-update\.js$/, /runtime\..*\.js$/],
include: "initial",
},
]);
// when there are many pages, it will cause too many meaningless requests
config.plugins.delete("prefetch");
// set svg-sprite-loader
config.module.rule("svg").exclude.add(resolve("src/icons")).end();
config.module
.rule("icons")
.test(/\.svg$/)
.include.add(resolve("src/icons"))
.end()
.use("svg-sprite-loader")
.loader("svg-sprite-loader")
.options({
symbolId: "icon-[name]",
})
.end();
config.when(process.env.NODE_ENV !== "development", (config) => {
config
.plugin("ScriptExtHtmlWebpackPlugin")
.after("html")
.use("script-ext-html-webpack-plugin", [
{
// `runtime` must same as runtimeChunk name. default is `runtime`
inline: /runtime\..*\.js$/,
},
])
.end();
config.optimization.splitChunks({
chunks: "all",
cacheGroups: {
libs: {
name: "chunk-libs",
test: /[\\/]node_modules[\\/]/,
priority: 10,
chunks: "initial", // only package third parties that are initially dependent
},
elementUI: {
name: "chunk-elementUI", // split elementUI into a single package
priority: 20, // the weight needs to be larger than libs and app or it will be packaged into libs or app
test: /[\\/]node_modules[\\/]_?element-ui(.*)/, // in order to adapt to cnpm
},
commons: {
name: "chunk-commons",
test: resolve("src/components"), // can customize your rules
minChunks: 3, // minimum common number
priority: 5,
reuseExistingChunk: true,
},
},
});
// https:// webpack.js.org/configuration/optimization/#optimizationruntimechunk
config.optimization.runtimeChunk("single");
});
},
};

37
service/.gitignore vendored

@ -0,0 +1,37 @@
# Logs
logs
*.log
# Runtime data
pids
*.pid
*.seed
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage/
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# node-waf configuration
.lock-wscript
# Dependency directory
# https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git
node_modules/
# IDE config
.idea
# output
output/
output.tar.gz
runtime/
app/
config.development.js
adapter.development.js

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2020 iamdarcy 黑亮(sligxl@163.com)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

@ -0,0 +1,16 @@
const Application = require('thinkjs');
const babel = require('think-babel');
const watcher = require('think-watcher');
const notifier = require('node-notifier');
const instance = new Application({
ROOT_PATH: __dirname,
watcher: watcher,
transpiler: [babel, {
presets: ['think-node']
}],
notifier: notifier.notify.bind(notifier),
env: 'development'
});
instance.run();

File diff suppressed because one or more lines are too long

Binary file not shown.

File diff suppressed because it is too large Load Diff

@ -0,0 +1,54 @@
{
"name": "hioshop",
"description": "hioshop - open source mini program shop",
"version": "1.0.0",
"scripts": {
"start": "node development.js",
"compile": "babel --no-babelrc src/ --presets think-node --out-dir app/",
"lint": "eslint src/",
"lint-fix": "eslint --fix src/"
},
"dependencies": {
"gm": "^1.23.0",
"jsonwebtoken": "^8.0.0",
"jushuitan": "^1.0.2",
"kcors": "^2.2.1",
"lodash": "^4.17.4",
"md5": "^2.2.1",
"mime-types": "^2.1.24",
"moment": "^2.18.1",
"nanoid": "^2.1.1",
"node-wget": "^0.4.3",
"pinyin": "^2.9.0",
"qiniu": "^7.2.1",
"querystring": "^0.2.0",
"request": "^2.81.0",
"request-promise": "^4.2.1",
"think-cache": "^1.0.0",
"think-cache-file": "^1.0.8",
"think-logger3": "^1.0.0",
"think-model": "^1.0.0",
"think-model-mysql": "^1.0.0",
"think-view": "^1.0.11",
"think-view-nunjucks": "^1.0.7",
"thinkjs": "^3.0.0",
"weixinpay": "^1.0.12",
"xml2js": "^0.4.19"
},
"devDependencies": {
"babel-cli": "^6.24.1",
"babel-preset-think-node": "^1.0.0",
"node-notifier": "^5.0.2",
"think-watcher": "^3.0.0",
"think-inspect": "0.0.2",
"think-babel": "^1.0.3",
"eslint": "^4.2.0",
"eslint-config-think": "^1.0.0"
},
"repository": "",
"license": "MIT",
"engines": {
"node": ">=6.0.0"
},
"readmeFilename": "README.md"
}

@ -0,0 +1,15 @@
{
"apps": [{
"name": "hiolabs",
"script": "production.js",
"cwd": "/var/www/hioshop-server",
"exec_mode": "fork",
"max_memory_restart": "1G",
"autorestart": true,
"node_args": [],
"args": [],
"env": {
}
}]
}

@ -0,0 +1,9 @@
const Application = require('thinkjs');
const instance = new Application({
ROOT_PATH: __dirname,
proxy: true, // use proxy
env: 'production'
});
instance.run();

@ -0,0 +1,4 @@
// default config test
module.exports = {
};

@ -0,0 +1,108 @@
const Base = require('./base.js');
const moment = require('moment');
module.exports = class extends Base {
/**
* index action
* @return {Promise} []
*/
async indexAction() {
const page = this.get('page') || 1;
const size = this.get('size') || 10;
const model = this.model('ad');
const data = await model.where({
is_delete: 0
}).order(['id ASC']).page(page, size).countSelect();
for (const item of data.data) {
if (item.end_time != 0) {
item.end_time = moment.unix(item.end_time).format('YYYY-MM-DD HH:mm:ss');
}
if (item.enabled == 1) {
item.enabled = true;
} else {
item.enabled = false;
}
}
return this.success(data);
}
async updateSortAction() {
const id = this.post('id');
const sort = this.post('sort');
const model = this.model('ad');
const data = await model.where({
id: id
}).update({
sort_order: sort
});
return this.success(data);
}
async infoAction() {
const id = this.get('id');
const model = this.model('ad');
const data = await model.where({
id: id
}).find();
return this.success(data);
}
async storeAction() {
if (!this.isPost) {
return false;
}
const values = this.post();
console.log(values);
values.end_time = parseInt(new Date(values.end_time).getTime() / 1000);
const id = this.post('id');
const model = this.model('ad');
if (id > 0) {
await model.where({
id: id
}).update(values);
} else {
let ex = await model.where({
goods_id: values.goods_id,
is_delete:0
}).find();
if (think.isEmpty(ex)) {
delete values.id;
if (values.link_type == 0) {
values.link = '';
} else {
values.goods_id = 0;
}
await model.add(values);
} else {
return this.fail(100, '发生错误');
}
}
return this.success(values);
}
async getallrelateAction() {
let data = await this.model('goods').where({
is_on_sale: 1,
is_delete: 0
}).field('id,name,list_pic_url').select();
return this.success(data);
}
async destoryAction() {
const id = this.post('id');
await this.model('ad').where({
id: id
}).limit(1).update({
is_delete: 1
});
return this.success();
}
async saleStatusAction() {
const id = this.get('id');
const status = this.get('status');
let sale = 0;
if (status == 'true') {
sale = 1;
}
const model = this.model('ad');
await model.where({
id: id
}).update({
enabled: sale
});
}
};

@ -0,0 +1,143 @@
const Base = require('./base.js');
const moment = require('moment');
const md5 = require('md5');
module.exports = class extends Base {
/**
* index action
* @return {Promise} []
*/
async indexAction() {
const data = await this.model('admin').where({
// is_show: 1,
is_delete: 0
}).select();
for (const item of data) {
if (item.last_login_time != 0) {
item.last_login_time = moment.unix(item.last_login_time).format('YYYY-MM-DD HH:mm:ss');
} else {
item.last_login_time = '还没登录过'
}
item.password = '';
}
return this.success(data);
}
async adminDetailAction() {
let id = this.post('id')
let info = await this.model('admin').where({
id: id
}).find();
return this.success(info);
}
async adminAddAction() {
let user = this.post('user');
let password = user.password;
let upData = {
username: info.username,
password_salt: 'HIOLABS'
};
if (password.replace(/(^\s*)|(\s*$)/g, "").length != 0) {
password = md5(info.password + '' + upData.password_salt);
upData.password = password;
}
await this.model('admin').add(upData);
return this.success();
}
async adminSaveAction() {
let user = this.post('user');
let change = this.post('change');
let upData = {
username: user.username,
};
if (change == true) {
let newPassword = user.newpassword;
if (newPassword.replace(/(^\s*)|(\s*$)/g, "").length != 0) {
newPassword = md5(user.newpassword + '' + user.password_salt);
upData.password = newPassword;
}
}
let ex = await this.model('admin').where({
username: user.username,
id: ['<>', user.id]
}).find();
if (!think.isEmpty(ex)) {
return this.fail(400, '重名了')
}
// if (user.id == 14) {
// return this.fail(400, '演示版后台的管理员密码不能修改!本地开发,删除这个判断')
// }
await this.model('admin').where({
id: user.id
}).update(upData);
return this.success();
}
async infoAction() {
const id = this.get('id');
const model = this.model('user');
const data = await model.where({
id: id
}).find();
return this.success(data);
}
async storeAction() {
if (!this.isPost) {
return false;
}
const values = this.post();
const id = this.post('id');
const model = this.model('user');
values.is_show = values.is_show ? 1 : 0;
values.is_new = values.is_new ? 1 : 0;
if (id > 0) {
await model.where({
id: id
}).update(values);
} else {
delete values.id;
await model.add(values);
}
return this.success(values);
}
async deleAdminAction() {
const id = this.post('id');
await this.model('admin').where({
id: id
}).limit(1).delete();
return this.success();
}
async showsetAction() {
const model = this.model('show_settings');
let data = await model.find();
return this.success(data);
}
async showsetStoreAction() {
let id = 1;
const values = this.post();
const model = this.model('show_settings');
await model.where({
id: id
}).update(values);
return this.success(values);
}
async changeAutoStatusAction() {
const status = this.post('status');
await this.model('settings').where({
id: 1
}).update({
autoDelivery: status
});
return this.success();
}
async storeShipperSettingsAction() {
const values = this.post();
await this.model('settings').where({
id: values.id
}).update(values);
return this.success();
}
async senderInfoAction() {
let info = await this.model('settings').where({
id: 1
}).find();
return this.success(info);
}
};

@ -0,0 +1,41 @@
const Base = require('./base.js');
module.exports = class extends Base {
async loginAction() {
const username = this.post('username');
const password = this.post('password');
const admin = await this.model('admin').where({
username: username
}).find();
if (think.isEmpty(admin)) {
return this.fail(401, '用户名或密码不正确!');
}
console.log(think.md5(password + '' + admin.password_salt));
console.log(admin.password);
if (think.md5(password + '' + admin.password_salt) !== admin.password) {
return this.fail(400, '用户名或密码不正确!!');
}
// 更新登录信息
await this.model('admin').where({
id: admin.id
}).update({
last_login_time: parseInt(Date.now() / 1000),
last_login_ip: this.ctx.ip
});
const TokenSerivce = this.service('token', 'admin');
let sessionData = {}
sessionData.user_id = admin.id
const sessionKey = await TokenSerivce.create(sessionData);
if (think.isEmpty(sessionKey)) {
return this.fail('登录失败');
}
const userInfo = {
id: admin.id,
username: admin.username,
name:admin.name
};
return this.success({
token: sessionKey,
userInfo: userInfo
});
}
};

@ -0,0 +1,14 @@
module.exports = class extends think.Controller {
async __before() {
// 根据token值获取用户id
think.token = this.ctx.header['x-hioshop-token'] || '';
const tokenSerivce = think.service('token', 'admin');
think.userId = await tokenSerivce.getUserId();
// 只允许登录操作
if (this.ctx.controller != 'auth') {
if (think.userId <= 0 || think.userId == undefined) {
return this.fail(401, '请先登录');
}
}
}
};

@ -0,0 +1,161 @@
const Base = require('./base.js');
module.exports = class extends Base {
/**
* index action
* @return {Promise} []
*/
async indexAction() {
const model = this.model('category');
const data = await model.order(['sort_order ASC']).select();
const topCategory = data.filter((item) => {
return item.parent_id === 0;
});
const categoryList = [];
topCategory.map((item) => {
item.level = 1;
categoryList.push(item);
data.map((child) => {
if (child.parent_id === item.id) {
child.level = 2;
categoryList.push(child);
}
if (child.is_show == 1) {
child.is_show = true;
} else {
child.is_show = false;
}
if (child.is_channel == 1) {
child.is_channel = true;
} else {
child.is_channel = false;
}
if (child.is_category == 1) {
child.is_category = true;
} else {
child.is_category = false;
}
});
});
return this.success(categoryList);
}
async updateSortAction() {
const id = this.post('id');
const sort = this.post('sort');
const model = this.model('category');
const data = await model.where({
id: id
}).update({
sort_order: sort
});
return this.success(data);
}
async topCategoryAction() {
const model = this.model('category');
const data = await model.where({
parent_id: 0
}).order(['id ASC']).select();
return this.success(data);
}
async infoAction() {
const id = this.get('id');
const model = this.model('category');
const data = await model.where({
id: id
}).find();
return this.success(data);
}
async storeAction() {
if (!this.isPost) {
return false;
}
const values = this.post();
const id = this.post('id');
const model = this.model('category');
values.is_show = values.is_show ? 1 : 0;
values.is_channel = values.is_channel ? 1 : 0;
values.is_category = values.is_category ? 1 : 0;
if (id > 0) {
await model.where({
id: id
}).update(values);
} else {
delete values.id;
await model.add(values);
}
return this.success(values);
}
async destoryAction() {
const id = this.post('id');
let data = await this.model('category').where({
parent_id: id
}).select();
if (data.length > 0) {
return this.fail();
} else {
await this.model('category').where({
id: id
}).limit(1).delete();
return this.success();
}
}
async showStatusAction() {
const id = this.get('id');
const status = this.get('status');
let ele = 0;
if (status == 'true') {
ele = 1;
}
const model = this.model('category');
await model.where({
id: id
}).update({
is_show: ele
});
}
async channelStatusAction() {
const id = this.get('id');
const status = this.get('status');
let stat = 0;
if (status == 'true') {
stat = 1;
}
const model = this.model('category');
await model.where({
id: id
}).update({
is_channel: stat
});
}
async categoryStatusAction() {
const id = this.get('id');
const status = this.get('status');
let stat = 0;
if (status == 'true') {
stat = 1;
}
const model = this.model('category');
await model.where({
id: id
}).update({
is_category: stat
});
}
async deleteBannerImageAction() {
let id = this.post('id');
await this.model('category').where({
id: id
}).update({
img_url: ''
});
return this.success();
}
async deleteIconImageAction() {
let id = this.post('id');
await this.model('category').where({
id: id
}).update({
icon_url: ''
});
return this.success();
}
};

@ -0,0 +1,13 @@
const Base = require('./base.js');
module.exports = class extends Base {
/**
* index action
* @return {Promise} []
*/
async indexAction() {
const data = await this.model('shipper').where({
enabled:1
}).select();
return this.success(data);
}
};

@ -0,0 +1,943 @@
const Base = require('./base.js');
const moment = require('moment');
const fs = require('fs');
const path = require("path");
const qiniu = require('qiniu');
module.exports = class extends Base {
/**
* index action
* @return {Promise} []
*/
async indexAction() {
const page = this.get('page') || 1;
const size = this.get('size');
const name = this.get('name') || '';
const model = this.model('goods');
const data = await model.where({
name: ['like', `%${name}%`],
is_delete: 0
}).order(['sort_order asc']).page(page, size).countSelect();
// let newData = data;
for (const item of data.data) {
const info = await this.model('category').where({
id: item.category_id
}).find();
item.category_name = info.name;
if (item.is_on_sale == 1) {
item.is_on_sale = true;
} else {
item.is_on_sale = false;
}
if (item.is_index == 1) {
item.is_index = true;
} else {
item.is_index = false;
}
let product = await this.model('product').where({
goods_id: item.id,
is_delete: 0
}).select();
for (const ele of product) {
let spec = await this.model('goods_specification').where({
id: ele.goods_specification_ids,
is_delete: 0
}).find();
ele.value = spec.value;
ele.is_on_sale = ele.is_on_sale ? "1" : "0";
}
item.product = product;
}
return this.success(data);
}
async getExpressDataAction() {
let kd = [];
let cate = [];
const kdData = await this.model('freight_template').where({
is_delete: 0
}).select();
for (const item of kdData) {
kd.push({
value: item.id,
label: item.name
})
}
const cateData = await this.model('category').where({
parent_id: 0
}).select();
for (const item of cateData) {
cate.push({
value: item.id,
label: item.name
})
}
let infoData = {
kd: kd,
cate: cate
};
return this.success(infoData);
}
async copygoodsAction() {
const goodsId = this.post('id');
let data = await this.model('goods').where({
id: goodsId
}).find();
delete data.id;
data.is_on_sale = 0;
let insertId = await this.model('goods').add(data);
let goodsGallery = await this.model('goods_gallery').where({
goods_id: goodsId,
is_delete:0,
}).select();
for (const item of goodsGallery) {
let gallery = {
img_url: item.img_url,
sort_order: item.sort_order,
goods_id: insertId
}
await this.model('goods_gallery').add(gallery);
}
return this.success(insertId);
}
async updateStock(goods_sn, goods_number) {
console.log('存在,现在就更新');
await this.model('product').where({
goods_sn: goods_sn
}).update({
goods_number: goods_number
});
}
async updateGoodsNumberAction() {
let all_goods = await this.model('goods').where({
is_delete: 0,
is_on_sale: 1
}).select();
for (const item of all_goods) {
let goodsSum = await this.model('product').where({
goods_id: item.id
}).sum('goods_number');
await this.model('goods').where({
id: item.id
}).update({
goods_number: goodsSum
});
await think.timeout(2000);
}
return this.success();
}
async onsaleAction() {
const page = this.get('page') || 1;
const size = this.get('size');
const model = this.model('goods');
const data = await model.where({
is_delete: 0,
is_on_sale: 1
}).order(['sort_order asc']).page(page, size).countSelect();
for (const item of data.data) {
const info = await this.model('category').where({
id: item.category_id
}).find();
item.category_name = info.name;
// if (info.parent_id != 0) {
// const parentInfo = await this.model('category').where({id: info.parent_id}).find();
// item.category_p_name = parentInfo.name;
// }
if (item.is_on_sale == 1) {
item.is_on_sale = true;
} else {
item.is_on_sale = false;
}
if (item.is_index == 1) {
item.is_index = true;
} else {
item.is_index = false;
}
let product = await this.model('product').where({
goods_id: item.id,
is_delete: 0
}).select();
for (const ele of product) {
let spec = await this.model('goods_specification').where({
id: ele.goods_specification_ids,
is_delete: 0
}).find();
ele.value = spec.value;
ele.is_on_sale = ele.is_on_sale ? "1" : "0";
}
item.product = product;
}
return this.success(data);
}
async outAction() {
const page = this.get('page') || 1;
const size = this.get('size');
const model = this.model('goods');
const data = await model.where({
is_delete: 0,
goods_number: ['<=', 0]
}).order(['sort_order asc']).page(page, size).countSelect();
for (const item of data.data) {
const info = await this.model('category').where({
id: item.category_id
}).find();
item.category_name = info.name;
if (item.is_on_sale == 1) {
item.is_on_sale = true;
} else {
item.is_on_sale = false;
}
if (item.is_index == 1) {
item.is_index = true;
} else {
item.is_index = false;
}
let product = await this.model('product').where({
goods_id: item.id,
is_delete: 0
}).select();
for (const ele of product) {
let spec = await this.model('goods_specification').where({
id: ele.goods_specification_ids,
is_delete: 0
}).find();
ele.value = spec.value;
ele.is_on_sale = ele.is_on_sale ? "1" : "0";
}
item.product = product;
}
return this.success(data);
}
async dropAction() {
const page = this.get('page') || 1;
const size = this.get('size');
const model = this.model('goods');
const data = await model.where({
is_delete: 0,
is_on_sale: 0
}).order(['id DESC']).page(page, size).countSelect();
for (const item of data.data) {
const info = await this.model('category').where({
id: item.category_id
}).find();
item.category_name = info.name;
if (item.is_on_sale == 1) {
item.is_on_sale = true;
} else {
item.is_on_sale = false;
}
if (item.is_index == 1) {
item.is_index = true;
} else {
item.is_index = false;
}
let product = await this.model('product').where({
goods_id: item.id,
is_delete: 0
}).select();
for (const ele of product) {
let spec = await this.model('goods_specification').where({
id: ele.goods_specification_ids,
is_delete: 0
}).find();
ele.value = spec.value;
ele.is_on_sale = ele.is_on_sale ? "1" : "0";
}
item.product = product;
}
return this.success(data);
}
async sortAction() {
const page = this.get('page') || 1;
const size = this.get('size');
const model = this.model('goods');
const index = this.get('index');
if (index == 1) {
const data = await model.where({
is_delete: 0
}).order(['sell_volume DESC']).page(page, size).countSelect();
for (const item of data.data) {
const info = await this.model('category').where({
id: item.category_id
}).find();
item.category_name = info.name;
if (item.is_on_sale == 1) {
item.is_on_sale = true;
} else {
item.is_on_sale = false;
}
if (item.is_index == 1) {
item.is_index = true;
} else {
item.is_index = false;
}
let product = await this.model('product').where({
goods_id: item.id,
is_delete: 0
}).select();
for (const ele of product) {
let spec = await this.model('goods_specification').where({
id: ele.goods_specification_ids,
is_delete: 0
}).find();
ele.value = spec.value;
ele.is_on_sale = ele.is_on_sale ? "1" : "0";
}
item.product = product;
}
return this.success(data);
} else if (index == 2) {
const data = await model.where({
is_delete: 0
}).order(['retail_price DESC']).page(page, size).countSelect();
for (const item of data.data) {
const info = await this.model('category').where({
id: item.category_id
}).find();
item.category_name = info.name;
if (item.is_on_sale == 1) {
item.is_on_sale = true;
} else {
item.is_on_sale = false;
}
if (item.is_index == 1) {
item.is_index = true;
} else {
item.is_index = false;
}
let product = await this.model('product').where({
goods_id: item.id,
is_delete: 0
}).select();
for (const ele of product) {
let spec = await this.model('goods_specification').where({
id: ele.goods_specification_ids,
is_delete: 0
}).find();
ele.value = spec.value;
ele.is_on_sale = ele.is_on_sale ? "1" : "0";
}
item.product = product;
}
return this.success(data);
} else if (index == 3) {
const data = await model.where({
is_delete: 0
}).order(['goods_number DESC']).page(page, size).countSelect();
for (const item of data.data) {
const info = await this.model('category').where({
id: item.category_id
}).find();
item.category_name = info.name;
if (item.is_on_sale == 1) {
item.is_on_sale = true;
} else {
item.is_on_sale = false;
}
if (item.is_index == 1) {
item.is_index = true;
} else {
item.is_index = false;
}
let product = await this.model('product').where({
goods_id: item.id,
is_delete: 0
}).select();
for (const ele of product) {
let spec = await this.model('goods_specification').where({
id: ele.goods_specification_ids,
is_delete: 0
}).find();
ele.value = spec.value;
ele.is_on_sale = ele.is_on_sale ? "1" : "0";
}
item.product = product;
}
return this.success(data);
}
}
async saleStatusAction() {
const id = this.get('id');
const status = this.get('status');
let sale = 0;
if (status == 'true') {
sale = 1;
}
const model = this.model('goods');
await model.where({
id: id
}).update({
is_on_sale: sale
});
await this.model('cart').where({
goods_id: id
}).update({
is_on_sale: sale,
checked: sale
});
}
async productStatusAction() {
const id = this.get('id');
const status = this.get('status');
const model = this.model('product');
await model.where({
id: id
}).update({
is_on_sale: status
});
// 4.14更新
await this.model('cart').where({
product_id: id,
is_delete: 0
}).update({
is_on_sale: status
})
}
async indexShowStatusAction() {
const id = this.get('id');
const status = this.get('status');
let stat = 0;
if (status == 'true') {
stat = 1;
}
const model = this.model('goods');
await model.where({
id: id
}).update({
is_index: stat
});
}
async infoAction() {
const id = this.get('id');
const model = this.model('goods');
const data = await model.where({
id: id
}).find();
let category_id = data.category_id;
let infoData = {
info: data,
category_id: category_id,
};
return this.success(infoData);
}
async getAllSpecificationAction() {
const specInfo = await this.model('specification').where({
id: ['>', 0]
}).select();
let specOptionsData = [];
for (const spitem of specInfo) {
let info = {
value: spitem.id,
label: spitem.name
};
specOptionsData.push(info);
}
return this.success(specOptionsData);
}
async getAllCategory1Action() { // 我写的算法
const model = this.model('category');
const data = await model.where({
is_show: 1,
level: 'L1'
}).select();
const c_data = await model.where({
is_show: 1,
level: 'L2'
}).select();
let newData = [];
for (const item of data) {
let children = [];
for (const citem of c_data) {
if (citem.parent_id == item.id) {
children.push({
value: citem.id,
label: citem.name
})
}
}
newData.push({
value: item.id,
label: item.name,
children: children
});
}
return this.success(newData);
}
async getAllCategoryAction() { // 老婆的算法
const model = this.model('category');
const data = await model.where({
is_show: 1,
level: 'L1'
}).field('id,name').select();
let newData = [];
for (const item of data) {
let children = [];
const c_data = await model.where({
is_show: 1,
level: 'L2',
parent_id: item.id
}).field('id,name').select();
for (const c_item of c_data) {
children.push({
value: c_item.id,
label: c_item.name
})
}
newData.push({
value: item.id,
label: item.name,
children: children
});
}
return this.success(newData);
}
async storeAction() {
const values = this.post('info');
const specData = this.post('specData');
const specValue = this.post('specValue');
const cateId = this.post('cateId');
const model = this.model('goods');
let picUrl = values.list_pic_url;
let goods_id = values.id;
values.category_id = cateId;
values.is_index = values.is_index ? 1 : 0;
values.is_new = values.is_new ? 1 : 0;
let id = values.id;
if (id > 0) {
await model.where({
id: id
}).update(values);
await this.model('cart').where({
goods_id: id
}).update({
checked: values.is_on_sale,
is_on_sale: values.is_on_sale,
list_pic_url: picUrl,
freight_template_id: values.freight_template_id
});
await this.model('product').where({
goods_id: id
}).update({
is_delete: 1
});
await this.model('goods_specification').where({
goods_id: id
}).update({
is_delete: 1
});
for (const item of specData) {
if (item.id > 0) {
await this.model('cart').where({
product_id: item.id,
is_delete: 0,
}).update({
retail_price: item.retail_price,
goods_specifition_name_value: item.value,
goods_sn: item.goods_sn
});
delete item.is_delete;
item.is_delete = 0;
await this.model('product').where({
id: item.id
}).update(item);
let specificationData = {
value: item.value,
specification_id: specValue,
is_delete: 0
};
await this.model('goods_specification').where({
id: item.goods_specification_ids
}).update(specificationData);
} else {
let specificationData = {
value: item.value,
goods_id: id,
specification_id: specValue
}
let specId = await this.model('goods_specification').add(specificationData);
item.goods_specification_ids = specId;
item.goods_id = id;
await this.model('product').add(item);
}
}
for(const [index, item] of values.gallery.entries()){
if(item.is_delete == 1 && item.id > 0){
await this.model('goods_gallery').where({
id:item.id
}).update({
is_delete:1
})
}
else if(item.is_delete == 0 && item.id > 0){
await this.model('goods_gallery').where({
id:item.id
}).update({
sort_order:index
})
}
else if(item.is_delete == 0 && item.id == 0){
await this.model('goods_gallery').add({
goods_id:id,
img_url:item.url,
sort_order:index
})
}
}
} else {
delete values.id;
goods_id = await model.add(values);
for (const item of specData) {
let specificationData = {
value: item.value,
goods_id: goods_id,
specification_id: specValue
}
let specId = await this.model('goods_specification').add(specificationData);
item.goods_specification_ids = specId;
item.goods_id = goods_id;
item.is_on_sale = 1;
await this.model('product').add(item);
}
for(const [index, item] of values.gallery.entries()){
await this.model('goods_gallery').add({
goods_id:goods_id,
img_url:item.url,
sort_order:index
})
}
}
let pro = await this.model('product').where({
goods_id: goods_id,
is_on_sale: 1,
is_delete: 0
}).select();
if (pro.length > 1) {
let goodsNum = await this.model('product').where({
goods_id: goods_id,
is_on_sale: 1,
is_delete: 0
}).sum('goods_number');
let retail_price = await this.model('product').where({
goods_id: goods_id,
is_on_sale: 1,
is_delete: 0
}).getField('retail_price');
let maxPrice = Math.max(...retail_price);
let minPrice = Math.min(...retail_price);
let cost = await this.model('product').where({
goods_id: goods_id,
is_on_sale: 1,
is_delete: 0
}).getField('cost');
let maxCost = Math.max(...cost);
let minCost = Math.min(...cost);
let goodsPrice = '';
if(minPrice == maxPrice){
goodsPrice = minPrice;
}
else{
goodsPrice = minPrice + '~' + maxPrice;
}
let costPrice = minCost + '~' + maxCost;
await this.model('goods').where({
id: goods_id
}).update({
goods_number: goodsNum,
retail_price: goodsPrice,
cost_price: costPrice,
min_retail_price: minPrice,
min_cost_price: minCost,
});
} else {
let info = {
goods_number: pro[0].goods_number,
retail_price: pro[0].retail_price,
cost_price: pro[0].cost,
min_retail_price: pro[0].retail_price,
min_cost_price: pro[0].cost,
}
await this.model('goods').where({
id: goods_id
}).update(info);
}
return this.success(goods_id);
}
async updatePriceAction() {
let data = this.post('');
let goods_id = data.goods_id;
await this.model('goods_specification').where({
id: data.goods_specification_ids
}).update({
value: data.value
});
await this.model('product').where({
id: data.id
}).update(data);
let pro = await this.model('product').where({
goods_id: goods_id,
is_on_sale: 1,
is_delete: 0
}).select();
if(pro.length == 0){
return this.fail(100,'商品的规格数量至少1个')
}
await this.model('cart').where({
product_id: data.id,
is_delete: 0,
}).update({
retail_price: data.retail_price,
goods_specifition_name_value: data.value,
goods_sn: data.goods_sn
});
delete data.value;
if (pro.length > 1) {
let goodsNum = await this.model('product').where({
goods_id: goods_id,
is_on_sale: 1,
is_delete: 0
}).sum('goods_number');
let retail_price = await this.model('product').where({
goods_id: goods_id,
is_on_sale: 1,
is_delete: 0
}).getField('retail_price');
let maxPrice = Math.max(...retail_price);
let minPrice = Math.min(...retail_price);
let cost = await this.model('product').where({
goods_id: goods_id,
is_on_sale: 1,
is_delete: 0
}).getField('cost');
let maxCost = Math.max(...cost);
let minCost = Math.min(...cost);
let goodsPrice = '';
if(minPrice == maxPrice){
goodsPrice = minPrice;
}
else{
goodsPrice = minPrice + '~' + maxPrice;
}
let costPrice = minCost + '~' + maxCost;
await this.model('goods').where({
id: goods_id
}).update({
goods_number: goodsNum,
retail_price: goodsPrice,
cost_price: costPrice,
min_retail_price: minPrice,
min_cost_price: minCost,
});
} else if(pro.length == 1){
let info = {
goods_number: pro[0].goods_number,
retail_price: pro[0].retail_price,
cost_price: pro[0].cost,
min_retail_price: pro[0].retail_price,
min_cost_price: pro[0].cost,
}
await this.model('goods').where({
id: goods_id
}).update(info);
}
return this.success();
}
async checkSkuAction() {
const info = this.post('info');
if (info.id > 0) {
const model = this.model('product');
const data = await model.where({
id: ['<>', info.id],
goods_sn: info.goods_sn,
is_delete: 0
}).find();
if (!think.isEmpty(data)) {
return this.fail(100, '重复')
} else {
return this.success();
}
} else {
const model = this.model('product');
const data = await model.where({
goods_sn: info.goods_sn,
is_delete: 0
}).find();
if (!think.isEmpty(data)) {
return this.fail(100, '重复')
} else {
return this.success();
}
}
}
async updateSortAction() {
const id = this.post('id');
const sort = this.post('sort');
const model = this.model('goods');
const data = await model.where({
id: id
}).update({
sort_order: sort
});
return this.success(data);
}
async updateShortNameAction() {
const id = this.post('id');
const short_name = this.post('short_name');
const model = this.model('goods');
const data = await model.where({
id: id
}).update({
short_name: short_name
});
return this.success(data);
}
async galleryListAction() {
const id = this.get('id');
const model = this.model('goods_gallery');
const data = await model.where({
goods_id: id,
is_delete:0
}).select();
// console.log(data);
return this.success(data);
}
async galleryAction() {
const url = this.post('url');
const id = this.post('goods_id');
let info = {
goods_id: id,
img_url: url
}
await this.model('goods_gallery').add(info);
return this.success();
}
async getGalleryListAction() {
const goodsId = this.post('goodsId');
const data = await this.model('goods_gallery').where({
goods_id: goodsId,
is_delete:0
}).order('sort_order asc').select();
let galleryData = [];
for (const item of data) {
let pdata = {
id: item.id,
url: item.img_url,
is_delete:0,
}
galleryData.push(pdata);
}
let info = {
galleryData: galleryData,
}
return this.success(info);
}
async deleteGalleryFileAction() {
const url = this.post('url');
const id = this.post('id');
await this.model('goods_gallery').where({
id: id
}).limit(1).update({
is_delete: 1
});
return this.success('文件删除成功');
}
async galleryEditAction() {
if (!this.isPost) {
return false;
}
const values = this.post();
let data = values.data;
// console.log(data);
const model = this.model('goods_gallery');
for (const item of data) {
let id = item.id;
let sort = parseInt(item.sort_order);
// console.log(sort);
await this.model('goods_gallery').where({
id: id
}).update({
sort_order: sort
});
}
return this.success();
}
async deleteListPicUrlAction() {
const id = this.post('id');
console.log(id);
await this.model('goods').where({
id: id
}).limit(1).update({
list_pic_url: 0
});
return this.success();
}
async destoryAction() {
const id = this.post('id');
await this.model('goods').where({
id: id
}).limit(1).update({
is_delete: 1
});
await this.model('product').where({
goods_id: id
}).update({
is_delete: 1
});
await this.model('goods_specification').where({
goods_id: id
}).update({
is_delete: 1
});
return this.success();
}
async uploadHttpsImageAction() {
let url = this.post('url');
let accessKey = think.config('qiniuHttps.access_key');
let secretKey = think.config('qiniuHttps.secret_key');
let domain = think.config('qiniuHttps.domain');
var mac = new qiniu.auth.digest.Mac(accessKey, secretKey);
var config = new qiniu.conf.Config();
let zoneNum = think.config('qiniuHttps.zoneNum');
if(zoneNum == 0){
config.zone = qiniu.zone.Zone_z0;
}
else if(zoneNum == 1){
config.zone = qiniu.zone.Zone_z1;
}
else if(zoneNum == 2){
config.zone = qiniu.zone.Zone_z2;
}
else if(zoneNum == 3){
config.zone = qiniu.zone.Zone_na0;
}
else if(zoneNum == 4){
config.zone = qiniu.zone.Zone_as0;
}
var bucketManager = new qiniu.rs.BucketManager(mac, config);
let bucket = think.config('qiniuHttps.bucket');
let key = think.uuid(32);
await think.timeout(500);
const uploadQiniu = async() => {
return new Promise((resolve, reject) => {
try {
bucketManager.fetch(url, bucket, key, function(err, respBody, respInfo) {
if (err) {
console.log(err);
//throw err;
} else {
if (respInfo.statusCode == 200) {
resolve(respBody.key)
} else {
console.log(respInfo.statusCode);
}
}
});
} catch (e) {
return resolve(null);
}
})
};
const httpsUrl = await uploadQiniu();
console.log(httpsUrl);
let lastUrl = domain + httpsUrl;
return this.success(lastUrl);
}
};

@ -0,0 +1,254 @@
const Base = require('./base.js');
const moment = require('moment');
module.exports = class extends Base {
async checkLoginAction(){
if(think.userId == 0){
return this.fail(404,'请登录');
}
}
async indexAction() {
const goodsOnsale = await this.model('goods').where({is_on_sale: 1,is_delete:0}).count();
const orderToDelivery = await this.model('order').where({order_status: 300}).count();
const user = await this.model('user').count();
let data = await this.model('settings').field('countdown').find();
let timestamp = data.countdown;
let info = {
user: user,
goodsOnsale: goodsOnsale,
timestamp:timestamp,
orderToDelivery: orderToDelivery,
}
return this.success(info);
}
async getQiniuTokenAction(){
const TokenSerivce = this.service('qiniu'); // 服务里返回token
let data = await TokenSerivce.getQiniuToken(); // 取得token值 goods
let qiniuToken = data.uploadToken;
let domain = data.domain;
let info ={
token:qiniuToken,
url:domain
};
return this.success(info);
}
async mainAction() {
const index = this.get('pindex');
console.log('index:' + index);
let todayTimeStamp = new Date(new Date().setHours(0, 0, 0, 0)) / 1000; //今天零点的时间戳
let yesTimeStamp = todayTimeStamp - 86400; //昨天零点的时间戳
let sevenTimeStamp = todayTimeStamp - 86400 * 7; //7天前零点的时间戳
let thirtyTimeStamp = todayTimeStamp - 86400 * 30; //30天前零点的时间戳
let newUser = 1;
let oldUser = 0;
let addCart = 0;
let addOrderNum = 0;
let addOrderSum = 0;
let payOrderNum = 0;
let payOrderSum = 0;
let newData = [];
let oldData = [];
if (index == 0) {
newData = await this.model('user').where({
id: ['>', 0],
register_time: ['>', todayTimeStamp]
}).select();
newUser = newData.length;
for(const item of newData){
item.nickname = Buffer.from(item.nickname, 'base64').toString();
}
oldData = await this.model('user').where({
id: ['>', 0],
register_time: ['<', todayTimeStamp],
last_login_time: ['>', todayTimeStamp]
}).select();
for(const item of oldData){
item.nickname = Buffer.from(item.nickname, 'base64').toString();
}
oldUser = oldData.length;
addCart = await this.model('cart').where({is_delete: 0, add_time: ['>', todayTimeStamp]}).count();
addOrderNum = await this.model('order').where({
is_delete: 0,
add_time: ['>', todayTimeStamp]
}).count();
addOrderSum = await this.model('order').where({
is_delete: 0,
add_time: ['>', todayTimeStamp]
}).sum('actual_price');
payOrderNum = await this.model('order').where({
is_delete: 0,
add_time: ['>', todayTimeStamp],
order_status: ['IN', [201, 802, 300, 301]]
}).count();
payOrderSum = await this.model('order').where({
is_delete: 0,
add_time: ['>', todayTimeStamp],
order_status: ['IN', [201, 802, 300, 301]]
}).sum('actual_price');
}
else if (index == 1) {
newData = await this.model('user').where({
id: ['>', 0],
register_time: ['BETWEEN', yesTimeStamp, todayTimeStamp]
}).select();
for(const item of newData){
item.nickname = Buffer.from(item.nickname, 'base64').toString();
}
newUser = newData.length;
oldData = await this.model('user').where({
id: ['>', 0],
register_time: ['<', yesTimeStamp],
last_login_time: ['BETWEEN', yesTimeStamp, todayTimeStamp]
}).select();
for(const item of oldData){
item.nickname = Buffer.from(item.nickname, 'base64').toString();
}
oldUser = oldData.length;
addCart = await this.model('cart').where({
is_delete: 0,
add_time: ['BETWEEN', yesTimeStamp, todayTimeStamp]
}).count();
addOrderNum = await this.model('order').where({
is_delete: 0,
add_time: ['BETWEEN', yesTimeStamp, todayTimeStamp]
}).count();
addOrderSum = await this.model('order').where({
is_delete: 0,
add_time: ['BETWEEN', yesTimeStamp, todayTimeStamp]
}).sum('actual_price');
payOrderNum = await this.model('order').where({
is_delete: 0,
add_time: ['BETWEEN', yesTimeStamp, todayTimeStamp],
order_status: ['IN', [201, 802, 300, 301]]
}).count();
console.log('------------321----------');
console.log(payOrderNum);
console.log('-----------3321-----------');
payOrderSum = await this.model('order').where({
is_delete: 0,
add_time: ['BETWEEN', yesTimeStamp, todayTimeStamp],
order_status: ['IN', [201, 802, 300, 301]]
}).sum('actual_price');
console.log('-----------123-----------');
console.log(payOrderSum);
console.log('-----------123-----------');
}
else if (index == 2) {
newData = await this.model('user').where({
id: ['>', 0],
register_time: ['>', sevenTimeStamp]
}).select();
for(const item of newData){
item.nickname = Buffer.from(item.nickname, 'base64').toString();
}
newUser = newData.length;
oldData = await this.model('user').where({
id: ['>', 0],
register_time: ['<', sevenTimeStamp],
last_login_time: ['>', sevenTimeStamp]
}).select();
for(const item of oldData){
item.nickname = Buffer.from(item.nickname, 'base64').toString();
}
oldUser = oldData.length;
addCart = await this.model('cart').where({
is_delete: 0,
add_time: ['>', sevenTimeStamp]
}).count();
addOrderNum = await this.model('order').where({
is_delete: 0,
add_time: ['>', sevenTimeStamp]
}).count();
addOrderSum = await this.model('order').where({
is_delete: 0,
add_time: ['>', sevenTimeStamp]
}).sum('actual_price');
payOrderNum = await this.model('order').where({
is_delete: 0,
add_time: ['>', sevenTimeStamp],
order_status: ['IN', [201, 802, 300, 301]]
}).count();
payOrderSum = await this.model('order').where({
is_delete: 0,
add_time: ['>', sevenTimeStamp],
order_status: ['IN', [201, 802, 300, 301]]
}).sum('actual_price');
}
else if (index == 3) {
newData = await this.model('user').where({
id: ['>', 0],
register_time: ['>', thirtyTimeStamp]
}).select();
for(const item of newData){
item.nickname = Buffer.from(item.nickname, 'base64').toString();
}
newUser = newData.length;
oldData = await this.model('user').where({
id: ['>', 0],
register_time: ['<', thirtyTimeStamp],
last_login_time: ['>', thirtyTimeStamp]
}).select();
for(const item of oldData){
item.nickname = Buffer.from(item.nickname, 'base64').toString();
}
oldUser = oldData.length;
addCart = await this.model('cart').where({
is_delete: 0,
add_time: ['>', thirtyTimeStamp]
}).count();
addOrderNum = await this.model('order').where({
is_delete: 0,
add_time: ['>', thirtyTimeStamp]
}).count();
addOrderSum = await this.model('order').where({
is_delete: 0,
add_time: ['>', thirtyTimeStamp]
}).sum('actual_price');
payOrderNum = await this.model('order').where({
is_delete: 0,
add_time: ['>', thirtyTimeStamp],
order_status: ['IN', [201, 802, 300, 301]]
}).count();
payOrderSum = await this.model('order').where({
is_delete: 0,
add_time: ['>', thirtyTimeStamp],
order_status: ['IN', [201, 802, 300, 301]]
}).sum('actual_price');
}
if (addOrderSum == null) {
addOrderSum = 0;
}
if (payOrderSum == null) {
payOrderSum = 0;
}
if(newData.length > 0){
for(const item of newData){
item.register_time = moment.unix(item.register_time).format('YYYY-MM-DD HH:mm:ss');
item.last_login_time = moment.unix(item.last_login_time).format('YYYY-MM-DD HH:mm:ss');
}
}
if(oldData.length > 0){
for(const item of oldData){
item.register_time = moment.unix(item.register_time).format('YYYY-MM-DD HH:mm:ss');
item.last_login_time = moment.unix(item.last_login_time).format('YYYY-MM-DD HH:mm:ss');
}
}
let info = {
newUser: newUser,
oldUser: oldUser,
addCart: addCart,
newData: newData,
oldData: oldData,
addOrderNum: addOrderNum,
addOrderSum: addOrderSum,
payOrderNum: payOrderNum,
payOrderSum: payOrderSum
}
return this.success(info);
}
};

@ -0,0 +1,23 @@
const Base = require('./base.js');
const moment = require('moment');
module.exports = class extends Base {
/**
* index action
* @return {Promise} []
*/
async indexAction() {
const page = this.get('page') || 1;
const size = this.get('size') || 10;
const name = this.get('name') || '';
const model = this.model('cart');
const data = await model.where({goods_name: ['like', `%${name}%`]}).order(['id DESC']).page(page, size).countSelect();
for (const item of data.data) {
item.add_time = moment.unix(item.add_time).format('YYYY-MM-DD HH:mm:ss');
}
return this.success(data);
}
};

@ -0,0 +1,76 @@
const Base = require('./base.js');
const moment = require('moment');
module.exports = class extends Base {
/**
* index action
* @return {Promise} []
*/
async indexAction() {
const model = this.model('notice');
const data = await model.select();
for (const item of data) {
item.end_time = moment.unix(item.end_time).format('YYYY-MM-DD HH:mm:ss');
}
return this.success(data);
}
async updateContentAction() {
const id = this.post('id');
const content = this.post('content');
const model = this.model('notice');
const data = await model.where({id: id}).update({content: content});
return this.success(data);
}
async addAction() {
const content = this.post('content');
let end_time = this.post('time');
end_time = parseInt(new Date(end_time).getTime() / 1000);
let info = {
content:content,
end_time:end_time
}
const model = this.model('notice');
const data = await model.add(info);
return this.success(data);
}
async updateAction() {
const content = this.post('content');
let end_time = this.post('time');
let id = this.post('id');
end_time = parseInt(new Date(end_time).getTime() / 1000);
const currentTime = parseInt(new Date().getTime() / 1000);
let info = {
content:content,
end_time:end_time
};
if(end_time > currentTime){
info.is_delete = 0;
}
else{
info.is_delete = 1;
}
const model = this.model('notice');
const data = await model.where({id:id}).update(info);
return this.success(data);
}
async destoryAction() {
const id = this.post('id');
await this.model('notice').where({id: id}).limit(1).delete();
return this.success();
}
};

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save