售后单列表、spu销售统计、交易趋势、sku销量统计

This commit is contained in:
DESKTOP-8FGKA8Q\chunfen 2024-08-05 18:04:49 +08:00
parent 618979614a
commit 7e3a5fed04
21 changed files with 3064 additions and 14700 deletions

File diff suppressed because it is too large Load Diff

View File

@ -10,13 +10,17 @@
"dependencies": { "dependencies": {
"axios": "^0.21.1", "axios": "^0.21.1",
"core-js": "^3.6.5", "core-js": "^3.6.5",
"dayjs": "^1.11.12",
"echarts": "^5.5.1",
"element-ui": "^2.15.6", "element-ui": "^2.15.6",
"file-saver": "^2.0.5",
"luxon": "^3.4.4", "luxon": "^3.4.4",
"nprogress": "^0.2.0", "nprogress": "^0.2.0",
"vue": "^2.6.11", "vue": "^2.6.11",
"vue-router": "^3.2.0", "vue-router": "^3.2.0",
"vue-socket.io": "^3.0.10", "vue-socket.io": "^3.0.10",
"vuex": "^3.4.0" "vuex": "^3.4.0",
"xlsx": "^0.18.5"
}, },
"devDependencies": { "devDependencies": {
"@vue/cli-plugin-babel": "^5.0.8", "@vue/cli-plugin-babel": "^5.0.8",
@ -35,6 +39,7 @@
"lint-staged": "^9.5.0", "lint-staged": "^9.5.0",
"sass": "^1.26.5", "sass": "^1.26.5",
"sass-loader": "^8.0.2", "sass-loader": "^8.0.2",
"script-loader": "^0.7.2",
"vue-template-compiler": "^2.6.11" "vue-template-compiler": "^2.6.11"
}, },
"gitHooks": { "gitHooks": {

View File

@ -4,6 +4,30 @@ export function getSalesReportData(params) {
return http({ return http({
url: "/api/data_center/sales_report", url: "/api/data_center/sales_report",
method: "get", method: "get",
params, 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
})
} }

View File

@ -70,3 +70,11 @@ export function printSuccess(params) {
params params
}); });
} }
export function getAfterSaleOrders(params) {
return http({
url: "/api/plat_after_sale_orders",
method: "get",
params
})
}

View File

@ -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) { export function getLossLog(params) {
return http({ return http({
url: "/api/supplier/loss_record", url: "/api/supplier/loss_record",

View File

@ -44,3 +44,19 @@ export function userConfirm(id, data) {
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
})
}

View File

@ -85,6 +85,11 @@ const list = [
name: "货品列表", name: "货品列表",
component: () => import("../views/plat/goodsList.vue"), component: () => import("../views/plat/goodsList.vue"),
}, },
{
path: "PLAT_AFTER_SALE_ORDER_LIST",
name: "售后单列表",
component: () => import("../views/plat/afterSaleOrder.vue"),
},
{ {
path: "GROUP_MANAGEMENT", path: "GROUP_MANAGEMENT",
name: "团购管理", name: "团购管理",
@ -110,6 +115,21 @@ const list = [
name: "销售数据", name: "销售数据",
component: () => import("../views/dataCenter/salesReport.vue"), 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", path: "SUPPLIER_MANAGE",
name: "供应商管理", name: "供应商管理",

View 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
View File

View 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>

View 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>

View 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>

View File

@ -42,8 +42,8 @@
</el-select> </el-select>
</el-form-item> </el-form-item>
</div> </div>
<div v-for="(item, i) in skus" :key="i"> <div v-for="(item, i) in skus" :key="i" class="skuBox">
<div>{{ i + 1 }}.</div> <div class="tit">规格{{ i + 1 }}</div>
<el-form-item label="商品规格:"> <el-form-item label="商品规格:">
<el-input placeholder="商品规格" v-model="skus[i].title"></el-input> <el-input placeholder="商品规格" v-model="skus[i].title"></el-input>
</el-form-item> </el-form-item>
@ -66,14 +66,22 @@
<el-input v-model="skus[i].cost" placeholder="商品成本"> <el-input v-model="skus[i].cost" placeholder="商品成本">
</el-input> </el-input>
</el-form-item> </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> <el-button type="danger" @click="handleDelete(i)">删除</el-button>
</div> </div>
</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-form-item>
<el-button type="primary" @click="handleSave()">保存</el-button> <el-button type="primary" @click="handleSave()">保存</el-button>
<el-button plain @click="cancel()">取消</el-button> <el-button plain @click="cancel()">取消</el-button>
<el-button type="success" @click="handleAdd()">增加规格</el-button>
</el-form-item> </el-form-item>
</div> </div>
</el-form> </el-form>
@ -208,6 +216,7 @@ export default {
status: "0", status: "0",
num: "0", num: "0",
cost: "0", cost: "0",
sale_stock: 0,
reserve: "0", reserve: "0",
}; };
this.skus.push(sku); this.skus.push(sku);
@ -231,7 +240,20 @@ export default {
}; };
</script> </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 { .el-upload--picture-card {
width: 50px; width: 50px;
height: 50px; height: 50px;

View File

@ -1,7 +1,7 @@
<template> <template>
<div> <div>
<el-card class="box-card"> <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> <div>
<el-form-item label="商品列表:"> <el-form-item label="商品列表:">
<el-select v-model="goodsData.goods_id" placeholder="选择商品" filterable :disabled="true"> <el-select v-model="goodsData.goods_id" placeholder="选择商品" filterable :disabled="true">
@ -62,6 +62,10 @@
<el-input v-model="goodsData.cost" placeholder="商品成本"> <el-input v-model="goodsData.cost" placeholder="商品成本">
</el-input> </el-input>
</el-form-item> </el-form-item>
<el-form-item label="在售库存:">
<el-input v-model="goodsData.sale_stock" placeholder="在售库存">
</el-input>
</el-form-item>
</div> </div>
</div> </div>
<div> <div>
@ -110,6 +114,7 @@ export default {
status: "", status: "",
num: "", num: "",
cost: "", cost: "",
sale_stock: '',
sku_code: "", sku_code: "",
thumb_url: [], thumb_url: [],
goods: { goods: {
@ -214,6 +219,7 @@ export default {
status: this.goodsData.status, status: this.goodsData.status,
num: this.goodsData.num, num: this.goodsData.num,
cost: this.goodsData.cost, cost: this.goodsData.cost,
sale_stock: this.goodsData.sale_stock,
thumb_url: this.goodsData.thumb_url thumb_url: this.goodsData.thumb_url
}; };
if (sku.status == "下架") { if (sku.status == "下架") {
@ -229,7 +235,10 @@ export default {
sku, sku,
}; };
updateGoods(this.skuId, updateData).then((res) => { updateGoods(this.skuId, updateData).then((res) => {
this.$message(res.data.message); this.$message({
type: "success",
message: "编辑成功"
})
this.$router.push("/GOODS_LIST"); this.$router.push("/GOODS_LIST");
}); });
}, },

File diff suppressed because it is too large Load Diff

View File

@ -13,8 +13,8 @@
<template slot="title"> <template slot="title">
<span>{{ item.name }}</span> <span>{{ item.name }}</span>
</template> </template>
<el-menu-item :index="'/' + children.code" :key="children.id" v-for="children in item.children">{{ <el-menu-item :index="'/' + children.code" :key="children.id" v-for="children in item.children">
children.name }} {{ children.name }}
</el-menu-item> </el-menu-item>
</el-submenu> </el-submenu>
</div> </div>
@ -31,12 +31,14 @@
</div> </div>
<div class="right"> <div class="right">
<el-breadcrumb separator-class="el-icon-arrow-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 v-for="(item, index) in titie" :key="index">{{ item.name }}</el-breadcrumb-item>
</el-breadcrumb-item>
</el-breadcrumb> </el-breadcrumb>
</div> </div>
</li> </li>
<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 style="margin-right: 10px;">{{ usernmae }}</div>
<div class="token" @click="hanleLogout">登出</div> <div class="token" @click="hanleLogout">登出</div>
</li> </li>
@ -49,18 +51,63 @@
</el-main> </el-main>
</el-container> </el-container>
</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> </div>
</template> </template>
<script> <script>
import { removeToken } from "@/util/auth"; import { removeToken } from "@/util/auth"
import { getMenu } from "../api/menu.js"; import { getMenu } from "../api/menu.js"
import { websiteMessage, messageRead } from "../api/user.js"
export default { export default {
mounted() { mounted() {
getMenu().then((res) => { getMenu().then((res) => {
this.menu = res.data.data; this.menu = res.data.data
console.log(this.menu) })
});
this.usernmae = localStorage.getItem('userName'); this.usernmae = localStorage.getItem('userName');
this.getNoReadNum()
}, },
data() { data() {
return { return {
@ -71,8 +118,16 @@ export default {
head: "", // name head: "", // name
onindex: 0, // onindex: 0, //
openeds: ["GOODS_MANAGE"], openeds: ["GOODS_MANAGE"],
usernmae: '' usernmae: '',
}; noReadNum: 0,
total: 0,
msgList: [],
page: 1,
pageSize: 10,
showMsg: false,
curTopTab: '2',
loading: false
}
}, },
watch: { watch: {
// table // table
@ -93,8 +148,8 @@ export default {
this.levelData = newArr; this.levelData = newArr;
}, },
deep: true, deep: true,
immediate: true, immediate: true
}, }
}, },
methods: { methods: {
next() { next() {
@ -137,9 +192,59 @@ export default {
} }
} }
}, },
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> </script>
<style scoped lang="scss"> <style scoped lang="scss">
.aside-show { .aside-show {
transition: all 0.3s; transition: all 0.3s;
@ -201,7 +306,7 @@ export default {
.add { .add {
cursor: pointer; cursor: pointer;
font-size: 25px; font-size: 20px;
color: #606266; color: #606266;
} }
@ -210,22 +315,26 @@ export default {
background-color: #fff; background-color: #fff;
border-bottom: 1px solid #f6f6f6; border-bottom: 1px solid #f6f6f6;
box-shadow: 0 1px 4px rgb(0 21 41 / 8%); box-shadow: 0 1px 4px rgb(0 21 41 / 8%);
ul { ul {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
li { li {
display: flex; display: flex;
align-items: center; align-items: center;
.right { .right {
margin-left: 20px; margin-left: 20px;
} }
.token { .token {
cursor: pointer; cursor: pointer;
} }
.msg{
margin-right: 15px;
font-size: 20px;
cursor: pointer;
&:hover{
color: #409EFF;
}
}
} }
} }
} }
@ -252,4 +361,83 @@ export default {
.el-menu-item-group__title { .el-menu-item-group__title {
padding: 0 0 !important; 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> </style>

View 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>

View File

@ -174,7 +174,7 @@ export default {
const params = new FormData(); const params = new FormData();
params.append("inventoryFile", this.fileList[0].raw) params.append("inventoryFile", this.fileList[0].raw)
let token = localStorage.getItem("token") 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: { headers: {
Authorization: `Bearer ${token}` Authorization: `Bearer ${token}`
} }

View File

@ -61,13 +61,13 @@
</div> </div>
</el-card> </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 label-width="90px">
<el-form-item label="规格编码"> <el-form-item label="规格编码">
<el-input v-model="curInfo.external_sku_id" clearable></el-input> <el-input v-model="curInfo.external_sku_id" clearable></el-input>
</el-form-item> </el-form-item>
<el-form-item label="数量"> <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>
<el-form-item label="成本"> <el-form-item label="成本">
<el-input v-model="curInfo.cost" clearable></el-input> <el-input v-model="curInfo.cost" clearable></el-input>

View File

@ -28,6 +28,10 @@
</div> </div>
</div> </div>
<el-card> <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 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="sku_id" label="商品id" width="80" align="center" />
<el-table-column prop="goods_sku.title" label="商品标题" /> <el-table-column prop="goods_sku.title" label="商品标题" />
@ -43,6 +47,11 @@
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="created_at" label="创建时间" align="center" /> <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> </el-table>
<div class="page-pagination"> <div class="page-pagination">
<el-pagination <el-pagination
@ -57,11 +66,59 @@
</div> </div>
</el-card> </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> </div>
</template> </template>
<script> <script>
import { getPurchaseLog } from "@/api/supplyChain" import { getPurchaseLog, addPurchaseLog, updatePurchaseLog } from "@/api/supplyChain"
export default { export default {
data() { data() {
return { return {
@ -74,7 +131,12 @@ export default {
title: '', title: '',
external_sku_id: '' external_sku_id: ''
}, },
addTime: [] addTime: [],
commitloading: false,
dialogVisible: false,
curInfo: {},
showImport: false,
fileList: []
} }
}, },
methods: { methods: {
@ -107,6 +169,76 @@ export default {
handleSearch() { handleSearch() {
this.page = 1 this.page = 1
this.fetchList() 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() { mounted() {
@ -129,4 +261,7 @@ export default {
align-items: center; align-items: center;
} }
} }
.opaBox{
margin-bottom: 15px;
}
</style> </style>

View File

@ -8,7 +8,8 @@ module.exports = {
// 配置代理 // 配置代理
"/api": { "/api": {
// target: "http://erp.local", // target: "http://erp.local",
target: "http://erp.chutang66.com", // target: "http://erp.chutang66.com",
target: "http://192.168.0.52:81",
changeOrigin: true, // 开启代理 changeOrigin: true, // 开启代理
pathRewrite: { pathRewrite: {
// 重命名 // 重命名