Merge pull request 'zhangyu' (#1) from zhangyu into main

Reviewed-on: #1
main
zhangyv 2 years ago
commit 468f4caeef

@ -17,7 +17,74 @@ export default {
@import "tailwindcss/base";
@import "tailwindcss/utilities";
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
*::-webkit-scrollbar {
height: 0px;
width: 0px;
/* 横向滚动条高度 */
}
*::-webkit-scrollbar-thumb {
background: #fff;
border-radius: 0px;
}
*::-webkit-scrollbar-track {
background: #fff;
border-radius: 0px;
}
*::-webkit-scrollbar-thumb:horizontal {
background: #fff;
/* 横向滚动条thumb颜色 */
}
*::-webkit-scrollbar-track:horizontal {
background: #fff;
/* 横向滚动条轨道颜色 */
}
page {
min-height: 100vh;
// min-height: calc(100vh - 44px);
min-height: calc(100vh);
background-color: rgb(247 248 250);
box-sizing: border-box;
display: flex;
flex-direction: column;
}
.content {
display: flex;
height: 100%;
flex: 1;
flex-direction: column;
}
.line2 {
display: -webkit-box;
margin-bottom: 5px;
max-height: 44px;
white-space: normal;
text-overflow: ellipsis;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
word-break: break-all;
overflow: hidden;
display: -webkit-box;
margin-bottom: 5px;
max-height: 44px;
white-space: normal;
text-overflow: ellipsis;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
word-break: break-all;
overflow: hidden;
}
</style>

@ -0,0 +1,14 @@
import {
request
} from "@/utils/request";
export default {
uploadImage(data) {
return request({
url: "/admin/system/uploadImage",
method: "POST",
data,
});
},
};

@ -0,0 +1,41 @@
import {
request
} from "@/utils/request";
export default {
list(data) {
return request({
url: "/admin/goods/goodsList",
method: "POST",
data,
});
},
goodsEditAttribute(data) {
return request({
url: "/admin/goods/goodsEditAttribute",
method: "POST",
data,
});
},
classify: {
list(data) {
return request({
url: "/admin/classify/list",
method: "POST",
data,
});
},
},
freightRules(data) {
return request({
url: "/admin/freightRules/list",
method: "POST",
data,
});
},
};

@ -0,0 +1,16 @@
import {
request
} from "@/utils/request";
export default {
dataCount: {
oneLine(data) {
return request({
url: "/admin/dataCount/oneLine",
method: "POST",
data,
});
},
}
};

@ -0,0 +1,56 @@
import {
request
} from "@/utils/request";
export default {
orderList(data) {
return request({
url: "/admin/order/orderList",
method: "POST",
data,
});
},
orderSend(data) {
return request({
url: "/admin/order/orderSend",
method: "POST",
data,
});
},
GetExpressList(data) {
return request({
url: "/admin/order/GetExpressList",
method: "POST",
data,
});
},
printOrder(data) {
return request({
url: "/admin/order/printOrder",
method: "POST",
data,
});
},
updateNotes(data) {
return request({
url: "/admin/order/updateNotes",
method: "POST",
data,
});
},
confirmCancel(data) {
return request({
url: "/admin/order/confirmCancel",
method: "POST",
data,
});
},
};

File diff suppressed because it is too large Load Diff

@ -0,0 +1,100 @@
<template>
<view class="myTable">
<wd-toast />
<kevyloading v-if="loading" type="bsm-loader" color="#618af8" transparent></kevyloading>
<scroll-view scroll-y="true" class="scroll-Y" @scrolltolower="lower">
<slot :list="list"></slot>
<view v-if="list.length == 0">
<wd-status-tip image="search" tip="当前查询无结果" />
</view>
</scroll-view>
</view>
</template>
<script setup>
import { ref } from 'vue'
import kevyloading from "@/components/kevy-loading/kevy-loading";
import { useToast } from '@/uni_modules/wot-design-uni'
const toast = useToast()
const props = defineProps({
apiObj: {
type: Function,
default: () => (() => { })
},
params: {
type: Object,
default: () => ({})
}
})
const query = ref({
page: 1,
pageSize: 20
})
const loading = ref(false)
const total = ref(0)
const list = ref([])
const getData = async () => {
console.log(getData);
loading.value = true
const res = await props.apiObj({
...query.value,
...props.params
})
if (res.data.rows.length) {
query.value.pageSize = res.data.pageSize
total.value = res.data.total
list.value = [...list.value, ...res.data.rows]
} else {
toast.success('全部加载完了')
}
loading.value = false
}
getData()
const upData = async (upParams = {}) => {
loading.value = true
query.value.page = 1
query.value.pageSize = 20
const res = await props.apiObj({
...query.value,
...props.params,
...upParams
})
console.log({
...query.value,
...props.params,
...upParams
});
query.value.pageSize = res.data.pageSize
total.value = res.data.total
list.value = res.data.rows
loading.value = false
}
const lower = e => {
query.value.page++
getData()
}
defineExpose({
upData
})
</script>
<style lang="scss">
.scroll-Y {
height: calc(100vh - 120px);
}
</style>

@ -1,26 +1,82 @@
<template>
<view class="myTable">
<wd-pagination v-model="value" :total="total" :page-size="page" @change="handleChange" show-icon show-message />
<kevyloading v-if="loading" type="bsm-loader" color="#618af8" transparent></kevyloading>
<wd-table :data="list" :border="true">
<slot></slot>
</wd-table>
<wd-pagination v-model="query.page" :total="total" :page-size="query.pageSize" @change="handleChange" show-icon
show-message />
</view>
</template>
<script setup>
import { ref } from 'vue'
import kevyloading from "@/components/kevy-loading/kevy-loading";
const props = defineProps({
apiObj: {
type: Function,
default: () => (() => { })
},
params: {
type: Object,
default: () => ({})
}
})
const value = ref("")
const query = ref({
page: 1,
pageSize: 20
})
const loading = ref(false)
const total = ref(0)
const page = ref(1)
const list = ref([])
const getData = async () => {
loading.value = true
const res = await props.apiObj({
...query.value,
...props.params
})
query.value.pageSize = res.data.pageSize
total.value = res.data.total
list.value = res.data.rows
loading.value = false
}
getData()
function handleChange(e) {
console.log(e);
const upData = async (upParams = {}) => {
loading.value = true
query.value.page = 1
query.value.pageSize = 20
const res = await props.apiObj({
...query.value,
...props.params,
...upParams
})
query.value.pageSize = res.data.pageSize
total.value = res.data.total
list.value = res.data.rows
loading.value = false
}
function handleChange({ value }) {
query.value.page = value
getData()
}
defineExpose({
upData
})
</script>
<style lang="scss"></style>

@ -41,6 +41,18 @@
}
}
},
{
"path": "goods/edit",
"style": {
"navigationBarTitleText": "修改商品",
"enablePullDownRefresh": false,
"mp-alipay": {
"transparentTitle": "always",
"titlePenetrate": "YES",
"gestureBack": "YES"
}
}
},
{
"path": "order/index",
"style": {
@ -60,6 +72,7 @@
"navigationBarTextStyle": "black",
"navigationBarTitleText": "uni-app",
"navigationBarBackgroundColor": "#F8F8F8",
"navigationStyle": "custom",
"backgroundColor": "#F8F8F8"
},
"uniIdRouter": {}

@ -10,10 +10,18 @@
<script setup>
import utils from '@/utils/utils.js'
const user_info = uni.getStorageSync("user_info");
if (user_info.type == 1) {
utils.toUrl("/store/index/index")
const token = uni.getStorageSync("token");
if (token) {
const user_info = uni.getStorageSync("user_info");
if (user_info.type == 1) {
utils.toUrl("/store/index/index")
}
} else {
utils.toUrl("/pages/login/index")
}
</script>
<style>

@ -1,5 +1,5 @@
<template>
<view class="content min-h-dvh flex items-center justify-center">
<view class="content min-h-dvh flex items-center justify-center px-4">
<wd-form class="mb-36" ref="form" :model="model">
<wd-cell-group border>
<wd-input label="用户名" label-width="100px" prop="username" clearable v-model="model.username" placeholder="请输入用户名"
@ -8,7 +8,7 @@
placeholder="请输入密码" :rules="[{ required: true, message: '请填写密码' }]" />
</wd-cell-group>
<view class="footer mt-4">
<wd-button type="primary" size="medium" @click="handleSubmit" block>登录</wd-button>
<wd-button :loading="loading" type="primary" size="medium" @click="handleSubmit" block>登录</wd-button>
</view>
</wd-form>
</view>
@ -25,9 +25,10 @@ const model = ref({
password: "",
})
const loading = ref(false)
const form = ref(null)
function handleSubmit() {
loading.value = true
form.value
.validate()
.then(({ valid, errors }) => {
@ -46,18 +47,22 @@ function handleSubmit() {
title: "登录成功",
});
if (res.data.type == 1) {
console.log(res.data.user_info);
if (res.data.user_info.type == 1) {
utils.toUrl("/store/index/index")
}
}
loading.value = false
})
}
})
.catch((error) => {
console.log(error, 'error')
loading.value = false
})
}
</script>

@ -0,0 +1,328 @@
<template>
<view class="skuEdit">
<wd-table :data="skuLibrary" :stripe="false">
<wd-table-col prop="name" label="SKU">
<template #value="scope">
<view class="custom-class">
<span style="margin-right: 4px" v-for="(item, index) of scope.row
.attr_list" :key="index">
{{ item.name }}
</span>
</view>
</template>
</wd-table-col>
<wd-table-col prop="school" label="售价">
<template #value="scope">
<view class="px-2 pb-1 bg-white">
<wd-input placeholder="售价" v-model="scope.row.price" type="number" />
</view>
</template>
</wd-table-col>
<wd-table-col prop="major" label="原价">
<template #value="scope">
<view class="px-2 pb-1 bg-white">
<wd-input placeholder="原价" v-model="scope.row.original_price" type="number">
</wd-input>
</view>
</template>
</wd-table-col>
<wd-table-col prop="major" label="库存">
<template #value="scope">
<view class="px-2 pb-1 bg-white">
<wd-input placeholder="库存" v-model="scope.row.stock" type="number">
</wd-input>
</view>
</template>
</wd-table-col>
<wd-table-col prop="major" label="产品号">
<template #value="scope">
<view class="px-2 pb-1 bg-white">
<wd-input placeholder="产品号" v-model="scope.row.no">
</wd-input>
</view>
</template>
</wd-table-col>
</wd-table>
<view class="bg-gray-100 rounded mb-2">
<div class="p-2 bg-white w-full">
<div class="name mb-2 text-xs">规格设置</div>
<view class="flex bg-white px-3 py-1 rounded w-full">
<div class="flex-1 mr-4">
<wd-input type="text" v-model="addGroupData.name" />
</div>
<wd-button @click="addSkuGroup"></wd-button>
</view>
</div>
<div class="p-2 bg-white">
<div style="display: flex; flex-flow: column; align-items: flex-start;">
<div class="name mb-2 text-xs">规格组</div>
<div class="w-full bg-gray-100 p-2" v-for="(item, index) in skuGroup" :key="index">
<div class="flex items-center justify-between w-full bg-white p-2">
<div class="mr-3">
<wd-tag type="primary" custom-class="space" closable @close="moveGroup(index)">{{
item.name }}</wd-tag>
</div>
<div class="mr-3">
<wd-input type="text" v-model="addGouppItemData[index]" />
</div>
<wd-button type="warning" @click="addGroupItem(index)"></wd-button>
</div>
<div type="flex" style="margin: 12px 0;">
<div class="name mb-2 text-xs">规格:</div>
<view class="flex gap-2 flex-wrap">
<wd-tag custom-class="space1" closable round type="warning" class="mx-1"
v-for="(value, key) in item.groupItem" :key="key" style="margin-left: 10px"
@close="removeGroupItem(index, key)">{{ value.name
}}</wd-tag>
</view>
</div>
</div>
</div>
</div>
</view>
<wd-toast />
</view>
</template>
<script>
import { useToast } from '@/uni_modules/wot-design-uni'
const toast = useToast()
export default {
name: "skuEdit",
data() {
return {
// sku
skuDefault: [
{
attr_list: [{ group_name: "默认", name: "默认" }],
price: "", //
original_price: "", //
stock: "", //
pic_url: "", //
no: "", //
},
],
skuGroup: [],
addGroupData: {
name: "",
groupItem: [],
}, //
addGouppItemData: [],
skuLibrary: [], //
//
all_price: "",
all_original_price: "",
all_stock: "",
all_no: "",
// sku
}
},
methods: {
/**
* 处理规格数据
*/
setGoodsAttrItem(attrGroup, attrList, index) {
var attrList1 = [];
if (index < attrGroup.length) {
if (index === 0 || attrList.length === 0) {
if (attrGroup[index].groupItem.length > 0) {
attrGroup[index].groupItem.forEach((element) => {
element.group_name = attrGroup[index].name;
attrList1.push([element]);
});
}
} else {
if (attrGroup[index].groupItem.length > 0) {
attrList.forEach((element) => {
attrGroup[index].groupItem.forEach((element1) => {
element1.group_name = attrGroup[index].name;
attrList1.push(element.concat([element1]));
});
});
} else {
attrList1 = attrList;
}
}
++index;
return this.setGoodsAttrItem(attrGroup, attrList1, index);
} else {
return attrList;
}
},
/**
* 获取其他详细数据
*/
getAttrDataInfo(attr) {
var attrList = [];
attr.forEach((element) => {
var setAttr = {};
if (this.skuLibrary) {
this.skuLibrary.forEach((element2) => {
if (element2.attr_list.length === element.length) {
var loading = true;
if (
loading &&
this.compareAttr(element2.attr_list, element)
) {
setAttr = element2;
loading = false;
}
}
});
}
var data = {
id: setAttr && setAttr.id ? setAttr.id : 0,
attr_list: element,
price: setAttr && setAttr.price ? setAttr.price : element.reduce((price, i) => price + i.price, 0).toFixed(2),
original_price:
setAttr && setAttr.original_price
? setAttr.original_price
: element.reduce((price, i) => price + i.price, 0).toFixed(2),
stock: setAttr && setAttr.stock ? setAttr.stock : 0,
pic_url: setAttr && setAttr.pic_url ? setAttr.pic_url : "",
no: setAttr && setAttr.no ? setAttr.no : "",
};
for (const key in setAttr) {
if (key.indexOf("member") !== -1) {
data[key] = setAttr[key];
}
}
attrList.push(data);
});
return attrList;
},
compareAttr(val1, val2) {
var compareLen = 0;
val1.forEach((element1) => {
val2.forEach((element2) => {
if (element1.name === element2.name) {
compareLen++;
}
});
});
return compareLen === val1.length;
},
//
addSkuGroup() {
//
console.log("添加了一个规格组");
this.skuGroup.push(this.addGroupData);
console.log("skuGroup发生了变换");
//
this.addGroupData = {
name: "",
groupItem: [],
};
},
//
moveGroup(index) {
if (this.skuGroup[index].groupItem.length === 0) {
console.log("删除的组合没有规格!!!");
this.skuGroup.splice(index, 1);
return
}
this.skuGroup.splice(index, 1);
var attrList = this.setGoodsAttrItem(this.skuGroup, [], 0);
this.skuLibrary = this.getAttrDataInfo(attrList);
this.calculateCombinationPrice(this.skuLibrary);
},
//
calculateCombinationPrice(skuLibrary) {
console.log(skuLibrary);
skuLibrary.forEach((sku) => {
// SKU
let combinationPrice = 0;
// SKU
sku.attr_list.forEach((attr) => {
//
combinationPrice += attr.price;
});
// SKU
sku.price = combinationPrice.toFixed(2);
sku.original_price = combinationPrice.toFixed(2);
});
this.skuLibrary = skuLibrary
},
//
addGroupItem(index) {
const _skuGroup = this.skuGroup
if (this.skuGroup[index].groupItem.length === 0) {
console.log("新的组合出现了!!!");
//
setTimeout(() => {
// console.log(this.skuGroup);
this.calculateCombinationPrice(this.skuLibrary);
});
} else {
console.log(_skuGroup);
}
if (!this.addGouppItemData[index]) {
toast.error('请填写规格名称!')
return
}
this.skuGroup[index].groupItem.push({
group_name: this.skuGroup[index].name,
name: this.addGouppItemData[index],
price: 0
});
console.log(this.skuGroup);
// todo
var attrList = this.setGoodsAttrItem(this.skuGroup, [], 0);
console.log(attrList);
this.skuLibrary = this.getAttrDataInfo(attrList);
this.addGouppItemData = [];
// //
// this.calculateCombinationPrice(this.skuLibrary);
},
//
removeGroupItem(index, key) {
this.skuGroup[index].groupItem.splice(key, 1);
var attrList = this.setGoodsAttrItem(this.skuGroup, [], 0);
this.skuLibrary = this.getAttrDataInfo(attrList);
},
}
}
</script>
<style lang="scss" scoped>
:deep(.space) {
padding: 6px 10px;
}
:deep(.space1) {
padding: 6px 10px;
background: #f0883a !important;
color: white !important;
.wd-tag__close {
color: white;
}
}
</style>

@ -0,0 +1,167 @@
<template>
<view class="content p-2 bg-gray-100">
<wd-form ref="form" :model="model">
<wd-cell-group border>
<div class="bg-gray-100">
<div class="bg-gray-100 rounded mb-2">
<div class="bg-white flex flex-col pt-3 pl-3">
<div class="name mb-2 text-xs">缩略图</div>
<wd-upload :limit="1" :file-list="fileList" :action="action" :formData="formData" :header="header"
@success="successImage" name="image" :before-remove="beforeRemove"></wd-upload>
</div>
</div>
</div>
<!-- <div class="bg-gray-100">
<div class="bg-gray-100 rounded mb-2">
<div class="bg-white flex flex-col pt-3 pl-3">
<div class="name mb-2 text-xs">商品主图</div>
<wd-upload :file-list="fileList" :action="action" :formData="formData" :header="header"
@change="handleChange" name="image"></wd-upload>
</div>
</div>
</div> -->
<view class="h-2 bg-gray-100"></view>
<view class=" p-3 rounded mb-2">
<div class="name mb-2 text-xs">商品名称</div>
<view class="bg-white px-3 py-1 rounded">
<wd-textarea v-model="model.value" auto-height />
</view>
</view>
<view class="h-2 bg-gray-100"></view>
<view class="bg-gray-100 rounded mb-2">
<div class="p-2 bg-white">
<div class="name mb-2 text-xs">服务内容</div>
<view class="bg-white px-3 py-1 rounded">
<wd-input type="text" v-model="value" placeholder="例子: 正品保障,极速发货,7天退换货。多个请使用英文逗号“,”分隔"
@change="handleChange" />
</view>
</div>
</view>
<view class="h-2 bg-gray-100"></view>
<view class=" p-3 rounded mb-2">
<div class="name mb-2 text-xs">商品重量</div>
<view class="bg-white px-3 py-2 rounded flex items-center mb-4">
<wd-input-number v-model="value" @change="handleChange" />
<view class="text-xs from-neutral-300 ml-4">千克</view>
</view>
<wd-picker class="w-full" :columns="freightRules" label="运费模板" v-model="model.freight_id" />
</view>
<view class="h-2 bg-gray-100"></view>
<view class="p-3 rounded mb-2">
<div class="name mb-2 text-xs">商品状态</div>
<view class="bg-white px-3 py-2 rounded flex items-center mb-4">
<wd-switch v-model="model.status" />
</view>
</view>
<view class="h-2 bg-gray-100"></view>
<skuEdit></skuEdit>
</wd-cell-group>
<view class="footer mt-4">
<wd-button type="primary" size="large" block>保存</wd-button>
</view>
</wd-form>
</view>
</template>
<script setup>
import { ref } from 'vue'
import system from '@/api/modules/system.js'
import goods from '@/api/store/goods.js'
import { useToast, useMessage } from '@/uni_modules/wot-design-uni'
import skuEdit from "./components/skuEdit.vue"
const fileList = ref([])
const beforeRemove = ({ file, resolve, index }) => {
fileList.value.splice(index, 1)
resolve(true)
}
const action = 'https://saasdemo.byin.vip/admin/system/uploadImage'
const token = uni.getStorageSync("token");
const header = {
Authorization: `Bearer ${token}`
}
const formData = {
parent_id: 0,
type: "image",
}
function successImage(e) {
fileList.value.push({
url: e.file.url
})
}
const model = ref({
classify_list: [], //
name: "", //
keywords: "", //
sort: 1000,
status: 0, //
freight_id: 0, //
weight: 0, //
pic_url: "", //
pic_list: [], //
video: "", //
detail: "", //
use_sku: 0, // 使
sku_list: [], //
is_discount: 0, //
discount: 50, //
dist_price: 0, //
limit: 0, //
is_check: 0, //
check_type: 0, //
check_price: 0, //
})
const form = ref()
function handleSubmit1() {
form.value
.validate()
.then(({ valid, errors }) => {
if (valid) {
showSuccess({
msg: '校验通过'
})
}
})
.catch((error) => {
console.log(error, 'error')
})
}
const freightRules = ref([])
const GetfreightRules = () => {
goods.freightRules().then(res => {
freightRules.value = res.data.rows.map(item => {
return {
label: item.name,
value: item.id
}
})
})
}
GetfreightRules()
</script>
<style lang="scss"></style>

@ -1,11 +1,203 @@
<template>
<view class="content p-4">
<view class="content">
<view class=" bg-white sticky top-0 z-50">
<wd-search @search="search" @clear="search({ value: '' })" v-model="params.keywords" hide-cancel>
<template #prefix>
<wd-popover v-model="popover" mode="menu" :content="menu" @menuclick="changeSearchType">
<view class="search-type">
<text>{{ searchType }}</text>
<wd-icon custom-class="icon-arrow" name="fill-arrow-down"></wd-icon>
</view>
</wd-popover>
</template>
</wd-search>
<wd-drop-menu custom-class="flex w-full bg-white" v-show="classifyList.length">
<wd-drop-menu-item @change="search({ value: params.keywords })" custom-class="flex-1" v-model="classify_id"
:options="classifyList" label-key="name" value-key="id" />
</wd-drop-menu>
</view>
<div class="goodsBox p-2">
<myList ref="myListRef" :apiObj="goods.list" :params="{ ...params, classify_id }">
<template #default="{ list }">
<div>
<div v-for="item of list" class="goods">
<wd-card type="rectangle">
<template #title>
<view class="title">
<view>库存<span class="font-bold">{{ item.stock_num }}</span></view>
<view v-if="!(item.stock_num > 0)" class="title-tip">
<wd-icon name="warning" size="14px" custom-style="vertical-align: bottom" />
商品库存不足
</view>
</view>
</template>
<view style="height: 60px;" class="content">
<image :src="item.pic_url" width="40" height="40" alt="joy"
style="border-radius: 4px; margin-right: 12px;width: 60px;height: 60px;min-width: 60px;" />
<view>
<view class="line2" style="color: rgba(0,0,0,0.85); font-size: 16px;">{{ item.name }}</view>
<view class="font-bold" style="color: rgb(255, 0, 0); font-size: 16px;">{{ item.price_min }}</view>
</view>
</view>
<template #footer>
<view>
<wd-button @click="changeS(item)" v-if="item.status == 1" size="small" plain
style="margin-right: 8px;">下架</wd-button>
<wd-button @click="changeS(item)" v-if="item.status !== 1" size="small"
style="margin-right: 8px;">上架</wd-button>
<wd-button @click="utils.toUrl('/store/goods/edit')" size="small">编辑</wd-button>
</view>
</template>
</wd-card>
</div>
</div>
</template>
</myList>
</div>
<wd-toast />
</view>
</template>
<script setup>
import { ref } from 'vue'
import { useToast } from '@/uni_modules/wot-design-uni'
import goods from '@/api/store/goods.js'
import myList from "/components/myList/index.vue"
import utils from '@/utils/utils.js'
const toast = useToast()
const classify_id = ref(0)
const params = ref({
keywords: "",
status: "",
})
const myListRef = ref(null)
const search = ({ value }) => {
myListRef.value.upData({
keywords: value,
classify_id: classify_id.value,
status: params.value.status
})
}
const searchType = ref('全部')
const popover = ref(false)
const menu = ref([
{
content: '全部'
},
{
content: '已上架'
},
{
content: '已下架'
}
])
function changeSearchType({ item, index }) {
searchType.value = item.content
if (item.content == '全部') {
params.value.status = ""
}
if (item.content == '已上架') {
params.value.status = 1
}
if (item.content == '已下架') {
params.value.status = 0
}
console.log(params.value.status);
search({
value: ""
})
}
const changeS = (row) => {
goods.goodsEditAttribute({
id: row.id,
value: [1, 0][row.status],
type: "status"
}).then(res => {
if (res.code == 0) {
toast.success('操作成功')
row.status = [1, 0][row.status]
} else {
showNotify({ type: 'error', message: '出错了' })
}
})
}
const classifyList = ref([])
const getClassify = () => {
goods.classify.list().then(res => {
classifyList.value = res.data
classifyList.value.unshift({
id: 0,
name: "店铺分类"
})
})
}
getClassify()
</script>
<style></style>
<style lang="scss" scoped>
.search-type {
position: relative;
height: 30px;
line-height: 30px;
padding: 0 8px 0 16px;
font-size: 24rpx;
color: rgba(0, 0, 0, .45);
}
.search-type::after {
position: absolute;
content: '';
width: 1px;
right: 0;
top: 5px;
bottom: 5px;
background: rgba(0, 0, 0, 0.25);
}
.search-type {
:deep(.icon-arrow) {
display: inline-block;
font-size: 20px;
vertical-align: middle;
}
}
.goodsBox {
.content,
.title {
display: flex;
flex-direction: row;
justify-content: flex-start;
align-items: center;
}
.content {
justify-content: flex-start;
}
.title {
justify-content: space-between;
}
.title-tip {
color: rgba(0, 0, 0, 0.25);
font-size: 12px;
}
}
</style>

@ -1,17 +1,48 @@
<template>
<view class="content p-4">
<view class="w-full grid grid-cols-2 gap-4">
<view @click="utils.toUrl('/store/order/index')"
class="text-white bg-gradient-to-r from-orange-200 to-orange-400 shadow rounded-md p-4">
<wd-icon name="circle1" size="24px"></wd-icon>
<view class="mt-2 text-end font-bold ">订单中心</view>
</view>
<view @click="utils.toUrl('/store/goods/index')"
class="text-white bg-gradient-to-r from-orange-200 to-orange-400 shadow rounded-md p-4">
<wd-icon name="goods" size="24px"></wd-icon>
<view class="mt-2 text-end font-bold">商品管理</view>
</view>
<!-- <view class="bg-dark shadow-md rounded-md p-4">
<view class="content pt-[44px]">
<view class="w-full">
<wd-navbar fixed safeAreaInsetTop :leftText="user_info?.info?.name || '商城首页'">
<template #right>
<wd-icon name="setting" size="22px"></wd-icon>
</template>
</wd-navbar>
</view>
<view class="order mb-2">
<wd-grid bg-color="#f7f8fa" v-show="oneLine.ok">
<wd-grid-item icon="round" :text="`用户 (${oneLine.user_count})`" />
<wd-grid-item icon="round" :text="`商品 (${oneLine.goods_count})`" />
<wd-grid-item icon="round" :text="`售罄 (${oneLine.empty_stock_count})`" />
<wd-grid-item icon="round" :text="`订单 (${oneLine.order_count})`" />
</wd-grid>
</view>
<view style="transition: 1s;" class="flex-1 w-full h-full bg-white pt-4 rounded-tr-3xl rounded-tl-3xl shadow-lg oh">
<view class="w-full grid grid-cols-2 gap-3 px-3">
<view @click="utils.toUrl('/store/goods/index')" class="text-white rounded-3xl p-4 pb-3 shadow-lg overflow-hidden"
style="background-image: linear-gradient(to top, #7ea0ff 0%, #a9bdf5 100%);">
<view class="font-bold">商品管理</view>
<view class="h-0.5 w-5 mt-0.5 bg-white"></view>
<view class="flex justify-end">
<div class="rotate-[-28deg] translate-y-5 translate-x-5">
<wd-icon name="goods opacity-80" size="46px"></wd-icon>
</div>
</view>
</view>
<view @click="utils.toUrl('/store/order/index')" class="text-white rounded-3xl p-4 pb-3 shadow-lg overflow-hidden"
style="background-image: linear-gradient(to top, #7ea0ff 0%, #a9bdf5 100%);">
<view class="font-bold">订单中心</view>
<view class="h-0.5 w-5 mt-0.5 bg-white"></view>
<view class="flex justify-end">
<div class="rotate-[-20deg] translate-y-5 translate-x-5">
<wd-icon name="gift opacity-80" size="46px"></wd-icon>
</div>
</view>
</view>
<!-- <view class="bg-dark shadow-md rounded-md p-4">
<wd-icon name="goods" size="22px"></wd-icon>
<view class="mt-2 text-end font-bold">订单中心</view>
</view>
@ -20,6 +51,7 @@
<wd-icon name="goods" size="22px"></wd-icon>
<view class="mt-2 text-end font-bold">订单中心</view>
</view> -->
</view>
</view>
@ -27,33 +59,20 @@
</template>
<script setup>
import { ref } from 'vue'
import utils from '@/utils/utils.js'
</script>
<style>
.content {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
import index from '@/api/store/index.js'
.logo {
height: 200rpx;
width: 200rpx;
margin-top: 200rpx;
margin-left: auto;
margin-right: auto;
margin-bottom: 50rpx;
}
const user_info = uni.getStorageSync("user_info");
.text-area {
display: flex;
justify-content: center;
const oneLine = ref({})
const getOneLine = () => {
index.dataCount.oneLine().then(res => {
oneLine.value = res.data
oneLine.value.ok = true
})
}
getOneLine()
</script>
.title {
font-size: 36rpx;
color: #8f8f94;
}
</style>
<style lang="scss" scoped></style>

@ -1,11 +1,494 @@
<template>
<view class="content p-4">
<view class="content">
<wd-message-box></wd-message-box>
<wd-message-box selector="wd-message-box-slot" use-slot>
<view>
<wd-form :model="shipmentsModel">
<wd-cell-group border>
<view class="mb-4">
<wd-radio-group v-model="shipmentsModel.send_type" shape="button" @change="change">
<wd-radio :value="1">快递发货</wd-radio>
<wd-radio :value="2">无需物流</wd-radio>
</wd-radio-group>
</view>
<view class="mb-4 overflow-hidden bg-white border-gray-100 border-solid border-[8px] p-3 rounded"
v-if="shipmentsModel.send_type == 1">
<view class="mb-2">
<wd-radio-group shape="button" v-model="shipmentsModel.delivery_company">
<view class="flex overflow-auto">
<wd-radio v-for="item of expressList" :value="item.value">{{ item.label }}</wd-radio>
</view>
</wd-radio-group>
</view>
<wd-input label-width="100px" clearable v-model="shipmentsModel.delivery_no" placeholder="快递单号">
</wd-input>
</view>
</wd-cell-group>
</wd-form>
</view>
</wd-message-box>
<view class=" bg-white sticky top-0 z-50">
<wd-search @search="search" @clear="search({ value: '' })" v-model="params.keywords" hide-cancel>
<template #prefix>
<wd-popover v-model="popover" mode="menu" :content="menu" @menuclick="changeSearchType">
<view class="search-type">
<text>{{ searchType }}</text>
<wd-icon custom-class="icon-arrow" name="fill-arrow-down"></wd-icon>
</view>
</wd-popover>
</template>
</wd-search>
<!-- <wd-drop-menu>
<wd-drop-menu-item v-model="shipmentsModel.delivery_company" :options="expressList" />
</wd-drop-menu> -->
<wd-tabs @change="(e) => {
params.status = e.index;
search({ value: params.keywords })
}" v-model="params.status">
<wd-tab v-for="item in status" :key="item" :title="`${item.content}`"></wd-tab>
</wd-tabs>
</view>
<view class="goodsBox p-2">
<myList ref="myListRef" :apiObj="order.orderList" :params="{ ...params, status: params.status - 1 }">
<template #default="{ list }">
<view>
<view v-for="item of list" class="goods">
<wd-card type="rectangle">
<template #title>
<view class="title">
<view>
<span class="mr-2" v-if="item.shop">{{ item.shop.name }}</span>
<span class="mr-2" v-else></span>
<span class="font-bold">({{ status[item.status + 1].content }})</span>
</view>
<view class="title-tip">
<span style="font-size: 24rpx;margin-left: 8px;">单号{{ item.order_no }}</span>
</view>
</view>
</template>
<view v-for="subItem of item.details" style="height: 60px;" class="content mb-4">
<image :src="subItem.goods_pic" width="40" height="40" alt="joy"
style="border-radius: 4px; margin-right: 12px;width: 60px;height: 60px;min-width: 60px;" />
<view>
<view class="line2" style="color: rgba(0,0,0,0.85); font-size: 16px;">{{ subItem.goods_name }}</view>
<!-- <view class="font-bold" style="color: rgb(255, 0, 0); font-size: 16px;">{{ subItem.price }}
</view> -->
<view class="font-bold">小计: {{ subItem.price }} <text
style="color: rgb(255, 0, 0); font-size: 24rpx;">({{
subItem.num }}) </text></view>
</view>
</view>
<view class="bg-gray-50 p-2">
<view class="text-[12px]" v-if="item.user">
<view class="mb-1">
下单用户{{ item.user.nickname }}
<text class="font-bold">
( 会员ID{{ item.user.id }} )
</text>
<view class="bg-gray-100 my-2 p-2">
<view>收货人{{ item.receiver_name }} &nbsp; 电话{{ item.receiver_phone }}</view>
<view>收货地址{{ item.delivery_address }} {{ item.delivery_address_detail }}</view>
</view>
</view>
<view class="flex items-center" v-if='[0, 1, 2][item.delivery_type]'>配送方式:
<wd-tag class="ml-2" :type="['', 'success', 'primary'][item.delivery_type]">
{{ ["", "快递配送", "到店自提"][item.delivery_type] }}
</wd-tag>
<view class="ml-2" v-if="item.delivery_type == 1">
<wd-tag type="warning">
运费: {{ item.delivery_money }}
</wd-tag>
</view>
</view>
</view>
</view>
<template #footer>
<view class="bg-gray-50 p-2 mb-2.5 flex justify-between" style="font-size: 22rpx;">
<view>应付: {{ (Number(item.total_price) + Number(item.delivery_money)).toFixed(2) }} </view>
<view>余额支付: {{ item.pay_balance }} </view>
<view v-if="((Number(item.total_price) + Number(item.delivery_money)) -
item.pay_price) > 0">优惠: {{ ((Number(item.total_price) + Number(item.delivery_money)) -
item.pay_price).toFixed(2) }} </view>
</view>
<view class="flex justify-between items-center">
<view class="font-bold">实付: {{ item.pay_price }} </view>
<view class="flex-1 flex justify-end">
<view v-if="item.apply_cancel === 1" class="mr-2">
<wd-button type="error" @click="orderApproval(item)" size="small">退款</wd-button>
</view>
<view class="mr-2">
<wd-button @click="printing(item)" size="small">小票打印</wd-button>
</view>
<view class="mr-2">
<wd-button @click="orderNotes(item)" size="small">备注</wd-button>
</view>
<view v-if="item.status == 1" class="">
<wd-button @click="shipments(item)" size="small">发货</wd-button>
</view>
</view>
</view>
</template>
</wd-card>
</view>
</view>
</template>
</myList>
</view>
<wd-toast />
</view>
</template>
<script setup>
import utils from '@/utils/utils.js'
import order from '@/api/store/order.js'
import myList from "/components/myList/index.vue"
import { useMessage } from '@/uni_modules/wot-design-uni'
import { useToast } from '@/uni_modules/wot-design-uni'
import { ref } from 'vue'
const message = useMessage('wd-message-box-slot')
const message1 = useMessage()
const toast = useToast()
const classify_id = ref(0)
const params = ref({
keywords: "",
status: "",
type: 'order_no'
})
const myListRef = ref(null)
const search = ({ value }) => {
myListRef.value.upData({
keywords: value,
classify_id: classify_id.value,
status: params.value.status - 1
})
}
const searchType = ref('订单编号')
const popover = ref(false)
const status = ref([
{
content: '全部'
},
{
content: '未付款'
},
{
content: '待发货'
},
{
content: '已发货'
},
{
content: '已完成'
},
{
content: '已取消'
},
{
content: '待处理'
},
{
content: '回收站'
}
])
const menu = ref([
{
content: '订单编号'
},
{
content: '商品名称'
},
{
content: '手机号'
},
{
content: '会员昵称'
},
{
content: '收货人'
},
])
function changeSearchType({ item, index }) {
searchType.value = item.content
console.log(searchType.value);
if (item.content == '订单编号') {
params.value.type = "order_no"
}
if (item.content == '商品名称') {
params.value.type = "goods_name"
}
if (item.content == '手机号') {
params.value.type = "receiver_phone"
}
if (item.content == '会员昵称') {
params.value.type = "nickname"
}
if (item.content == '收货人') {
params.value.type = "receiver_name"
}
}
const changeS = (row) => {
// goods.goodsEditAttribute({
// id: item.id,
// value: [1, 0][item.status],
// type: "status"
// }).then(res => {
// if (res.code == 0) {
// toast.success('')
// item.status = [1, 0][item.status]
// } else {
// showNotify({ type: 'error', message: '' })
// }
// })
}
const expressList = ref([])
const GetExpressList = () => {
order.GetExpressList().then(res => {
expressList.value = Object.entries(res.data).reduce((express, item) => {
express.push({ label: item[1], value: item[0] })
return express
}, [])
})
}
GetExpressList()
const shipmentsModel = ref({
send_type: 2,
delivery_company: ""
})
const shipments = (row) => {
message
.confirm({
title: '订单发货',
})
.then((resp) => {
if (shipmentsModel.value.send_type == 2) {
order.orderSend({
id: row.id,
send_type: "2"
})
row.status = 2
toast.success('操作成功')
setTimeout(() => {
shipmentsModel.value = {
send_type: 2,
delivery_company: ""
}
}, 300);
}
if (shipmentsModel.value.send_type == 1) {
if (shipmentsModel.value.delivery_company && shipmentsModel.value.delivery_no) {
order.orderSend({
id: row.id,
send_type: "1",
delivery_company: shipmentsModel.value.delivery_company,
delivery_no: shipmentsModel.value.delivery_no,
})
row.status = 2
row.success('操作成功')
setTimeout(() => {
shipmentsModel.value = {
send_type: 2,
delivery_company: ""
}
}, 300);
} else {
toast.error('发货失败,请完善选择填写')
shipments(row)
}
}
})
.catch((error) => {
console.log(error)
setTimeout(() => {
shipmentsModel.value = {
send_type: 2,
delivery_company: ""
}
}, 300);
})
}
const printing = (row) => {
message1
.confirm({
title: '打印小票',
})
.then((resp) => {
order.printOrder({
id: row.id,
send_type: "2"
}).then(res => {
if (res.code == 0) {
toast.success('调用成功')
} else {
toast.error('调用失败')
}
})
})
.catch((error) => {
console.log(error)
})
}
const orderNotes = (row) => {
message1
.prompt({
title: '订单备注',
})
.then((resp) => {
order.updateNotes({
id: row.id,
notes: resp.value
}).then(res => {
if (res.code == 0) {
toast.success('操作成功')
} else {
toast.error('操作失败')
}
})
})
.catch((error) => {
console.log(error)
})
}
const orderApproval = (row) => {
message1
.confirm({
title: '退款审批',
confirmButtonText: "同意",
cancelButtonText: "拒绝",
})
.then((resp) => {
order.confirmCancel({
id: row.id,
apply_cancel_notes: "同意",
handle_status: 1
}).then(res => {
if (res.code == 0) {
toast.success('操作成功')
row.apply_cancel = 0
} else {
toast.error('操作失败')
}
})
})
.catch((error) => {
if (error.action == 'cancel') {
order.confirmCancel({
id: row.id,
apply_cancel_notes: "拒绝",
handle_status: 0
}).then(res => {
if (res.code == 0) {
toast.success('操作成功')
row.apply_cancel = 0
} else {
toast.error('操作失败')
}
})
}
})
}
</script>
<style></style>
<style lang="scss" scoped>
.search-type {
position: relative;
height: 30px;
line-height: 30px;
padding: 0 8px 0 16px;
font-size: 24rpx;
color: rgba(0, 0, 0, .45);
}
.search-type::after {
position: absolute;
content: '';
width: 1px;
right: 0;
top: 5px;
bottom: 5px;
background: rgba(0, 0, 0, 0.25);
}
.search-type {
:deep(.icon-arrow) {
display: inline-block;
font-size: 20px;
vertical-align: middle;
}
}
.goodsBox {
.content,
.title {
display: flex;
flex-direction: row;
justify-content: flex-start;
align-items: center;
}
.content {
justify-content: flex-start;
}
.title {
justify-content: space-between;
}
.title-tip {
color: rgba(0, 0, 0, 0.25);
font-size: 12px;
}
}
</style>

@ -17,7 +17,6 @@ const env = {
*/
export function request(options) {
options.header = {
Authorization: `Bearer ${uni.getStorageSync("token")}`,
}

Loading…
Cancel
Save