| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687 |
- <template>
- <view class="container">
- <!-- 搜索栏 -->
- <view class="search-bar">
- <view class="search-bar-con">
- <view class="search-input-wrapper">
- <uni-icons class="search-icon" type="search" size="18" color="#999"></uni-icons>
- <input
- class="search-input"
- v-model="searchVal"
- placeholder="请输入搜索内容"
- placeholder-class="placeholder"
- @input="onSearch"
- @confirm="onSearch"
- :focus="isFocus"
- />
- <view v-if="searchVal" class="clear-btn" @click="onClear">
- <uni-icons type="clear" size="18" color="#999"></uni-icons>
- </view>
- </view>
- </view>
- <!-- 分类标签 -->
- <up-tabs :list="tabList"
- @click="tabChange"
- lineColor="#F8C008"
- lineWidth="24"
- lineHeight="2"
- :itemStyle="{
- flex:1,
- height:'44px',
- marginTop:'8px'
- }"
- :activeStyle="{
- color: '#F8C008',
- fontWeight: 'bold',
- transform: 'scale(1.05)'
- }"
- :inactiveStyle="{
- color: '#333333',
- transform: 'scale(1)'
- }"></up-tabs>
- <!-- 管理按钮 -->
- <view v-if="goodsList.length" class='nav acea-row row-between-wrapper'>
- <view>共 <text class='num font-color'>{{ goodsList.length }}</text>件商品</view>
- <view class='administrate acea-row row-center-wrapper' @click='manage'>
- {{ footerswitch ? '管理' : '取消' }}
- </view>
- </view>
- </view>
- <!-- 商品列表 -->
- <view class="product-list">
- <up-checkbox-group shape="circle" @change="checkboxChange" class="centent" activeColor="#F8C008">
- <view class="product-card" v-for="(item, index) in goodsList" :key="index">
- <view class="product-header">
- <!-- 多选框 -->
- <up-checkbox
- :name="item.id.toString()"
- :checked="item.checked"
- v-if="!footerswitch"
- style="margin-right: 10rpx;"
- activeColor="#F8C008"
- />
- <image class="product-image" :src="item.image" mode="aspectFit" />
- <view class="product-info">
- <view class="nameweight">
- <text class="product-name">{{ item.storeName }}</text>
- <text class="product-weight">{{ item.weight }}g</text>
- </view>
- <view class="nameweight">
- <view class="price-info">
- <text class="label">工费</text>
- <view class="value"><text class="unit">¥</text>{{ item.totalLaborCost }}<text class="unit">/g</text></view>
- </view>
- <view class="price-info">
- <text class="label">附加费</text>
- <view class="value"><text class="unit">¥</text>{{ item.additionalAmount }}</view>
- </view>
- </view>
- <view class="product-stats">
- <text class="stat">销量:{{ Number(item.sales || 0) + Number(item.ficti || 0) }}</text>
- <text class="stat">库存:{{ item.stock }}</text>
- </view>
- </view>
- </view>
- <view class="action-buttons">
- <button class="btn btn-delete" @click="deleteFn(item,index)">删除</button>
- <button class="btn btn-offline" v-show="params.isShow==1" @click="OffShellFn(item,index)">下架</button>
- <button class="btn btn-offline" v-show="params.isShow==0" @click="PutOnShellFn(item,index)">上架</button>
- <button class="btn btn-edit" v-show="params.isShow==0" @click="toEditProduct(item)">编辑</button>
- </view>
- </view>
- </up-checkbox-group>
- <view class="loadingicon acea-row row-center-wrapper" v-if="goodScroll">
- <text
- class="loading iconfont icon-jiazai"
- :hidden="loading == false"
- ></text>
- </view>
- <view class="no-data" v-if="isNoDataState">
- <image
- src="https://my-go-easy-im.oss-cn-shenzhen.aliyuncs.com/goeasy-im-%E6%B0%B4%E8%B4%9D%E5%95%86%E5%9F%8E/zhanwu_20250827104005_1720_6.png"
- />
- </view>
- <view class="mores-txt flex" v-if="!goodScroll && !isNoDataState">
- <text>我是有底线的</text>
- </view>
- </view>
- <!-- 底部操作栏 -->
- <view v-if="!footerswitch" class='footer acea-row row-between-wrapper'>
- <view>
- <up-checkbox-group shape="circle" @change="checkboxAllChange">
- <up-checkbox value="all" :checked="!!isAllSelect" activeColor="#F8C008" />
- <text class='checkAll'>全选</text>
- </up-checkbox-group>
- </view>
- <view class='button acea-row row-middle'>
- <button v-if="params.isShow==1" class='bnt' @click="batchOffShell">批量下架</button>
- <button v-if="params.isShow==0" class='bnt' @click="batchPutOnShell">批量上架</button>
- <!-- <button class='bnt cart-color delete-btn' @click="batchDelete">批量删除</button>-->
- </view>
- </view>
- </view>
- </template>
- <script setup>
- import {computed, ref,watch} from 'vue'
- import { onLoad, onShow, onReachBottom } from "@dcloudio/uni-app";
- import { productsList, productPutOnShell, productOffShell, productDelete, batchStatus } from "@/api/merchant.js";
- import { useAppStore } from "@/stores/app";
- const appStore = useAppStore();
- // 管理相关状态
- const footerswitch = ref(true); // true: 显示正常模式, false: 显示管理模式
- const isAllSelect = ref(false); // 是否全选
- const selectValue = ref([]); // 选中的商品ID数组
- const tabList = ref([
- {name:'销售中',code:1},
- {name:'已下架',code:0}
- ])
- const searchVal = ref('')
- const goodsList = ref([]);
- const goodType = ref(1);
- // Pagination
- const params = ref({
- page: 1,
- limit: 10,
- isShow:1,
- });
- const loading = ref(false);
- const goodScroll = ref(true);
- const merchantInfo = ref({})
- const isFocus = ref(false)
- const isNoDataState = computed(() => {
- return goodsList.value.length === 0 && !loading.value;
- });
- onShow(() => {
- merchantInfo.value = appStore.userInfo.merchant;
- getGroomList()
- })
- // 切换管理状态
- const manage = () => {
- footerswitch.value = !footerswitch.value;
- // 退出管理状态时,清空选择
- if (footerswitch.value) {
- resetSelection();
- }
- }
- // 重置选择状态
- const resetSelection = () => {
- goodsList.value.forEach(item => {
- item.checked = false;
- });
- isAllSelect.value = false;
- selectValue.value = [];
- }
- // 多选框变化
- const checkboxChange = (values) => {
- goodsList.value.forEach(item => {
- item.checked = values.includes(item.id.toString());
- });
- selectValue.value = values;
- isAllSelect.value = goodsList.value.length === values.length;
- };
- // 全选变化
- const checkboxAllChange = (event) => {
- if (event.length > 0) {
- setAllSelectValue(1);
- } else {
- setAllSelectValue(0);
- }
- };
- // 设置全选状态
- const setAllSelectValue = (status) => {
- const selectValues = [];
- goodsList.value.forEach(item => {
- if (status) {
- item.checked = true;
- selectValues.push(item.id);
- isAllSelect.value = true;
- } else {
- item.checked = false;
- isAllSelect.value = false;
- }
- });
- selectValue.value = selectValues;
- console.log(selectValue.value)
- };
- // 检查是否有选中商品
- const checkHasSelected = () => {
- if (!selectValue.value || selectValue.value.length === 0) {
- uni.showToast({ title: '请先选择商品', icon: 'none' });
- return false;
- }
- return true;
- }
- // 批量下架
- const batchOffShell = async () => {
- if (!checkHasSelected()) return;
- uni.showModal({
- title: '提示',
- content: `确定要下架选中的${selectValue.value.length}件商品吗?`,
- success: async (res) => {
- if (res.confirm) {
- try {
- const { code, message } = await batchStatus({ ids: selectValue.value, status:0 });
- if (code === 200) {
- uni.showToast({ title: '批量下架成功', icon: 'success' });
- // 从列表中移除下架的商品
- goodsList.value = goodsList.value.filter(item => !selectValue.value.includes(item.id.toString()));
- resetSelection();
- footerswitch.value = true; // 退出管理模式
- } else {
- uni.showToast({ title: message || '操作失败', icon: 'none' });
- }
- } catch (err) {
- uni.showToast({ title: err.message || '操作失败', icon: 'none' });
- }
- }
- }
- });
- }
- // 批量上架
- const batchPutOnShell = async () => {
- if (!checkHasSelected()) return;
- uni.showModal({
- title: '提示',
- content: `确定要上架选中的${selectValue.value.length}件商品吗?`,
- success: async (res) => {
- if (res.confirm) {
- try {
- const { code, message } = await batchStatus({ ids: selectValue.value,status:1 });
- if (code === 200) {
- uni.showToast({ title: '批量上架成功', icon: 'success' });
- // 从列表中移除上架的商品
- goodsList.value = goodsList.value.filter(item => !selectValue.value.includes(item.id.toString()));
- resetSelection();
- footerswitch.value = true; // 退出管理模式
- } else {
- uni.showToast({ title: message || '操作失败', icon: 'none' });
- }
- } catch (err) {
- uni.showToast({ title: err.message || '操作失败', icon: 'none' });
- }
- }
- }
- });
- }
- // 批量删除
- const batchDelete = async () => {
- if (!checkHasSelected()) return;
- uni.showModal({
- title: '警告',
- content: `确定要删除选中的${selectValue.value.length}件商品吗?此操作不可恢复!`,
- success: async (res) => {
- if (res.confirm) {
- try {
- const { code, message } = await batchDeleteApi({ ids: selectValue.value.join(',') });
- if (code === 200) {
- uni.showToast({ title: '批量删除成功', icon: 'success' });
- // 从列表中移除删除的商品
- goodsList.value = goodsList.value.filter(item => !selectValue.value.includes(item.id.toString()));
- resetSelection();
- footerswitch.value = true; // 退出管理模式
- } else {
- uni.showToast({ title: message || '操作失败', icon: 'none' });
- }
- } catch (err) {
- uni.showToast({ title: err.message || '操作失败', icon: 'none' });
- }
- }
- }
- });
- }
- const tabChange = (item) => {
- console.log('item',item)
- goodsList.value = [];
- loading.value = false;
- goodScroll.value = true;
- params.value.isShow = item.code;
- params.value.page = 1;
- getGroomList();
- // 切换标签时退出管理模式
- footerswitch.value = true;
- resetSelection();
- }
- const onSearch = () => {
- goodsList.value = [];
- loading.value = false;
- goodScroll.value = true;
- params.value.page = 1;
- getGroomList();
- // 搜索时退出管理模式
- footerswitch.value = true;
- resetSelection();
- }
- // 清除搜索内容
- const onClear = () => {
- console.log('清除搜索内容');
- searchVal.value = '';
- onSearch();
- }
- const getGroomList = async () => {
- if (!goodScroll.value) return;
- try {
- loading.value = true;
- params.value.merchantId = merchantInfo.value.id;
- params.value.keyword = searchVal.value;
- const { data } = await productsList(params.value);
- // 初始化选择状态
- const newList = data.list || [];
- newList.forEach(item => {
- item.checked = false;
- });
- goodsList.value = [...goodsList.value, ...newList];
- goodScroll.value = data.list.length >= params.value.limit;
- params.value.page++;
- } catch (err) {
- console.error(err);
- } finally {
- loading.value = false;
- }
- };
- async function OffShellFn(obj,index) {
- const {code} = await productOffShell(obj.id);
- if(code == 200){
- uni.showToast({ title: "操作成功", icon: "none" });
- goodsList.value.splice(index,1);
- }
- }
- async function PutOnShellFn(obj,index) {
- const {code} = await productPutOnShell(obj.id);
- if(code == 200){
- uni.showToast({ title: "操作成功", icon: "none" });
- goodsList.value.splice(index,1);
- }
- }
- function toEditProduct (obj){
- uni.navigateTo({
- url:`/pages/merchantCenters/releaseProduct?id=${obj.id}`
- })
- }
- async function deleteFn(obj,index){
- uni.showModal({
- title: '警告',
- content: '确定要删除此商品吗?此操作不可恢复!',
- success: async (res) => {
- if (res.confirm) {
- const {code} = await productDelete(obj.id);
- if(code == 200){
- uni.showToast({ title: "操作成功", icon: "none" });
- goodsList.value.splice(index,1);
- }
- }
- }
- });
- }
- onReachBottom(() => {
- getGroomList();
- });
- </script>
- <style scoped>
- /* 管理栏样式 */
- .nav {
- width: 100%;
- height: 90rpx;
- background-color: #fff;
- padding: 0 30rpx;
- box-sizing: border-box;
- font-size: 28rpx;
- color: #282828;
- border-top: 1px solid #f0f0f0;
- border-bottom: 1px solid #f0f0f0;
- margin-top: 20rpx;
- }
- .nav .administrate {
- width: 120rpx;
- height: 50rpx;
- border-radius: 8rpx;
- border: 1px solid #F8C008;
- color: #F8C008;
- font-size: 24rpx;
- }
- .num {
- color: #F8C008;
- font-weight: bold;
- margin: 0 4rpx;
- }
- /* 底部操作栏样式 */
- .footer {
- z-index: 9;
- width: 100%;
- height: 96rpx;
- background-color: #fff;
- position: fixed;
- padding: 0 30rpx;
- box-sizing: border-box;
- border-top: 1rpx solid #eee;
- border-bottom: 1px solid #EEEEEE;
- bottom: 0rpx;
- }
- .footer .checkAll {
- font-size: 28rpx;
- color: #282828;
- margin-left: 16rpx;
- }
- .footer .button {
- display: flex;
- gap: 20rpx;
- }
- .footer .button .bnt {
- font-size: 28rpx;
- color: #333333;
- border-radius: 8rpx;
- background-color: #F8C008;
- width: 180rpx;
- height: 60rpx;
- line-height: 60rpx;
- text-align: center;
- border: none;
- }
- .footer .button .delete-btn {
- background-color: #e64340;
- }
- /* 商品卡片调整 */
- .product-card {
- width: 100%;
- position: relative;
- background-color: #fff;
- border-radius: 16rpx;
- padding: 30rpx;
- margin: 20rpx 30rpx;
- box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.05);
- }
- .product-header {
- display: flex;
- align-items: flex-start;
- margin-bottom: 20rpx;
- }
- .product-image {
- width: 180rpx;
- height: 180rpx;
- border-radius: 12rpx;
- margin-right: 20rpx;
- }
- .product-info {
- flex: 1;
- }
- .nameweight {
- display: flex;
- justify-content: space-between;
- align-items: center;
- margin-bottom: 20rpx;
- }
- .product-name {
- font-size: 28rpx;
- font-weight: bold;
- color: #333;
- flex: 1;
- margin-right: 20rpx;
- }
- .product-weight {
- font-size: 24rpx;
- color: #999;
- background: #f5f5f5;
- padding: 4rpx 12rpx;
- border-radius: 8rpx;
- }
- .price-info {
- display: flex;
- align-items: center;
- margin-bottom: 10rpx;
- }
- .price-info .label {
- font-size: 24rpx;
- color: #666;
- margin-right: 10rpx;
- min-width: 60rpx;
- }
- .price-info .value {
- font-size: 28rpx;
- color: #e64340;
- font-weight: bold;
- }
- .price-info .unit {
- font-size: 20rpx;
- }
- .product-stats {
- display: flex;
- gap: 30rpx;
- margin-top: 10rpx;
- }
- .product-stats .stat {
- font-size: 24rpx;
- color: #999;
- }
- .action-buttons {
- display: flex;
- justify-content: flex-start;
- align-items: center;
- gap: 20rpx;
- padding-top: 20rpx;
- border-top: 1rpx solid #f0f0f0;
- }
- .btn {
- font-size: 28rpx;
- border-radius: 8rpx;
- background: transparent;
- flex: 1;
- height: 60rpx;
- line-height: 60rpx;
- }
- .btn-delete {
- color: #F52929;
- background-color: #FEEAEA;
- }
- .btn-offline {
- color: #333333;
- background-color: #F5F7FA;
- }
- .btn-edit {
- color: #333333;
- background-color: #F8C008;
- }
- /* 搜索栏样式 */
- .search-bar {
- background-color: #fff;
- position: sticky;
- top: 0;
- z-index: 100;
- padding: 20rpx 30rpx 0;
- }
- .search-bar-con {
- padding-bottom: 20rpx;
- }
- .search-input-wrapper {
- display: flex;
- align-items: center;
- background-color: #f5f5f5;
- border-radius: 50rpx;
- padding: 0 20rpx;
- height: 70rpx;
- }
- .search-icon {
- margin-right: 10rpx;
- }
- .search-input {
- flex: 1;
- height: 100%;
- font-size: 28rpx;
- color: #333;
- }
- .placeholder {
- color: #999;
- font-size: 28rpx;
- }
- .clear-btn {
- width: 40rpx;
- height: 40rpx;
- border-radius: 50%;
- background: #e0e0e0;
- display: flex;
- align-items: center;
- justify-content: center;
- margin-left: 10rpx;
- }
- /* 加载状态 */
- .loadingicon {
- text-align: center;
- color: #999;
- font-size: 24rpx;
- padding: 30rpx 0;
- }
- /* 无数据状态 */
- .no-data {
- display: flex;
- justify-content: center;
- padding: 100rpx 0;
- }
- .no-data image {
- width: 300rpx;
- height: 300rpx;
- }
- .mores-txt {
- text-align: center;
- color: #999;
- font-size: 24rpx;
- padding: 30rpx 0 60rpx;
- border-top: 1rpx solid #f0f0f0;
- margin-top: 20rpx;
- align-items: center;
- justify-content: center;
- }
- </style>
|