售后单列表、spu销售统计、交易趋势、sku销量统计
This commit is contained in:
parent
618979614a
commit
7e3a5fed04
13565
resources/frontend/package-lock.json
generated
13565
resources/frontend/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -10,13 +10,17 @@
|
||||
"dependencies": {
|
||||
"axios": "^0.21.1",
|
||||
"core-js": "^3.6.5",
|
||||
"dayjs": "^1.11.12",
|
||||
"echarts": "^5.5.1",
|
||||
"element-ui": "^2.15.6",
|
||||
"file-saver": "^2.0.5",
|
||||
"luxon": "^3.4.4",
|
||||
"nprogress": "^0.2.0",
|
||||
"vue": "^2.6.11",
|
||||
"vue-router": "^3.2.0",
|
||||
"vue-socket.io": "^3.0.10",
|
||||
"vuex": "^3.4.0"
|
||||
"vuex": "^3.4.0",
|
||||
"xlsx": "^0.18.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vue/cli-plugin-babel": "^5.0.8",
|
||||
@ -35,6 +39,7 @@
|
||||
"lint-staged": "^9.5.0",
|
||||
"sass": "^1.26.5",
|
||||
"sass-loader": "^8.0.2",
|
||||
"script-loader": "^0.7.2",
|
||||
"vue-template-compiler": "^2.6.11"
|
||||
},
|
||||
"gitHooks": {
|
||||
|
||||
34
resources/frontend/src/api/dataCenter.js
vendored
34
resources/frontend/src/api/dataCenter.js
vendored
@ -1,9 +1,33 @@
|
||||
import http from "@/util/http.js";
|
||||
|
||||
export function getSalesReportData(params) {
|
||||
return http({
|
||||
url: "/api/data_center/sales_report",
|
||||
method: "get",
|
||||
params,
|
||||
});
|
||||
return http({
|
||||
url: "/api/data_center/sales_report",
|
||||
method: "get",
|
||||
params
|
||||
})
|
||||
}
|
||||
|
||||
export function getSkuSalesCount(params) {
|
||||
return http({
|
||||
url: "/api/data_center/sale_statistics",
|
||||
method: "get",
|
||||
params
|
||||
})
|
||||
}
|
||||
|
||||
export function getSpuSalesCount(params) {
|
||||
return http({
|
||||
url: "/api/data_center/spu_sale_statistics",
|
||||
method: "get",
|
||||
params
|
||||
})
|
||||
}
|
||||
|
||||
export function getGmvCount(params) {
|
||||
return http({
|
||||
url: "/api/data_center/gmv_statistics",
|
||||
method: "get",
|
||||
params
|
||||
})
|
||||
}
|
||||
8
resources/frontend/src/api/plat.js
vendored
8
resources/frontend/src/api/plat.js
vendored
@ -70,3 +70,11 @@ export function printSuccess(params) {
|
||||
params
|
||||
});
|
||||
}
|
||||
|
||||
export function getAfterSaleOrders(params) {
|
||||
return http({
|
||||
url: "/api/plat_after_sale_orders",
|
||||
method: "get",
|
||||
params
|
||||
})
|
||||
}
|
||||
|
||||
16
resources/frontend/src/api/supplyChain.js
vendored
16
resources/frontend/src/api/supplyChain.js
vendored
@ -39,6 +39,22 @@ export function getPurchaseLog(params) {
|
||||
})
|
||||
}
|
||||
|
||||
export function addPurchaseLog(data) {
|
||||
return http({
|
||||
url: "/api/supplier/purchase_record",
|
||||
method: "post",
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function updatePurchaseLog(id, data) {
|
||||
return http({
|
||||
url: `/api/supplier/purchase_record/${id}`,
|
||||
method: "patch",
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function getLossLog(params) {
|
||||
return http({
|
||||
url: "/api/supplier/loss_record",
|
||||
|
||||
16
resources/frontend/src/api/user.js
vendored
16
resources/frontend/src/api/user.js
vendored
@ -44,3 +44,19 @@ export function userConfirm(id, data) {
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
export function websiteMessage(params) {
|
||||
return http({
|
||||
url: "/api/website_message",
|
||||
method: "get",
|
||||
params
|
||||
})
|
||||
}
|
||||
|
||||
export function messageRead(id, data) {
|
||||
return http({
|
||||
url: `/api/website_message/${id}`,
|
||||
method: "patch",
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
20
resources/frontend/src/router/list.js
vendored
20
resources/frontend/src/router/list.js
vendored
@ -85,6 +85,11 @@ const list = [
|
||||
name: "货品列表",
|
||||
component: () => import("../views/plat/goodsList.vue"),
|
||||
},
|
||||
{
|
||||
path: "PLAT_AFTER_SALE_ORDER_LIST",
|
||||
name: "售后单列表",
|
||||
component: () => import("../views/plat/afterSaleOrder.vue"),
|
||||
},
|
||||
{
|
||||
path: "GROUP_MANAGEMENT",
|
||||
name: "团购管理",
|
||||
@ -110,6 +115,21 @@ const list = [
|
||||
name: "销售数据",
|
||||
component: () => import("../views/dataCenter/salesReport.vue"),
|
||||
},
|
||||
{
|
||||
path: "sale_statistics",
|
||||
name: "sku销售统计",
|
||||
component: () => import("../views/dataCenter/skuStatistics.vue"),
|
||||
},
|
||||
{
|
||||
path: "spu_sale_statistics",
|
||||
name: "spu销售统计",
|
||||
component: () => import("../views/dataCenter/spuStatistics.vue"),
|
||||
},
|
||||
{
|
||||
path: "gmv_statistics",
|
||||
name: "spu销售统计",
|
||||
component: () => import("../views/dataCenter/gmvStatistics.vue"),
|
||||
},
|
||||
{
|
||||
path: "SUPPLIER_MANAGE",
|
||||
name: "供应商管理",
|
||||
|
||||
220
resources/frontend/src/util/Export2Excel.js
vendored
Normal file
220
resources/frontend/src/util/Export2Excel.js
vendored
Normal file
@ -0,0 +1,220 @@
|
||||
/* eslint-disable */
|
||||
import { saveAs } from 'file-saver'
|
||||
import * as XLSX from 'xlsx'
|
||||
|
||||
function generateArray(table) {
|
||||
var out = [];
|
||||
var rows = table.querySelectorAll('tr');
|
||||
var ranges = [];
|
||||
for (var R = 0; R < rows.length; ++R) {
|
||||
var outRow = [];
|
||||
var row = rows[R];
|
||||
var columns = row.querySelectorAll('td');
|
||||
for (var C = 0; C < columns.length; ++C) {
|
||||
var cell = columns[C];
|
||||
var colspan = cell.getAttribute('colspan');
|
||||
var rowspan = cell.getAttribute('rowspan');
|
||||
var cellValue = cell.innerText;
|
||||
if (cellValue !== "" && cellValue == +cellValue) cellValue = +cellValue;
|
||||
|
||||
//Skip ranges
|
||||
ranges.forEach(function (range) {
|
||||
if (R >= range.s.r && R <= range.e.r && outRow.length >= range.s.c && outRow.length <= range.e.c) {
|
||||
for (var i = 0; i <= range.e.c - range.s.c; ++i) outRow.push(null);
|
||||
}
|
||||
});
|
||||
|
||||
//Handle Row Span
|
||||
if (rowspan || colspan) {
|
||||
rowspan = rowspan || 1;
|
||||
colspan = colspan || 1;
|
||||
ranges.push({
|
||||
s: {
|
||||
r: R,
|
||||
c: outRow.length
|
||||
},
|
||||
e: {
|
||||
r: R + rowspan - 1,
|
||||
c: outRow.length + colspan - 1
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
//Handle Value
|
||||
outRow.push(cellValue !== "" ? cellValue : null);
|
||||
|
||||
//Handle Colspan
|
||||
if (colspan)
|
||||
for (var k = 0; k < colspan - 1; ++k) outRow.push(null);
|
||||
}
|
||||
out.push(outRow);
|
||||
}
|
||||
return [out, ranges];
|
||||
};
|
||||
|
||||
function datenum(v, date1904) {
|
||||
if (date1904) v += 1462;
|
||||
var epoch = Date.parse(v);
|
||||
return (epoch - new Date(Date.UTC(1899, 11, 30))) / (24 * 60 * 60 * 1000);
|
||||
}
|
||||
|
||||
function sheet_from_array_of_arrays(data, opts) {
|
||||
var ws = {};
|
||||
var range = {
|
||||
s: {
|
||||
c: 10000000,
|
||||
r: 10000000
|
||||
},
|
||||
e: {
|
||||
c: 0,
|
||||
r: 0
|
||||
}
|
||||
};
|
||||
for (var R = 0; R != data.length; ++R) {
|
||||
for (var C = 0; C != data[R].length; ++C) {
|
||||
if (range.s.r > R) range.s.r = R;
|
||||
if (range.s.c > C) range.s.c = C;
|
||||
if (range.e.r < R) range.e.r = R;
|
||||
if (range.e.c < C) range.e.c = C;
|
||||
var cell = {
|
||||
v: data[R][C]
|
||||
};
|
||||
if (cell.v == null) continue;
|
||||
var cell_ref = XLSX.utils.encode_cell({
|
||||
c: C,
|
||||
r: R
|
||||
});
|
||||
|
||||
if (typeof cell.v === 'number') cell.t = 'n';
|
||||
else if (typeof cell.v === 'boolean') cell.t = 'b';
|
||||
else if (cell.v instanceof Date) {
|
||||
cell.t = 'n';
|
||||
cell.z = XLSX.SSF._table[14];
|
||||
cell.v = datenum(cell.v);
|
||||
} else cell.t = 's';
|
||||
|
||||
ws[cell_ref] = cell;
|
||||
}
|
||||
}
|
||||
if (range.s.c < 10000000) ws['!ref'] = XLSX.utils.encode_range(range);
|
||||
return ws;
|
||||
}
|
||||
|
||||
function Workbook() {
|
||||
if (!(this instanceof Workbook)) return new Workbook();
|
||||
this.SheetNames = [];
|
||||
this.Sheets = {};
|
||||
}
|
||||
|
||||
function s2ab(s) {
|
||||
var buf = new ArrayBuffer(s.length);
|
||||
var view = new Uint8Array(buf);
|
||||
for (var i = 0; i != s.length; ++i) view[i] = s.charCodeAt(i) & 0xFF;
|
||||
return buf;
|
||||
}
|
||||
|
||||
export function export_table_to_excel(id) {
|
||||
var theTable = document.getElementById(id);
|
||||
var oo = generateArray(theTable);
|
||||
var ranges = oo[1];
|
||||
|
||||
/* original data */
|
||||
var data = oo[0];
|
||||
var ws_name = "SheetJS";
|
||||
|
||||
var wb = new Workbook(),
|
||||
ws = sheet_from_array_of_arrays(data);
|
||||
|
||||
/* add ranges to worksheet */
|
||||
// ws['!cols'] = ['apple', 'banan'];
|
||||
ws['!merges'] = ranges;
|
||||
|
||||
/* add worksheet to workbook */
|
||||
wb.SheetNames.push(ws_name);
|
||||
wb.Sheets[ws_name] = ws;
|
||||
|
||||
var wbout = XLSX.write(wb, {
|
||||
bookType: 'xlsx',
|
||||
bookSST: false,
|
||||
type: 'binary'
|
||||
});
|
||||
|
||||
saveAs(new Blob([s2ab(wbout)], {
|
||||
type: "application/octet-stream"
|
||||
}), "test.xlsx")
|
||||
}
|
||||
|
||||
export function export_json_to_excel({
|
||||
multiHeader = [],
|
||||
header,
|
||||
data,
|
||||
filename,
|
||||
merges = [],
|
||||
autoWidth = true,
|
||||
bookType = 'xlsx'
|
||||
} = {}) {
|
||||
/* original data */
|
||||
filename = filename || 'excel-list'
|
||||
data = [...data]
|
||||
data.unshift(header);
|
||||
|
||||
for (let i = multiHeader.length - 1; i > -1; i--) {
|
||||
data.unshift(multiHeader[i])
|
||||
}
|
||||
|
||||
var ws_name = "SheetJS";
|
||||
var wb = new Workbook(),
|
||||
ws = sheet_from_array_of_arrays(data);
|
||||
|
||||
if (merges.length > 0) {
|
||||
if (!ws['!merges']) ws['!merges'] = [];
|
||||
merges.forEach(item => {
|
||||
ws['!merges'].push(XLSX.utils.decode_range(item))
|
||||
})
|
||||
}
|
||||
|
||||
if (autoWidth) {
|
||||
/*设置worksheet每列的最大宽度*/
|
||||
const colWidth = data.map(row => row.map(val => {
|
||||
/*先判断是否为null/undefined*/
|
||||
if (val == null) {
|
||||
return {
|
||||
'wch': 10
|
||||
};
|
||||
}
|
||||
/*再判断是否为中文*/
|
||||
else if (val.toString().charCodeAt(0) > 255) {
|
||||
return {
|
||||
'wch': val.toString().length * 2
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
'wch': val.toString().length
|
||||
};
|
||||
}
|
||||
}))
|
||||
/*以第一行为初始值*/
|
||||
let result = colWidth[0];
|
||||
for (let i = 1; i < colWidth.length; i++) {
|
||||
for (let j = 0; j < colWidth[i].length; j++) {
|
||||
if (result[j]['wch'] < colWidth[i][j]['wch']) {
|
||||
result[j]['wch'] = colWidth[i][j]['wch'];
|
||||
}
|
||||
}
|
||||
}
|
||||
ws['!cols'] = result;
|
||||
}
|
||||
|
||||
/* add worksheet to workbook */
|
||||
wb.SheetNames.push(ws_name);
|
||||
wb.Sheets[ws_name] = ws;
|
||||
|
||||
var wbout = XLSX.write(wb, {
|
||||
bookType: bookType,
|
||||
bookSST: false,
|
||||
type: 'binary'
|
||||
});
|
||||
saveAs(new Blob([s2ab(wbout)], {
|
||||
type: "application/octet-stream"
|
||||
}), `${filename}.${bookType}`);
|
||||
}
|
||||
0
resources/frontend/src/util/time.js
vendored
Normal file
0
resources/frontend/src/util/time.js
vendored
Normal file
272
resources/frontend/src/views/dataCenter/gmvStatistics.vue
Normal file
272
resources/frontend/src/views/dataCenter/gmvStatistics.vue
Normal file
@ -0,0 +1,272 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="cardBox">
|
||||
<div class="searchBox">
|
||||
<div class="row">
|
||||
<span>统计时间:</span>
|
||||
<el-select v-model="time_type" style="width: 100px;margin-right: 5px;" @change="changeTimeType">
|
||||
<el-option v-for="item in timeTypeList" :key="item.value" :label="item.label" :value="item.value">
|
||||
</el-option>
|
||||
</el-select>
|
||||
<el-date-picker
|
||||
v-if="time_type == 'day' || time_type == 'week' || time_type == 'seven' || time_type == 'thirty'"
|
||||
v-model="dayValue"
|
||||
:clearable="false"
|
||||
type="date"
|
||||
placeholder="选择日期"
|
||||
format="yyyy-MM-dd"
|
||||
value-format="yyyy-MM-dd"
|
||||
@change="changeDayTime">
|
||||
</el-date-picker>
|
||||
|
||||
<el-date-picker
|
||||
v-else-if="time_type == 'month'"
|
||||
v-model="monthValue"
|
||||
type="month"
|
||||
:clearable="false"
|
||||
format="yyyy-MM"
|
||||
value-format="yyyy-MM"
|
||||
placeholder="选择月"
|
||||
@change="changeMonthTime">
|
||||
</el-date-picker>
|
||||
|
||||
<el-date-picker
|
||||
v-else-if="time_type == 'custom'"
|
||||
v-model="customValue"
|
||||
type="datetimerange"
|
||||
range-separator="-"
|
||||
start-placeholder="开始时间"
|
||||
end-placeholder="结束时间"
|
||||
format="yyyy-MM-dd"
|
||||
value-format="yyyy-MM-dd"
|
||||
:clearable="false"
|
||||
style="width: 250px;"
|
||||
@change="changeCustomTime">
|
||||
</el-date-picker>
|
||||
|
||||
<div class="time">
|
||||
<span>当前统计时间:</span>
|
||||
<span v-if="startTime == endTime">{{ startTime }}</span>
|
||||
<span v-else>{{ startTime }}~{{ endTime }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<el-card>
|
||||
<div class="echartBox" id="myEchart">
|
||||
|
||||
</div>
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getGmvCount } from "@/api/dataCenter.js"
|
||||
import dayjs from 'dayjs'
|
||||
import * as echarts from 'echarts'
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
loading: false,
|
||||
time_type: 'day',
|
||||
timeTypeList: [
|
||||
{ label: '自然日', value: 'day' },
|
||||
{ label: '自然周', value: 'week' },
|
||||
{ label: '自然月', value: 'month' },
|
||||
{ label: '近7天', value: 'seven' },
|
||||
{ label: '近30天', value: 'thirty' },
|
||||
{ label: '自定义', value: 'custom' }
|
||||
],
|
||||
dayValue: '',
|
||||
monthValue: '',
|
||||
customValue: [],
|
||||
startTime: '',
|
||||
endTime: '',
|
||||
dateList: [],
|
||||
Sales: [],
|
||||
SaleCount: [],
|
||||
myChart: null
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.getInitList()
|
||||
window.onresize = () => {
|
||||
if(this.myChart) {
|
||||
this.myChart.resize()
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getInitList() {
|
||||
let time = this.getDayTime()
|
||||
this.dayValue = this.startTime = this.endTime = time
|
||||
this.fetchData()
|
||||
},
|
||||
changeTimeType() {
|
||||
if(this.time_type == 'day') {
|
||||
let time = this.getDayTime()
|
||||
this.dayValue = this.startTime = this.endTime = time
|
||||
} else if(this.time_type == 'week') {
|
||||
this.dayValue = this.endTime = dayjs().format('YYYY-MM-DD')
|
||||
this.startTime = dayjs(this.getFirstDay(this.dayValue)).format('YYYY-MM-DD')
|
||||
} else if(this.time_type == 'month') {
|
||||
this.monthValue = dayjs().format('YYYY-MM')
|
||||
this.startTime = this.monthValue + '-01'
|
||||
this.endTime = this.monthValue + '-' + this.getDaysInMonth(this.monthValue)
|
||||
} else if(this.time_type == 'seven') {
|
||||
this.dayValue = this.endTime = dayjs().format('YYYY-MM-DD')
|
||||
this.startTime = dayjs().subtract(7, 'day').format('YYYY-MM-DD')
|
||||
} else if(this.time_type == 'thirty') {
|
||||
this.dayValue = this.endTime = dayjs().format('YYYY-MM-DD')
|
||||
this.startTime = dayjs().subtract(30, 'day').format('YYYY-MM-DD')
|
||||
} else if(this.time_type == 'custom') {
|
||||
this.startTime = this.endTime = dayjs().format('YYYY-MM-DD')
|
||||
this.customValue = [this.startTime, this.startTime]
|
||||
}
|
||||
this.fetchData()
|
||||
},
|
||||
fetchData() {
|
||||
this.loading = true
|
||||
let params = {
|
||||
type: this.time_type == 'day' ? 1 : 2,
|
||||
start_day: this.startTime,
|
||||
end_day: this.endTime
|
||||
}
|
||||
if(this.time_type == 'day') {
|
||||
params.interval = 60
|
||||
}
|
||||
getGmvCount(params).then((res) => {
|
||||
this.dateList = []
|
||||
this.Sales = []
|
||||
this.SaleCount = []
|
||||
res.data.data.forEach((it) => {
|
||||
this.dateList.push(it.day)
|
||||
this.Sales.push(it.goods_total)
|
||||
this.SaleCount.push(it.goods_total_amount)
|
||||
})
|
||||
this.renderChart()
|
||||
}).catch(() => {
|
||||
this.loading = false
|
||||
})
|
||||
},
|
||||
renderChart() {
|
||||
this.myChart = echarts.init(document.getElementById('myEchart'))
|
||||
this.myChart.setOption({
|
||||
grid: {
|
||||
left: '1%',
|
||||
bottom: '2%',
|
||||
containLabel: true
|
||||
},
|
||||
color: ['#3cd08f', '#f89f34'],
|
||||
tooltip: {
|
||||
trigger: 'axis'
|
||||
},
|
||||
legend: {
|
||||
icon: 'rect',
|
||||
left: 30,
|
||||
data: ['总销量', '总销售额']
|
||||
},
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
data: this.dateList
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value'
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: '总销量',
|
||||
type: 'line',
|
||||
smooth: true,
|
||||
data: this.Sales,
|
||||
},
|
||||
{
|
||||
name: '总销售额',
|
||||
type: 'line',
|
||||
smooth: true,
|
||||
data: this.SaleCount
|
||||
}
|
||||
]
|
||||
})
|
||||
this.loading = false
|
||||
},
|
||||
// 获取当前日期
|
||||
getDayTime() {
|
||||
let time = dayjs().format('YYYY-MM-DD')
|
||||
return time
|
||||
},
|
||||
// 获取所在周的周一
|
||||
getFirstDay(date) {
|
||||
let day = new Date(date).getDay() || 7
|
||||
return new Date(new Date(date).getFullYear(), new Date(date).getMonth(), new Date(date).getDate() + 1 - day)
|
||||
},
|
||||
getDaysInMonth(date) {
|
||||
let year = date.split('-')[0] * 1
|
||||
let month = date.split('-')[1] * 1
|
||||
const startOfMonth = dayjs(new Date(year, month - 1, 1))
|
||||
const endOfMonth = startOfMonth.endOf('month')
|
||||
return endOfMonth.date()
|
||||
},
|
||||
changeDayTime() {
|
||||
if(this.time_type == 'day') {
|
||||
this.startTime = this.endTime = this.dayValue
|
||||
} else if(this.time_type == 'week') {
|
||||
this.endTime = this.dayValue
|
||||
this.startTime = dayjs(this.getFirstDay(this.dayValue)).format('YYYY-MM-DD')
|
||||
} else if(this.time_type == 'seven') {
|
||||
this.endTime = this.dayValue
|
||||
this.startTime = dayjs().subtract(7, 'day').format('YYYY-MM-DD')
|
||||
} else if(this.time_type == 'thirty') {
|
||||
this.endTime = this.dayValue
|
||||
this.startTime = dayjs().subtract(30, 'day').format('YYYY-MM-DD')
|
||||
}
|
||||
this.fetchData()
|
||||
},
|
||||
changeMonthTime() {
|
||||
this.startTime = this.monthValue + '-01'
|
||||
this.endTime = this.monthValue + '-' + this.getDaysInMonth(this.monthValue)
|
||||
this.fetchData()
|
||||
},
|
||||
changeCustomTime() {
|
||||
this.startTime = this.customValue[0]
|
||||
this.endTime = this.customValue[1]
|
||||
this.fetchData()
|
||||
}
|
||||
},
|
||||
beforeDestroy() {
|
||||
if (!this.myChart) {
|
||||
return
|
||||
}
|
||||
this.myChart.dispose()
|
||||
this.myChart = null
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.searchBox{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
white-space: nowrap;
|
||||
.row{
|
||||
font-size: 14px;
|
||||
margin-bottom: 20px;
|
||||
margin-right: 15px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
.time{
|
||||
margin-left: 20px;
|
||||
color: #999;
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
.echartBox{
|
||||
width: 100%;
|
||||
height: 480px;
|
||||
}
|
||||
</style>
|
||||
|
||||
296
resources/frontend/src/views/dataCenter/skuStatistics.vue
Normal file
296
resources/frontend/src/views/dataCenter/skuStatistics.vue
Normal file
@ -0,0 +1,296 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="cardBox">
|
||||
<div class="searchBox">
|
||||
<div class="row">
|
||||
<span>统计时间:</span>
|
||||
<el-select v-model="time_type" style="width: 100px;margin-right: 5px;" @change="changeTimeType">
|
||||
<el-option v-for="item in timeTypeList" :key="item.value" :label="item.label" :value="item.value">
|
||||
</el-option>
|
||||
</el-select>
|
||||
<el-date-picker
|
||||
v-if="time_type == 'day' || time_type == 'week' || time_type == 'seven' || time_type == 'thirty'"
|
||||
v-model="dayValue"
|
||||
:clearable="false"
|
||||
type="date"
|
||||
placeholder="选择日期"
|
||||
format="yyyy-MM-dd"
|
||||
value-format="yyyy-MM-dd"
|
||||
@change="changeDayTime">
|
||||
</el-date-picker>
|
||||
|
||||
<el-date-picker
|
||||
v-else-if="time_type == 'month'"
|
||||
v-model="monthValue"
|
||||
type="month"
|
||||
:clearable="false"
|
||||
format="yyyy-MM"
|
||||
value-format="yyyy-MM"
|
||||
placeholder="选择月"
|
||||
@change="changeMonthTime">
|
||||
</el-date-picker>
|
||||
|
||||
<el-date-picker
|
||||
v-else-if="time_type == 'custom'"
|
||||
v-model="customValue"
|
||||
type="datetimerange"
|
||||
range-separator="-"
|
||||
start-placeholder="开始时间"
|
||||
end-placeholder="结束时间"
|
||||
format="yyyy-MM-dd"
|
||||
value-format="yyyy-MM-dd"
|
||||
:clearable="false"
|
||||
style="width: 250px;"
|
||||
@change="changeCustomTime">
|
||||
</el-date-picker>
|
||||
|
||||
<div class="time">
|
||||
<span>当前统计时间:</span>
|
||||
<span v-if="startTime == endTime">{{ startTime }}</span>
|
||||
<span v-else>{{ startTime }}~{{ endTime }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<el-card>
|
||||
<div class="opaBox">
|
||||
<el-button type="success" icon="el-icon-download" @click="handleExport" :loading="downloadLoading">导出</el-button>
|
||||
</div>
|
||||
<el-table v-loading="loading" border :data="saleList">
|
||||
<el-table-column label="商品名称" prop="name"></el-table-column>
|
||||
<el-table-column label="sku规格" prop="title"></el-table-column>
|
||||
<el-table-column label="规格编码" prop="external_sku_id"></el-table-column>
|
||||
<el-table-column label="销量" prop="goods_total"></el-table-column>
|
||||
<el-table-column label="销售额" prop="goods_total_amount"></el-table-column>
|
||||
|
||||
<el-table-column label="昨日销量" prop="yesterday_avg_num" v-if="time_type == 'day'"></el-table-column>
|
||||
<el-table-column label="3日内销量" prop="three_day_avg_num" v-if="time_type == 'day'"></el-table-column>
|
||||
<el-table-column label="7日内销量" prop="seven_day_avg_num" v-if="time_type == 'day'"></el-table-column>
|
||||
<el-table-column label="已发货数" prop="shipping_num" v-if="time_type == 'day'"></el-table-column>
|
||||
<el-table-column label="未发货数" prop="unshipping_num" v-if="time_type == 'day'"></el-table-column>
|
||||
|
||||
<el-table-column label="库存" prop="stock"></el-table-column>
|
||||
<el-table-column label="可售库存" prop="sale_stock"></el-table-column>
|
||||
<el-table-column label="状态" prop="status"></el-table-column>
|
||||
</el-table>
|
||||
<div class="page-pagination">
|
||||
<el-pagination
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="handleCurrentChange"
|
||||
:current-page="page"
|
||||
:page-sizes="[10, 20, 50, 100]"
|
||||
:page-size="pageSize"
|
||||
layout="prev, pager, next, jumper, sizes, total"
|
||||
:total="total">
|
||||
</el-pagination>
|
||||
</div>
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getSkuSalesCount } from "@/api/dataCenter.js"
|
||||
import dayjs from 'dayjs'
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
loading: false,
|
||||
time_type: 'day',
|
||||
timeTypeList: [
|
||||
{ label: '自然日', value: 'day' },
|
||||
{ label: '自然周', value: 'week' },
|
||||
{ label: '自然月', value: 'month' },
|
||||
{ label: '近7天', value: 'seven' },
|
||||
{ label: '近30天', value: 'thirty' },
|
||||
{ label: '自定义', value: 'custom' }
|
||||
],
|
||||
dayValue: '',
|
||||
monthValue: '',
|
||||
customValue: [],
|
||||
startTime: '',
|
||||
endTime: '',
|
||||
page: 1,
|
||||
pageSize: 10,
|
||||
total: 0,
|
||||
saleList: [],
|
||||
downloadLoading: false,
|
||||
autoWidth: true,
|
||||
bookType: 'xlsx'
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.getInitList()
|
||||
},
|
||||
methods: {
|
||||
getInitList() {
|
||||
let time = this.getDayTime()
|
||||
this.dayValue = this.startTime = this.endTime = time
|
||||
this.fetchData()
|
||||
},
|
||||
changeTimeType() {
|
||||
if(this.time_type == 'day') {
|
||||
let time = this.getDayTime()
|
||||
this.dayValue = this.startTime = this.endTime = time
|
||||
} else if(this.time_type == 'week') {
|
||||
this.dayValue = this.endTime = dayjs().format('YYYY-MM-DD')
|
||||
this.startTime = dayjs(this.getFirstDay(this.dayValue)).format('YYYY-MM-DD')
|
||||
} else if(this.time_type == 'month') {
|
||||
this.monthValue = dayjs().format('YYYY-MM')
|
||||
this.startTime = this.monthValue + '-01'
|
||||
this.endTime = this.monthValue + '-' + this.getDaysInMonth(this.monthValue)
|
||||
} else if(this.time_type == 'seven') {
|
||||
this.dayValue = this.endTime = dayjs().format('YYYY-MM-DD')
|
||||
this.startTime = dayjs().subtract(7, 'day').format('YYYY-MM-DD')
|
||||
} else if(this.time_type == 'thirty') {
|
||||
this.dayValue = this.endTime = dayjs().format('YYYY-MM-DD')
|
||||
this.startTime = dayjs().subtract(30, 'day').format('YYYY-MM-DD')
|
||||
} else if(this.time_type == 'custom') {
|
||||
this.startTime = this.endTime = dayjs().format('YYYY-MM-DD')
|
||||
this.customValue = [this.startTime, this.startTime]
|
||||
}
|
||||
this.page = 1
|
||||
this.fetchData()
|
||||
},
|
||||
fetchData() {
|
||||
this.loading = true
|
||||
let params = {
|
||||
type: this.time_type == 'day' ? 1 : 2,
|
||||
start_day: this.startTime,
|
||||
end_day: this.endTime,
|
||||
page: this.page,
|
||||
per_page: this.pageSize
|
||||
}
|
||||
getSkuSalesCount(params).then((res) => {
|
||||
this.saleList = res.data.data.data
|
||||
this.total = res.data.data.total
|
||||
this.loading = false
|
||||
}).catch(() => {
|
||||
this.loading = false
|
||||
})
|
||||
},
|
||||
// 获取当前日期
|
||||
getDayTime() {
|
||||
let time = dayjs().format('YYYY-MM-DD')
|
||||
return time
|
||||
},
|
||||
// 获取所在周的周一
|
||||
getFirstDay(date) {
|
||||
let day = new Date(date).getDay() || 7
|
||||
return new Date(new Date(date).getFullYear(), new Date(date).getMonth(), new Date(date).getDate() + 1 - day)
|
||||
},
|
||||
getDaysInMonth(date) {
|
||||
let year = date.split('-')[0] * 1
|
||||
let month = date.split('-')[1] * 1
|
||||
const startOfMonth = dayjs(new Date(year, month - 1, 1))
|
||||
const endOfMonth = startOfMonth.endOf('month')
|
||||
return endOfMonth.date()
|
||||
},
|
||||
changeDayTime() {
|
||||
if(this.time_type == 'day') {
|
||||
this.startTime = this.endTime = this.dayValue
|
||||
} else if(this.time_type == 'week') {
|
||||
this.endTime = this.dayValue
|
||||
this.startTime = dayjs(this.getFirstDay(this.dayValue)).format('YYYY-MM-DD')
|
||||
} else if(this.time_type == 'seven') {
|
||||
this.endTime = this.dayValue
|
||||
this.startTime = dayjs().subtract(7, 'day').format('YYYY-MM-DD')
|
||||
} else if(this.time_type == 'thirty') {
|
||||
this.endTime = this.dayValue
|
||||
this.startTime = dayjs().subtract(30, 'day').format('YYYY-MM-DD')
|
||||
}
|
||||
this.page = 1
|
||||
this.fetchData()
|
||||
},
|
||||
changeMonthTime() {
|
||||
this.startTime = this.monthValue + '-01'
|
||||
this.endTime = this.monthValue + '-' + this.getDaysInMonth(this.monthValue)
|
||||
this.page = 1
|
||||
this.fetchData()
|
||||
},
|
||||
changeCustomTime() {
|
||||
this.startTime = this.customValue[0]
|
||||
this.endTime = this.customValue[1]
|
||||
this.page = 1
|
||||
this.fetchData()
|
||||
},
|
||||
handleSizeChange(val) {
|
||||
this.page = 1
|
||||
this.pageSize = val
|
||||
this.fetchData()
|
||||
},
|
||||
handleCurrentChange(val) {
|
||||
this.page = val
|
||||
this.fetchData()
|
||||
},
|
||||
handleExport() {
|
||||
this.downloadLoading = true
|
||||
let params = {
|
||||
type: this.time_type == 'day' ? 1 : 2,
|
||||
start_day: this.startTime,
|
||||
end_day: this.endTime,
|
||||
page: 1,
|
||||
per_page: this.total
|
||||
}
|
||||
getSkuSalesCount(params).then((res) => {
|
||||
if(!res.data.data.data.length) {
|
||||
this.$message({
|
||||
message: '暂无数据',
|
||||
type: 'error'
|
||||
})
|
||||
return
|
||||
}
|
||||
import('@/util/Export2Excel').then(excel => {
|
||||
const tHeader = ['商品名称', 'sku规格', '规格编码', '销量', '销售额']
|
||||
const filterVal = ['name', 'title', 'external_sku_id', 'goods_total', 'goods_total_amount']
|
||||
const list = res.data.data.data
|
||||
const data = this.formatJson(filterVal, list)
|
||||
excel.export_json_to_excel({
|
||||
header: tHeader,
|
||||
data,
|
||||
filename: 'sku销售统计数据',
|
||||
autoWidth: this.autoWidth,
|
||||
bookType: this.bookType
|
||||
})
|
||||
this.downloadLoading = false
|
||||
}).catch(() => {
|
||||
this.downloadLoading = false
|
||||
})
|
||||
}).catch(() => {
|
||||
this.downloadLoading = false
|
||||
})
|
||||
},
|
||||
formatJson(filterVal, jsonData) {
|
||||
return jsonData.map(v => filterVal.map(j => {
|
||||
return v[j]
|
||||
}))
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.searchBox{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
white-space: nowrap;
|
||||
.row{
|
||||
font-size: 14px;
|
||||
margin-bottom: 20px;
|
||||
margin-right: 15px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
.time{
|
||||
margin-left: 20px;
|
||||
color: #999;
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
.opaBox{
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
</style>
|
||||
|
||||
251
resources/frontend/src/views/dataCenter/spuStatistics.vue
Normal file
251
resources/frontend/src/views/dataCenter/spuStatistics.vue
Normal file
@ -0,0 +1,251 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="cardBox">
|
||||
<div class="searchBox">
|
||||
<div class="row">
|
||||
<span>统计时间:</span>
|
||||
<el-select v-model="time_type" style="width: 100px;margin-right: 5px;" @change="changeTimeType">
|
||||
<el-option v-for="item in timeTypeList" :key="item.value" :label="item.label" :value="item.value">
|
||||
</el-option>
|
||||
</el-select>
|
||||
<el-date-picker
|
||||
v-if="time_type == 'day' || time_type == 'week' || time_type == 'seven' || time_type == 'thirty'"
|
||||
v-model="dayValue"
|
||||
:clearable="false"
|
||||
type="date"
|
||||
placeholder="选择日期"
|
||||
format="yyyy-MM-dd"
|
||||
value-format="yyyy-MM-dd"
|
||||
@change="changeDayTime">
|
||||
</el-date-picker>
|
||||
|
||||
<el-date-picker
|
||||
v-else-if="time_type == 'month'"
|
||||
v-model="monthValue"
|
||||
type="month"
|
||||
:clearable="false"
|
||||
format="yyyy-MM"
|
||||
value-format="yyyy-MM"
|
||||
placeholder="选择月"
|
||||
@change="changeMonthTime">
|
||||
</el-date-picker>
|
||||
|
||||
<el-date-picker
|
||||
v-else-if="time_type == 'custom'"
|
||||
v-model="customValue"
|
||||
type="datetimerange"
|
||||
range-separator="-"
|
||||
start-placeholder="开始时间"
|
||||
end-placeholder="结束时间"
|
||||
format="yyyy-MM-dd"
|
||||
value-format="yyyy-MM-dd"
|
||||
:clearable="false"
|
||||
style="width: 250px;"
|
||||
@change="changeCustomTime">
|
||||
</el-date-picker>
|
||||
|
||||
<div class="time">
|
||||
<span>当前统计时间:</span>
|
||||
<span v-if="startTime == endTime">{{ startTime }}</span>
|
||||
<span v-else>{{ startTime }}~{{ endTime }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<el-card>
|
||||
<div class="opaBox">
|
||||
<el-button type="success" icon="el-icon-download" @click="handleExport" :loading="downloadLoading">导出</el-button>
|
||||
</div>
|
||||
<el-table v-loading="loading" border :data="saleList">
|
||||
<el-table-column label="类型名称" prop="type_name"></el-table-column>
|
||||
<el-table-column label="库存" prop="stock"></el-table-column>
|
||||
<el-table-column label="可售库存" prop="sale_stock"></el-table-column>
|
||||
<el-table-column label="销量" prop="goods_total"></el-table-column>
|
||||
<el-table-column label="销售额" prop="goods_total_amount"></el-table-column>
|
||||
|
||||
<el-table-column label="已发货数" prop="shipping_num" v-if="time_type == 'day'"></el-table-column>
|
||||
<el-table-column label="未发货数" prop="unshipping_num" v-if="time_type == 'day'"></el-table-column>
|
||||
|
||||
<el-table-column label="总销量" prop="goods_total"></el-table-column>
|
||||
<el-table-column label="总销售金额" prop="goods_total_amount"></el-table-column>
|
||||
</el-table>
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getSpuSalesCount } from "@/api/dataCenter.js"
|
||||
import dayjs from 'dayjs'
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
loading: false,
|
||||
time_type: 'day',
|
||||
timeTypeList: [
|
||||
{ label: '自然日', value: 'day' },
|
||||
{ label: '自然周', value: 'week' },
|
||||
{ label: '自然月', value: 'month' },
|
||||
{ label: '近7天', value: 'seven' },
|
||||
{ label: '近30天', value: 'thirty' },
|
||||
{ label: '自定义', value: 'custom' }
|
||||
],
|
||||
dayValue: '',
|
||||
monthValue: '',
|
||||
customValue: [],
|
||||
startTime: '',
|
||||
endTime: '',
|
||||
saleList: [],
|
||||
downloadLoading: false,
|
||||
autoWidth: true,
|
||||
bookType: 'xlsx'
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.getInitList()
|
||||
},
|
||||
methods: {
|
||||
getInitList() {
|
||||
let time = this.getDayTime()
|
||||
this.dayValue = this.startTime = this.endTime = time
|
||||
this.fetchData()
|
||||
},
|
||||
changeTimeType() {
|
||||
if(this.time_type == 'day') {
|
||||
let time = this.getDayTime()
|
||||
this.dayValue = this.startTime = this.endTime = time
|
||||
} else if(this.time_type == 'week') {
|
||||
this.dayValue = this.endTime = dayjs().format('YYYY-MM-DD')
|
||||
this.startTime = dayjs(this.getFirstDay(this.dayValue)).format('YYYY-MM-DD')
|
||||
} else if(this.time_type == 'month') {
|
||||
this.monthValue = dayjs().format('YYYY-MM')
|
||||
this.startTime = this.monthValue + '-01'
|
||||
this.endTime = this.monthValue + '-' + this.getDaysInMonth(this.monthValue)
|
||||
} else if(this.time_type == 'seven') {
|
||||
this.dayValue = this.endTime = dayjs().format('YYYY-MM-DD')
|
||||
this.startTime = dayjs().subtract(7, 'day').format('YYYY-MM-DD')
|
||||
} else if(this.time_type == 'thirty') {
|
||||
this.dayValue = this.endTime = dayjs().format('YYYY-MM-DD')
|
||||
this.startTime = dayjs().subtract(30, 'day').format('YYYY-MM-DD')
|
||||
} else if(this.time_type == 'custom') {
|
||||
this.startTime = this.endTime = dayjs().format('YYYY-MM-DD')
|
||||
this.customValue = [this.startTime, this.startTime]
|
||||
}
|
||||
this.fetchData()
|
||||
},
|
||||
fetchData() {
|
||||
this.loading = true
|
||||
let params = {
|
||||
type: this.time_type == 'day' ? 1 : 2,
|
||||
start_day: this.startTime,
|
||||
end_day: this.endTime
|
||||
}
|
||||
getSpuSalesCount(params).then((res) => {
|
||||
this.saleList = res.data.data
|
||||
this.loading = false
|
||||
}).catch(() => {
|
||||
this.loading = false
|
||||
})
|
||||
},
|
||||
// 获取当前日期
|
||||
getDayTime() {
|
||||
let time = dayjs().format('YYYY-MM-DD')
|
||||
return time
|
||||
},
|
||||
// 获取所在周的周一
|
||||
getFirstDay(date) {
|
||||
let day = new Date(date).getDay() || 7
|
||||
return new Date(new Date(date).getFullYear(), new Date(date).getMonth(), new Date(date).getDate() + 1 - day)
|
||||
},
|
||||
getDaysInMonth(date) {
|
||||
let year = date.split('-')[0] * 1
|
||||
let month = date.split('-')[1] * 1
|
||||
const startOfMonth = dayjs(new Date(year, month - 1, 1))
|
||||
const endOfMonth = startOfMonth.endOf('month')
|
||||
return endOfMonth.date()
|
||||
},
|
||||
changeDayTime() {
|
||||
if(this.time_type == 'day') {
|
||||
this.startTime = this.endTime = this.dayValue
|
||||
} else if(this.time_type == 'week') {
|
||||
this.endTime = this.dayValue
|
||||
this.startTime = dayjs(this.getFirstDay(this.dayValue)).format('YYYY-MM-DD')
|
||||
} else if(this.time_type == 'seven') {
|
||||
this.endTime = this.dayValue
|
||||
this.startTime = dayjs().subtract(7, 'day').format('YYYY-MM-DD')
|
||||
} else if(this.time_type == 'thirty') {
|
||||
this.endTime = this.dayValue
|
||||
this.startTime = dayjs().subtract(30, 'day').format('YYYY-MM-DD')
|
||||
}
|
||||
this.fetchData()
|
||||
},
|
||||
changeMonthTime() {
|
||||
this.startTime = this.monthValue + '-01'
|
||||
this.endTime = this.monthValue + '-' + this.getDaysInMonth(this.monthValue)
|
||||
this.fetchData()
|
||||
},
|
||||
changeCustomTime() {
|
||||
this.startTime = this.customValue[0]
|
||||
this.endTime = this.customValue[1]
|
||||
this.fetchData()
|
||||
},
|
||||
handleExport() {
|
||||
if(!this.saleList.length) {
|
||||
this.$message({
|
||||
message: '暂无数据',
|
||||
type: 'error'
|
||||
})
|
||||
return
|
||||
}
|
||||
this.downloadLoading = true
|
||||
import('@/util/Export2Excel').then(excel => {
|
||||
const tHeader = ['类型名称', '库存', '可售库存', '未发货数', '未发货数', '总销量', '总销售金额']
|
||||
const filterVal = ['type_name', 'stock', 'sale_stock', 'shipping_num', 'unshipping_num', 'goods_total', 'goods_total_amount']
|
||||
const list = this.saleList
|
||||
const data = this.formatJson(filterVal, list)
|
||||
excel.export_json_to_excel({
|
||||
header: tHeader,
|
||||
data,
|
||||
filename: 'sku销售统计数据',
|
||||
autoWidth: this.autoWidth,
|
||||
bookType: this.bookType
|
||||
})
|
||||
this.downloadLoading = false
|
||||
}).catch(() => {
|
||||
this.downloadLoading = false
|
||||
})
|
||||
},
|
||||
formatJson(filterVal, jsonData) {
|
||||
return jsonData.map(v => filterVal.map(j => {
|
||||
return v[j]
|
||||
}))
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.searchBox{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
white-space: nowrap;
|
||||
.row{
|
||||
font-size: 14px;
|
||||
margin-bottom: 20px;
|
||||
margin-right: 15px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
.time{
|
||||
margin-left: 20px;
|
||||
color: #999;
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
.opaBox{
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -42,8 +42,8 @@
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</div>
|
||||
<div v-for="(item, i) in skus" :key="i">
|
||||
<div>{{ i + 1 }}.</div>
|
||||
<div v-for="(item, i) in skus" :key="i" class="skuBox">
|
||||
<div class="tit">规格{{ i + 1 }}</div>
|
||||
<el-form-item label="商品规格:">
|
||||
<el-input placeholder="商品规格" v-model="skus[i].title"></el-input>
|
||||
</el-form-item>
|
||||
@ -66,14 +66,22 @@
|
||||
<el-input v-model="skus[i].cost" placeholder="商品成本">
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="在售库存:">
|
||||
<el-input v-model="skus[i].sale_stock" placeholder="在售库存">
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-button type="danger" @click="handleDelete(i)">删除</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="btn">
|
||||
|
||||
<el-form-item>
|
||||
<el-button type="success" @click="handleAdd()">增加规格</el-button>
|
||||
</el-form-item>
|
||||
|
||||
<div style="margin-top: 30px;">
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="handleSave()">保存</el-button>
|
||||
<el-button plain @click="cancel()">取消</el-button>
|
||||
<el-button type="success" @click="handleAdd()">增加规格</el-button>
|
||||
</el-form-item>
|
||||
</div>
|
||||
</el-form>
|
||||
@ -208,6 +216,7 @@ export default {
|
||||
status: "0",
|
||||
num: "0",
|
||||
cost: "0",
|
||||
sale_stock: 0,
|
||||
reserve: "0",
|
||||
};
|
||||
this.skus.push(sku);
|
||||
@ -231,7 +240,20 @@ export default {
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
<style scoped lang="scss">
|
||||
.skuBox{
|
||||
border: 1px solid #e5e5e5;
|
||||
border-radius: 5px;
|
||||
padding: 15px 0;
|
||||
margin-bottom: 15px;
|
||||
background-color: #f3f3f3;
|
||||
.tit{
|
||||
padding-left: 40px;
|
||||
font-weight: 600;
|
||||
font-size: 15px;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
}
|
||||
.el-upload--picture-card {
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-card class="box-card">
|
||||
<el-form ref="form" :inline="true" :model="goodsData">
|
||||
<el-form ref="form" :inline="true" :model="goodsData" label-position="right" label-width="100px">
|
||||
<div>
|
||||
<el-form-item label="商品列表:">
|
||||
<el-select v-model="goodsData.goods_id" placeholder="选择商品" filterable :disabled="true">
|
||||
@ -62,6 +62,10 @@
|
||||
<el-input v-model="goodsData.cost" placeholder="商品成本">
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="在售库存:">
|
||||
<el-input v-model="goodsData.sale_stock" placeholder="在售库存">
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
@ -110,6 +114,7 @@ export default {
|
||||
status: "",
|
||||
num: "",
|
||||
cost: "",
|
||||
sale_stock: '',
|
||||
sku_code: "",
|
||||
thumb_url: [],
|
||||
goods: {
|
||||
@ -214,6 +219,7 @@ export default {
|
||||
status: this.goodsData.status,
|
||||
num: this.goodsData.num,
|
||||
cost: this.goodsData.cost,
|
||||
sale_stock: this.goodsData.sale_stock,
|
||||
thumb_url: this.goodsData.thumb_url
|
||||
};
|
||||
if (sku.status == "下架") {
|
||||
@ -229,7 +235,10 @@ export default {
|
||||
sku,
|
||||
};
|
||||
updateGoods(this.skuId, updateData).then((res) => {
|
||||
this.$message(res.data.message);
|
||||
this.$message({
|
||||
type: "success",
|
||||
message: "编辑成功"
|
||||
})
|
||||
this.$router.push("/GOODS_LIST");
|
||||
});
|
||||
},
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,255 +1,443 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-container>
|
||||
<el-container>
|
||||
<el-aside :class="show ? 'aside-show' : 'aside-hide'">
|
||||
<el-menu router background-color="#282c34" :unique-opened="true" text-color="#fff" :default-active="$route.path"
|
||||
:default-openeds="openeds">
|
||||
<div v-for="item in menu" :key="item.id">
|
||||
<el-menu-item :index="'/' + item.code" v-if="!item.children">
|
||||
<span>{{ item.name }}</span>
|
||||
</el-menu-item>
|
||||
<el-submenu v-else :index="'/' + item.code">
|
||||
<template slot="title">
|
||||
<span>{{ item.name }}</span>
|
||||
</template>
|
||||
<el-menu-item :index="'/' + children.code" :key="children.id" v-for="children in item.children">{{
|
||||
children.name }}
|
||||
</el-menu-item>
|
||||
</el-submenu>
|
||||
</div>
|
||||
</el-menu>
|
||||
</el-aside>
|
||||
<div>
|
||||
<el-container>
|
||||
<el-container>
|
||||
<el-aside :class="show ? 'aside-show' : 'aside-hide'">
|
||||
<el-menu router background-color="#282c34" :unique-opened="true" text-color="#fff" :default-active="$route.path"
|
||||
:default-openeds="openeds">
|
||||
<div v-for="item in menu" :key="item.id">
|
||||
<el-menu-item :index="'/' + item.code" v-if="!item.children">
|
||||
<span>{{ item.name }}</span>
|
||||
</el-menu-item>
|
||||
<el-submenu v-else :index="'/' + item.code">
|
||||
<template slot="title">
|
||||
<span>{{ item.name }}</span>
|
||||
</template>
|
||||
<el-menu-item :index="'/' + children.code" :key="children.id" v-for="children in item.children">
|
||||
{{ children.name }}
|
||||
</el-menu-item>
|
||||
</el-submenu>
|
||||
</div>
|
||||
</el-menu>
|
||||
</el-aside>
|
||||
|
||||
<el-main>
|
||||
<div class="head">
|
||||
<ul>
|
||||
<li>
|
||||
<div @click="add" class="add">
|
||||
<i class="el-icon-s-unfold" v-if="show"></i>
|
||||
<i class="el-icon-s-fold" v-else></i>
|
||||
</div>
|
||||
<div class="right">
|
||||
<el-breadcrumb separator-class="el-icon-arrow-right">
|
||||
<el-breadcrumb-item v-for="(item, index) in titie" :key="index">{{ item.name }}
|
||||
</el-breadcrumb-item>
|
||||
</el-breadcrumb>
|
||||
</div>
|
||||
</li>
|
||||
<li>
|
||||
<div style="margin-right: 10px;">{{ usernmae }}</div>
|
||||
<div class="token" @click="hanleLogout">登出</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<el-main>
|
||||
<div class="head">
|
||||
<ul>
|
||||
<li>
|
||||
<div @click="add" class="add">
|
||||
<i class="el-icon-s-unfold" v-if="show"></i>
|
||||
<i class="el-icon-s-fold" v-else></i>
|
||||
</div>
|
||||
<div class="right">
|
||||
<el-breadcrumb separator-class="el-icon-arrow-right">
|
||||
<el-breadcrumb-item v-for="(item, index) in titie" :key="index">{{ item.name }}</el-breadcrumb-item>
|
||||
</el-breadcrumb>
|
||||
</div>
|
||||
</li>
|
||||
<li>
|
||||
<div class="msg" @click="openMessage">
|
||||
<el-badge :hidden="noReadNum == 0" :value="noReadNum" :max="99"><i class="el-icon-message"></i></el-badge>
|
||||
</div>
|
||||
<div style="margin-right: 10px;">{{ usernmae }}</div>
|
||||
<div class="token" @click="hanleLogout">登出</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="box-card">
|
||||
<router-view></router-view>
|
||||
</div>
|
||||
</el-main>
|
||||
</el-container>
|
||||
</el-container>
|
||||
</div>
|
||||
<div class="box-card">
|
||||
<router-view></router-view>
|
||||
</div>
|
||||
</el-main>
|
||||
</el-container>
|
||||
</el-container>
|
||||
|
||||
<el-dialog :visible.sync="showMsg" title="站内信" width="1100px" custom-class="vanmsgbox" @close="showMsg = false">
|
||||
<div class="msgbox">
|
||||
<el-tabs type="border-card" @tab-click="handleTabClick" v-model="curTopTab">
|
||||
<el-tab-pane name="0">
|
||||
<template #label>
|
||||
<span>未读消息</span>
|
||||
<span v-if="noReadNum !== 0" class="numtag">{{ noReadNum }}</span>
|
||||
</template>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="已读消息" name="1"></el-tab-pane>
|
||||
</el-tabs>
|
||||
<div class="listbox" v-loading="loading">
|
||||
<div class="item" v-for="item in msgList">
|
||||
<div class="title" :class="item.status ? '' : 'notread'">
|
||||
<div class="tit">{{ item.title }}</div>
|
||||
<span v-if="!item.status" class="not" @click="markRead(item)">标为已读</span>
|
||||
<span v-else>已读</span>
|
||||
</div>
|
||||
<div class="info">
|
||||
<div class="tit" v-if="item.content" v-html="item.content.replace(/\n/g,'<br/>')"></div>
|
||||
<div class="time">{{ item.created_at }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="msgList.length == 0 && !loading">
|
||||
<el-empty description="暂无消息" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="bottom">
|
||||
<el-pagination
|
||||
:current-page="page"
|
||||
:page-sizes="[10, 20, 50, 100]"
|
||||
:page-size="pageSize"
|
||||
layout="prev, pager, next, sizes, total"
|
||||
:total="total"
|
||||
@current-change="handleCurrentChange"
|
||||
@size-change="handleSizeChange">
|
||||
</el-pagination>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { removeToken } from "@/util/auth";
|
||||
import { getMenu } from "../api/menu.js";
|
||||
import { removeToken } from "@/util/auth"
|
||||
import { getMenu } from "../api/menu.js"
|
||||
import { websiteMessage, messageRead } from "../api/user.js"
|
||||
|
||||
export default {
|
||||
mounted() {
|
||||
getMenu().then((res) => {
|
||||
this.menu = res.data.data;
|
||||
console.log(this.menu)
|
||||
});
|
||||
this.usernmae = localStorage.getItem('userName');
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
menu: [], // 侧边栏
|
||||
show: false, // 导航栏折叠
|
||||
levelData: [], // table导航栏
|
||||
titie: [], // 面包屑
|
||||
head: "", // 路由name
|
||||
onindex: 0, // 索引
|
||||
openeds: ["GOODS_MANAGE"],
|
||||
usernmae: ''
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
// table构造
|
||||
$route: {
|
||||
handler: function (val) {
|
||||
this.titie = val.matched;
|
||||
this.head = val.name;
|
||||
this.levelData.push({ name: val.name, path: val.path });
|
||||
const newArr = [];
|
||||
const obj = {};
|
||||
for (var i = 0; i < this.levelData.length; i++) {
|
||||
if (!obj[this.levelData[i].name]) {
|
||||
newArr.push(this.levelData[i]);
|
||||
obj[this.levelData[i].name] = true;
|
||||
}
|
||||
}
|
||||
mounted() {
|
||||
getMenu().then((res) => {
|
||||
this.menu = res.data.data
|
||||
})
|
||||
this.usernmae = localStorage.getItem('userName');
|
||||
this.getNoReadNum()
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
menu: [], // 侧边栏
|
||||
show: false, // 导航栏折叠
|
||||
levelData: [], // table导航栏
|
||||
titie: [], // 面包屑
|
||||
head: "", // 路由name
|
||||
onindex: 0, // 索引
|
||||
openeds: ["GOODS_MANAGE"],
|
||||
usernmae: '',
|
||||
noReadNum: 0,
|
||||
total: 0,
|
||||
msgList: [],
|
||||
page: 1,
|
||||
pageSize: 10,
|
||||
showMsg: false,
|
||||
curTopTab: '2',
|
||||
loading: false
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
// table构造
|
||||
$route: {
|
||||
handler: function (val) {
|
||||
this.titie = val.matched;
|
||||
this.head = val.name;
|
||||
this.levelData.push({ name: val.name, path: val.path });
|
||||
const newArr = [];
|
||||
const obj = {};
|
||||
for (var i = 0; i < this.levelData.length; i++) {
|
||||
if (!obj[this.levelData[i].name]) {
|
||||
newArr.push(this.levelData[i]);
|
||||
obj[this.levelData[i].name] = true;
|
||||
}
|
||||
}
|
||||
|
||||
this.levelData = newArr;
|
||||
},
|
||||
deep: true,
|
||||
immediate: true,
|
||||
},
|
||||
this.levelData = newArr;
|
||||
},
|
||||
deep: true,
|
||||
immediate: true
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
next() {
|
||||
this.hanletop();
|
||||
},
|
||||
methods: {
|
||||
next() {
|
||||
this.hanletop();
|
||||
},
|
||||
hanletop() {
|
||||
document.getElementById("bottom").scrollIntoView({ behavior: "smooth" });
|
||||
},
|
||||
hanlebottom() {
|
||||
document.getElementById("top").scrollIntoView({ behavior: "smooth" });
|
||||
},
|
||||
hanleLogout() {
|
||||
removeToken();
|
||||
this.$router.push({ path: "/Login" });
|
||||
},
|
||||
handlerclick(e) {
|
||||
if (this.$route.path !== e) {
|
||||
this.$router.push({ path: e });
|
||||
}
|
||||
},
|
||||
add() {
|
||||
this.show = !this.show;
|
||||
},
|
||||
hanblDelete(index, titie) {
|
||||
var list = this.levelData[index].name;
|
||||
hanletop() {
|
||||
document.getElementById("bottom").scrollIntoView({ behavior: "smooth" });
|
||||
},
|
||||
hanlebottom() {
|
||||
document.getElementById("top").scrollIntoView({ behavior: "smooth" });
|
||||
},
|
||||
hanleLogout() {
|
||||
removeToken();
|
||||
this.$router.push({ path: "/Login" });
|
||||
},
|
||||
handlerclick(e) {
|
||||
if (this.$route.path !== e) {
|
||||
this.$router.push({ path: e });
|
||||
}
|
||||
},
|
||||
add() {
|
||||
this.show = !this.show;
|
||||
},
|
||||
hanblDelete(index, titie) {
|
||||
var list = this.levelData[index].name;
|
||||
|
||||
this.onindex = index;
|
||||
this.levelData.splice(this.onindex, 1);
|
||||
if (titie === this.head) {
|
||||
var item;
|
||||
var name;
|
||||
for (let i = 0; i < this.levelData.length; i++) {
|
||||
item = this.levelData[i].path;
|
||||
name = this.levelData[i].name;
|
||||
}
|
||||
if (this.levelData.length) {
|
||||
if (name !== list) {
|
||||
this.$router.push({ path: item });
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
this.onindex = index;
|
||||
this.levelData.splice(this.onindex, 1);
|
||||
if (titie === this.head) {
|
||||
var item;
|
||||
var name;
|
||||
for (let i = 0; i < this.levelData.length; i++) {
|
||||
item = this.levelData[i].path;
|
||||
name = this.levelData[i].name;
|
||||
}
|
||||
if (this.levelData.length) {
|
||||
if (name !== list) {
|
||||
this.$router.push({ path: item });
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
getNoReadNum() {
|
||||
let params = {
|
||||
page: 1,
|
||||
status: 0
|
||||
}
|
||||
websiteMessage(params).then((res) => {
|
||||
this.noReadNum = res.data.meta.total
|
||||
})
|
||||
},
|
||||
openMessage() {
|
||||
this.curTopTab = '0'
|
||||
this.showMsg = true
|
||||
this.page = 1
|
||||
this.getMsgList()
|
||||
},
|
||||
getMsgList() {
|
||||
this.loading = true
|
||||
let params = {
|
||||
page: this.page,
|
||||
per_page: this.pageSize,
|
||||
status: this.curTopTab == '2' ? '' : this.curTopTab
|
||||
}
|
||||
websiteMessage(params).then((res) => {
|
||||
this.msgList = res.data.data
|
||||
this.total = res.data.meta.total
|
||||
this.loading = false
|
||||
}).catch(() => {
|
||||
this.loading = false
|
||||
})
|
||||
},
|
||||
handleTabClick() {
|
||||
this.page = 1
|
||||
this.getMsgList()
|
||||
},
|
||||
markRead(item) {
|
||||
messageRead(item.id, {status: 1}).then((res) => {
|
||||
item.status = 1
|
||||
this.getNoReadNum()
|
||||
})
|
||||
},
|
||||
handleCurrentChange(e) {
|
||||
this.page = e
|
||||
this.getMsgList()
|
||||
},
|
||||
handleSizeChange(e) {
|
||||
this.page = 1
|
||||
this.pageSize = e
|
||||
this.getMsgList()
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.aside-show {
|
||||
.aside-show {
|
||||
transition: all 0.3s;
|
||||
opacity: 0;
|
||||
width: 0px !important;
|
||||
}
|
||||
}
|
||||
|
||||
.aside-hide {
|
||||
.aside-hide {
|
||||
transition: all 0.3s;
|
||||
opacity: 1;
|
||||
width: 200px !important;
|
||||
}
|
||||
}
|
||||
|
||||
.el-container {
|
||||
.el-container {
|
||||
height: 100vh;
|
||||
}
|
||||
}
|
||||
|
||||
.el-aside {
|
||||
.el-aside {
|
||||
background-color: #d3dce6;
|
||||
color: #333;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
}
|
||||
|
||||
.el-aside::-webkit-scrollbar {
|
||||
.el-aside::-webkit-scrollbar {
|
||||
width: 8px;
|
||||
/*对垂直流动条有效*/
|
||||
}
|
||||
}
|
||||
|
||||
.el-aside::-webkit-scrollbar-thumb {
|
||||
.el-aside::-webkit-scrollbar-thumb {
|
||||
background-color: rgba(144, 147, 153, 0.3);
|
||||
border-radius: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
.el-main {
|
||||
.el-main {
|
||||
background-color: #f0f2f5;
|
||||
color: #333;
|
||||
padding: 0 0 !important;
|
||||
}
|
||||
}
|
||||
|
||||
.el-main::-webkit-scrollbar {
|
||||
.el-main::-webkit-scrollbar {
|
||||
width: 10px;
|
||||
/*对垂直流动条有效*/
|
||||
}
|
||||
}
|
||||
|
||||
.el-main::-webkit-scrollbar-thumb {
|
||||
.el-main::-webkit-scrollbar-thumb {
|
||||
background-color: rgba(144, 147, 153, 0.3);
|
||||
}
|
||||
}
|
||||
|
||||
.box-card {
|
||||
.box-card {
|
||||
min-height: calc(100vh - 120px);
|
||||
margin: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.conent {
|
||||
.conent {
|
||||
width: 100%;
|
||||
min-height: calc(100vh - 200px);
|
||||
position: relative;
|
||||
}
|
||||
}
|
||||
|
||||
.add {
|
||||
.add {
|
||||
cursor: pointer;
|
||||
font-size: 25px;
|
||||
font-size: 20px;
|
||||
color: #606266;
|
||||
}
|
||||
}
|
||||
|
||||
.head {
|
||||
.head {
|
||||
padding: 10px;
|
||||
background-color: #fff;
|
||||
border-bottom: 1px solid #f6f6f6;
|
||||
box-shadow: 0 1px 4px rgb(0 21 41 / 8%);
|
||||
|
||||
ul {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
li {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
||||
li {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.right {
|
||||
margin-left: 20px;
|
||||
}
|
||||
|
||||
.token {
|
||||
cursor: pointer;
|
||||
}
|
||||
align-items: center;
|
||||
.right {
|
||||
margin-left: 20px;
|
||||
}
|
||||
.token {
|
||||
cursor: pointer;
|
||||
}
|
||||
.msg{
|
||||
margin-right: 15px;
|
||||
font-size: 20px;
|
||||
cursor: pointer;
|
||||
&:hover{
|
||||
color: #409EFF;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.el-aside {
|
||||
.el-aside {
|
||||
background: #282c34;
|
||||
box-shadow: 2px 0 6px rgb(0 21 41 / 35%);
|
||||
}
|
||||
}
|
||||
|
||||
::v-deep .el-menu {
|
||||
::v-deep .el-menu {
|
||||
border: none;
|
||||
}
|
||||
}
|
||||
|
||||
.el-menu-item:hover {
|
||||
.el-menu-item:hover {
|
||||
outline: 0 !important;
|
||||
background: #5470c6 !important;
|
||||
}
|
||||
}
|
||||
|
||||
.el-menu-item.is-active {
|
||||
.el-menu-item.is-active {
|
||||
color: #fff !important;
|
||||
background: #5470c6 !important;
|
||||
}
|
||||
}
|
||||
|
||||
.el-menu-item-group__title {
|
||||
.el-menu-item-group__title {
|
||||
padding: 0 0 !important;
|
||||
}
|
||||
}
|
||||
.msgbox{
|
||||
padding: 20px;
|
||||
.numtag{
|
||||
padding: 1px 4px;
|
||||
font-size: 12px;
|
||||
background: #f00;
|
||||
color: #fff;
|
||||
margin-left: 10px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
.listbox{
|
||||
height: 550px;
|
||||
overflow: auto;
|
||||
.item{
|
||||
color: #555;
|
||||
font-size: 14px;
|
||||
padding: 20px 30px;
|
||||
box-sizing: border-box;
|
||||
border-bottom: 1px solid #D7D7D7;
|
||||
.title{
|
||||
margin-bottom: 10px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
position: relative;
|
||||
&.notread::after{
|
||||
position: absolute;
|
||||
left: -14px;
|
||||
width: 7px;
|
||||
height: 7px;
|
||||
border-radius: 50%;
|
||||
top: 8px;
|
||||
content: '';
|
||||
background: #f00;
|
||||
}
|
||||
.tit{
|
||||
font-size: 16px;
|
||||
width: calc(100% - 150px);
|
||||
}
|
||||
span{
|
||||
font-size: 12px;
|
||||
color: #777;
|
||||
&.not{
|
||||
color: #409eff;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
}
|
||||
.info{
|
||||
margin-bottom: 10px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
.tit{
|
||||
font-size: 14px;
|
||||
width: calc(100% - 200px);
|
||||
}
|
||||
.time{
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.bottom{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 20px 0;
|
||||
border-top: 1px solid #D7D7D7;
|
||||
}
|
||||
::v-deep .vanmsgbox .el-tabs__content{
|
||||
display: none;
|
||||
}
|
||||
::v-deep .vanmsgbox .el-tabs--border-card{
|
||||
box-shadow: none;
|
||||
}
|
||||
::v-deep .vanmsgbox .el-dialog__body{
|
||||
padding: 0 !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
190
resources/frontend/src/views/plat/afterSaleOrder.vue
Normal file
190
resources/frontend/src/views/plat/afterSaleOrder.vue
Normal file
@ -0,0 +1,190 @@
|
||||
<template>
|
||||
<div class="pageBox">
|
||||
<div class="cardBox">
|
||||
<div class="searchBox">
|
||||
<div class="row">
|
||||
<span>店铺:</span>
|
||||
<el-select v-model="filter.shop_id" placeholder="店铺">
|
||||
<el-option v-for="item in shopsList" :key="item.id" :label="item.name" :value="item.id">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</div>
|
||||
<div class="row">
|
||||
<span>售后单状态:</span>
|
||||
<el-select v-model="filter.after_sales_status" placeholder="请选择">
|
||||
<el-option v-for="item in statusList" :key="item.id" :label="item.name" :value="item.id">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</div>
|
||||
<div class="row">
|
||||
<span>订单编号:</span>
|
||||
<el-input v-model="filter.order_sn" clearable></el-input>
|
||||
</div>
|
||||
<div class="row">
|
||||
<span>售后单编号:</span>
|
||||
<el-input v-model="filter.after_sales_biz_sn" clearable></el-input>
|
||||
</div>
|
||||
<div class="row">
|
||||
<span>创建时间:</span>
|
||||
<el-date-picker
|
||||
v-model="addTime"
|
||||
type="datetimerange"
|
||||
range-separator="-"
|
||||
start-placeholder="开始时间"
|
||||
end-placeholder="结束时间"
|
||||
value-format="yyyy-MM-dd HH:mm:ss"
|
||||
style="width: 340px">
|
||||
</el-date-picker>
|
||||
</div>
|
||||
<div class="row">
|
||||
<el-button type="primary" icon="el-icon-search" @click="handleSearch">筛选</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<el-card>
|
||||
<el-table v-loading="loading" :data="afterList" style="width: 100%" border>
|
||||
<el-table-column prop="after_sales_biz_sn" label="售后单编号" />
|
||||
<el-table-column prop="order_sn" label="父订单编号" />
|
||||
<el-table-column label="门店id">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ Shops[scope.row.shop_id] }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="refund_amount" label="退款金额" />
|
||||
<el-table-column prop="refund_shipping_amount" label="用户申请退运费金额" />
|
||||
<el-table-column prop="reason" label="退款原因" />
|
||||
<el-table-column prop="apply_type" label="申请类型" />
|
||||
<el-table-column label="售后单状态">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ STATUS[scope.row.after_sales_status] }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="after_sale_created_at" label="售后单创建时间" />
|
||||
</el-table>
|
||||
<div class="page-pagination">
|
||||
<el-pagination
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="handleCurrentChange"
|
||||
:current-page="page"
|
||||
:page-sizes="[10, 20, 50, 100]"
|
||||
:page-size="pageSize"
|
||||
layout="prev, pager, next, jumper, sizes, total"
|
||||
:total="total">
|
||||
</el-pagination>
|
||||
</div>
|
||||
</el-card>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getAfterSaleOrders } from "@/api/plat"
|
||||
import { storeList } from "@/api/shop"
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
loading: false,
|
||||
page: 1,
|
||||
pageSize: 10,
|
||||
total: 0,
|
||||
afterList: [],
|
||||
filter: {
|
||||
shop_id: '',
|
||||
after_sales_status: '',
|
||||
order_sn: '',
|
||||
after_sales_biz_sn: ''
|
||||
},
|
||||
shopsList: [],
|
||||
Shops: {},
|
||||
addTime: [],
|
||||
statusList: [
|
||||
{ id: 0, name: '未发起售后' },
|
||||
{ id: 1, name: '退款中' },
|
||||
{ id: 2, name: '退款成功' },
|
||||
{ id: 3, name: '待处理' },
|
||||
{ id: 4, name: '拒绝退款' },
|
||||
{ id: 6, name: '待(顾客)退货' },
|
||||
{ id: 7, name: '待(团长)确认退货' },
|
||||
{ id: 8, name: '(顾客)撤销' },
|
||||
{ id: 9, name: '(系统)关闭' }
|
||||
],
|
||||
STATUS: {
|
||||
'0': '未发起售后',
|
||||
'1': '退款中',
|
||||
'2': '退款成功',
|
||||
'3': '待处理',
|
||||
'4': '拒绝退款',
|
||||
'6': '待(顾客)退货',
|
||||
'7': '待(团长)确认退货',
|
||||
'8': '(顾客)撤销',
|
||||
'9': '(系统)关闭',
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
fetchList() {
|
||||
this.loading = true
|
||||
let params = {
|
||||
page: this.page,
|
||||
per_page: this.pageSize,
|
||||
...this.filter,
|
||||
created_at_start: this.addTime ? this.addTime[0] : '',
|
||||
created_at_end: this.addTime ? this.addTime[1] : ''
|
||||
}
|
||||
getAfterSaleOrders(params).then((res) => {
|
||||
this.afterList = res.data.data
|
||||
this.total = res.data.meta.total
|
||||
this.loading = false
|
||||
}).catch(() => {
|
||||
this.loading = false
|
||||
})
|
||||
},
|
||||
handleSizeChange(val) {
|
||||
this.page = 1
|
||||
this.pageSize = val
|
||||
this.fetchList()
|
||||
},
|
||||
handleCurrentChange(val) {
|
||||
this.page = val
|
||||
this.fetchList()
|
||||
},
|
||||
handleSearch() {
|
||||
this.page = 1
|
||||
this.fetchList()
|
||||
},
|
||||
getShopsList() {
|
||||
let params = {
|
||||
page: 1,
|
||||
per_page: 999
|
||||
}
|
||||
storeList(params).then((res) => {
|
||||
this.shopsList = res.data.data
|
||||
res.data.data.forEach((it) => {
|
||||
this.Shops[it.id] = it.name
|
||||
})
|
||||
})
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.fetchList()
|
||||
this.getShopsList()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.searchBox{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
white-space: nowrap;
|
||||
.row{
|
||||
font-size: 14px;
|
||||
margin-bottom: 20px;
|
||||
margin-right: 15px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@ -174,7 +174,7 @@ export default {
|
||||
const params = new FormData();
|
||||
params.append("inventoryFile", this.fileList[0].raw)
|
||||
let token = localStorage.getItem("token")
|
||||
axios.post("/api/daily_stock_record/purchase_import", params, {
|
||||
axios.post("/api/supplier/daily_stock_record/inventory_import", params, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${token}`
|
||||
}
|
||||
|
||||
@ -61,13 +61,13 @@
|
||||
</div>
|
||||
</el-card>
|
||||
|
||||
<el-dialog :title="curInfo.id ? '编辑' : '新增供应商'" :visible.sync="dialogVisible" width="500px">
|
||||
<el-dialog :title="curInfo.id ? '编辑' : '新增'" :visible.sync="dialogVisible" width="500px">
|
||||
<el-form label-width="90px">
|
||||
<el-form-item label="规格编码">
|
||||
<el-input v-model="curInfo.external_sku_id" clearable></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="数量">
|
||||
<el-input v-model="curInfo.num" clearable></el-input>
|
||||
<el-input v-model="curInfo.num" clearable :disabled="curInfo.id ? true : false"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="成本">
|
||||
<el-input v-model="curInfo.cost" clearable></el-input>
|
||||
|
||||
@ -28,6 +28,10 @@
|
||||
</div>
|
||||
</div>
|
||||
<el-card>
|
||||
<div class="opaBox">
|
||||
<el-button type="primary" icon="el-icon-plus" @click="handleAdd">新增</el-button>
|
||||
<el-button type="warning" icon="el-icon-upload2" @click="handleImport">导入</el-button>
|
||||
</div>
|
||||
<el-table v-loading="loading" :data="procureList" style="width: 100%" border>
|
||||
<el-table-column prop="sku_id" label="商品id" width="80" align="center" />
|
||||
<el-table-column prop="goods_sku.title" label="商品标题" />
|
||||
@ -43,6 +47,11 @@
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="created_at" label="创建时间" align="center" />
|
||||
<el-table-column label="操作" width="120" align="center">
|
||||
<template slot-scope="scope">
|
||||
<el-button type="primary" @click="handleEdit(scope.row)" icon="el-icon-edit" size="mini">编辑</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<div class="page-pagination">
|
||||
<el-pagination
|
||||
@ -57,11 +66,59 @@
|
||||
</div>
|
||||
</el-card>
|
||||
|
||||
<el-dialog :title="curInfo.id ? '编辑' : '新增'" :visible.sync="dialogVisible" width="500px">
|
||||
<el-form label-width="90px">
|
||||
<el-form-item label="规格编码">
|
||||
<el-input v-model="curInfo.external_sku_id" clearable></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="数量">
|
||||
<el-input v-model="curInfo.num" clearable></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="成本">
|
||||
<el-input v-model="curInfo.cost" clearable></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="采购人">
|
||||
<el-input v-model="curInfo.buyer_name" clearable></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="供应商">
|
||||
<el-input v-model="curInfo.supplier_name" clearable></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="过期时间">
|
||||
<el-date-picker
|
||||
v-model="curInfo.expire_time"
|
||||
type="date"
|
||||
placeholder="选择日期"
|
||||
format="yyyy-MM-dd"
|
||||
value-format="yyyy-MM-dd">
|
||||
</el-date-picker>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<el-button @click="dialogVisible = false">取 消</el-button>
|
||||
<el-button type="primary" @click="commitSupplier" :loading="commitloading">确 定</el-button>
|
||||
</span>
|
||||
</el-dialog>
|
||||
|
||||
<el-dialog title="导入" :visible.sync="showImport" width="500px">
|
||||
<div style="text-align: center;">
|
||||
<el-upload class="upload-demo" drag action="" :limit="1" :multiple="false"
|
||||
accept="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.ms-excel"
|
||||
:file-list="fileList" :auto-upload="false" :on-change="importFileChange" :on-remove="fileRemove">
|
||||
<i class="el-icon-upload"></i>
|
||||
<div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
|
||||
</el-upload>
|
||||
</div>
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<el-button @click="showImport = false">取 消</el-button>
|
||||
<el-button type="primary" @click="commitUpload" :loading="commitloading">上 传</el-button>
|
||||
</span>
|
||||
</el-dialog>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getPurchaseLog } from "@/api/supplyChain"
|
||||
import { getPurchaseLog, addPurchaseLog, updatePurchaseLog } from "@/api/supplyChain"
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
@ -74,7 +131,12 @@ export default {
|
||||
title: '',
|
||||
external_sku_id: ''
|
||||
},
|
||||
addTime: []
|
||||
addTime: [],
|
||||
commitloading: false,
|
||||
dialogVisible: false,
|
||||
curInfo: {},
|
||||
showImport: false,
|
||||
fileList: []
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
@ -107,6 +169,76 @@ export default {
|
||||
handleSearch() {
|
||||
this.page = 1
|
||||
this.fetchList()
|
||||
},
|
||||
// 新增供应商
|
||||
handleAdd() {
|
||||
this.curInfo = {}
|
||||
this.dialogVisible = true
|
||||
},
|
||||
handleEdit(row) {
|
||||
this.curInfo = JSON.parse(JSON.stringify(row))
|
||||
this.dialogVisible = true
|
||||
},
|
||||
commitSupplier() {
|
||||
this.commitloading = true
|
||||
if(this.curInfo.id) {
|
||||
updatePurchaseLog(this.curInfo.id, this.curInfo).then((res) => {
|
||||
this.fetchList()
|
||||
this.$message({ type: "success", message: "更新成功!" })
|
||||
this.dialogVisible = false
|
||||
this.commitloading = false
|
||||
}).catch(() => {
|
||||
this.commitloading = false
|
||||
})
|
||||
} else {
|
||||
addPurchaseLog(this.curInfo).then((res) => {
|
||||
this.page = 1
|
||||
this.fetchList()
|
||||
this.$message({ type: "success", message: "新增成功!" })
|
||||
this.dialogVisible = false
|
||||
this.commitloading = false
|
||||
}).catch(() => {
|
||||
this.commitloading = false
|
||||
})
|
||||
}
|
||||
},
|
||||
handleImport() {
|
||||
this.fileList = []
|
||||
this.showImport = true
|
||||
},
|
||||
importFileChange(file, fileList) {
|
||||
console.log(fileList)
|
||||
this.fileList = fileList
|
||||
},
|
||||
fileRemove() {
|
||||
this.fileList = []
|
||||
},
|
||||
commitUpload() {
|
||||
if(this.fileList.length) {
|
||||
this.commitloading = true
|
||||
const params = new FormData();
|
||||
params.append("lossFile", this.fileList[0].raw)
|
||||
let token = localStorage.getItem("token")
|
||||
axios.post("/api/purchase_record/purchase_import", params, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${token}`
|
||||
}
|
||||
}).then((res) => {
|
||||
if (res.status === 200) {
|
||||
this.$message.success("导入成功")
|
||||
this.page = 1
|
||||
this.fetchList()
|
||||
this.commitloading = false
|
||||
this.showImport = false
|
||||
} else {
|
||||
this.commitloading = false
|
||||
}
|
||||
}).catch(() => {
|
||||
this.commitloading = false
|
||||
})
|
||||
} else {
|
||||
this.$message.error("请先上传文件");
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
@ -129,4 +261,7 @@ export default {
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
.opaBox{
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
</style>
|
||||
|
||||
3
resources/frontend/vue.config.js
vendored
3
resources/frontend/vue.config.js
vendored
@ -8,7 +8,8 @@ module.exports = {
|
||||
// 配置代理
|
||||
"/api": {
|
||||
// target: "http://erp.local",
|
||||
target: "http://erp.chutang66.com",
|
||||
// target: "http://erp.chutang66.com",
|
||||
target: "http://192.168.0.52:81",
|
||||
changeOrigin: true, // 开启代理
|
||||
pathRewrite: {
|
||||
// 重命名
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user