- 框架初始化
 - 安装插件
 - 修复PHP8.4报错
This commit is contained in:
2025-04-19 17:21:20 +08:00
commit c6a4e1f5f6
5306 changed files with 967782 additions and 0 deletions

View File

@@ -0,0 +1,87 @@
{include file="/shopro/common/script" /}
<style>
.activity-index .sa-main {
--el-main-padding: 20px 40px;
}
.activity-index .title {
line-height: 20px;
font-size: 16px;
color: var(--sa-title);
margin-bottom: 12px;
}
.activity-index .activity-item {
width: 250px;
padding: 18px 20px;
background: var(--sa-table-header-bg);
border-radius: 4px;
margin: 0 16px 16px 0;
cursor: pointer;
}
.activity-index .activity-item:hover {
transition: width height 0.5s;
transform: scale(1.05);
}
.activity-index .left {
width: 44px;
height: 44px;
background: var(--el-color-primary);
border-radius: 4px;
overflow: hidden;
margin-right: 12px;
}
.activity-index .left img {
width: 100%;
height: 100%;
}
.activity-index .activity-title {
line-height: 18px;
font-size: 14px;
font-weight: 600;
color: var(--sa-subtitle);
margin: 2px 0 6px;
}
.activity-index .activity-subtitle {
line-height: 16px;
font-size: 12px;
color: var(--sa-subfont);
}
</style>
<div id="index" class="activity-index panel panel-default panel-intro" v-cloak>
<el-container class="panel-block">
<el-header class="sa-header">
<div class="sa-title sa-flex">
<div class="sa-title-left">
<div class="left-name">营销活动</div>
</div>
</div>
</el-header>
<el-main class="sa-main">
<template v-for="item in activityData">
<div class="title">
{{item.title}}
</div>
<div class="sa-flex sa-flex-wrap">
<div class="activity-item sa-flex" v-for="(value,key) in item.children"
@click="onActivity(key,value.title)">
<div class="left">
<img :src="`/assets/addons/shopro/img/activity/${key}.png`" />
</div>
<div>
<div class="activity-title">{{value.title}}</div>
<div class="activity-subtitle">{{value.subtitle}}</div>
</div>
</div>
</div>
</template>
</el-main>
</el-container>
</div>

View File

@@ -0,0 +1,674 @@
{include file="/shopro/common/script" /}
<style>
.activity-form .w-120 {
width: 120px;
}
.activity-form .el-form-item-inner {
--el-form-label-font-size: 12px;
}
.activity-form .el-form-item-inner .el-form-item__label {
width: fit-content !important;
}
.activity-form .tip,
.activity-form .delete {
margin-left: 12px;
}
.activity-form .rules-title {
width: 100%;
max-width: 360px;
height: 32px;
line-height: 32px;
padding: 0 16px;
border-radius: 4px;
background: var(--sa-table-header-bg);
font-size: 12px;
color: var(--sa-subtitle);
}
.activity-form .goods-image {
margin-right: 12px;
}
.activity-form .goods-title {
color: var(--sa-font);
margin-bottom: 6px;
}
.activity-form .goods-price {
color: var(--el-color-danger);
}
.activity-form .sa-template-wrap .setting {
flex: none;
width: 100px;
}
</style>
<div id="addEdit" class="activity-form" v-cloak>
<el-container class="panel-block">
<el-main>
<el-scrollbar height="100%">
<el-form :model="form.model" :rules="form.rules" ref="formRef" label-width="110px">
<el-form-item label="活动名称" prop="title">
<el-input class="sa-w-360" v-model="form.model.title" placeholder="例如:国庆活动" />
</el-form-item>
<el-form-item v-if="form.model.status == 'ing'" label="活动时间" required>
<el-form-item prop="start_time">
<el-date-picker v-model="form.model.start_time" type="datetime"
value-format="YYYY-MM-DD HH:mm:ss" format="YYYY-MM-DD HH:mm:ss"
:disabled="state.activityStatus" prefix-icon="Calendar" placeholder="开始时间"
:editable="false">
</el-date-picker>
</el-form-item>
<span class="ml-2 mr-2"></span>
<el-form-item prop="end_time">
<el-date-picker v-model="form.model.end_time" type="datetime"
value-format="YYYY-MM-DD HH:mm:ss" format="YYYY-MM-DD HH:mm:ss" prefix-icon="Calendar"
placeholder="结束时间" :editable="false" @change="onChangeEndtime"></el-date-picker>
</el-form-item>
</el-form-item>
<el-form-item v-if="form.model.status != 'ing'" label="活动时间" prop="dateTime">
<div>
<el-date-picker v-model="form.model.dateTime" type="datetimerange"
value-format="YYYY-MM-DD HH:mm:ss" format="YYYY-MM-DD HH:mm:ss"
:default-time="[new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 2, 1, 23, 59, 59)]"
range-separator="至" start-placeholder="开始时间" end-placeholder="结束时间"
prefix-icon="Calendar" :editable="false" />
</div>
</el-form-item>
<template v-if="form.model.type == 'full_reduce' || form.model.type == 'full_discount'">
<el-form-item label="优惠类型" prop="rules.type" required>
<el-radio-group v-model="form.model.rules.type">
<el-radio label="money">消费金额</el-radio>
<el-radio label="num">购买件数</el-radio>
</el-radio-group>
</el-form-item>
<div class="el-form-item-inner" v-for="(ditem, dindex) in form.model.rules.discounts"
:key="dindex">
<el-form-item>
<el-form-item :label="`规则${dindex + 1}`" required>
<el-form-item class="is-no-asterisk" label="消费满"
:prop="'rules.discounts.' + dindex + '.full'"
:rules="form.rules.rules.discounts.full">
<el-input class="w-120" v-model="ditem.full" type="number">
<template #append>
{{ form.model.rules.type == 'money' ? '元' : '件' }}
</template>
</el-input>
</el-form-item>
<el-form-item class="is-no-asterisk ml-2"
:label="`${form.model.type == 'full_reduce' ? '优惠' : '折扣'}`"
:prop="'rules.discounts.' + dindex + '.discount'"
:rules="form.rules.rules.discounts.discount">
<el-input class="w-120" v-model="ditem.discount" type="number">
<template #append>
{{ form.model.type == 'full_reduce' ? '元' : '折' }}
</template>
</el-input>
<div class="tip" v-if="form.model.rules.type == 'money' && dindex == 0">
{{
form.model.type == 'full_reduce' ? '满减' : '满折'
}}金额优惠按照商品实际金额计算
</div>
<el-button v-if="dindex" class="delete" type="danger" link
@click="onDeleteDiscounts(dindex)">
删除
</el-button>
</el-form-item>
</el-form-item>
</el-form-item>
</div>
<el-form-item>
<el-button v-if="
form.model.rules.discounts && form.model.rules.discounts.length < 5
" type="primary" link @click="onAddDiscounts">+ 添加优惠</el-button>
</el-form-item>
</template>
<template v-if="form.model.type == 'full_gift'">
<el-form-item label="参与次数" required>
<el-radio-group v-model="state.limitNumType" @change="onChangeLimitNumType">
<el-radio label="all">不限制</el-radio>
<el-radio label="part">
每人最多可参与
<el-input v-if="state.limitNumType == 'part'" class="w-120 ml-2"
v-model="form.model.rules.limit_num">
<template #append>次数</template>
</el-input>
</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="赠送时机" prop="rules.event" required>
<el-radio-group v-model="form.model.rules.event">
<el-radio label="paid">支付完成</el-radio>
<el-radio label="confirm">
<div class="sa-flex">
确认收货
<el-popover popper-class="sa-popper" trigger="hover">
<div>必须全部确认收货才能满足条件</div>
<template #reference>
<el-icon class="warning">
<warning />
</el-icon>
</template>
</el-popover>
</div>
</el-radio>
<el-radio label="finish">交易完成</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="优惠类型" prop="rules.type" required>
<el-radio-group v-model="form.model.rules.type">
<el-radio label="money">满足金额</el-radio>
<el-radio label="num">满足件数</el-radio>
</el-radio-group>
</el-form-item>
<div class="el-form-item-inner" v-for="(ditem, dindex) in form.model.rules.discounts"
:key="ditem">
<el-form-item>
<div class="rules-title">{{ `规则${dindex + 1}` }}</div>
</el-form-item>
<el-form-item>
<el-form-item label="消费满" :prop="'rules.discounts.' + dindex + '.full'"
:rules="form.rules.rules.discounts.full">
<el-input class="w-120" v-model="ditem.full" type="number">
<template #append>
{{ form.model.rules.type == 'money' ? '元' : '件' }}
</template>
</el-input>
<div v-if="dindex == 0" class="tip"> 满赠金额优惠按照商品实际金额计算 </div>
<el-button v-if="dindex" class="delete" type="danger" link
@click="onDeleteDiscounts(dindex)">删除</el-button>
</el-form-item>
</el-form-item>
<el-form-item>
<el-form-item label="赠送单数" :prop="'rules.discounts.' + dindex + '.gift_num'"
:rules="form.rules.rules.discounts.gift_num">
<el-input class="w-120" v-positiveinteger v-model="ditem.gift_num" type="number">
<template #append></template>
</el-input>
<div v-if="dindex == 0" class="tip">
该单数指赠品发放单数如设置100单那参与此活动的前100个订单可获取赠品
</div>
</el-form-item>
</el-form-item>
<el-form-item>
<el-form-item label="赠送类型" :prop="'rules.discounts.' + dindex + '.types'"
:rules="form.rules.rules.discounts.types">
<el-checkbox-group v-model="ditem.types">
<el-checkbox label="coupon">优惠券</el-checkbox>
<el-checkbox label="score">积分</el-checkbox>
<el-checkbox label="money">余额</el-checkbox>
</el-checkbox-group>
</el-form-item>
</el-form-item>
<div class="ml-4">
<!-- 优惠券 -->
<el-form-item v-if="ditem.types.includes('coupon')">
<div>
<el-form-item label="优惠券">
<el-button type="primary" link @click="onSelectCoupon(dindex)">
选择优惠券</el-button>
</el-form-item>
<el-form-item>
<div class="sa-template-wrap">
<template v-if="ditem.coupon_list.length > 0">
<div class="header sa-flex">
<div class="key">名称</div>
<div class="key">优惠内容</div>
<div class="oper">操作</div>
</div>
<div class="item" v-for="(element, index) in ditem.coupon_list"
:key="element">
<div class="key">
<div class="sa-table-line-1">{{ element.name }}</div>
</div>
<div class="key">
<div class="sa-table-line-1">
{{ element.amount_text }}
</div>
</div>
<div class="oper">
<el-button type="danger" link
@click="onDeleteCoupon(dindex, index)">
移除
</el-button>
</div>
</div>
</template>
</div>
</el-form-item>
</div>
</el-form-item>
<!-- 积分 -->
<el-form-item v-if="ditem.types.includes('score')">
<el-form-item label="积分">
<el-input class="w-120" v-positiveinteger v-model="ditem.score" type="number">
<template #append>积分</template>
</el-input>
</el-form-item>
</el-form-item>
<!-- 余额 -->
<el-form-item v-if="ditem.types.includes('money')">
<el-form-item label="余额">
<el-input class="w-120" v-model="ditem.money" type="number">
<template #append></template>
</el-input>
</el-form-item>
</el-form-item>
</div>
</div>
<el-form-item>
<el-button type="primary" link @click="onAddDiscounts">+ 添加优惠</el-button>
</el-form-item>
</template>
<template v-if="form.model.type == 'free_shipping'">
<el-form-item label="优惠类型" prop="rules.type" required>
<el-radio-group v-model="form.model.rules.type">
<el-radio label="money">按消费金额包邮</el-radio>
<el-radio label="num">按购买件数包邮</el-radio>
</el-radio-group>
</el-form-item>
<div class="el-form-item-inner">
<el-form-item>
<el-form-item :label="`规则`" required>
<el-form-item class="is-no-asterisk" label="消费满" prop="rules.full_num"
:rules="form.rules.rules.full_num">
<el-input class="w-120" v-model="form.model.rules.full_num" type="number">
<template #append>
{{ form.model.rules.type == 'money' ? '元' : '件' }}
</template>
</el-input>
<span class="tip">满邮金额优惠按照商品实际金额计算</span>
</el-form-item>
</el-form-item>
</el-form-item>
<el-form-item>
<el-form-item label="不支持地区" required>
<div>
<div class="sa-flex">
<template v-for="level in form.model.rules.district_text" :key="level">
<template v-for="name in level" :key="name">{{ name }},</template>
</template>
</div>
<el-button type="primary" link @click="onSelectArea">添加地区</el-button>
</div>
</el-form-item>
</el-form-item>
</div>
</template>
<template v-if="form.model.type == 'groupon' || form.model.type == 'groupon_ladder'">
<el-form-item label="预热时间" prop="prehead_time">
<el-date-picker v-model="form.model.prehead_time" type="datetime"
value-format="YYYY-MM-DD HH:mm:ss" format="YYYY-MM-DD HH:mm:ss" placeholder="预热时间"
prefix-icon="Calendar" :disabled="state.activityStatus" :editable="false">
</el-date-picker>
</el-form-item>
<el-form-item label="拼团解散时间" prop="rules.valid_time" :rules="form.rules.rules.valid_time">
<el-input class="w-120" v-model="form.model.rules.valid_time" type="number"
:disabled="state.activityStatus">
<template #append>小时</template>
</el-input>
</el-form-item>
<el-form-item v-if="form.model.type == 'groupon'" label="成团人数" prop="rules.team_num"
:rules="form.rules.rules.team_num">
<el-input class="w-120" v-positiveinteger v-model="form.model.rules.team_num"
placeholder="最少两人" type="number" :disabled="state.activityStatus">
<template #append></template>
</el-input>
</el-form-item>
<template v-if="form.model.type == 'groupon_ladder'">
<el-form-item label="成团人数" required>
<el-form-item class="is-no-asterisk" label="第一阶梯人数" prop="rules.ladders.ladder_one"
:rules="form.rules.rules.ladder_one">
<el-input class="w-120" v-positiveinteger
v-model="form.model.rules.ladders.ladder_one" placeholder="最少两人" type="number"
:disabled="state.activityStatus">
<template #append></template>
</el-input>
</el-form-item>
</el-form-item>
<el-form-item>
<el-form-item class="is-no-asterisk" label="第二阶梯人数" prop="rules.ladders.ladder_two"
:rules="form.rules.rules.ladder_two">
<el-input class="w-120" v-positiveinteger
v-model="form.model.rules.ladders.ladder_two" placeholder="最少两人" type="number"
:disabled="state.activityStatus">
<template #append></template>
</el-input>
</el-form-item>
</el-form-item>
<el-form-item v-if="Object.keys(form.model.rules.ladders).includes('ladder_three')">
<el-form-item class="is-no-asterisk" label="第三阶梯人数" prop="rules.ladders.ladder_three"
:rules="form.rules.rules.ladder_three">
<el-input class="w-120" v-positiveinteger
v-model="form.model.rules.ladders.ladder_three" placeholder="最少两人" type="number"
:disabled="state.activityStatus">
<template #append></template>
</el-input>
<el-button class="delete" type="danger" link @click="onDeleteLadders">删除
</el-button>
</el-form-item>
</el-form-item>
<el-form-item v-if="Object.keys(form.model.rules.ladders).length < 3">
<el-button type="primary" link @click="onAddLadders" :disabled="state.activityStatus">+
添加拼团梯队
</el-button>
</el-form-item>
</template>
<el-form-item label="单独购买">
<el-switch v-model="form.model.rules.is_alone" active-value="1" inactive-value="0"
:disabled="state.activityStatus"></el-switch>
<span class="ml-2" :class="form.model.rules.is_alone == 0 ?'':'sa-color--primary'">
{{ form.model.rules.is_alone == 0 ? '不允许' : '允许' }}
</span>
</el-form-item>
<el-form-item label="虚拟成团">
<el-switch v-model="form.model.rules.is_fictitious" active-value="1" inactive-value="0"
:disabled="state.activityStatus"></el-switch>
<span class="ml-2" :class="form.model.rules.is_fictitious == 0 ?'':'sa-color--primary'">
{{ form.model.rules.is_fictitious == 0 ? '不允许' : '允许' }}
</span>
<div class="tip">
开启虚拟成团后,在拼团有效期内人数不够的团,系统会虚拟用户凑满人数,使拼团成功。
虚拟的用户不生成订单,只需对真实买家发货。(请在资料管理中添加足够数量的虚拟用户,否则虚拟成团不会成功)
</div>
</el-form-item>
<div class="el-form-item-inner" v-if="form.model.rules.is_fictitious == 1">
<el-form-item>
<el-form-item class="is-no-asterisk" label="最多虚拟人数" prop="rules.fictitious_num"
:rules="form.rules.rules.fictitious_num">
<el-input class="w-120" v-model="form.model.rules.fictitious_num" type="number"
:disabled="state.activityStatus">
<template #append></template>
</el-input>
<div class="tip"> 单团最多虚拟人数的名额限制,不填时,不限制名额 </div>
</el-form-item>
</el-form-item>
<el-form-item>
<el-form-item class="is-no-asterisk" label="虚拟成团时间" prop="rules.fictitious_time"
:rules="form.rules.rules.fictitious_time">
<el-input class="w-120" v-model="form.model.rules.fictitious_time" type="number"
:disabled="state.activityStatus">
<template #append>小时</template>
</el-input>
<div class="tip">将会在拼团解散时间之前尝试虚拟成团</div>
</el-form-item>
</el-form-item>
</div>
<el-form-item label="参团卡显示">
<el-switch v-model="form.model.rules.is_team_card" active-value="1" inactive-value="0"
:disabled="state.activityStatus"></el-switch>
<span class="ml-2" :class="form.model.rules.is_team_card == 0?'':'sa-color--primary'">
{{ form.model.rules.is_team_card == 0 ? '关闭' : '开启' }}
</span>
<div class="tip">
开启参团卡显示后,商品详情页显示未成团的团列表,买家可以直接选择一个参团。
</div>
</el-form-item>
<el-form-item label="拼团销量展示">
<el-radio-group v-model="form.model.rules.sales_show_type" :disabled="state.activityStatus">
<el-radio label="real">真实活动销量</el-radio>
<el-radio label="goods">
<div class="sa-flex">
商品总销量
<div class="tip">商品总销量包含虚拟销量</div>
</div>
</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="是否参与分销">
<el-switch v-model="form.model.rules.is_commission" active-value="1" inactive-value="0"
:disabled="state.activityStatus"></el-switch>
<span class="ml-2" :class="form.model.rules.is_commission == 0?'':'sa-color--primary'">
{{ form.model.rules.is_commission == 0 ? '不参与' : '参与' }}
</span>
</el-form-item>
<el-form-item label="是否包邮">
<el-switch v-model="form.model.rules.is_free_shipping" active-value="1" inactive-value="0"
:disabled="state.activityStatus"></el-switch>
<span class="ml-2" :class="form.model.rules.is_free_shipping == 0?'':'sa-color--primary'">
{{ form.model.rules.is_free_shipping == 0 ? '不包邮' : '包邮' }}
</span>
</el-form-item>
<el-form-item label="团长优惠">
<el-switch v-model="form.model.rules.is_leader_discount" active-value="1" inactive-value="0"
:disabled="state.activityStatus"></el-switch>
</el-form-item>
<el-form-item label="限购数量">
<el-input class="w-120" v-positiveinteger v-model="form.model.rules.limit_num" type="number"
:disabled="state.activityStatus">
<template #append></template>
</el-input>
</el-form-item>
<el-form-item label="退款方式">
<div>
<el-radio-group v-model="form.model.rules.refund_type" :disabled="state.activityStatus">
<el-radio label="back">原路返回</el-radio>
<el-radio label="money">退回到余额</el-radio>
</el-radio-group>
<div class="tip">拼团失败解散时,默认退款方式</div>
</div>
</el-form-item>
<el-form-item label="订单支付时间" prop="rules.order_auto_close"
:rules="form.rules.rules.order_auto_close">
<el-input class="w-120" v-model="form.model.rules.order_auto_close" type="number"
:disabled="state.activityStatus">
<template #append>分钟</template>
</el-input>
</el-form-item>
</template>
<template v-if="form.model.type == 'seckill'">
<el-form-item label="预热时间" prop="prehead_time">
<el-date-picker v-model="form.model.prehead_time" type="datetime"
value-format="YYYY-MM-DD HH:mm:ss" format="YYYY-MM-DD HH:mm:ss" placeholder="预热时间"
prefix-icon="Calendar" :disabled="state.activityStatus" :editable="false">
</el-date-picker>
</el-form-item>
<el-form-item label="是否参与分销">
<el-switch v-model="form.model.rules.is_commission" active-value="1" inactive-value="0"
:disabled="state.activityStatus"></el-switch>
<span class="ml-2" :class="form.model.rules.is_commission == 0?'':'sa-color--primary'">
{{ form.model.rules.is_commission == 0 ? '不参与' : '参与' }}
</span>
</el-form-item>
<el-form-item label="是否包邮">
<el-switch v-model="form.model.rules.is_free_shipping" active-value="1" inactive-value="0"
:disabled="state.activityStatus"></el-switch>
<span class="ml-2" :class="form.model.rules.is_free_shipping == 0?'':'sa-color--primary'">
{{ form.model.rules.is_free_shipping == 0 ? '不包邮' : '包邮' }}
</span>
</el-form-item>
<el-form-item label="秒杀销量展示">
<el-radio-group v-model="form.model.rules.sales_show_type" :disabled="state.activityStatus">
<el-radio label="real">真实活动销量</el-radio>
<el-radio label="goods">
<div class="sa-flex">
商品总销量
<div class="tip">商品总销量包含虚拟销量</div>
</div>
</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="限购数量">
<el-input class="w-120" v-positiveinteger v-model="form.model.rules.limit_num" type="number"
:disabled="state.activityStatus">
<template #append></template>
</el-input>
</el-form-item>
<el-form-item label="订单支付时间" prop="rules.order_auto_close" :rules="form.rules.order_auto_close">
<el-input class="w-120" v-model="form.model.rules.order_auto_close" type="number"
:disabled="state.activityStatus">
<template #append>分钟</template>
</el-input>
</el-form-item>
</template>
<template v-if="form.model.type == 'signin'">
<el-form-item label="日签奖励" prop="rules.everyday">
<span>每日签到固定积分</span>
<el-input class="w-120 ml-2" v-positiveinteger v-model="form.model.rules.everyday"
type="number">
<template #append>积分</template>
</el-input>
</el-form-item>
<el-form-item label="递增签到" prop="rules.is_inc" required>
<el-switch v-model="form.model.rules.is_inc" active-value="1" inactive-value="0">
</el-switch>
<span class="ml-2" :class="form.model.rules.is_inc == 0 ?'':'sa-color--primary'">
{{ form.model.rules.is_inc == 0 ? '关闭' : '开启' }}
</span>
</el-form-item>
<div v-if="form.model.rules.is_inc == 1" class="el-form-item-inner">
<el-form-item>
<el-form-item class="is-no-asterisk" label="次日起递增奖励" prop="rules.inc_num">
<el-input class="w-120" v-positiveinteger v-model="form.model.rules.inc_num"
type="number">
<template #append>积分</template>
</el-input>
</el-form-item>
<el-form-item class="is-no-asterisk ml-2" label="自" prop="rules.until_day">
<el-input class="w-120" v-positiveinteger v-model="form.model.rules.until_day"
type="number">
<template #append></template>
</el-input>
<span class="desc ml-2">后不再递增</span>
</el-form-item>
</el-form-item>
</div>
<el-form-item label="连续签到">
<el-switch v-model="state.is_discounts" active-value="1" inactive-value="0"
@change="onChangeDiscounts"></el-switch>
<span class="ml-2" :class="state.is_discounts == 0?'':'sa-color--primary'">
{{ state.is_discounts == 0 ? '关闭' : '开启' }}
</span>
</el-form-item>
<div v-if="state.is_discounts == 1" class="el-form-item-inner">
<el-form-item v-for="(d, dindex) in form.model.rules.discounts" :key="d">
<el-form-item :label="`条件${dindex + 1}`" required>
<el-form-item class="is-no-asterisk" label="连续签到"
:prop="'rules.discounts.' + dindex + '.full'"
:rules="form.rules.rules.discounts.full">
<el-input class="w-120" v-positiveinteger v-model="d.full" type="number">
<template #append></template>
</el-input>
</el-form-item>
<el-form-item class="is-no-asterisk ml-2" label="赠送积分"
:prop="'rules.discounts.' + dindex + '.value'"
:rules="form.rules.rules.discounts.value">
<el-input class="w-120" v-positiveinteger v-model="d.value" type="number">
<template #append>积分</template>
</el-input>
<el-button v-if="dindex" class="delete" type="danger" link size="small"
@click="onDeleteDiscounts">
删除
</el-button>
</el-form-item>
</el-form-item>
</el-form-item>
<el-form-item>
<el-button v-if="form.model.rules.discounts.length < 3" type="primary" link
@click="onAddDiscounts">
+ 添加连续签到天数
</el-button>
</el-form-item>
</div>
<el-form-item label="补签设置">
<el-switch v-model="form.model.rules.is_replenish" active-value="1" inactive-value="0">
</el-switch>
<span class="ml-2" :class="form.model.rules.is_replenish == 0 ?'':'sa-color--primary'">
{{ form.model.rules.is_replenish == 0 ? '关闭' : '开启' }}
</span>
</el-form-item>
<div v-if="form.model.rules.is_replenish == 1" class="el-form-item-inner">
<el-form-item>
<el-form-item label="用户在" prop="rules.replenish_limit">
<el-input class="w-120" v-positiveinteger v-model="form.model.rules.replenish_limit"
type="number">
<template #append></template>
</el-input>
</el-form-item>
<el-form-item class="is-no-asterisk ml-2" label="内可补签" prop="rules.replenish_days">
<el-input class="w-120" v-positiveinteger v-model="form.model.rules.replenish_days"
type="number">
<template #append></template>
</el-input>
</el-form-item>
</el-form-item>
<el-form-item>
<el-form-item label="每次补签消耗积分" prop="rules.replenish_num">
<el-input class="w-120" v-positiveinteger v-model="form.model.rules.replenish_num"
type="number">
<template #append>积分</template>
</el-input>
</el-form-item>
</el-form-item>
</div>
</template>
<el-form-item label="活动说明">
<el-input class="sa-w-360" v-model="form.model.richtext_title" placeholder="请选择活动说明">
<template #append>
<span class="cursor-pointer" @click="onSelectRichtext">选择活动说明</span>
</template>
</el-input>
</el-form-item>
<template v-if="form.model.type != 'signin'">
<el-form-item v-if="!isActivity" label="活动商品" prop="state.goodsType">
<el-radio-group v-model="state.goodsType" :disabled="state.activityStatus"
@change="onChangeGoodsType">
<el-radio label="all">全部商品</el-radio>
<el-radio label="part">部分商品</el-radio>
</el-radio-group>
</el-form-item>
<template v-if="state.goodsType == 'part'">
<el-form-item :label="isActivity ? '活动商品' : ''"
:prop="state.goodsType == 'part' || isActivity ? 'goods_list' : ''">
<el-button type="primary" link @click="onSelectGoods" :disabled="state.activityStatus">+
添加商品
</el-button>
</el-form-item>
</template>
<el-form-item v-if="form.model.goods_list.length > 0">
<div class="sa-template-wrap" :class="isActivity ? 'sa-template-wrap-activity' : ''">
<div class="header sa-flex">
<div class="key">商品信息</div>
<div v-if="isActivity" class="key setting">设置</div>
<div class="oper">操作</div>
</div>
<div>
<div class="item" v-for="(element, index) in form.model.goods_list" :key="element">
<div class="key goods-item">
<sa-image class="goods-image" :url="element.image" size="40"></sa-image>
<div class="">
<div class="goods-title sa-table-line-1">
{{ element.title }}
</div>
<div class="goods-price"> ¥{{ element.price.join('~') }} </div>
</div>
</div>
<div v-if="isActivity" class="key setting">
<el-button type="primary" link
@click="onSetActivitySkuPrices(index, element.id)">设置商品</el-button>
</div>
<div class="oper">
<el-button type="danger" link @click="onDeleteGoods(index)"
:disabled="state.activityStatus">
移除
</el-button>
</div>
</div>
</div>
</div>
</el-form-item>
</template>
</el-form>
</el-scrollbar>
</el-main>
<el-footer class="sa-footer--submit sa-flex sa-row-right">
<el-button type="primary" @click="onConfirm">确定</el-button>
</el-footer>
</el-container>
</div>

View File

@@ -0,0 +1,106 @@
{include file="/shopro/common/script" /}
<div id="index" class="activity-index panel panel-default panel-intro" v-cloak>
<el-container class="panel-block">
<el-header class="sa-header">
<div class="sa-title sa-flex sa-row-between">
<div class="sa-title-left">
<div class="left-name">{{state.title}}</div>
<sa-filter-condition v-model="state.filter" @filter-delete="onChangeFilter">
</sa-filter-condition>
</div>
<div class="sa-title-right">
<el-button class="sa-button-refresh" icon="RefreshRight" @click="getData"></el-button>
<el-button class="sa-button-refresh" icon="Search" @click="onOpenFilter"></el-button>
{if $auth->check('shopro/activity/activity/add')}
<el-button icon="Plus" type="primary" @click="onAdd">添加</el-button>
{/if}
{if $auth->check('shopro/activity/activity/recyclebin')}
<el-button type="danger" icon="Delete" plain @click="onRecyclebin">回收站</el-button>
{/if}
</div>
</div>
</el-header>
<el-main class="sa-main">
<el-table height="100%" class="sa-table" :data="state.data" stripe @sort-change="onChangeSort">
<el-table-column prop="id" label="ID" min-width="90" sortable="custom"> </el-table-column>
<el-table-column label="活动名称" min-width="200">
<template #default="scope">
<div class="sa-table-line-1">{{ scope.row.title }}</div>
</template>
</el-table-column>
<el-table-column v-if="state.type != 'signin'" label="参与商品" min-width="244">
<template #default="scope">
<template v-if="scope.row.goods_ids">
<el-popover width="300" trigger="hover">
<template v-if="scope.row.goods.length>0">
<div class="sa-flex" v-for="item in scope.row.goods" :key="item">
<sa-image class="mr-2" :url="item.image" size="40"></sa-image>
<div>
<div class="sa-table-line-1 mb-1">
{{ item.title }}
</div>
<div>#{{ item.id }}</div>
</div>
</div>
</template>
<div v-else>
#{{scope.row.goods_ids}}
</div>
<template #reference>
<span class="sa-color--primary">{{scope.row.goods_ids.split(',')?.length }}</span>
</template>
</el-popover>
件商品
</template>
<div v-if="!scope.row.goods_ids">全部商品</div>
</template>
</el-table-column>
<el-table-column label="活动状态" min-width="110">
<template #default="scope">
<div :class="`${state.statusStyle[scope.row.status]}`">
{{ scope.row.status_text }}
</div>
</template>
</el-table-column>
<el-table-column label="活动时间" min-width="250">
<template #default="scope">
<div>
<div>开始时间:{{ scope.row.start_time }}</div>
<div>结束时间:{{ scope.row.end_time }}</div>
</div>
</template>
</el-table-column>
<el-table-column prop="updatetime" label="更新时间" width="172"></el-table-column>
<el-table-column label="活动说明" min-width="158">
<template #default="scope">
<div class="sa-table-line-1">{{ scope.row.richtext_title || '-'}}</div>
</template>
</el-table-column>
<el-table-column label="操作" min-width="160" fixed="right">
<template #default="scope">
{if $auth->check('shopro/activity/groupon/index')}
<el-button v-if="state.type == 'groupon' || state.type == 'groupon_ladder'" type="primary" link
@click="onGroupon(scope.row.id)">查看</el-button>
{/if}
{if $auth->check('shopro/activity/activity/edit')}
<el-button type="primary" link @click="onEdit(scope.row.id)">编辑</el-button>
{/if}
<el-popconfirm width="fit-content" confirm-button-text="确认" cancel-button-text="取消"
title="确认删除这条记录?" @confirm="onDelete(scope.row.id)">
<template #reference>
{if $auth->check('shopro/activity/activity/delete')}
<el-button type="danger" link>删除</el-button>
{/if}
</template>
</el-popconfirm>
</template>
</el-table-column>
</el-table>
</el-main>
<el-footer class="sa-footer sa-flex sa-row-right">
<sa-pagination v-model="pagination" @pagination-change="getData"></sa-pagination>
</el-footer>
</el-container>
<sa-filter v-model="state.filter" @filter-change="onChangeFilter"></sa-filter>
</div>

View File

@@ -0,0 +1,20 @@
{include file="/shopro/common/script" /}
<div id="recyclebin" class="activity-recyclebin" v-cloak>
<el-container class="panel-block">
<el-main>
<el-table height="100%" class="sa-table" :data="state.data" stripe @sort-change="onChangeSort">
<el-table-column prop="id" label="ID" width="90" sortable="custom"></el-table-column>
<el-table-column label="名称" min-width="100">
<template #default="scope">
<div class="sa-table-line-1">{{ scope.row.title || '-' }}</div>
</template>
</el-table-column>
<el-table-column prop="deletetime" label="删除时间" width="172" sortable="custom"></el-table-column>
</el-table>
</el-main>
<el-footer class="sa-footer sa-flex sa-row-right">
<sa-pagination class="is-ellipsis" v-model="pagination" @pagination-change="getData"></sa-pagination>
</el-footer>
</el-container>
</div>

View File

@@ -0,0 +1,33 @@
{include file="/shopro/common/script" /}
<div id="select" class="activity-select" v-cloak>
<el-container class="panel-block">
<el-main>
<el-table height="100%" class="sa-table" :data="state.data" stripe>
<el-table-column prop="id" label="ID" min-width="90"></el-table-column>
<el-table-column label="名称" min-width="128">
<template #default="scope">
<div class="sa-table-line-1">
{{ scope.row.title }}
</div>
</template>
</el-table-column>
<el-table-column label="类型" min-width="74">
<template #default="scope">
<div class="sa-table-line-1">
{{ scope.row.type_text }}
</div>
</template>
</el-table-column>
<el-table-column fixed="right" label="操作" min-width="120">
<template #default="scope">
<el-button type="primary" link @click="onConfirm(scope.row)">选择</el-button>
</template>
</el-table-column>
</el-table>
</el-main>
<el-footer class="sa-footer sa-flex sa-row-right">
<sa-pagination v-model="pagination" @pagination-change="getData"></sa-pagination>
</el-footer>
</el-container>
</div>

View File

@@ -0,0 +1,171 @@
{include file="/shopro/common/script" /}
<style>
.activity-skus .sku-table-wrap {
width: 100%;
overflow: auto;
}
.activity-skus .sku-table-wrap .sku-table {
font-size: 12px;
font-weight: 500;
}
.activity-skus .sku-table-wrap .sku-table thead {
line-height: 40px;
background: var(--sa-table-header-bg);
color: var(--subtitle);
}
.activity-skus .sku-table-wrap .sku-table tbody {}
.activity-skus .sku-table-wrap .sku-table tbody tr {
line-height: 48px;
color: var(--sa-font);
}
.activity-skus .sku-table-wrap .sku-table tbody tr:nth-of-type(2n) {
background: var(--sa-table-striped);
}
.activity-skus .sku-table-wrap .sku-table th,
.activity-skus .sku-table-wrap .sku-table td {
padding: 0 16px;
text-align: left;
}
.activity-skus .sku-table-wrap .sku-item {
min-width: 100px;
flex-shrink: 0;
}
</style>
<div id="skus" class="activity-skus" v-cloak>
<el-container class="panel-block">
<el-main>
<div class="sku-table-wrap">
<table class="sku-table" rules="none">
<thead>
<tr>
<th class="sku-item" v-for="ss in state.skus" :key="ss">
{{ ss.name }}
</th>
<th class="sku-item">库存</th>
<th class="sku-item">价格</th>
<th class="sku-item">销量</th>
<th class="sku-item">活动库存</th>
<th v-if="['groupon', 'seckill'].includes(state.model.type)" class="sku-item">
活动价格
</th>
<th class="sku-item" v-if="
state.model.type == 'groupon' &&
state.model.rules.is_leader_discount == 1
">
团长价格
</th>
<template v-if="state.model.type == 'groupon_ladder'">
<th class="sku-item">
{{ state.model.rules.ladders.ladder_one }}人团价格
</th>
<th class="sku-item" v-if="state.model.rules.is_leader_discount == 1">
{{ state.model.rules.ladders.ladder_one }}人团长价格
</th>
<th class="sku-item">
{{ state.model.rules.ladders.ladder_two }}人团价格
</th>
<th class="sku-item" v-if="state.model.rules.is_leader_discount == 1">
{{ state.model.rules.ladders.ladder_two }}人团长价格
</th>
<template v-if="Object.keys(state.model.rules.ladders).includes('ladder_three')">
<th class="sku-item">
{{ state.model.rules.ladders.ladder_three }}人团价格
</th>
<th class="sku-item" v-if="state.model.rules.is_leader_discount == 1">
{{ state.model.rules.ladders.ladder_three }}人团长价格
</th>
</template>
</template>
<th class="sku-item">操作</th>
</tr>
</thead>
<tbody>
<tr v-for="(sp, spindex) in state.sku_prices" :key="sp">
<td class="sku-item" v-for="st in sp.goods_sku_text" :key="st">
{{ st }}
</td>
<td class="sku-item">{{ sp.stock }}</td>
<td class="sku-item">{{ sp.price }}</td>
<td class="sku-item">{{ sp.sales }}</td>
<th class="sku-item">
<el-input v-if="state.activity_sku_prices[spindex].status == 'up'" type="number"
v-model="state.activity_sku_prices[spindex].stock"></el-input>
</th>
<th v-if="['groupon', 'seckill'].includes(state.model.type)" class="sku-item">
<el-input v-if="state.activity_sku_prices[spindex].status == 'up'" type="number"
v-model="state.activity_sku_prices[spindex].price" :disabled="state.activityStatus">
</el-input>
</th>
<th class="sku-item" v-if="
state.model.type == 'groupon' &&
state.model.rules.is_leader_discount == 1
">
<el-input v-if="state.activity_sku_prices[spindex].status == 'up'" type="number"
v-model="state.activity_sku_prices[spindex].leader_price"
:disabled="state.activityStatus"></el-input>
</th>
<template v-if="state.model.type == 'groupon_ladder'">
<th class="sku-item">
<el-input v-if="state.activity_sku_prices[spindex].status == 'up'" type="number"
v-model="state.activity_sku_prices[spindex].ladder_one"
:disabled="state.activityStatus"></el-input>
</th>
<th class="sku-item" v-if="state.model.rules.is_leader_discount == 1">
<el-input v-if="state.activity_sku_prices[spindex].status == 'up'" type="number"
v-model="state.activity_sku_prices[spindex].ladder_one_leader"
:disabled="state.activityStatus"></el-input>
</th>
<th class="sku-item">
<el-input v-if="state.activity_sku_prices[spindex].status == 'up'" type="number"
v-model="state.activity_sku_prices[spindex].ladder_two"
:disabled="state.activityStatus"></el-input>
</th>
<th class="sku-item" v-if="state.model.rules.is_leader_discount == 1">
<el-input v-if="state.activity_sku_prices[spindex].status == 'up'" type="number"
v-model="state.activity_sku_prices[spindex].ladder_two_leader"
:disabled="state.activityStatus"></el-input>
</th>
<template v-if="Object.keys(state.model.rules.ladders).includes('ladder_three')">
<th class="sku-item">
<el-input type="number"
v-model="state.activity_sku_prices[spindex].ladder_three"
v-if="state.activity_sku_prices[spindex].status == 'up'"
:disabled="state.activityStatus"></el-input>
</th>
<th class="sku-item" v-if="state.model.rules.is_leader_discount == 1">
<el-input v-if="state.activity_sku_prices[spindex].status == 'up'" type="number"
v-model="state.activity_sku_prices[spindex].ladder_three_leader"
:disabled="state.activityStatus"></el-input>
</th>
</template>
</template>
<th class="sku-item">
<template v-if="!state.activityStatus">
<el-button v-if="state.activity_sku_prices[spindex].status == 'up'" class="is-link"
type="danger" @click="state.activity_sku_prices[spindex].status = 'down'">取消
</el-button>
<el-button v-if="state.activity_sku_prices[spindex].status == 'down'"
class="is-link" type="primary"
@click="state.activity_sku_prices[spindex].status = 'up'">参与</el-button>
</template>
<template v-if="state.activityStatus">-</template>
</th>
</tr>
</tbody>
</table>
</div>
</el-main>
<el-footer class="sa-footer--submit sa-flex sa-row-right">
<el-button type="primary" @click="onConfirm">确定</el-button>
</el-footer>
</el-container>
</div>

View File

@@ -0,0 +1,96 @@
{include file="/shopro/common/script" /}
<style>
.groupon-detail .goods-item .goods-title {
color: var(--el-color-primary);
}
.groupon-detail .goods-item .goods-num {
font-size: 12px;
}
</style>
<div id="detail" class="groupon-detail" v-cloak>
<el-container class="panel-block">
<el-main>
<el-table class="sa-table" :data="[{}]" stripe>
<el-table-column label="拼团商品" min-width="490">
<template #default>
<div v-if="state.data.goods" class="goods-item sa-flex">
<sa-image class="mr-2" :url="state.data.goods.image" size="40"></sa-image>
<div>
<div class="goods-title sa-table-line-1"
@click="onOpenGoodsDetail(state.data.goods_id)">
{{ state.data.goods.title || '-' }}
</div>
<div class="goods-num"> 成团人数:{{ state.data.num }} </div>
</div>
</div>
<div v-else>{{state.data.goods_id}}</div>
</template>
</el-table-column>
<el-table-column label="开团时间" width="172">
<template #default>
{{ state.data.createtime || '-' }}
</template>
</el-table-column>
<el-table-column label="拼团状态" min-width="80">
<template #default>
<div :class="`sa-color--${state.statusClass[state.data.status]}`">
{{ state.data.status_text || '-' }}
</div>
</template>
</el-table-column>
</el-table>
<el-table class="sa-table" :data="state.data.groupon_logs" stripe>
<el-table-column label="身份" min-width="80">
<template #default="scope">
<span v-if="scope.row.is_leader == 1">团长</span>
<span v-else>团员</span>
</template>
</el-table-column>
<el-table-column label="头像" width="64">
<template #default="scope">
<sa-image :url="scope.row.avatar" size="32" radius="16"></sa-image>
</template>
</el-table-column>
<el-table-column label="昵称" width="258">
<template #default="scope">
<sa-user-profile :user="scope.row" :id="scope.row.user_id" :isavatar="false"
:ishover="!scope.row.is_fictitious"></sa-user-profile>
</template>
</el-table-column>
<el-table-column label="参团时间" width="172">
<template #default="scope">
{{ scope.row.createtime || '-' }}
</template>
</el-table-column>
<el-table-column label="操作" min-width="170">
<template #default="scope">
<template v-if="scope.row.is_temp">
<el-button type="primary" link @click="onConfirm(scope.row)">确定
</el-button>
<el-button type="danger" link @click="onCancel(scope.$index)">取消
</el-button>
</template>
<span v-if="scope.row.is_fictitious == 1 && !scope.row.is_temp">虚拟</span>
</template>
</el-table-column>
</el-table>
</el-main>
<el-footer v-if="state.data.status == 'ing'" class="sa-footer--submit sa-flex sa-row-between">
<el-popconfirm width="fit-content" confirm-button-text="确认" cancel-button-text="取消" title="确定要解散拼团吗?"
@confirm="onInvalid">
<template #reference>
{if $auth->check('shopro/activity/groupon/invalid')}
<el-button>解散拼团</el-button>
{/if}
</template>
</el-popconfirm>
{if $auth->check('shopro/activity/groupon/addUser')}
<el-button type="primary" :disabled="!(state.data.groupon_logs.length<state.data.num)" @click="onAddUser">
添加虚拟人数</el-button>
{/if}
</el-footer>
</el-container>
</div>

View File

@@ -0,0 +1,105 @@
{include file="/shopro/common/script" /}
<style>
.groupon-index .goods-item .goods-title {
color: var(--el-color-primary);
}
.groupon-index .goods-item .goods-num {
font-size: 12px;
}
.groupon-index .avatar {
margin-right: 4px;
}
</style>
<div id="index" class="groupon-index panel panel-default panel-intro" v-cloak>
<el-container class="panel-block">
<el-header class="sa-header">
<el-tabs class="sa-tabs" v-model="state.filter.data.status" @tab-change="onChangeTab">
<el-tab-pane v-for="item in state.statusList" :key="item" :label="item.name" :name="item.type">
</el-tab-pane>
</el-tabs>
<div class="sa-title sa-flex sa-row-between">
<div class="sa-title-left">
<div class="left-name">拼团列表</div>
<sa-filter-condition v-model="state.filter" @filter-delete="onChangeFilter">
</sa-filter-condition>
</div>
<div class="sa-title-right">
<el-button class="sa-button-refresh" icon="RefreshRight" @click="getData"></el-button>
<el-button class="sa-button-refresh" icon="Search" @click="onOpenFilter"></el-button>
</div>
</div>
</el-header>
<el-main class="sa-main">
<el-table height="100%" class="sa-table" :data="state.data" stripe @sort-change="onChangeSort">
<el-table-column prop="id" label="ID" min-width="90" sortable="custom"> </el-table-column>
<el-table-column label="拼团商品信息" min-width="240">
<template #default="scope">
<div v-if="scope.row.goods" class="goods-item sa-flex">
<sa-image class="mr-2" :url="scope.row.goods.image" size="40"></sa-image>
<div>
<div class="goods-title sa-table-line-1" @click="onOpenGoodsDetail(scope.row.goods_id)">
{{ scope.row.goods.title || '-' }}
</div>
<div class="goods-num"> 成团人数:{{ scope.row.num }} </div>
</div>
</div>
<div v-else>{{scope.row.goods_id}}</div>
</template>
</el-table-column>
<el-table-column label="开团时间" width="172">
<template #default="scope">
{{ scope.row.createtime || '-' }}
</template>
</el-table-column>
<el-table-column label="团长" min-width="124">
<template #default="scope">
<sa-user-profile :user="scope.row.user" :id="scope.row.user_id" />
</template>
</el-table-column>
<el-table-column label="已参团成员" min-width="180">
<template #default="scope">
<el-scrollbar>
<div class="sa-flex">
<template v-for="item in scope.row.groupon_logs" :key="item">
<sa-image class="avatar" :url="item.avatar" size="32" radius="16"></sa-image>
</template>
</div>
</el-scrollbar>
</template>
</el-table-column>
<el-table-column label="剩余名额" min-width="90">
<template #default="scope">
{{ scope.row.num - scope.row.current_num }}
</template>
</el-table-column>
<el-table-column label="组团有效时间" width="172">
<template #default="scope">
{{ scope.row.finish_time || '-' }}
</template>
</el-table-column>
<el-table-column label="拼团状态" min-width="88">
<template #default="scope">
<div :class="`sa-color--${state.statusClass[scope.row.status]}`">
{{ scope.row.status_text || '-' }}
</div>
</template>
</el-table-column>
<el-table-column fixed="right" label="操作" min-width="100">
<template #default="scope">
{if $auth->check('shopro/activity/groupon/detail')}
<el-button type="primary" link @click="onDetail(scope.row.id)">查看详情</el-button>
{/if}
</template>
</el-table-column>
</el-table>
</el-main>
<el-footer class="sa-footer sa-flex sa-row-right">
<sa-pagination v-model="pagination" @pagination-change="getData"></sa-pagination>
</el-footer>
</el-container>
<sa-filter v-model="state.filter" @filter-change="onChangeFilter"></sa-filter>
</div>

View File

@@ -0,0 +1,118 @@
{include file="/shopro/common/script" /}
<style>
.desc {
font-size: 14px;
color: #999999;
margin-left: 12px;
}
.title {
margin: 0 0 18px 50px;
}
.price-title {
margin-right: 8px;
}
.price2-title {
margin: 0 8px 0 16px;
}
.el-form .sa-w-160 {
max-width: 160px;
width: 100%;
display: flex;
align-items: center;
flex-wrap: nowrap;
}
</style>
<div id="addEdit" class="molive-form" v-cloak>
<el-container class="panel-block">
<el-main>
<el-scrollbar height="100%">
<el-form :model="form.model" :rules="form.rules" ref="formRef" label-width="120px">
<div class="sa-color--warning title">在小程序直播控制台添加的商品,不支持通过此系统操作。</div>
<el-form-item label="商品来源">
<el-radio-group v-model="form.model.type">
<el-radio :label="0">我的小程序</el-radio>
<el-radio :label="1">其他小程序</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="商品选择" prop="goods_id" v-if="form.model.type === 0">
<el-button type="primary" link @click="selectGoods" v-if="!form.model.goods_id">+ 添加商品
</el-button>
<div class="sa-template-wrap">
<template v-if="form.model.goods_id">
<div class="header">
<div class="key">商品信息</div>
<div class="oper">操作</div>
</div>
<div class="item">
<div class="goods-item key">
<sa-image class="goods-image" :url="goods.image" size="40">
</sa-image>
<div>
<div class="goods-title sa-table-line-1">{{ goods.title }}</div>
</div>
</div>
<div class="oper">
<el-button type="danger" link @click="deleteItems()">移除
</el-button>
</div>
</div>
</template>
</div>
</el-form-item>
<el-form-item label="商品封面">
<sa-uploader v-model="form.model.cover_img_url" fileType="image"></sa-uploader>
<div class="desc"> 图片尺寸最大300像素*300像素 </div>
</el-form-item>
<el-form-item label="商品名称" prop="name">
<el-input v-model="form.model.name" :maxlength="14" :minlength="3" show-word-limit
placeholder="请输入商品名称"></el-input>
</el-form-item>
<el-form-item label="价格形式" prop="price_type">
<el-radio-group v-model="form.model.price_type">
<el-radio :label="1">一口价</el-radio>
<el-radio :label="2">价格区间</el-radio>
<el-radio :label="3">显示折扣价</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="价格">
<div class="price-title" v-if="form.model.price_type !== 1">{{
form.model.price_type === 2 ? '最小价格' : '市场价'
}}</div>
<el-input v-model="form.model.price" placeholder="请输入价格" class="sa-w-160" type="number"
:step="0.01" :min="0" :precision="2">
<template #append></template>
</el-input>
<div class="price2-title" v-if="form.model.price_type !== 1">{{
form.model.price_type === 2 ? '最大价格' : '现价'
}}</div>
<el-input v-model="form.model.price2" placeholder="请输入价格" class="sa-w-160" type="number"
:step="0.01" :min="0" :precision="2" v-if="form.model.price_type !== 1">
<template #append></template>
</el-input>
</el-form-item>
<el-form-item label="APPID" prop="third_party_appid" v-if="form.model.type === 1">
<el-input v-model="form.model.third_party_appid" placeholder="请输入该小程序APPID"></el-input>
</el-form-item>
<el-form-item label="商品路径" prop="url">
<div>
<el-input v-model="form.model.url" placeholder="请输入商品路径"></el-input>
<div class="desc">
请确保小程序页面路径可被访问。例如pages/goods/index?query=value
</div>
</div>
</el-form-item>
</el-form>
</el-scrollbar>
</el-main>
<el-footer class="sa-footer--submit sa-flex sa-row-right">
<el-button type="primary" @click="onConfirm">确定</el-button>
</el-footer>
</el-container>
</div>

View File

@@ -0,0 +1,252 @@
{include file="/shopro/common/script" /}
<style>
.price-title {
text-decoration: line-through;
margin-right: 8px;
color: var(--sa-subfont);
}
.live-qrcode {
width: 150px;
height: 150px;
}
.empty-data {
width: 210px;
height: 150px;
}
</style>
<div id="index" class="mplive-index panel panel-default panel-intro" v-cloak>
<el-container class="panel-block">
<el-header class="sa-header">
<el-tabs class="sa-tabs" v-model="dispatchType">
<el-tab-pane label="直播间管理" name="live"></el-tab-pane>
<el-tab-pane label="商品库管理" name="goods"></el-tab-pane>
</el-tabs>
<div class="sa-title sa-flex sa-row-between">
<div class="sa-title-left">
<div class="left-name">{{ dispatchType === 'live' ? '直播间管理' : '商品库管理' }}</div>
<sa-filter-condition v-model="state.filter" @filter-delete="onChangeFilter">
</sa-filter-condition>
</div>
<div v-if="dispatchType === 'live'">
<el-popover placement="bottom" :width="180" trigger="click">
<template #reference>
<el-button class="sa-button-refresh">主播端</el-button>
</template>
<img class="live-qrcode" src="/assets/addons/shopro/img/live-qrcode.png" />
</el-popover>
<!-- :loading="loading" -->
{if $auth->check('shopro/app/mplive/room/sync')}
<el-button class="sa-button-refresh" icon="RefreshRight" @click="sync">同步直播间</el-button>
{/if}
{if $auth->check('shopro/app/mplive/room/add')}
<el-button class="sa-button-refresh" type="primary" icon="Plus" @click="addRow">创建直播间</el-button>
{/if}
</div>
<div v-if="dispatchType === 'goods'">
<el-button class="sa-button-refresh" icon="RefreshRight" @click="getData()"></el-button>
<el-button class="sa-button-refresh" icon="Search" @click="openFilter"></el-button>
{if $auth->check('shopro/app/mplive/goods/add')}
<el-button class="sa-button-refresh" type="primary" icon="Plus" @click="addGoods">添加商品</el-button>
{/if}
</div>
</div>
</el-header>
<!-- v-loading="loading" -->
<el-main class="sa-p-0">
<el-table height="100%" class="sa-table" :data="live.data" stripe @sort-change="onChangeSort" v-if="dispatchType === 'live'">
<el-table-column label="房间ID" sortable="custom" min-width="120" align="center">
<template #default="scope">
<div class="sa-table-line-1">{{ scope.row.roomid }}</div>
</template>
</el-table-column>
<el-table-column label="直播类型" min-width="120" align="center">
<template #default="scope">
<div class="sa-table-line-1">{{ scope.row.type_text }}</div>
</template>
</el-table-column>
<el-table-column label="直播间标题" min-width="200" align="center">
<template #default="scope">
<div class="sa-table-line-1">{{ scope.row.name }}</div>
</template>
</el-table-column>
<el-table-column label="主播昵称" min-width="120" align="center">
<template #default="scope">
<div class="sa-table-line-1">{{ scope.row.anchor_name }}</div>
</template>
</el-table-column>
<el-table-column label="状态" min-width="120" align="center">
<template #default="scope">
<div class="sa-table-line-1" :class="
scope.row.status === 101
? 'sa-color--success'
: scope.row.status === 102
? 'sa-color--warning'
: scope.row.status === 105
? 'sa-color--info'
: 'sa-color--danger'
">{{ scope.row.status_text }}</div>
</template>
</el-table-column>
<el-table-column label="背景图" min-width="80" align="center">
<template #default="scope">
<div class="sa-flex sa-row-center">
<sa-image :url="scope.row.cover_img" size="30">
</sa-image>
</div>
</template>
</el-table-column>
<el-table-column label="分享图" min-width="80" align="center">
<template #default="scope">
<div class="sa-flex sa-row-center">
<sa-image :url="scope.row.share_img" size="30"></sa-image>
</div>
</template>
</el-table-column>
<el-table-column label="封面图" min-width="80" align="center">
<template #default="scope">
<div class="sa-flex sa-row-center">
<sa-image :url="scope.row.feeds_img" size="30"></sa-image>
</div>
</template>
</el-table-column>
<el-table-column label="开播时间" min-width="200" align="center">
<template #default="scope">
<div class="sa-table-line-1">{{
Moment(scope.row.start_time * 1000).format('YYYY-MM-DD HH:mm')
}}</div>
</template>
</el-table-column>
<el-table-column label="结束时间" min-width="200" align="center">
<template #default="scope">
<div class="sa-table-line-1">{{
Moment(scope.row.end_time * 1000).format('YYYY-MM-DD HH:mm')
}}</div>
</template>
</el-table-column>
<el-table-column label="操作" min-width="340" fixed="right" align="center">
<template #default="scope">
{if $auth->check('shopro/app/mplive/room/edit')}
<el-button link type="primary" @click="editRow(scope.row.roomid)">编辑</el-button>
{/if}
{if $auth->check('shopro/app/mplive/room/pushurl')}
<el-button link type="primary" @click="pushUrl(scope.row.roomid)"
v-if="scope.row.type === 1 && (scope.row.status === 101 || scope.row.status === 102)">推流地址</el-button>
{/if}
{if $auth->check('shopro/app/mplive/room/qrcode')}
<el-button link type="primary" @click="shareQrcode(scope.row.roomid)"
v-if="scope.row.status === 101 || scope.row.status === 102">分享二维码</el-button>
{/if}
{if $auth->check('shopro/app/mplive/room/playback')}
<el-button link type="primary" @click="playBack(scope.row.roomid)"
v-if="scope.row.status === 103">回放</el-button>
{/if}
<el-popconfirm width="fit-content" confirm-button-text="确认" cancel-button-text="取消"
title="确认删除这条记录?" @confirm="deleteApi(scope.row.roomid)">
<template #reference>
{if $auth->check('shopro/app/mplive/room/delete')}
<el-button link type="danger">
删除
</el-button>
{/if}
</template>
</el-popconfirm>
</template>
</el-table-column>
</el-table>
<el-table height="100%" class="sa-table" :data="goods.data" stripe v-if="dispatchType === 'goods'">
<el-table-column prop="id" label="ID" min-width="80"></el-table-column>
<el-table-column label="商品来源" min-width="120" align="center">
<template #default="scope">
<div class="sa-table-line-1">{{ scope.row.type_text }}</div>
</template>
</el-table-column>
<el-table-column label="商品封面" min-width="80" align="center">
<template #default="scope">
<div class="sa-flex sa-row-center">
<sa-image :url="scope.row.cover_img_url" size="30">
</sa-image>
</div>
</template>
</el-table-column>
<el-table-column label="商品名称" min-width="220" align="center">
<template #default="scope">
<div class="sa-table-line-1">{{ scope.row.name }}</div>
</template>
</el-table-column>
<el-table-column label="价格形式" min-width="120" align="center">
<template #default="scope">
<div class="sa-table-line-1">{{ scope.row.price_type_text }}</div>
</template>
</el-table-column>
<el-table-column label="价格" min-width="200" align="center">
<template #default="scope">
<div class="sa-table-line-1">
<div class="sa-flex sa-row-center">
<div :class="{ 'price-title': scope.row.price_type === 3 }">{{ scope.row.price }}元</div>
<div>
{{ formatPrice(scope.row.price2, scope.row.price_type) }}
</div>
</div>
</div>
</template>
</el-table-column>
<el-table-column label="商品路径" min-width="300" align="center">
<template #default="scope">
<div class="sa-table-line-1">{{ scope.row.url }}</div>
</template>
</el-table-column>
<el-table-column label="审核状态" min-width="120" align="center" fixed="right">
<template #default="scope">
<div class="sa-flex sa-row-center">
<div class="sa-table-line-1" :class="
scope.row.audit_status === 2
? 'sa-color--success'
: scope.row.audit_status === 3
? 'sa-color--danger'
: scope.row.audit_status === 1 ? 'sa-color--warning' : 'sa-color--info'
">{{ scope.row.audit_status_text }}</div>
<el-button link icon="RefreshRight" @click="getStatus(scope.row.id)"></el-button>
</div>
</template>
</el-table-column>
<el-table-column label="操作" min-width="200" fixed="right">
<template #default="scope">
{if $auth->check('shopro/app/mplive/goods/edit')}
<el-button link type="primary" @click="editGoods(scope.row.id)">编辑</el-button>
{/if}
{if $auth->check('shopro/app/mplive/goods/audit')}
<el-button link type="primary" @click="check(scope.row.id, 'resubmit')"
v-if="scope.row.audit_status === 0 || scope.row.audit_status === 3">提交审核</el-button>
{/if}
{if $auth->check('shopro/app/mplive/goods/audit')}
<el-button link type="primary" v-if="scope.row.audit_status === 1"
@click="check(scope.row.id, 'reset')">撤回审核</el-button>
{/if}
<el-popconfirm width="fit-content" confirm-button-text="确认" cancel-button-text="取消"
title="确认删除这条记录?" @confirm="deleteGoods(scope.row.id)">
<template #reference>
{if $auth->check('shopro/app/mplive/goods/delete')}
<el-button link type="danger">删除</el-button>
{/if}
</template>
</el-popconfirm>
</template>
</el-table-column>
</el-table>
</el-main>
<el-footer class="sa-footer sa-flex sa-row-between sa-flex-wrap" v-if="dispatchType === 'goods'">
<div class="sa-batch sa-flex">
</div>
<sa-pagination v-model="pagination" @pagination-change="getData"></sa-pagination>
</el-footer>
</el-container>
<sa-filter v-model="state.filter" @filter-change="onChangeFilter"></sa-filter>
</div>

View File

@@ -0,0 +1,134 @@
{include file="/shopro/common/script" /}
<style>
.desc {
font-size: 14px;
color: #999999;
margin-left: 12px;
}
.qrcode-img {
width: 150px;
height: 150px;
}
</style>
<div id="addEdit" class="molive-form" v-cloak>
<el-container class="panel-block">
<el-main>
<el-scrollbar height="100%">
<el-form :model="form.model" :rules="form.rules" ref="formRef" label-width="120px">
<el-form-item label="直播类型" prop="type">
<div>
<el-radio-group v-model="form.model.type">
<el-radio :label="0">手机直播</el-radio>
<el-radio :label="1">推流设备直播</el-radio>
</el-radio-group>
<div class="desc" v-if="form.model.type === 0">通过“小程序直播”小程序开播</div>
<div class="desc" v-if="form.model.type === 1">通过第三方推流设备发起直播,请自行定义画面宽高比</div>
</div>
</el-form-item>
<el-form-item label="直播间标题" prop="name">
<el-input v-model="form.model.name" placeholder="请输入直播间标题"></el-input>
</el-form-item>
<el-form-item label="背景图" prop="cover_img">
<sa-uploader v-model="form.model.cover_img" fileType="image"></sa-uploader>
<div class="desc"> 直播间背景图图片建议像素1080*1920大小不超过2M </div>
</el-form-item>
<el-form-item label="分享图" prop="share_img">
<sa-uploader v-model="form.model.share_img" fileType="image"></sa-uploader>
<div class="desc"> 直播间分享图图片建议像素800*640大小不超过1M </div>
</el-form-item>
<el-form-item label="封面图" prop="feeds_img">
<sa-uploader v-model="form.model.feeds_img" fileType="image"></sa-uploader>
<div class="desc">
购物直播频道封面图图片建议像素800*800大小不超过100KB
</div>
</el-form-item>
<el-form-item label="开播时间" prop="date_time">
<div>
<el-date-picker v-model="form.model.date_time" type="datetimerange"
value-format="YYYY-MM-DD HH:mm:ss" format="YYYY-MM-DD HH:mm:ss"
:default-time="defaultTime"
range-separator="至" start-placeholder="开始时间" end-placeholder="结束时间"
prefix-icon="Calendar" :editable="false" :disabled-date="disabledDate" />
</div>
<div class="desc">
开播时间需要在当前时间的30分钟后 并且 开始时间不能在 6 个月后<br />
开播时间和结束时间间隔不得短于30分钟不得超过72小时<br />
开播时间段仅供参考,不是实际直播间可以开播的时间。<br />
直播间在开始时间前也可以开播,并且到结束时间后不会强制结束。<br />
若到结束时间仍未开播,则直播间无法再开播。
</div>
</el-form-item>
<el-form-item label="主播昵称" prop="anchor_name">
<el-input v-model="form.model.anchor_name" placeholder="请输入主播昵称"></el-input>
</el-form-item>
<el-form-item label="主播微信账号" prop="anchor_wechat">
<div>
<el-input v-model="form.model.anchor_wechat" placeholder="请输入主播微信账号"></el-input>
<div class="desc">
每个直播间需要绑定一个用作核实主播身份,不会展示给观众。<br />
主播微信号,如果未实名认证,需要先前往“小程序直播”小程序进行实名验证。
</div>
<el-popover :width="180" trigger="click">
<template #reference>
<el-button class="is-link" type="primary">小程序认证</el-button>
</template>
<img class="qrcode-img" src="/assets/addons/shopro/img/live-qrcode.png" />
</el-popover>
</div>
</el-form-item>
<el-form-item label="主播副号" prop="sub_anchor_wechat">
<el-input v-model="form.model.sub_anchor_wechat" placeholder="请输入主播副号"></el-input>
</el-form-item>
<el-form-item label="官方收录">
<div>
<el-switch v-model="form.model.is_feeds_public" :active-value="1"
:inactive-value="0"></el-switch>
<div class="desc">
开启后本场直播将有可能被官方推荐。<br />
此项设置在直播间创建完成后可以在控制台内修改。
</div>
</div>
</el-form-item>
<el-form-item label="允许点赞">
<el-radio-group v-model="form.model.close_like">
<el-radio :label="0">开启</el-radio>
<el-radio :label="1">关闭</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="展示商品货架">
<el-radio-group v-model="form.model.close_goods">
<el-radio :label="0">开启</el-radio>
<el-radio :label="1">关闭</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="允许评论">
<el-radio-group v-model="form.model.close_comment">
<el-radio :label="0">开启</el-radio>
<el-radio :label="1">关闭</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="允许回放">
<el-radio-group v-model="form.model.close_replay">
<el-radio :label="0">开启</el-radio>
<el-radio :label="1">关闭</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="打开客服">
<el-radio-group v-model="form.model.close_kf">
<el-radio :label="0">开启</el-radio>
<el-radio :label="1">关闭</el-radio>
</el-radio-group>
</el-form-item>
</el-form>
</el-scrollbar>
</el-main>
<el-footer class="sa-footer--submit sa-flex sa-row-right">
<el-button type="primary" @click="onConfirm">确定</el-button>
</el-footer>
</el-container>
</div>

View File

@@ -0,0 +1,68 @@
{include file="/shopro/common/script" /}
<style>
.program {
width: 360px;
height: 260px;
background: #f5f5f5;
border-radius: 4px;
}
.path {
width: 360px;
height: 260px;
background: #f5f5f5;
border-radius: 4px;
}
.title {
font-size: 14px;
line-height: 20px;
color: var(--sa-subtitle);
}
.desc {
color: var(--sa-subfont);
font-size: 14px;
line-height: 20px;
word-break: break-all;
word-wrap: break-word;
}
</style>
<div id="playback" class="mplive-index panel panel-default panel-intro" v-cloak>
<el-container class="panel-block">
<!-- v-loading="loading" -->
<el-main class="sa-p-0">
<el-table :data="table.data" class="sa-table" stripe>
<template #empty>
<sa-empty />
</template>
<el-table-column label="回放片段" min-width="140">
<template #default="scope">
<div class="sa-table-line-1">{{ '片段' + scope.row.index || '-' }}</div>
</template>
</el-table-column>
<el-table-column label="创建时间" min-width="140">
<template #default="scope">
<div class="sa-table-line-1">{{
dayjs(scope.row.create_time).format('YYYY-MM-DD HH:mm:ss') || '-'
}}</div>
</template>
</el-table-column>
<el-table-column label="过期时间" min-width="140">
<template #default="scope">
<div class="sa-table-line-1">{{
dayjs(scope.row.expire_time).format('YYYY-MM-DD HH:mm:ss') || '-'
}}</div>
</template>
</el-table-column>
<el-table-column fixed="right" label="操作" min-width="120">
<template #default="scope">
<el-button class="is-link" type="primary" @click="play(scope.row.media_url)">播放</el-button>
</template>
</el-table-column>
</el-table>
</el-main>
</el-container>
</div>

View File

@@ -0,0 +1,61 @@
{include file="/shopro/common/script" /}
<style>
.title {
font-size: 16px;
line-height: 24px;
color: var(--sa-title);
margin-bottom: 16px;
}
.sa-m-b-4 {
margin-bottom: 4px;
}
.sa-m-r-4 {
margin-bottom: 4px;
}
.sa-m-b-16 {
margin-bottom: 16px;
}
.sa-m-b-40 {
margin-bottom: 40px;
}
.desc {
font-size: 14px;
line-height: 20px;
color: var(--sa-subtitle);
word-break: break-all;
word-wrap: break-word;
}
.subtitle {
color: var(--sa-subfont);
font-size: 14px;
line-height: 20px;
}
</style>
<div id="pushUrl" class="mplive-index panel panel-default panel-intro" v-cloak>
<el-container class="panel-block">
<!-- v-loading="loading" -->
<el-main class="sa-p-0">
<div class="title">推流地址</div>
<div class="sa-flex copy-box sa-m-b-4">
<div class="desc sa-m-r-4">在第三方推流应用中,以下地址进行推流</div>
<el-button class="is-link sa-m-b-4" type="primary" @click="onClipboard(state.pushUrl)">复制链接</el-button>
</div>
<div class="desc sa-m-b-16">{{ state.pushUrl }}</div>
<div class="subtitle sa-m-b-40">此地址为当前直播间唯一推流地址,不要泄露给第三方。</div>
<div class="title sa-m-b-16">备注</div>
<div class="desc sa-m-b-4">服务器地址:{{ state.serverAddress }}</div>
<div class="desc sa-m-b-16">串流密钥:{{ state.key }}</div>
<div class="sa-flex">
<div class="subtitle sa-m-r-4">推流直播操作详见</div>
<el-button class="is-link sa-m-b-4" type="primary" @click="onJump">指引</el-button>
</div>
</el-main>
</el-container>
</div>

View File

@@ -0,0 +1,64 @@
{include file="/shopro/common/script" /}
<style>
.program {
width: 360px;
height: 260px;
background: #f5f5f5;
border-radius: 4px;
padding: 16px;
margin-bottom: 30px;
}
.path {
width: 360px;
height: 260px;
background: #f5f5f5;
border-radius: 4px;
padding: 16px;
margin-bottom: 30px;
}
.title {
font-size: 14px;
line-height: 20px;
color: var(--sa-subtitle);
margin-bottom: 8px;
}
.desc {
color: var(--sa-subfont);
font-size: 14px;
line-height: 20px;
word-break: break-all;
word-wrap: break-word;
margin-bottom: 24px;
}
</style>
<div id="qrcode" class="mplive-index panel panel-default panel-intro" v-cloak>
<el-container class="panel-block">
<!-- v-loading="loading" -->
<el-main >
<div class="sa-flex sa-flex-wrap sa-row-between">
<div class="program sa-flex sa-col-top sa-row-between">
<div>
<div class="title">直播间小程序码</div>
<div class="desc ">小程序码不带参数</div>
<el-button type="primary" @click="saveImg">保存图片</el-button>
</div>
<sa-image class="" :url="state.cdnUrl" size="120"></sa-image>
</div>
<div class="path">
<div class="title">直播间页面路径</div>
<div class="desc ">{{ state.path }}</div>
<el-button type="primary" @click="onClipboard(state.path)">复制链接</el-button>
<div class="desc">链接是直播间原始页面路径,如需加入参数,详见<el-button class="is-link" type="primary"
@click="onJump">使用方法</el-button></div>
</div>
</div>
</el-main>
</el-container>
</div>

View File

@@ -0,0 +1,79 @@
{include file="/shopro/common/script" /}
<div id="select" class="room-select" v-cloak>
<el-container class="panel-block">
<el-main>
<el-table height="100%" class="sa-table" :data="state.data" stripe @selection-change="onSelectionChange">
<el-table-column type="selection" :selectable="isSelectable" width="48"></el-table-column>
<el-table-column label="房间ID" min-width="120" align="center">
<template #default="scope">
<div class="sa-table-line-1">{{ scope.row.roomid }}</div>
</template>
</el-table-column>
<el-table-column label="直播类型" min-width="120" align="center">
<template #default="scope">
<div class="sa-table-line-1">{{ scope.row.type_text }}</div>
</template>
</el-table-column>
<el-table-column label="直播间标题" min-width="200" align="center">
<template #default="scope">
<div class="sa-table-line-1">{{ scope.row.name }}</div>
</template>
</el-table-column>
<el-table-column label="主播昵称" min-width="120" align="center">
<template #default="scope">
<div class="sa-table-line-1">{{ scope.row.anchor_name }}</div>
</template>
</el-table-column>
<el-table-column label="状态" min-width="120" align="center">
<template #default="scope">
<div class="sa-table-line-1" :class="
scope.row.status === 101
? 'sa-color--success'
: scope.row.status === 102
? 'sa-color--warning'
: scope.row.status === 105
? 'sa-color--info'
: 'sa-color--danger'
">{{ scope.row.status_text }}</div>
</template>
</el-table-column>
<el-table-column label="背景图" min-width="80" align="center">
<template #default="scope">
<div class="sa-flex sa-row-center">
<sa-image :url="scope.row.cover_img" size="30">
</sa-image>
</div>
</template>
</el-table-column>
<el-table-column label="分享图" min-width="80" align="center">
<template #default="scope">
<div class="sa-flex sa-row-center">
<sa-image :url="scope.row.share_img" size="30"></sa-image>
</div>
</template>
</el-table-column>
<el-table-column label="封面图" min-width="80" align="center">
<template #default="scope">
<div class="sa-flex sa-row-center">
<sa-image :url="scope.row.feeds_img" size="30"></sa-image>
</div>
</template>
</el-table-column>
<el-table-column label="开播时间" width="172">
<template #default="scope">
{{Moment(scope.row.start_time * 1000).format('YYYY-MM-DD HH:mm')}}
</template>
</el-table-column>
<el-table-column label="结束时间" width="172">
<template #default="scope">
{{Moment(scope.row.end_time * 1000).format('YYYY-MM-DD HH:mm')}}
</template>
</el-table-column>
</el-table>
</el-main>
<el-footer class="sa-footer--submit sa-flex sa-row-right">
<el-button type="primary" @click="onConfirm">确 定</el-button>
</el-footer>
</el-container>
</div>

View File

@@ -0,0 +1,102 @@
{include file="/shopro/common/script" /}
<style>
.score-shop-form .title {
line-height: 22px;
font-size: 14px;
font-weight: 400;
color: var(--sa-subtitle);
}
.score-shop-form .sku-table-wrap {
width: 100%;
overflow: auto;
}
.score-shop-form .sku-table-wrap .sku-table {
font-size: 12px;
font-weight: 500;
}
.score-shop-form .sku-table-wrap .sku-table thead {
line-height: 40px;
background: var(--sa-table-header-bg);
color: var(--subtitle);
}
.score-shop-form .sku-table-wrap .sku-table tbody tr {
line-height: 48px;
color: var(--sa-font);
}
.score-shop-form .sku-table-wrap .sku-table tbody tr:nth-of-type(2n) {
background: var(--sa-table-striped);
}
.score-shop-form .sku-table-wrap .sku-table th,
.score-shop-form .sku-table-wrap .sku-table td {
padding: 0 16px;
text-align: left;
}
.score-shop-form .sku-table-wrap .sku-item {
min-width: 100px;
flex-shrink: 0;
}
</style>
<div id="addEdit" class="score-shop-form" v-cloak>
<el-container class="panel-block">
<el-main>
<el-scrollbar height="100%">
<div class="title mb-4">商品名称:{{ state.title }}</div>
<div class="sku-table-wrap">
<table class="sku-table" rules="none">
<thead>
<tr>
<th class="sku-item" v-for="ss in goods.skus" :key="ss">
{{ ss.name }}
</th>
<th class="sku-item">是否参与</th>
<th class="sku-item">商品价格</th>
<th class="sku-item">可兑换数量</th>
<th class="sku-item">兑换积分</th>
<th class="sku-item">兑换价格</th>
</tr>
</thead>
<tbody>
<tr v-for="(sp, spindex) in goods.sku_prices" :key="sp">
<td class="sku-item" v-for="st in sp.goods_sku_text" :key="st">
{{ st }}
</td>
<td class="sku-item">
<el-switch v-model="goods.score_sku_prices[spindex].status" active-value="up"
inactive-value="down" />
</td>
<td class="sku-item">{{ sp.price }}</td>
<th class="sku-item">
<el-input v-if="goods.score_sku_prices[spindex].status == 'up'" type="number"
v-model="goods.score_sku_prices[spindex].stock"></el-input>
</th>
<th class="sku-item">
<el-input v-if="goods.score_sku_prices[spindex].status == 'up'" type="number"
v-model="goods.score_sku_prices[spindex].score"></el-input>
</th>
<th class="sku-item">
<el-input v-if="goods.score_sku_prices[spindex].status == 'up'" type="number"
v-model="goods.score_sku_prices[spindex].price"></el-input>
</th>
</tr>
</tbody>
</table>
</div>
</el-scrollbar>
</el-main>
<el-footer class="sa-footer--submit sa-flex sa-row-right">
<el-button type="primary" @click="onConfirm">确定</el-button>
</el-footer>
</el-container>
</div>

View File

@@ -0,0 +1,159 @@
{include file="/shopro/common/script" /}
<style>
.score-shop-index .sa-table-wrap {
height: 100%;
margin-left: -48px;
overflow: hidden;
}
.score-shop-index .sa-table-wrap .sa-expand-table .el-table__header-wrapper {
display: none;
}
.score-shop-index .goods-item .sa-image {
margin-right: 12px;
}
.score-shop-index .goods-item .goods-title {
height: 20px;
line-height: 20px;
font-size: 14px;
font-weight: 500;
color: var(--sa-font);
}
.score-shop-index .goods-item .goods-subtitle {
height: 16px;
line-height: 16px;
font-size: 12px;
font-weight: 400;
color: var(--sa-subfont);
margin-bottom: 6px;
}
.score-shop-index .goods-item .goods-sku {
width: fit-content;
height: 20px;
background: var(--el-color-primary);
border-radius: 10px;
display: flex;
align-items: center;
padding: 0 8px;
font-size: 12px;
color: #fff;
cursor: pointer;
}
.score-shop-index .sku-text {
font-size: 12px;
color: var(--sa-font);
}
</style>
<div id="index" class="score-shop-index panel panel-default panel-intro" v-cloak>
<el-container class="panel-block">
<el-header class="sa-header">
<div class="sa-title sa-flex sa-row-between">
<div class="sa-title-left">
<div class="left-name">积分商城</div>
<sa-filter-condition v-model="state.filter" @filter-delete="onChangeFilter">
</sa-filter-condition>
</div>
<div class="sa-title-right">
<el-button class="sa-button-refresh" icon="RefreshRight" @click="getData"></el-button>
<el-button class="sa-button-refresh" icon="Search" @click="onOpenFilter"></el-button>
{if $auth->check('shopro/app/score_shop/add')}
<el-button icon="Plus" type="primary" @click="onAdd">添加</el-button>
{/if}
{if $auth->check('shopro/app/score_shop/recyclebin')}
<el-button type="danger" icon="Delete" plain @click="onRecyclebin">回收站</el-button>
{/if}
</div>
</div>
</el-header>
<el-main class="sa-main">
<div class="sa-table-wrap">
<el-table height="100%" class="sa-table" :data="state.data" :expand-row-keys="expandRowKeys"
row-key="id" stripe>
<el-table-column type="expand">
<template #default="props">
<el-table class="sa-table sa-expand-table" :data="skuPrices.data" stripe>
<el-table-column width="48"></el-table-column>
<el-table-column min-width="90"></el-table-column>
<el-table-column min-width="440">
<template #default="scope">
<div class="sa-flex">
<sa-image :url="scope.row.image || props.row.image" size="32">
</sa-image>
<div class="sku-text ml-2">
{{ scope.row.goods_sku_text?.join('/') }}
</div>
</div>
</template>
</el-table-column>
<el-table-column prop="score_price" min-width="200"></el-table-column>
<el-table-column prop="sales" min-width="100"></el-table-column>
<el-table-column prop="stock" min-width="100"></el-table-column>
<el-table-column min-width="120"></el-table-column>
</el-table>
</template>
</el-table-column>
<el-table-column prop="id" label="ID" min-width="90"></el-table-column>
<el-table-column label="商品信息" min-width="440">
<template #default="scope">
<div class="goods-item sa-flex">
<sa-image :url="scope.row.image" size="64"></sa-image>
<div>
<div class="goods-title sa-table-line-1">{{scope.row.title}}</div>
<div class="goods-subtitle sa-table-line-1">{{scope.row.subtitle}}</div>
<div v-if="scope.row.is_sku" class="goods-sku"
@click.stop="expandRow(scope.row.id)">
多规格
<el-icon :class="[
'expand-arrow ml-1',
expandRowKeys.includes(scope.row.id) ? 'expand-arrow-up' : 'expand-arrow-down',
]">
<arrow-down />
</el-icon>
</div>
</div>
</div>
</template>
</el-table-column>
<el-table-column label="积分现金" min-width="200">
<template #default="scope">
<div v-if="scope.row.score_price" class="sa-flex">
{{ scope.row.score_price.score }}积分
<div v-if="Number(scope.row.score_price.price)">+¥{{ scope.row.score_price.price }}
</div>
</div>
<div v-else>-</div>
</template>
</el-table-column>
<el-table-column prop="score_sales" label="销量" min-width="100"></el-table-column>
<el-table-column prop="score_stock" label="库存" min-width="100"></el-table-column>
<el-table-column label="操作" min-width="120" fixed="right">
<template #default="scope">
{if $auth->check('shopro/app/score_shop/edit')}
<el-button type="primary" link @click="onEdit(scope.row)">编辑</el-button>
{/if}
<el-popconfirm width="fit-content" confirm-button-text="确认" cancel-button-text="取消"
title="确认删除这条记录?" @confirm="onDelete(scope.row.id)">
<template #reference>
{if $auth->check('shopro/app/score_shop/delete')}
<el-button type="danger" link>删除</el-button>
{/if}
</template>
</el-popconfirm>
</template>
</el-table-column>
</el-table>
</div>
</el-main>
<el-footer class="sa-footer sa-flex sa-row-right">
<sa-pagination v-model="pagination" @pagination-change="getData"></sa-pagination>
</el-footer>
</el-container>
<sa-filter v-model="state.filter" @filter-change="onChangeFilter"></sa-filter>
</div>

View File

@@ -0,0 +1,54 @@
{include file="/shopro/common/script" /}
<div id="recyclebin" class="score-shop-recyclebin" v-cloak>
<el-container class="panel-block">
<el-main>
<el-table height="100%" class="sa-table" :data="state.data" stripe @selection-change="onChangeSelection"
@sort-change="onChangeSort">
<el-table-column type="selection" width="48" align="center"></el-table-column>
<el-table-column prop="id" label="ID" min-width="90" sortable="custom"></el-table-column>
<el-table-column label="名称" min-width="100">
<template #default="scope">
<div class="sa-table-line-1">{{ scope.row.title || '-' }}</div>
</template>
</el-table-column>
<el-table-column prop="deletetime" label="删除时间" min-width="172" sortable="custom"></el-table-column>
<el-table-column fixed="right" label="操作" min-width="120">
<template #default="scope">
{if $auth->check('shopro/app/score_shop/restore')}
<el-button type="primary" link @click="onRestore(scope.row.id)">还原</el-button>
{/if}
<el-popconfirm width="fit-content" confirm-button-text="确认" cancel-button-text="取消"
title="确认销毁这条记录?" @confirm="onDestroy(scope.row.id)">
<template #reference>
{if $auth->check('shopro/app/score_shop/destroy')}
<el-button type="danger" link>销毁</el-button>
{/if}
</template>
</el-popconfirm>
</template>
</el-table-column>
</el-table>
</el-main>
<el-footer class="sa-footer sa-flex sa-row-between sa-flex-wrap">
<div class="sa-batch sa-flex">
<div class="tip">
已选择 <span>{{batchHandle.data.length}}</span></div>
<div class="sa-flex">
{if $auth->check('shopro/app/score_shop/restore')}
<el-button type="primary" :disabled="!batchHandle.data.length" @click="onBatchHandle('restore')">还原
</el-button>
{/if}
{if $auth->check('shopro/app/score_shop/destroy')}
<el-button type="danger" :disabled="!batchHandle.data.length" @click="onBatchHandle('destroy')">销毁
</el-button>
{/if}
{if $auth->check('shopro/app/score_shop/destroy')}
<el-button type="danger" @click="onBatchHandle('all')">清空回收站</el-button>
{/if}
</div>
</div>
<sa-pagination class="is-ellipsis" v-model="pagination" @pagination-change="getData"></sa-pagination>
</el-footer>
</el-container>
</div>

View File

@@ -0,0 +1,68 @@
{include file="/shopro/common/script" /}
<style>
.score-shop-select .goods-item .goods-image {
margin-right: 12px;
}
.score-shop-select .goods-item .goods-title {
height: 20px;
line-height: 20px;
font-size: 14px;
font-weight: 500;
color: var(--sa-font);
}
.score-shop-select .goods-item .goods-subtitle {
height: 16px;
line-height: 16px;
font-size: 12px;
font-weight: 400;
color: var(--sa-subfont);
margin-bottom: 6px;
}
</style>
<div id="select" class="score-shop-select" v-cloak>
<el-container class="panel-block">
<el-main>
<el-table height="100%" class="sa-table" :data="state.data" stripe @selection-change="onChangeSelection">
<el-table-column v-if="state.multiple" type="selection" width="48"></el-table-column>
<el-table-column prop="id" label="ID" min-width="80"></el-table-column>
<el-table-column label="商品信息" min-width="440">
<template #default="scope">
<div class="goods-item sa-flex">
<sa-image :url="scope.row.image" size="64"></sa-image>
<div>
<div class="goods-title sa-table-line-1">{{scope.row.title}}</div>
<div class="goods-subtitle sa-table-line-1">{{scope.row.subtitle}}</div>
<div v-if="scope.row.is_sku">
多规格
</div>
</div>
</div>
</template>
</el-table-column>
<el-table-column label="积分现金" min-width="200">
<template #default="scope">
<div class="sa-flex">
{{ scope.row.score_price.score }}积分
<div v-if="Number(scope.row.score_price.price)">+¥{{ scope.row.score_price.price }}</div>
</div>
</template>
</el-table-column>
<el-table-column prop="score_sales" label="销量" min-width="100"></el-table-column>
<el-table-column prop="score_stock" label="库存" min-width="100"></el-table-column>
<el-table-column v-if="!state.multiple" label="操作" width="80">
<template #default="scope">
<el-button type="primary" link @click="onSelect(scope.row)">选择</el-button>
</template>
</el-table-column>
</el-table>
</el-main>
<el-footer class="sa-footer--submit sa-flex" :class="state.multiple ? 'sa-row-between' : 'sa-row-right'">
<sa-pagination class="is-ellipsis" v-model="pagination" @pagination-change="getData"></sa-pagination>
<el-button v-if="state.multiple" type="primary" @click="onConfirm">确 定</el-button>
</el-footer>
</el-container>
</div>

View File

@@ -0,0 +1,264 @@
{include file="/shopro/common/script" /}
<style>
.category-form .style-item {
margin-right: 24px;
cursor: pointer;
}
.category-form .style-item:last-of-type {
margin-right: 0;
}
.category-form .style-item .top {
width: 78px;
height: 124px;
border-radius: 4px;
position: relative;
margin-bottom: 8px;
}
.category-form .style-item .top.is-active {
border: 1px solid var(--el-color-primary);
}
.category-form .style-item .top img {
width: 100%;
height: 100%;
border-radius: 4px;
}
.category-form .style-item .top .el-icon {
font-size: 14px;
color: var(--el-color-primary);
position: absolute;
top: -7px;
right: -7px;
display: none;
}
.category-form .style-item .top.is-active .el-icon {
display: block;
}
.category-form .style-item .style-title {
font-size: 12px;
line-height: 14px;
color: var(--sa-font);
}
.category-form .title {
width: 100%;
height: 40px;
background: var(--sa-table-header-bg);
padding: 0 16px;
color: var(--sa-subtitle);
font-size: 14px;
font-weight: 500;
}
.category-form .template-wrap {
overflow: auto;
}
.category-form .template-wrap .template-header {
width: 100%;
background: var(--sa-table-header-bg);
}
.category-form .template-wrap .template-item {
flex-shrink: 0;
height: 56px;
padding: 0 16px;
font-weight: 500;
font-size: 12px;
display: flex;
align-items: center;
}
.category-form .template-header .template-item {
height: 40px;
background: var(--sa-table-header-bg);
}
.category-form .template-wrap .el-tree {
flex: 1;
}
.category-form .template-wrap .el-tree-node__expand-icon {
display: none;
}
.category-form .template-wrap .el-tree-node__content {
height: unset;
}
.category-form .template-item.id {
width: 90px;
}
.category-form .template-item.input {
width: 380px;
}
.category-form .template-item.image {
width: 80px;
}
.category-form .template-item.description {
width: 240px;
}
.category-form .template-item.weigh {
width: 120px;
}
.category-form .template-item.oper {
width: 104px;
}
.category-form .append-title {
margin-left: 12px;
}
.style-popover img {
width: 220px;
height: 350px;
}
</style>
<div id="addEdit" class="category-form" v-cloak>
<el-container class="panel-block">
<el-main>
<el-scrollbar height="100%">
<el-form :model="form.model" :rules="form.rules" ref="formRef" label-width="100px">
<el-form-item label="分类类型">
<el-radio-group v-model="state.level" :disabled="state.type=='edit'" @change="onChangeLevel">
<el-radio :label="1">一级分类</el-radio>
<el-radio :label="2">二级分类</el-radio>
<el-radio :label="3">三级分类</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="分类样式">
<div class="style-item" v-for="(item, index) in state.styleList[state.level]" :key="index"
@click="form.model.style = item.type">
<div class="top" :class="form.model.style == item.type ? 'is-active' : ''">
<img :src="`/assets/addons/shopro/img/category/${item.type}.png`" />
<el-icon>
<circle-check-filled />
</el-icon>
</div>
<div class="sa-flex sa-row-center">
<div class="style-title">样式{{ item.name }}</div>
<el-popover popper-class="style-popover sa-popper" placement="right" trigger="hover">
<img :src="`/assets/addons/shopro/img/category/${item.type}.png`" />
<template #reference>
<el-icon class="warning">
<warning />
</el-icon>
</template>
</el-popover>
</div>
</div>
</el-form-item>
<el-form-item label="分类名称" prop="name">
<el-input class="sa-w-360" v-model="form.model.name" placeholder="请输入分类名称"></el-input>
</el-form-item>
<el-form-item label="描述" prop="description">
<el-input class="sa-w-360" v-model="form.model.description" placeholder="请输入描述"></el-input>
</el-form-item>
<el-form-item label="分类权重">
<el-input class="sa-w-360" v-model="form.model.weigh" type="number" :min="0"
placeholder="请输入分类权重"></el-input>
</el-form-item>
<div class="title sa-flex sa-row-between">
<div>分类数据</div>
<el-button v-if="state.level" type="primary" link @click="onAdd">+ 插入一级分类</el-button>
</div>
<div class="template-wrap">
<div class="template-header sa-flex">
<div v-if="state.type == 'edit'" class="template-item id"> ID </div>
<div class="template-item input">分类名称</div>
<div class="template-item image sa-flex sa-row-center"> 分类图片 </div>
<div class="template-item description">描述</div>
<div class="template-item weigh">
<el-popover placement="bottom" title="" width="120" trigger="hover">
<template #reference> 排序 </template>
<div class="popover-container">
权重以倒序排列默认值为0相同权重则以ID优先
</div>
</el-popover>
</div>
<div class="template-item oper">操作</div>
</div>
<div class="sa-flex">
<el-tree :data="state.treeData" node-key="id" default-expand-all
:expand-on-click-node="false" :props="defaultProps" :indent="0">
<template #default="{ node, data }">
<div v-if="!(data.deleted && data.deleted == 1)" class="sa-flex">
<div v-if="state.type == 'edit'" class="template-item id">
<span
v-if="(data.id + '').indexOf('add') == -1 && (data.id + '').substring(0, 3) !== 'new'">{{
data.id }}</span>
</div>
<div class="template-item input sa-flex"
:style="{'padding-left':`${node.level*16}px`}">
<div class="expanded-icon sa-flex">
<div v-if="data.children && data.children.length > 0">
<el-icon v-if="node.expanded"
@click="node.expanded = !node.expanded">
<semi-select />
</el-icon>
<el-icon v-if="!node.expanded"
@click="node.expanded = !node.expanded">
<plus />
</el-icon>
</div>
</div>
<div style="margin-left: 16px">
<el-input v-model="data.name" placeholder="请输入分类名称" />
</div>
<el-button v-if="node.level == 1 && state.level != 1" class="append-title"
type="primary" link @click="onAppend(data)">
+ 插入二级分类
</el-button>
<el-button v-if="node.level == 2 && state.level == 3" class="append-title"
type="primary" link @click="onAppend(data)">
+ 插入三级分类
</el-button>
</div>
<div class="template-item image sa-flex sa-row-center">
<el-popover popper-class="sa-popper" trigger="hover"
content="建议尺寸缩略图150X150">
<template #reference>
<sa-uploader v-model="data.image" size="32">
</sa-uploader>
</template>
</el-popover>
</div>
<div class="template-item description">
<el-input v-model="data.description" placeholder="请输入分类描述" />
</div>
<div class="template-item weigh">
<el-input v-model="data.weigh" type="number" :min="0" placeholder="请输入排序" />
</div>
<div class="template-item oper">
<el-button :type="data.status == 'normal'?'info':'success'" link
@click="data.status == 'normal'?data.status = 'hidden':data.status = 'normal'">
{{data.status == 'normal'?'隐藏':'显示'}}
</el-button>
<el-button type="danger" link @click="onRemove(node, data)">删除</el-button>
</div>
</div>
</template>
</el-tree>
</div>
</div>
</el-form>
</el-scrollbar>
</el-main>
<el-footer class="sa-footer--submit sa-flex sa-row-right">
<el-button type="primary" @click="onConfirm">确定</el-button>
</el-footer>
</el-container>
</div>

View File

@@ -0,0 +1,75 @@
{include file="/shopro/common/script" /}
<style>
.category-index .style {
width: 32px;
height: 32px;
}
.style-popover img {
width: 220px;
height: 350px;
}
</style>
<div id="index" class="category-index panel panel-default panel-intro" v-cloak>
<el-container class="panel-block">
<el-header class="sa-header">
<div class="sa-title sa-flex sa-row-between">
<div class="sa-title-left">
<div class="left-name">商品分类</div>
<sa-filter-condition v-model="state.filter" @filter-delete="onChangeFilter">
</sa-filter-condition>
</div>
<div class="sa-title-right">
<el-button class="sa-button-refresh" icon="RefreshRight" @click="getData"></el-button>
<el-button class="sa-button-refresh" icon="Search" @click="onOpenFilter"></el-button>
{if $auth->check('shopro/category/add')}
<el-button icon="Plus" type="primary" @click="onAdd">添加</el-button>
{/if}
</div>
</div>
</el-header>
<el-main class="sa-main">
<el-table height="100%" class="sa-table" :data="state.data" stripe>
<el-table-column prop="id" label="ID" min-width="90"> </el-table-column>
<el-table-column prop="name" label="分类名称" min-width="100">
<template #default="scope">
<div class="sa-table-line-1">{{ scope.row.name || '-' }}</div>
</template>
</el-table-column>
<el-table-column prop="style" label="分类样式" min-width="100">
<template #default="scope">
<el-popover popper-class="style-popover sa-popper" placement="right-start" trigger="hover">
<img :src="`/assets/addons/shopro/img/category/${scope.row.style}.png`" />
<template #reference>
<img class="style" :src="`/assets/addons/shopro/img/category/${scope.row.style}.png`" />
</template>
</el-popover>
</template>
</el-table-column>
<el-table-column prop="weigh" label="权重" min-width="100">
<template #default="scope">
<div class="sa-table-line-1">{{ scope.row.weigh || '0' }}</div>
</template>
</el-table-column>
<el-table-column fixed="right" label="操作" min-width="120">
<template #default="scope">
{if $auth->check('shopro/category/edit')}
<el-button type="primary" link @click="onEdit(scope.row.id)">编辑</el-button>
{/if}
<el-popconfirm width="fit-content" confirm-button-text="确认" cancel-button-text="取消"
title="确认删除这条记录?" @confirm="onDelete(scope.row.id)">
<template #reference>
{if $auth->check('shopro/category/delete')}
<el-button type="danger" link>删除</el-button>
{/if}
</template>
</el-popconfirm>
</template>
</el-table-column>
</el-table>
</el-main>
</el-container>
<sa-filter v-model="state.filter" @filter-change="onChangeFilter"></sa-filter>
</div>

View File

@@ -0,0 +1,21 @@
{include file="/shopro/common/script" /}
<div id="select" class="category-select" v-cloak>
<el-container class="panel-block">
<el-main>
<el-scrollbar height="100%">
<el-cascader-panel ref="categoryRef" v-model="state.selectedIds" :options="state.data" :props="{
multiple: state.multiple,
checkStrictly: true,
emitPath: false,
label: 'name',
value: 'id',
}">
</el-cascader-panel>
</el-scrollbar>
</el-main>
<el-footer class="sa-footer--submit sa-flex sa-row-right">
<el-button type="primary" @click="onConfirm">确定</el-button>
</el-footer>
</el-container>
</div>

View File

@@ -0,0 +1,42 @@
{include file="/shopro/common/script" /}
<div id="addEdit" class="common-word-form" v-cloak>
<el-container class="panel-block">
<el-main>
<el-scrollbar height="100%">
<el-form :model="form.model" :rules="form.rules" ref="formRef" label-width="100px">
<el-form-item label="客服分类" prop="room_id">
<el-cascader v-model="form.model.room_id" :options="chat.config.default_rooms" :props="{
label: 'name',
value: 'value',
checkStrictly: true,
emitPath: false,
}" clearable placeholder="请选择客服分类">
</el-cascader>
</el-form-item>
<el-form-item label="标题" prop="name">
<el-input class="sa-w-360" v-model="form.model.name" placeholder="请输入标题"></el-input>
</el-form-item>
<el-form-item label="问题内容" prop="content">
<form role="form">
<textarea id="commonWordContent" class="editor"></textarea>
</form>
</el-form-item>
<el-form-item label="权重">
<el-input class="sa-w-360" v-model="form.model.weigh" placeholder="请输入权重" type="number">
</el-input>
</el-form-item>
<el-form-item label="显示状态" prop="status">
<el-radio-group v-model="form.model.status">
<el-radio label="normal">正常</el-radio>
<el-radio label="hidden">隐藏</el-radio>
</el-radio-group>
</el-form-item>
</el-form>
</el-scrollbar>
</el-main>
<el-footer class="sa-footer--submit sa-flex sa-row-right">
<el-button type="primary" @click="onConfirm">确定</el-button>
</el-footer>
</el-container>
</div>

View File

@@ -0,0 +1,97 @@
{include file="/shopro/common/script" /}
<div id="index" class="common-word-index panel panel-default panel-intro" v-cloak>
<el-container class="panel-block">
<el-header class="sa-header">
<div class="sa-title sa-flex sa-row-between">
<div class="sa-title-left">
<div class="left-name">常用语</div>
<sa-filter-condition v-model="state.filter" @filter-delete="onChangeFilter">
</sa-filter-condition>
</div>
<div class="sa-title-right">
<el-button class="sa-button-refresh" icon="RefreshRight" @click="getData"></el-button>
<el-button class="sa-button-refresh" icon="Search" @click="onOpenFilter"></el-button>
{if $auth->check('shopro/chat/common_word/add')}
<el-button icon="Plus" type="primary" @click="onAdd">添加</el-button>
{/if}
</div>
</div>
</el-header>
<el-main class="sa-main">
<el-table height="100%" class="sa-table" :data="state.data" stripe @selection-change="onChangeSelection"
@sort-change="onChangeSort">
<el-table-column type="selection" width="48"></el-table-column>
<el-table-column prop="id" label="ID" min-width="90" sortable="custom"> </el-table-column>
<el-table-column label="标题" min-width="100">
<template #default="scope">
<div class="sa-table-line-1">
{{ scope.row.name || '-' }}
</div>
</template>
</el-table-column>
<el-table-column label="客服分类" min-width="100">
<template #default="scope">
<div class="sa-table-line-1">
{{ scope.row.room_name || '-' }}
</div>
</template>
</el-table-column>
<el-table-column label="状态" min-width="70">
<template #default="scope">
<el-tag :type="scope.row.status == 'normal' ? 'success' : 'info'">
{{ scope.row.status_text }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="权重" min-width="88">
<template #default="scope">
<div class="sa-table-line-1">{{ scope.row.weigh || 0 }}</div>
</template>
</el-table-column>
<el-table-column label="更新时间" width="172">
<template #default="scope">
{{ scope.row.updatetime || '-' }}
</template>
</el-table-column>
<el-table-column fixed="right" label="操作" min-width="120">
<template #default="scope">
{if $auth->check('shopro/chat/common_word/edit')}
<el-button type="primary" link @click="onEdit(scope.row.id)">编辑</el-button>
{/if}
<el-popconfirm width="fit-content" confirm-button-text="确认" cancel-button-text="取消"
title="确认删除这条记录?" @confirm="onDelete(scope.row.id)">
<template #reference>
{if $auth->check('shopro/chat/common_word/delete')}
<el-button type="danger" link>删除</el-button>
{/if}
</template>
</el-popconfirm>
</template>
</el-table-column>
</el-table>
</el-main>
<el-footer class="sa-footer sa-flex sa-row-between sa-flex-wrap">
<div class="sa-batch sa-flex">
<div class="tip">
已选择 <span>{{batchHandle.data.length}}</span></div>
<div class="sa-flex">
{if $auth->check('shopro/chat/common_word/delete')}
<el-button type="danger" :disabled="!batchHandle.data.length" @click="onBatchHandle('delete')">删除
</el-button>
{/if}
{if $auth->check('shopro/chat/common_word/edit')}
<el-button type="success" :disabled="!batchHandle.data.length" @click="onBatchHandle('normal')">正常
</el-button>
{/if}
{if $auth->check('shopro/chat/common_word/edit')}
<el-button type="info" :disabled="!batchHandle.data.length" @click="onBatchHandle('hidden')">隐藏
</el-button>
{/if}
</div>
</div>
<sa-pagination v-model="pagination" @pagination-change="getData"></sa-pagination>
</el-footer>
</el-container>
<sa-filter v-model="state.filter" @filter-change="onChangeFilter"></sa-filter>
</div>

View File

@@ -0,0 +1,42 @@
{include file="/shopro/common/script" /}
<div id="addEdit" class="customer-service-form" v-cloak>
<el-container class="panel-block">
<el-main>
<el-scrollbar height="100%">
<el-form :model="form.model" :rules="form.rules" ref="formRef" label-width="120px">
<el-form-item label="客服分类" prop="room_id">
<el-cascader class="sa-w-360" v-model="form.model.room_id" :options="chat.config.default_rooms" :props="{
label: 'name',
value: 'value',
checkStrictly: true,
emitPath: false,
}" clearable placeholder="请选择客服分类" @change="getCustomerServiceSelect">
</el-cascader>
</el-form-item>
<el-form-item v-if="form.model.room_id" label="所属管理员" prop="auth_id">
<el-cascader class="sa-w-360" v-model="form.model.auth_id" :options="customerService.select" :props="{
label: 'nickname',
value: 'id',
checkStrictly: true,
emitPath: false,
}" clearable placeholder="请选择所属管理员">
</el-cascader>
</el-form-item>
<el-form-item label="客服名称" prop="name">
<el-input class="sa-w-360" v-model="form.model.name" placeholder="请输入客服名称"></el-input>
</el-form-item>
<el-form-item label="客服头像" prop="avatar">
<sa-uploader v-model="form.model.avatar"></sa-uploader>
</el-form-item>
<el-form-item label="最优接待人数">
<el-input class="sa-w-360" v-model="form.model.max_num" placeholder="请输入最优接待人数" type="number"></el-input>
</el-form-item>
</el-form>
</el-scrollbar>
</el-main>
<el-footer class="sa-footer--submit sa-flex sa-row-right">
<el-button type="primary" @click="onConfirm">确定</el-button>
</el-footer>
</el-container>
</div>

View File

@@ -0,0 +1,108 @@
{include file="/shopro/common/script" /}
<div id="index" class="customer-service-index panel panel-default panel-intro" v-cloak>
<el-container class="panel-block">
<el-header class="sa-header">
<div class="sa-title sa-flex sa-row-between">
<div class="sa-title-left">
<div class="left-name">客服管理</div>
<sa-filter-condition v-model="state.filter" @filter-delete="onChangeFilter">
</sa-filter-condition>
</div>
<div class="sa-title-right">
<el-button class="sa-button-refresh" icon="RefreshRight" @click="getData"></el-button>
<el-button class="sa-button-refresh" icon="Search" @click="onOpenFilter"></el-button>
{if $auth->check('shopro/chat/customer_service/add')}
<el-button icon="Plus" type="primary" @click="onAdd">添加</el-button>
{/if}
</div>
</div>
</el-header>
<el-main class="sa-main">
<el-table height="100%" class="sa-table" :data="state.data" stripe @selection-change="onChangeSelection"
@sort-change="onChangeSort">
<el-table-column type="selection" width="48"></el-table-column>
<el-table-column prop="id" label="ID" min-width="90" sortable="custom"> </el-table-column>
<el-table-column label="客服名称" min-width="180">
<template #default="scope">
<div class="sa-flex">
<el-avatar class="mr-2" :size="32" :src="Fast.api.cdnurl(scope.row.avatar)">
<img src="/assets/addons/shopro/img/default-avatar.png" />
</el-avatar>
<div class="sa-table-line-1">
{{ scope.row.name || '-' }}
</div>
</div>
</template>
</el-table-column>
<el-table-column label="所属管理员" min-width="100">
<template #default="scope">
<div class="sa-table-line-1">
{{ scope.row.auth_model?.username || '-' }}
</div>
</template>
</el-table-column>
<el-table-column label="客服分类" min-width="100">
<template #default="scope">
<div class="sa-table-line-1">
{{ scope.row.room_name || '-' }}
</div>
</template>
</el-table-column>
<el-table-column label="最优接待人数" min-width="120">
<template #default="scope">
<div class="sa-table-line-1">
{{ scope.row.max_num || 0 }}
</div>
</template>
</el-table-column>
<el-table-column label="状态" min-width="70">
<template #default="scope">
<el-tag :type="scope.row.status == 'online' ? 'success' : 'info'">
{{ scope.row.status_text }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="上次服务时间" width="172">
<template #default="scope">
{{ scope.row.last_time || '-' }}
</template>
</el-table-column>
<el-table-column label="更新时间" width="172">
<template #default="scope">
{{ scope.row.updatetime || '-' }}
</template>
</el-table-column>
<el-table-column fixed="right" label="操作" min-width="120">
<template #default="scope">
{if $auth->check('shopro/chat/customer_service/edit')}
<el-button type="primary" link @click="onEdit(scope.row.id)">编辑</el-button>
{/if}
<el-popconfirm width="fit-content" confirm-button-text="确认" cancel-button-text="取消"
title="确认删除这条记录?" @confirm="onDelete(scope.row.id)">
<template #reference>
{if $auth->check('shopro/chat/customer_service/delete')}
<el-button type="danger" link>删除</el-button>
{/if}
</template>
</el-popconfirm>
</template>
</el-table-column>
</el-table>
</el-main>
<el-footer class="sa-footer sa-flex sa-row-between sa-flex-wrap">
<div class="sa-batch sa-flex">
<div class="tip">
已选择 <span>{{batchHandle.data.length}}</span></div>
<div class="sa-flex">
{if $auth->check('shopro/chat/customer_service/delete')}
<el-button type="danger" :disabled="!batchHandle.data.length" @click="onBatchHandle('delete')">删除
</el-button>
{/if}
</div>
</div>
<sa-pagination v-model="pagination" @pagination-change="getData"></sa-pagination>
</el-footer>
</el-container>
<sa-filter v-model="state.filter" @filter-change="onChangeFilter"></sa-filter>
</div>

View File

@@ -0,0 +1,42 @@
{include file="/shopro/common/script" /}
<div id="addEdit" class="question-form" v-cloak>
<el-container class="panel-block">
<el-main>
<el-scrollbar height="100%">
<el-form :model="form.model" :rules="form.rules" ref="formRef" label-width="100px">
<el-form-item label="客服分类" prop="room_id">
<el-cascader v-model="form.model.room_id" :options="chat.config.default_rooms" :props="{
label: 'name',
value: 'value',
checkStrictly: true,
emitPath: false,
}" clearable placeholder="请选择客服分类">
</el-cascader>
</el-form-item>
<el-form-item label="标题" prop="title">
<el-input class="sa-w-360" v-model="form.model.title" placeholder="请输入标题"></el-input>
</el-form-item>
<el-form-item label="问题内容" prop="content">
<form role="form">
<textarea id="questionContent" class="editor"></textarea>
</form>
</el-form-item>
<el-form-item label="权重">
<el-input class="sa-w-360" v-model="form.model.weigh" placeholder="请输入权重" type="number">
</el-input>
</el-form-item>
<el-form-item label="显示状态" prop="status">
<el-radio-group v-model="form.model.status">
<el-radio label="normal">正常</el-radio>
<el-radio label="hidden">隐藏</el-radio>
</el-radio-group>
</el-form-item>
</el-form>
</el-scrollbar>
</el-main>
<el-footer class="sa-footer--submit sa-flex sa-row-right">
<el-button type="primary" @click="onConfirm">确定</el-button>
</el-footer>
</el-container>
</div>

View File

@@ -0,0 +1,97 @@
{include file="/shopro/common/script" /}
<div id="index" class="question-index panel panel-default panel-intro" v-cloak>
<el-container class="panel-block">
<el-header class="sa-header">
<div class="sa-title sa-flex sa-row-between">
<div class="sa-title-left">
<div class="left-name">常见问题</div>
<sa-filter-condition v-model="state.filter" @filter-delete="onChangeFilter">
</sa-filter-condition>
</div>
<div class="sa-title-right">
<el-button class="sa-button-refresh" icon="RefreshRight" @click="getData"></el-button>
<el-button class="sa-button-refresh" icon="Search" @click="onOpenFilter"></el-button>
{if $auth->check('shopro/chat/question/add')}
<el-button icon="Plus" type="primary" @click="onAdd">添加</el-button>
{/if}
</div>
</div>
</el-header>
<el-main class="sa-main">
<el-table class="sa-table" height="100%" :data="state.data" stripe @selection-change="onChangeSelection"
@sort-change="onChangeSort">
<el-table-column type="selection" width="48"></el-table-column>
<el-table-column sortable="custom" prop="id" label="ID" min-width="90"> </el-table-column>
<el-table-column label="标题" min-width="100">
<template #default="scope">
<div class="sa-table-line-1">
{{ scope.row.title || '-' }}
</div>
</template>
</el-table-column>
<el-table-column label="客服分类" min-width="100">
<template #default="scope">
<div class="sa-table-line-1">
{{ scope.row.room_name || '-' }}
</div>
</template>
</el-table-column>
<el-table-column label="状态" min-width="70">
<template #default="scope">
<el-tag :type="scope.row.status == 'normal' ? 'success' : 'info'">
{{ scope.row.status_text }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="权重" min-width="88">
<template #default="scope">
<div class="sa-table-line-1">{{ scope.row.weigh || 0 }}</div>
</template>
</el-table-column>
<el-table-column label="更新时间" width="172">
<template #default="scope">
{{ scope.row.updatetime || '-' }}
</template>
</el-table-column>
<el-table-column fixed="right" label="操作" min-width="120">
<template #default="scope">
{if $auth->check('shopro/chat/question/edit')}
<el-button type="primary" link @click="onEdit(scope.row.id)">编辑</el-button>
{/if}
<el-popconfirm width="fit-content" confirm-button-text="确认" cancel-button-text="取消"
title="确认删除这条记录?" @confirm="onDelete(scope.row.id)">
<template #reference>
{if $auth->check('shopro/chat/question/delete')}
<el-button type="danger" link>删除</el-button>
{/if}
</template>
</el-popconfirm>
</template>
</el-table-column>
</el-table>
</el-main>
<el-footer class="sa-footer sa-flex sa-row-between sa-flex-wrap">
<div class="sa-batch sa-flex">
<div class="tip">
已选择 <span>{{batchHandle.data.length}}</span></div>
<div class="sa-flex">
{if $auth->check('shopro/chat/question/delete')}
<el-button type="danger" :disabled="!batchHandle.data.length" @click="onBatchHandle('delete')">删除
</el-button>
{/if}
{if $auth->check('shopro/chat/question/edit')}
<el-button type="success" :disabled="!batchHandle.data.length" @click="onBatchHandle('normal')">正常
</el-button>
{/if}
{if $auth->check('shopro/chat/question/edit')}
<el-button type="info" :disabled="!batchHandle.data.length" @click="onBatchHandle('hidden')">隐藏
</el-button>
{/if}
</div>
</div>
<sa-pagination v-model="pagination" @pagination-change="getData"></sa-pagination>
</el-footer>
</el-container>
<sa-filter v-model="state.filter" @filter-change="onChangeFilter"></sa-filter>
</div>

View File

@@ -0,0 +1,197 @@
{include file="/shopro/common/script" /}
<style>
.record-index .sa-title {
border-bottom: 1px solid var(--sa-table-header-bg);
}
.record-index .el-scrollbar {
padding: 20px;
}
.record-index .record-index-main {
--el-main-padding: 0;
}
.record-index .record-item {
margin-bottom: 20px;
align-items: flex-start;
}
.record-index .loading-status {
color: var(--el-color-info);
}
.record-index .center {
flex: 1;
display: flex;
flex-direction: column;
}
.record-index .record-item.sa-row-right .center {
align-items: flex-end;
}
.record-index .record-item.sa-row-left .center {
align-items: flex-start;
}
.record-index .record-message {
max-width: 50%;
padding: 8px;
font-size: 14px;
color: var(--sa-font);
white-space: normal;
word-break: break-all;
word-wrap: break-word;
}
.record-index .message-date {
color: var(--sa-subfont);
font-size: 12px;
}
.record-index .record-item.sa-row-right .record-message {
background: var(--t-bg-active);
border-radius: 4px 4px 0 4px;
}
.record-index .record-item.sa-row-left .record-message {
background: var(--sa-table-header-bg);
border-radius: 4px 4px 4px 0;
}
.record-index .record-emoji {
width: 24px;
height: 24px;
margin-right: 4px;
}
.record-index .record-emoji:last-of-type {
margin-right: 0;
}
.record-index img {
width: 100% !important;
}
.record-index .goods-item .goods-price {
color: var(--el-color-danger);
}
.record-index .order-sn {
font-size: 12px;
color: var(--el-color-primary);
}
.record-index .order-goods {
padding: 8px;
background: var(--sa-background-assist);
border-radius: 4px;
}
</style>
<div id="index" class="record-index" v-cloak>
<el-container class="panel-block">
<el-header>
<div class="sa-title sa-flex sa-row-between">
<div>{{ state.nickname }}</div>
<el-dropdown trigger="click" @command="onCommand">
<el-button class="sa-flex" link>
<div class="mr-2">{{ state.room_name }}</div>
<el-icon>
<arrow-down />
</el-icon>
</el-button>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item v-for="item in chat.config.default_rooms" :command="item.value">
{{ item.name }}
</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</div>
</el-header>
<el-main class="record-index-main">
<el-scrollbar height="100%">
<div class="loading-status sa-flex sa-row-center mb-2">
<button link v-show="state.data.length && pagination.lastPage > 1" @click="onLoadMore">
{{loadingMap[pagination.loadStatus].title}}
</button>
</div>
<template v-for="(item,index) in state.data">
<div class="sa-flex sa-row-center">
<div v-if="item.sender_identify == 'system'" class="message-system mb-4">
{{ item.content.text }}
</div>
<div v-if="showTime(item, index)" class="message-date mb-4">
{{ formatTime(item.createtime) }}
</div>
</div>
<div class="record-item sa-flex" :class="[
item.sender_identify == 'customer_service'
? 'sa-row-right'
: item.sender_identify == 'customer'
? 'sa-row-left'
: '',
]">
<el-avatar v-if="item.sender_identify == 'customer'" class="mr-2" :size="40"
:src="Fast.api.cdnurl(item.sender?.avatar)">
<img src="/assets/addons/shopro/img/default-avatar.png" />
</el-avatar>
<div class="center">
<div class="mb-1">{{item.sender?.nickname || item.sender?.name || item.sender_id}}</div>
<div class="record-message">
<!-- 文本 -->
<template v-if="item.message_type=='text'">
<div v-html="replaceEmoji(item.message)"></div>
</template>
<!-- 图片 -->
<template v-if="item.message_type=='image'">
<img :src="Fast.api.cdnurl(item.message)" />
</template>
<!-- 商品 -->
<template v-if="item.message_type=='goods'">
<div class="goods-item sa-flex">
<sa-image class="mr-2" :url="item.message.image" size="40"></sa-image>
<div>
<div class="sa-table-line-1">{{item.message.title}}</div>
<div class="goods-price">¥{{item.message.price.join(',')}}</div>
</div>
</div>
</template>
<!-- 订单 -->
<template v-if="item.message_type=='order'">
<div class="order-item">
<div class="order-sn mb-2">{{item.message.order_sn}}</div>
<div class="order-goods sa-flex">
<sa-image class="mr-2" :url="item.message.items[0]?.image" size="40">
</sa-image>
<div>
<div class="sa-table-line-1">{{item.message.items[0]?.goods_title}}
</div>
<div class="sa-flex sa-row-between">
<div class="order-goods-price">共{{item.message.items.length}}件商品
</div>
<div class="order-goods-total">合计 ¥{{item.message.pay_fee}}</div>
</div>
</div>
</div>
</div>
</template>
</div>
</div>
<el-avatar v-if="item.sender_identify== 'customer_service'" class="ml-2" :size="40"
:src="Fast.api.cdnurl(item.sender?.avatar)">
<img src="/assets/addons/shopro/img/default-avatar.png" />
</el-avatar>
</div>
</template>
</el-scrollbar>
</el-main>
</el-container>
</div>

View File

@@ -0,0 +1,109 @@
{include file="/shopro/common/script" /}
<style>
.user-index .auth-id {
color: var(--sa-subfont);
}
</style>
<div id="index" class="user-index panel panel-default panel-intro" v-cloak>
<el-container class="panel-block">
<el-header class="sa-header">
<div class="sa-title sa-flex sa-row-between">
<div class="sa-title-left">
<div class="left-name">会话管理</div>
<sa-filter-condition v-model="state.filter" @filter-delete="onChangeFilter">
</sa-filter-condition>
</div>
<div class="sa-title-right">
<el-button class="sa-button-refresh" icon="RefreshRight" @click="getData"></el-button>
<el-button class="sa-button-refresh" icon="Search" @click="onOpenFilter"></el-button>
</div>
</div>
</el-header>
<el-main class="sa-main">
<el-table height="100%" class="sa-table" :data="state.data" stripe @selection-change="onChangeSelection"
@sort-change="onChangeSort">
<el-table-column type="selection" width="48"></el-table-column>
<el-table-column prop="id" label="ID" min-width="90" sortable="custom"> </el-table-column>
<el-table-column label="用户信息" min-width="160">
<template #default="scope">
<div class="sa-flex sa-col-center">
<el-avatar class="mr-2" :size="32" :src="Fast.api.cdnurl(scope.row.avatar)">
<img src="/assets/addons/shopro/img/default-avatar.png" />
</el-avatar>
<div>
<div class="sa-table-line-1">
{{ scope.row.nickname || '-' }}
</div>
<div class="auth-id">
{{ scope.row.auth_id ? '用户' : '游客' }}
</div>
</div>
</div>
</template>
</el-table-column>
<el-table-column label="手机号" min-width="120">
<template #default="scope">
<div class="sa-table-line-1">
{{ scope.row.user?.mobile || '-' }}
</div>
</template>
</el-table-column>
<el-table-column label="最后会话客服" min-width="160">
<template #default="scope">
<div v-if="scope.row.customer_service" class="sa-flex sa-col-center">
<el-avatar class="mr-2" :size="32"
:src="Fast.api.cdnurl(scope.row.customer_service.avatar)">
<img src="/assets/addons/shopro/img/default-avatar.png" />
</el-avatar>
<div>
<div class="sa-table-line-1">
{{ scope.row.customer_service.name || '-' }}
</div>
<div class="auth-id">
{{ scope.row.customer_service.room_name }}
</div>
</div>
</div>
<div v-else>{{scope.row.customer_service_id}}</div>
</template>
</el-table-column>
<el-table-column label="最后会话时间" width="172">
<template #default="scope">
{{ scope.row.last_time || '-' }}
</template>
</el-table-column>
<el-table-column fixed="right" label="操作" min-width="120">
<template #default="scope">
{if $auth->check('shopro/chat/record/index')}
<el-button type="primary" link @click="onRecord(scope.row)">查看</el-button>
{/if}
<el-popconfirm width="fit-content" confirm-button-text="确认" cancel-button-text="取消"
title="此操作会删除当前会话所有聊天记录,是否确定?" @confirm="onDelete(scope.row.id)">
<template #reference>
{if $auth->check('shopro/chat/user/delete')}
<el-button type="danger" link>删除</el-button>
{/if}
</template>
</el-popconfirm>
</template>
</el-table-column>
</el-table>
</el-main>
<el-footer class="sa-footer sa-flex sa-row-between sa-flex-wrap">
<div class="sa-batch sa-flex">
<div class="tip">
已选择 <span>{{batchHandle.data.length}}</span></div>
<div class="sa-flex">
{if $auth->check('shopro/chat/user/delete')}
<el-button type="danger" :disabled="!batchHandle.data.length" @click="onBatchHandle('delete')">删除
</el-button>
{/if}
</div>
</div>
<sa-pagination v-model="pagination" @pagination-change="getData"></sa-pagination>
</el-footer>
</el-container>
<sa-filter v-model="state.filter" @filter-change="onChangeFilter"></sa-filter>
</div>

View File

@@ -0,0 +1,601 @@
{include file="/shopro/common/script" /}
<style>
.agent-detail .agent-detail-scrollbar>.el-scrollbar__wrap {
overflow-x: hidden;
}
.agent-detail .agent-detail-scrollbar>.el-scrollbar__bar.is-horizontal {
display: none;
}
.agent-detail .agent-content {
height: 450px;
line-height: 1;
padding: 20px;
background: var(--sa-table-header-bg);
border-radius: 8px;
margin: 0 0 20px;
}
.agent-detail .user-content .refresh {
line-height: 16px;
font-size: 12px;
font-weight: 400;
color: var(--sa-font);
cursor: pointer;
}
.agent-detail .user-content .refresh .el-icon {
font-size: 16px;
margin-right: 4px;
}
.agent-detail .user-content .nickname {
line-height: 22px;
font-size: 16px;
font-weight: 500;
color: var(--sa-subtitle);
}
.agent-detail .user-content .status {
font-size: 12px;
font-weight: 400;
color: #999999;
cursor: pointer;
}
.agent-content .el-form-item--small {
margin-bottom: 8px;
}
.agent-detail .user-content .commission-item {
width: 30%;
line-height: 18px;
font-size: 14px;
font-weight: 500;
}
.agent-detail .user-content .commission-item .title {
height: 24px;
line-height: 24px;
font-size: 12px;
font-weight: 400;
margin-bottom: 4px;
}
.agent-detail .apply-content .sa-image {
width: 140px;
height: 90px;
}
.agent-detail .dashboard-content {
height: fit-content;
}
.agent-detail .dashboard-content .title {
height: 18px;
line-height: 18px;
font-size: 14px;
font-weight: 500;
color: var(--sa-title);
margin-bottom: 16px;
}
.agent-detail .dashboard-content>.el-col {
border-bottom: 1px dashed var(--sa-border);
margin-bottom: 16px;
padding-bottom: 8px;
}
.agent-detail .dashboard-content>.el-col:last-of-type {
border-bottom: none;
margin-bottom: 0;
padding-bottom: 0;
}
.agent-detail .dashboard-content .item {
margin-bottom: 16px;
}
.agent-detail .dashboard-content .left {
line-height: 16px;
font-size: 12px;
font-weight: 400;
color: var(--sa-subfont);
margin-bottom: 8px;
display: flex;
align-items: center;
}
.agent-detail .dashboard-content .item {
line-height: 22px;
font-size: 18px;
font-weight: 500;
color: var(--sa-font);
}
.agent-detail .dashboard-content .unit {
font-size: 12px;
font-weight: 400;
color: var(--sa-font);
margin-left: 4px;
}
.agent-detail .rewards-item {
margin-right: 8px;
}
.agent-detail .rewards-item:last-of-type {
margin-right: 0;
}
</style>
<div id="detail" class="agent-detail panel panel-default panel-intro" v-cloak>
<el-container class="panel-block">
<el-main>
<el-scrollbar class="agent-detail-scrollbar" height="100%">
<el-row :gutter="20">
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
<div class="user-content agent-content">
<div class="title sa-flex sa-row-between">
<span>分销商信息</span>
<span class="refresh sa-flex" @click="getDetail">
<el-icon>
<refresh-right />
</el-icon>
刷新
</span>
</div>
<div v-if="state.data.user" class="sa-flex sa-row-center">
<sa-image :url="state.data.user.avatar" size="80" radius="40">
</sa-image>
</div>
<div class="nickname sa-flex sa-row-center mt-1">
{{
state.data.user
? state.data.user.nickname
: state.data.user_id
}}
</div>
<el-form size="small" label-position="right" label-width="76px">
<el-form-item label="分销商状态:">
<el-dropdown popper-class="agent-popover" trigger="click" @command="onChangeStatus">
<span class="status" :style="{
color: statusStyle[state.data.status]?.color,
}">
{{ state.data.status_text }}
<el-icon>
<arrow-down />
</el-icon>
</span>
<template #dropdown>
{if $auth->check('shopro/commission/agent/edit')}
<el-dropdown-menu>
<el-dropdown-item class="status" :style="{
color: value.color,
}" v-for="(value, key) in statusStyle" :key="key" :command="key">{{ value.label }}
</el-dropdown-item>
</el-dropdown-menu>
{/if}
</template>
</el-dropdown>
</el-form-item>
<el-form-item label="分销等级:">
<template v-if="state.data.level_info">
<div>{{ state.data.level_info.name }}</div>
<div>(等级{{ state.data.level_info.level }})</div>
</template>
<template v-if="!state.data.level_info">
{{ state.data.level }}
</template>
{if $auth->check('shopro/commission/agent/edit')}
<el-button class="ml-2" type="primary" link @click="onChangeLevel">更换</el-button>
{/if}
</el-form-item>
<el-form-item v-if="state.data.level_status > 0" label="待升级等级:">
<div v-if="state.data.level_status_info">
{{ state.data.level_status_info.name }}
</div>
<div>(等级{{ state.data.level_status || '-' }})</div>
{if $auth->check('shopro/commission/agent/edit')}
<el-button class="ml-2" type="primary" link
@click="onEdit({level_status: state.data.level_status})">同意</el-button>
<el-button type="danger" link @click="onEdit({level_status: 0})">拒绝</el-button>
{/if}
</el-form-item>
<el-form-item label="上级分销商:">
<sa-user-profile type="agent" :user="state.data.user?.parent_user"
:id="state.data.user?.parent_user_id" :isavatar="false"></sa-user-profile>
<el-button class="ml-2" type="primary" link @click="onChangeParentUser">更换
</el-button>
</el-form-item>
<el-form-item label="佣金比例:">
<div class="commission-item">
<div class="title">一级(自购)</div>
<div>
{{
state.data.level_info
? state.data.level_info.commission_rules.commission_1
: '0.00'
}}%
</div>
</div>
<div class="commission-item">
<div class="title">二级</div>
<div>
{{
state.data.level_info
? state.data.level_info.commission_rules.commission_2
: '0.00'
}}%
</div>
</div>
<div class="commission-item">
<div class="title">三级</div>
<div>
{{
state.data.level_info
? state.data.level_info.commission_rules.commission_3
: '0.00'
}}%
</div>
</div>
</el-form-item>
<el-form-item label="允许升级:">
{if $auth->check('shopro/commission/agent/edit')}
<el-switch v-model="state.data.upgrade_lock" :active-value="0" :inactive-value="1"
@change="state.data.user_id?onEdit({upgrade_lock: state.data.upgrade_lock}): ''">
</el-switch>
{/if}
</el-form-item>
</el-form>
</div>
</el-col>
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
<div class="apply-content agent-content">
<el-form size="small" label-position="right" label-width="76px">
<div class="title sa-flex sa-row-between mb-4">
<span>申请信息</span>
<div>
{if $auth->check('shopro/commission/agent/edit')}
<el-button v-if="!applyInfo.flag" type="primary" link
@click="applyInfo.flag = true">编辑</el-button>
<div v-if="applyInfo.flag" class="sa-flex">
<el-button type="danger" link @click="onCancelApplyInfo">
取消
</el-button>
<el-button type="primary" link @click="onSaveApplyInfo">保存
</el-button>
</div>
{/if}
</div>
</div>
<template v-for="(item, index) in applyInfo.data" :key="item">
<el-form-item :label="`${item.name}:`">
<div class="sa-flex sa-col-top">
<template v-if="item.type == 'text' || item.type == 'number'">
<el-input v-if="applyInfo.flag" class="sa-w-140" v-model="item.value">
</el-input>
<template v-if="!applyInfo.flag">
{{ item.value }}
</template>
</template>
<sa-image v-if="item.type == 'image'" :url="item.value"></sa-image>
<el-button v-if="applyInfo.flag" class="ml-2" type="danger" link
size="small" @click="onDeleteApplyInfo(index)">
删除
</el-button>
</div>
</el-form-item>
</template>
</el-form>
</div>
</el-col>
<el-col class="sa-col-24" :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
<el-row class="dashboard-content agent-content">
<el-col :span="24">
<div class="title sa-flex">
<span>团队统计</span>
{if $auth->check('shopro/commission/agent/team')}
<el-button class="ml-2" type="primary" link @click="onTeam">查看团队</el-button>
{/if}
</div>
<el-row>
<el-col class="item" :xs="12" :sm="8" :md="8" :lg="8" :xl="8">
<div class="left">团队人数:</div>
<div class="right">
{{ state.data.child_user_count_all }}
<span class="unit"></span>
</div>
</el-col>
<el-col class="item" :xs="12" :sm="8" :md="8" :lg="8" :xl="8">
<div class="left">一级团队人数:</div>
<div class="right">
{{ state.data.child_user_count_1 }}
<span class="unit"></span>
</div>
</el-col>
<el-col class="item" :xs="12" :sm="8" :md="8" :lg="8" :xl="8">
<div class="left">二级团队人数:</div>
<div class="right">
{{ state.data.child_user_count_2 }}
<span class="unit"></span>
</div>
</el-col>
<el-col class="item" :xs="12" :sm="8" :md="8" :lg="8" :xl="8">
<div class="left">
团队分销商人数:
<el-popover placement="top" trigger="hover">
<div v-for="(value, key) in state.data.child_agent_level_all"
:key="key">
等级{{ key }}{{ value }}人
</div>
<template #reference>
<div class="sa-flex">
<el-icon v-if="state.data.child_agent_count_all"
class="warning">
<Warning />
</el-icon>
</div>
</template>
</el-popover>
</div>
<div class="right">
{{ state.data.child_agent_count_all }}
<span class="unit"></span>
</div>
</el-col>
<el-col class="item" :xs="12" :sm="8" :md="8" :lg="8" :xl="8">
<div class="left">
一级分销商人数:
<el-popover placement="top" trigger="hover">
<div v-for="(value, key) in state.data.child_agent_level_1" :key="key">
等级{{ key }}{{ value }}人
</div>
<template #reference>
<div class="sa-flex">
<el-icon v-if="state.data.child_agent_count_1" class="warning">
<Warning />
</el-icon>
</div>
</template>
</el-popover>
</div>
<div class="right">
{{ state.data.child_agent_count_1 }}
<span class="unit"></span>
</div>
</el-col>
<el-col class="item" :xs="12" :sm="8" :md="8" :lg="8" :xl="8">
<div class="left">二级分销商人数:</div>
<div class="right">
{{ state.data.child_agent_count_2 }}
<span class="unit"></span>
</div>
</el-col>
</el-row>
</el-col>
<el-col :span="24">
<div class="title sa-flex">
<span>业绩统计</span>
</div>
<el-row>
<el-col class="item" :xs="12" :sm="6" :md="6" :lg="6" :xl="6">
<div class="left">团队分销总金额:</div>
<div class="right">
{{ state.data.child_order_money_all }}
<span class="unit"></span>
</div>
</el-col>
<el-col class="item" :xs="12" :sm="6" :md="6" :lg="6" :xl="6">
<div class="left">一级分销总金额:</div>
<div class="right">
{{ state.data.child_order_money_1 }}
<span class="unit"></span>
</div>
</el-col>
<el-col class="item" :xs="12" :sm="6" :md="6" :lg="6" :xl="6">
<div class="left">二级分销总金额:</div>
<div class="right">
{{ state.data.child_order_money_2 }}
<span class="unit"></span>
</div>
</el-col>
<el-col class="item" :xs="12" :sm="6" :md="6" :lg="6" :xl="6">
<div class="left">
自购分销总金额:
<el-popover popper-class="sa-popper" placement="top" trigger="hover"
content="分销商自购分销商品金额统计">
<template #reference>
<div class="sa-flex">
<el-icon class="warning">
<Warning />
</el-icon>
</div>
</template>
</el-popover>
</div>
<div class="right">
{{ state.data.child_order_money_0 }}
<span class="unit"></span>
</div>
</el-col>
<el-col class="item" :xs="12" :sm="6" :md="6" :lg="6" :xl="6">
<div class="left">团队分销订单:</div>
<div class="right">
{{ state.data.child_order_count_all }}
<span class="unit"></span>
</div>
</el-col>
<el-col class="item" :xs="12" :sm="6" :md="6" :lg="6" :xl="6">
<div class="left">一级分销订单:</div>
<div class="right">
{{ state.data.child_order_count_1 }}
<span class="unit"></span>
</div>
</el-col>
<el-col class="item" :xs="12" :sm="6" :md="6" :lg="6" :xl="6">
<div class="left">二级分销订单:</div>
<div class="right">
{{ state.data.child_order_count_2 }}
<span class="unit"></span>
</div>
</el-col>
<el-col class="item" :xs="12" :sm="6" :md="6" :lg="6" :xl="6">
<div class="left">
自购分销订单:
<el-popover popper-class="sa-popper" placement="top" trigger="hover"
content="分销商自购分销订单数量统计">
<template #reference>
<div class="sa-flex">
<el-icon class="warning">
<Warning />
</el-icon>
</div>
</template>
</el-popover>
</div>
<div class="right">
{{ state.data.child_order_count_0 }}
<span class="unit"></span>
</div>
</el-col>
</el-row>
</el-col>
<el-col :span="24">
<div class="title sa-flex">
<span>资产信息</span>
</div>
<el-row>
<el-col class="item" :xs="12" :sm="8" :md="8" :lg="8" :xl="8">
<div class="left">累计佣金:</div>
<div class="right">
{{ state.data.total_income }}
<span class="unit"></span>
</div>
</el-col>
<el-col class="item" :xs="12" :sm="8" :md="8" :lg="8" :xl="8">
<div class="left">待入账佣金:</div>
<div class="right">
{{ state.data.pending_reward }}
<span class="unit"></span>
</div>
</el-col>
<el-col class="item" :xs="12" :sm="8" :md="8" :lg="8" :xl="8">
<div class="left">消费金额:</div>
<div class="right">
{{ state.data.user?.total_consume || 0 }}
<span class="unit"></span>
</div>
</el-col>
</el-row>
</el-col>
</el-row>
</el-col>
</el-row>
<el-tabs class="sa-tabs" v-model="log.tabActive" @tab-change="onChangeTab">
<el-tab-pane label="分销动态" name="log"></el-tab-pane>
<el-tab-pane label="分销订单" name="order"></el-tab-pane>
<el-tab-pane label="佣金明细" name="reward"></el-tab-pane>
</el-tab-pane>
</el-tabs>
<el-table v-if="log.tabActive=='log'" class="sa-table" :data="log.data" stripe>
<el-table-column prop="id" label="ID" min-width="90"></el-table-column>
<el-table-column label="分销商" min-width="160">
<template #default="scope">
<sa-user-profile :user="scope.row.agent" :id="scope.row.agent_id"></sa-user-profile>
</template>
</el-table-column>
<el-table-column prop="remark" label="内容" min-width="300"></el-table-column>
<el-table-column label="操作人" min-width="160">
<template #default="scope">
<sa-user-profile type="oper" :user="scope.row.oper" :id="scope.row.oper_id">
</sa-user-profile>
</template>
</el-table-column>
<el-table-column prop="createtime" label="动态时间" width="172"></el-table-column>
</el-table>
<el-table v-if="log.tabActive=='order'" class="sa-table" :data="log.data" stripe>
<el-table-column prop="id" label="ID" min-width="90"></el-table-column>
<el-table-column label="订单号" min-width="260">
<template #default="scope">
{{ scope.row.order?.order_sn || scope.row.order_id }}
</template>
</el-table-column>
<el-table-column label="下单用户" min-width="160">
<template #default="scope">
<sa-user-profile :user="scope.row.buyer" :id="scope.row.buyer_id"></sa-user-profile>
</template>
</el-table-column>
<el-table-column label="分佣状态" min-width="100">
<template #default="scope">
<span :class="`sa-color--${log.status[scope.row.commission_reward_status]}`">
{{ scope.row.commission_reward_status_text }}
</span>
</template>
</el-table-column>
<el-table-column label="商品结算金额" min-width="160">
<template #default="scope"> {{ scope.row.amount }}元 </template>
</el-table-column>
<el-table-column label="分销总金额/到账金额" min-width="160">
<template #default="scope">
{{ countCommission(scope.row.rewards) }}
</template>
</el-table-column>
<el-table-column label="佣金详情" min-width="200" align="center">
<template #default="scope">
<div class="sa-flex sa-row-center">
<div class="rewards-item sa-flex sa-flex-col" v-for="rewards in scope.row.rewards"
:key="rewards">
<template v-if="rewards.agent">
<sa-image :url="rewards.agent.avatar" size="32" radius="16"></sa-image>
</template>
<template v-if="!rewards.agent">
{{ rewards.agent_id }}
</template>
<div class="commission sa-m-t-6">{{ rewards.commission }}元</div>
</div>
</div>
</template>
</el-table-column>
<el-table-column prop="commission_time" label="加入时间" width="172"></el-table-column>
</el-table>
<el-table v-if="log.tabActive=='reward'" class="sa-table" :data="log.data" stripe>
<el-table-column prop="id" label="ID" min-width="90"></el-table-column>
<el-table-column label="订单号" min-width="260">
<template #default="scope">
{{ scope.row.order?.order_sn || scope.row.order_id }}
</template>
</el-table-column>
<el-table-column label="下单用户" min-width="160">
<template #default="scope">
<sa-user-profile :user="scope.row.buyer" :id="scope.row.buyer_id"></sa-user-profile>
</template>
</el-table-column>
<el-table-column label="分销用户" min-width="160">
<template #default="scope">
<sa-user-profile :user="scope.row.agent" :id="scope.row.agent_id"></sa-user-profile>
</template>
</el-table-column>
<el-table-column label="分销金额" min-width="160">
<template #default="scope"> {{ scope.row.commission }}元 </template>
</el-table-column>
<el-table-column label="入账状态" min-width="80">
<template #default="scope">
<span :class="`sa-color--${log.status[scope.row.status]}`">
{{ scope.row.status_text }}
</span>
</template>
</el-table-column>
<el-table-column prop="type_text" label="入账方式" min-width="80"></el-table-column>
<el-table-column prop="commission_time" label="分佣时间" width="172"></el-table-column>
</el-table>
<el-footer class="sa-footer sa-flex sa-row-right">
<sa-pagination v-model="pagination" @pagination-change="getLog"></sa-pagination>
</el-footer>
</el-scrollbar>
</el-main>
</el-container>
</div>

View File

@@ -0,0 +1,204 @@
{include file="/shopro/common/script" /}
<style>
.agent-index .status-text {
margin-right: 12px;
}
</style>
<div id="index" class="agent-index panel panel-default panel-intro" v-cloak>
<el-container class="panel-block">
<el-header class="sa-header">
<el-tabs class="sa-tabs" v-model="state.filter.data.tabActive" @tab-change="onChangeTab">
<el-tab-pane v-for="item in type.data.status" :key="item" :label="item.name" :name="item.type">
</el-tab-pane>
</el-tabs>
<div class="sa-title sa-flex sa-row-between">
<div class="sa-title-left">
<div class="left-name">分销商</div>
<sa-filter-condition v-model="state.filter" @filter-delete="onChangeFilter">
</sa-filter-condition>
</div>
<div class="sa-title-right">
<el-button class="sa-button-refresh" icon="RefreshRight" @click="getData"></el-button>
<el-button class="sa-button-refresh" icon="Search" @click="onOpenFilter"></el-button>
</div>
</div>
</el-header>
<el-main class="sa-main">
<el-table v-if="state.filter.data.tabActive=='all'" height="100%" class="sa-table" :data="state.data"
stripe>
<el-table-column prop="user_id" label="ID" min-width="90">
</el-table-column>
<el-table-column label="分销商信息" min-width="150">
<template #default="scope">
<sa-user-profile :user="scope.row.user" :id="scope.row.user_id"></sa-user-profile>
</template>
</el-table-column>
<el-table-column label="等级" min-width="120">
<template #default="scope">
<template v-if="scope.row.level_info">
<div>{{ scope.row.level_info.name }}</div>
<div>(等级{{ scope.row.level_info.level }})</div>
</template>
<template v-else>{{ scope.row.level }}</template>
</template>
</el-table-column>
<el-table-column label="累计佣金" min-width="120">
<template #default="scope"> {{ scope.row.total_income }}元 </template>
</el-table-column>
<el-table-column label="消费金额" min-width="120">
<template #default="scope"> {{ scope.row.user?.total_consume || 0 }}元 </template>
</el-table-column>
<el-table-column label="自购分销业绩" min-width="120">
<template #default="scope">
<div>{{ scope.row.child_order_count_0 }}单</div>
<div>{{ scope.row.child_order_money_0 }}元</div>
</template>
</el-table-column>
<el-table-column label="上级分销商" min-width="120" align="center">
<template #default="scope">
<sa-user-profile type="agent" :user="scope.row.user?.parent_user"
:id="scope.row.user?.parent_user_id" mode="col"></sa-user-profile>
</template>
</el-table-column>
<el-table-column label="一级用户人数" min-width="120">
<template #default="scope"> {{ scope.row.child_user_count_1 }}人 </template>
</el-table-column>
<el-table-column label="一级分销商人数" min-width="160">
<template #default="scope">
<div>{{ scope.row.child_agent_count_1 }}人</div>
</template>
</el-table-column>
<el-table-column prop="createtime" label="创建时间" width="172"></el-table-column>
<el-table-column label="操作" min-width="140" fixed="right">
<template #default="scope">
<div class="sa-flex">
<span class="mr-2" :style="{
color: statusStyle[scope.row.status]?.color,
}">
{{ scope.row.status_text }}
</span>
{if $auth->check('shopro/commission/agent/detail')}
<el-button type="primary" link @click="onDetail(scope.row.user_id)">查看</el-button>
{/if}
</div>
</template>
</el-table-column>
</el-table>
<el-table v-if="state.filter.data.tabActive=='pending'" height="100%" class="sa-table" :data="state.data"
stripe>
<el-table-column prop="user_id" label="ID" min-width="90">
</el-table-column>
<el-table-column label="分销商信息" min-width="150">
<template #default="scope">
<sa-user-profile :user="scope.row.user" :id="scope.row.user_id" />
</template>
</el-table-column>
<el-table-column label="等级" min-width="120">
<template #default="scope">
<template v-if="scope.row.level_info">
<div>{{ scope.row.level_info.name }}</div>
<div>(等级{{ scope.row.level_info.level }})</div>
</template>
<template v-else>{{ scope.row.level }}</template>
</template>
</el-table-column>
<el-table-column label="上级分销商" min-width="120" align="center">
<template #default="scope">
<sa-user-profile type="agent" :user="scope.row.user?.parent_user"
:id="scope.row.user?.parent_user_id" mode="col" />
</template>
</el-table-column>
<el-table-column label="消费金额" min-width="120">
<template #default="scope"> {{ scope.row.user?.total_consume || 0 }}元 </template>
</el-table-column>
<el-table-column label="推广人数" min-width="120">
<template #default="scope"> {{ scope.row.child_user_count_1 }}人 </template>
</el-table-column>
<el-table-column label="提交次数" min-width="120">
<template #default="scope"> {{ scope.row.apply_num }}次</template>
</el-table-column>
<el-table-column prop="createtime" label="创建时间" min-width="172"></el-table-column>
<el-table-column label="操作" min-width="160" fixed="right">
<template #default="scope">
<div class="sa-flex">
{if $auth->check('shopro/commission/agent/edit')}
<el-button type="success" link @click="onEdit(scope.row.user_id, {status:'normal'})">
同意
</el-button>
{/if}
{if $auth->check('shopro/commission/agent/edit')}
<el-button type="warning" link @click="onEdit(scope.row.user_id,{status:'reject'} )">
驳回
</el-button>
{/if}
{if $auth->check('shopro/commission/agent/detail')}
<el-button type="primary" link @click="onDetail(scope.row.user_id)">查看</el-button>
{/if}
</div>
</template>
</el-table-column>
</el-table>
<el-table v-if="state.filter.data.tabActive==0" height="100%" class="sa-table" :data="state.data" stripe>
<el-table-column prop="user_id" label="ID" min-width="90"></el-table-column>
<el-table-column label="分销商信息" min-width="150">
<template #default="scope">
<sa-user-profile :user="scope.row.user" :id="scope.row.user_id" />
</template>
</el-table-column>
<el-table-column label="等级" min-width="120">
<template #default="scope">
<template v-if="scope.row.level_info">
<div>{{ scope.row.level_info.name }}</div>
<div>(等级{{ scope.row.level_info.level }})</div>
</template>
<template v-else>{{ scope.row.level }}</template>
</template>
</el-table-column>
<el-table-column label="消费金额" min-width="120">
<template #default="scope"> {{ scope.row.user?.total_consume || 0 }}元 </template>
</el-table-column>
<el-table-column label="推广人数" min-width="120">
<template #default="scope"> {{ scope.row.child_user_count_1 }}人 </template>
</el-table-column>
<el-table-column label="升级之后的等级" min-width="200">
<template #default="scope">
<div v-if="scope.row.level_status_info">
{{ scope.row.level_status_info.name }}
</div>
<div>等级{{ scope.row.level_status }}</div>
</template>
</el-table-column>
<el-table-column prop="createtime" label="创建时间" min-width="172"></el-table-column>
<el-table-column label="操作" min-width="200" fixed="right">
<template #default="scope">
<div class="sa-flex">
<span class="sa-color--info mr-2" v-if="!scope.row.level_status_info">
未找到等级
</span>
<template v-if="scope.row.level_status_info">
{if $auth->check('shopro/commission/agent/edit')}
<el-button type="success" link
@click=" onEdit(scope.row.user_id, {level_status: scope.row.level_status})">
同意
</el-button>
<el-button type="danger" link @click="onEdit(scope.row.user_id, { level_status: 0 })">
拒绝
</el-button>
{/if}
</template>
{if $auth->check('shopro/commission/agent/detail')}
<el-button type="primary" link @click="onDetail(scope.row.user_id)">查看</el-button>
{/if}
</div>
</template>
</el-table-column>
</el-table>
</el-main>
<el-footer class="sa-footer sa-flex sa-row-right">
<sa-pagination v-model="pagination" @pagination-change="getData"></sa-pagination>
</el-footer>
</el-container>
<sa-filter v-model="state.filter" @filter-change="onChangeFilter"></sa-filter>
</div>

View File

@@ -0,0 +1,81 @@
{include file="/shopro/common/script" /}
<style>
.agent-select .filter-item {
width: 330px;
}
.agent-select .filter-item .el-select {
width: 110px;
}
</style>
<div id="select" class="agent-select" v-cloak>
<el-container class="panel-block">
<el-header class="sa-header">
<el-alert class="mt-4">
<template #title>
温馨提示:更换上级推荐人之后,该用户之后的所有团队和业绩将移至新的推荐人名下
</template>
</el-alert>
<div class="sa-flex sa-flex-wrap sa-row-between mt-4">
<div class="sa-flex">
当前推荐人:
<sa-user-profile type="agent" :user="state.userDetail.parent_user"
:id="state.userDetail?.parent_user_id" :isHover="false"></sa-user-profile>
</div>
<el-input class="filter-item" v-model="state.filter.data.user.value" placeholder="请输入查询内容">
<template #prepend>
<el-select v-model="state.filter.data.user.field">
<el-option label="分销商ID" value="user_id"></el-option>
<el-option label="分销商昵称" value="user.nickname"></el-option>
<el-option label="分销商手机号" value="user.mobile"></el-option>
</el-select>
</template>
<template #append>
<button @click="getData">搜索</button>
</template>
</el-input>
</div>
</el-header>
<el-main>
<el-table height="100%" class="sa-table" :data="state.data" stripe>
<el-table-column prop="user_id" label="ID" min-width="90"></el-table-column>
<el-table-column label="分销商信息" min-width="150">
<template #default="scope">
<sa-user-profile :user="scope.row.user" :id="scope.row.user_id" :isHover="false" />
</template>
</el-table-column>
<el-table-column label="等级" min-width="150" align="center">
<template #default="scope">
<template v-if="scope.row.level_info">
{{ scope.row.level_info.name }}
(等级{{ scope.row.level_info.level }})
</template>
<template v-else>{{ scope.row.level }}</template>
</template>
</el-table-column>
<el-table-column label="手机号" min-width="120" align="center">
<template #default="scope">
{{ scope.row.user ? scope.row.user.mobile : '-' }}
</template>
</el-table-column>
<el-table-column label="操作" min-width="80" fixed="right">
<template #default="scope">
<span v-if="scope.row.user_id == state.parent_user_id" class="status"> 已选择 </span>
<el-button v-else class="is-link" type="primary" @click="onSelect(scope.row)">选择</el-button>
</template>
</el-table-column>
</el-table>
</el-main>
<el-footer class="sa-flex sa-row-between">
<el-checkbox v-model="state.parent_user_id" :true-label="0" :false-label="-1">设为平台直推</el-checkbox>
<sa-pagination class="is-ellipsis" v-model="pagination" @pagination-change="getData"></sa-pagination>
</el-footer>
<el-footer class="sa-footer--submit sa-flex sa-row-right">
<!-- {if $auth->check('shopro/commission/agent/changeParentUser')} -->
<el-button type="primary" @click="onConfirm">确定</el-button>
<!-- {/if} -->
</el-footer>
</el-container>
</div>

View File

@@ -0,0 +1,159 @@
{include file="/shopro/common/script" /}
<div id="team" class="agent-team" v-cloak>
<el-container class="panel-block">
<el-header class="sa-header sa-flex sa-flex-wrap mt-4">
<template v-if="state.data.user?.parent_user">
推荐人:
<sa-user-profile class="cursor-pointer" type="agent" :user="state.data.user?.parent_user" :id="state.data.user?.parent_user_id"
:isHover="false" @click="getTeam(state.data.user.parent_user_id)"></sa-user-profile>
</template>
</el-header>
<el-main>
<el-table class="sa-table mb-4" :data="[state.data]">
<el-table-column prop="user_id" label="ID" min-width="90"></el-table-column>
<el-table-column label="当前用户" min-width="150">
<template #default="scope">
<sa-user-profile :user="scope.row.user" :id="scope.row.user_id" :isHover="false">
</sa-user-profile>
</template>
</el-table-column>
<el-table-column label="等级" min-width="150">
<template #default="scope">
<div v-if="scope.row.level_info" class="sa-flex">
<sa-image :url="scope.row.level_info.image" size="32"></sa-image>
<span class="ml-2">{{ scope.row.level_info.name }}</span>
</div>
<template v-else>{{ scope.row.level }}</template>
</template>
</el-table-column>
<el-table-column label="状态" min-width="120" align="center">
<template #default="scope">
<span :style="{ color: statusStyle[scope.row.status]?.color }">
{{ scope.row.status_text }}
</span>
</template>
</el-table-column>
<el-table-column label="团队人数/分销商人数" min-width="160" align="center">
<template #default="scope">
{{ scope.row.child_user_count_all }}人/ {{ scope.row.child_agent_count_all }}人
</template>
</el-table-column>
<el-table-column label="一级团队人数/一级分销商人数" min-width="220" align="center">
<template #default="scope">
{{ scope.row.child_user_count_1 }}人/ {{ scope.row.child_agent_count_1 }}人
</template>
</el-table-column>
<el-table-column label="二级团队人数/二级分销商人数" min-width="220" align="center">
<template #default="scope">
{{ scope.row.child_user_count_2 }}人/ {{ scope.row.child_agent_count_2 }}人
</template>
</el-table-column>
<el-table-column label="团队分销总额/团队分销订单" min-width="220" align="center">
<template #default="scope">
{{ scope.row.child_order_money_all }}元/ {{ scope.row.child_order_count_all }}单
</template>
</el-table-column>
<el-table-column label="一级分销总额/一级分销订单" min-width="220" align="center">
<template #default="scope">
{{ scope.row.child_order_money_1 }}元/ {{ scope.row.child_order_count_1 }}单
</template>
</el-table-column>
<el-table-column label="二级分销总额/二级分销订单" min-width="220" align="center">
<template #default="scope">
{{ scope.row.child_order_money_2 }}元/ {{ scope.row.child_order_count_2 }}单
</template>
</el-table-column>
<el-table-column label="自购分销总金额/订单数" min-width="220" align="center">
<template #default="scope">
{{ scope.row.child_order_money_0 }}元/ {{ scope.row.child_order_count_0 }}单
</template>
</el-table-column>
<el-table-column label="累计佣金" min-width="160" align="center">
<template #default="scope"> {{ scope.row.total_income }}元 </template>
</el-table-column>
<el-table-column label="消费金额" min-width="160" align="center">
<template #default="scope"> {{ scope.row.user?.total_consume || 0 }}元 </template>
</el-table-column>
<el-table-column label="待入账佣金" min-width="160" align="center">
<template #default="scope"> {{ scope.row.pending_reward }}元 </template>
</el-table-column>
<el-table-column label="加入时间" min-width="172" align="center">
<template #default="scope"> {{ scope.row.createtime }} </template>
</el-table-column>
</el-table>
<el-table class="sa-table" :data="state.data.agent_team">
<el-table-column prop="user_id" label="ID" min-width="90"></el-table-column>
<el-table-column label="团队用户" min-width="150">
<template #default="scope">
<sa-user-profile class="cursor-pointer" :user="scope.row.user" :id="scope.row.user_id" :isHover="false" @click="getTeam(scope.row.user_id)">
</sa-user-profile>
</template>
</el-table-column>
<el-table-column label="等级" min-width="150">
<template #default="scope">
<div v-if="scope.row.level_info" class="sa-flex">
<sa-image :url="scope.row.level_info.image" size="32"></sa-image>
<span class="ml-2">{{ scope.row.level_info.name }}</span>
</div>
<template v-else>{{ scope.row.level }}</template>
</template>
</el-table-column>
<el-table-column label="状态" min-width="120" align="center">
<template #default="scope">
<span :style="{ color: statusStyle[scope.row.status]?.color }">
{{ scope.row.status_text }}
</span>
</template>
</el-table-column>
<el-table-column label="团队人数/分销商人数" min-width="160" align="center">
<template #default="scope">
{{ scope.row.child_user_count_all }}人/ {{ scope.row.child_agent_count_all }}人
</template>
</el-table-column>
<el-table-column label="一级团队人数/一级分销商人数" min-width="220" align="center">
<template #default="scope">
{{ scope.row.child_user_count_1 }}人/ {{ scope.row.child_agent_count_1 }}人
</template>
</el-table-column>
<el-table-column label="二级团队人数/二级分销商人数" min-width="220" align="center">
<template #default="scope">
{{ scope.row.child_user_count_2 }}人/ {{ scope.row.child_agent_count_2 }}人
</template>
</el-table-column>
<el-table-column label="团队分销总额/团队分销订单" min-width="220" align="center">
<template #default="scope">
{{ scope.row.child_order_money_all }}元/ {{ scope.row.child_order_count_all }}单
</template>
</el-table-column>
<el-table-column label="一级分销总额/一级分销订单" min-width="220" align="center">
<template #default="scope">
{{ scope.row.child_order_money_1 }}元/ {{ scope.row.child_order_count_1 }}单
</template>
</el-table-column>
<el-table-column label="二级分销总额/二级分销订单" min-width="220" align="center">
<template #default="scope">
{{ scope.row.child_order_money_2 }}元/ {{ scope.row.child_order_count_2 }}单
</template>
</el-table-column>
<el-table-column label="自购分销总金额/订单数" min-width="220" align="center">
<template #default="scope">
{{ scope.row.child_order_money_0 }}元/ {{ scope.row.child_order_count_0 }}单
</template>
</el-table-column>
<el-table-column label="累计佣金" min-width="160" align="center">
<template #default="scope"> {{ scope.row.total_income }}元 </template>
</el-table-column>
<el-table-column label="消费金额" min-width="160" align="center">
<template #default="scope"> {{ scope.row.user?.total_consume || 0 }}元 </template>
</el-table-column>
<el-table-column label="待入账佣金" min-width="160" align="center">
<template #default="scope"> {{ scope.row.pending_reward }}元 </template>
</el-table-column>
<el-table-column label="加入时间" min-width="172" align="center">
<template #default="scope"> {{ scope.row.createtime }} </template>
</el-table-column>
</el-table>
</el-main>
</el-container>
</div>

View File

@@ -0,0 +1,353 @@
{include file="/shopro/common/script" /}
<style>
.goods-form .sa-title.is-line {
margin-bottom: 16px;
}
.goods-form .goods-item {
margin-bottom: 16px;
}
.goods-form .goods-item .goods-title {
height: 16px;
line-height: 16px;
font-size: 14px;
font-weight: 500;
color: var(--sa-font);
margin-bottom: 8px;
}
.goods-form .goods-item .goods-sku {
width: fit-content;
height: 18px;
line-height: 18px;
background: var(--el-color-primary);
border-radius: 10px;
padding: 0 8px;
font-size: 12px;
color: var(--sa-background-assist);
}
.goods-form .commission-table {
overflow: hidden;
overflow-x: auto;
}
.goods-form .commission-table .commission-header {
border-left: 1px solid var(--sa-border);
}
.goods-form .commission-table .commission-header .col-item {
padding: 0 12px;
height: 40px;
line-height: 40px;
background: var(--sa-table-header-bg);
border-top: 1px solid var(--sa-border);
}
.goods-form .commission-table .commission-content {
border-left: 1px solid var(--sa-border);
}
.goods-form .commission-table .col-item {
width: 150px;
min-width: 150px;
padding: 0 12px;
height: 48px;
line-height: 48px;
display: flex;
align-items: center;
justify-content: center;
border-right: 1px solid var(--sa-border);
border-bottom: 1px solid var(--sa-border);
}
.goods-form .commission-table .col-item .el-input {
margin-right: 12px;
}
.goods-form .commission-table .col-item .el-input:last-of-type {
margin-right: 0;
}
.goods-form .commission-table .col-item.commission-item {
width: 240px;
min-width: 240px;
}
.goods-form .batch-edit {
color: var(--el-color-primary);
margin-left: 8px;
}
.commission-popover .commission-item {
margin-bottom: 12px;
}
.commission-popover .commission-item .el-input {
margin-right: 12px;
}
.commission-popover .commission-item .el-input:last-of-type {
margin-right: 0;
}
</style>
<div id="addEdit" class="goods-form" v-cloak>
<el-container class="panel-block">
<el-main>
<el-scrollbar height="100%">
<div class="sa-title is-line">商品信息</div>
<div v-for="goods in state.data?.goods" :key="goods">
<div class="goods-item sa-flex sa-col-top">
<sa-image class="mr-2" :url="goods.image" size="48"></sa-image>
<div>
<div class="goods-title sa-table-line-1">
{{ goods.title }}
</div>
<div v-if="goods.is_sku" class="goods-sku">
{{ goods.is_sku ? '多规格' : '' }}
</div>
</div>
</div>
</div>
<div class="sa-title is-line">佣金设置</div>
<el-form label-width="120px">
<el-form-item label="是否参与">
<el-radio-group v-model="state.commission_goods.status">
<el-radio :label="0">不参与</el-radio>
<el-radio :label="1">参与</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="分销商业绩">
<el-radio-group v-model="state.commission_goods.commission_order_status">
<el-radio :label="0">不计入</el-radio>
<el-radio :label="1">
<span class="sa-flex">
计入
<el-popover placement="top" :width="310" content="关闭则只分佣,不计入分销订单金额和订单数">
<template #reference>
<el-icon class="warning sa-m-l-8">
<warning />
</el-icon>
</template>
</el-popover>
</span>
</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="佣金规则">
<el-radio-group v-model="state.commission_goods.self_rules" @change="onChangeSelfRules">
<el-radio :label="0">默认规则</el-radio>
<el-radio :label="1" v-if="state.rulesType != 'batch'">独立规则</el-radio>
<el-radio :label="2">批量规则</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item
v-if="state.commission_goods.self_rules == 1 || state.commission_goods.self_rules == 2"
label="分销设置">
<el-switch v-model="state.commission_config_temp.status"
@change="onChangeCommissionConfigStatus" :active-value="1" :inactive-value="0" />
<span class="sa-m-l-8">
{{ state.commission_config_temp.status ? '自定义' : '默认' }}
</span>
</el-form-item>
<el-form-item label="分销层级">
<el-radio-group v-model="state.commission_config_temp.level"
:disabled="state.commission_config_temp.status == 0">
<el-radio :label="1">一级</el-radio>
<el-radio :label="2">二级</el-radio>
<el-radio :label="3">三级</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="分销自购">
<div>
<el-radio-group v-model="state.commission_config_temp.self_buy"
:disabled="state.commission_config_temp.status == 0">
<el-radio :label="0">关闭</el-radio>
<el-radio :label="1">开启</el-radio>
</el-radio-group>
<div class="tip"> 分销自购开启后,分销商自己购买时,下单可以给自己返佣 </div>
</div>
</el-form-item>
<el-form-item label="商品结算方式">
<div>
<el-radio-group v-model="state.commission_config_temp.reward_type"
:disabled="state.commission_config_temp.status == 0">
<el-radio label="goods_price">商品价</el-radio>
<el-radio label="pay_price">实际支付价</el-radio>
</el-radio-group>
<div class="tip">
商品价: 商品实际售价/规格价,实际支付价:实际支付的费用(不含运费)
</div>
</div>
</el-form-item>
<el-form-item label="佣金结算方式">
<el-radio-group v-model="state.commission_config_temp.reward_event"
:disabled="state.commission_config_temp.status == 0">
<el-radio label="paid">支付后结算</el-radio>
<el-radio label="confirm">确认收货结算</el-radio>
<el-radio label="finish">订单完成结算</el-radio>
<el-radio label="admin">手动打款</el-radio>
</el-radio-group>
</el-form-item>
<div class="commission-table">
<template v-if="state.commission_goods.self_rules == 0">
<div class="commission-header sa-flex">
<div class="col-item">分销等级名称</div>
<template v-for="commission in state.commission_config_temp.level" :key="commission">
<div v-if="commission == 1" class="col-item commission-item">
一级(自购)佣金比例
</div>
<div v-if="commission == 2" class="col-item commission-item"> 二级佣金比例 </div>
<div v-if="commission == 3" class="col-item commission-item"> 三级佣金比例 </div>
</template>
</div>
<div class="commission-content sa-flex" v-for="level in state.levelData" :key="level">
<div class="col-item">{{ level.name }}</div>
<template v-for="commission in state.commission_config_temp.level" :key="commission">
<div class="col-item commission-item">
{{ level.commission_rules[`commission_${commission}`] }}%
</div>
</template>
</div>
</template>
<template v-if="state.commission_goods.self_rules == 1">
<div class="commission-header sa-flex">
<div class="col-item">商品规格</div>
<div class="col-item">价格</div>
<div class="col-item">分销等级名称</div>
<template v-for="commission in state.commission_config_temp.level" :key="commission">
<div class="col-item commission-item">
<template v-if="commission == 1">一级(自购)佣金比例</template>
<template v-if="commission == 2">二级佣金比例</template>
<template v-if="commission == 3">三级佣金比例</template>
<el-popover popper-class="commission-popover"
v-model:visible="commissionPopover.flag[commission]" placement="top"
:width="220" trigger="click">
<div class="commission-item sa-flex">
<el-input v-model="commissionPopover.form.rate" type="number"
:disabled="commissionPopover.form.money != ''">
<template #append>%</template>
</el-input>
<el-input v-model="commissionPopover.form.money" type="number"
:disabled="commissionPopover.form.rate != ''">
<template #append></template>
</el-input>
</div>
<div class="sa-flex sa-row-right">
<el-button class="is-link" type="primary" size="small"
@click="onCancelCommissionPopover(commission)">取消</el-button>
<el-button type="primary" size="small"
@click="onConfirmCommissionPopover(commission)">确定</el-button>
</div>
<template #reference>
<el-icon class="batch-edit">
<edit />
</el-icon>
</template>
</el-popover>
</div>
</template>
</div>
<div class="commission-content sa-flex">
<div class="sa-flex sa-flex-col">
<div class="sa-flex" v-for="sku in state.detailData.sku_prices" :key="sku">
<div class="col-item" :style="{ height: 48 * state.levelData.length + 'px' }">
{{ state.detailData?.is_sku ? sku.goods_sku_text.join(',') : '默认规格' }}
</div>
<div class="col-item" :style="{ height: 48 * state.levelData.length + 'px' }">
{{ sku.price }}
</div>
<div>
<div class="col-item" v-for="level in state.levelData" :key="level">
{{ level.name }}
</div>
</div>
</div>
</div>
<div>
<div v-for="sku in state.commission_goods.commission_rules" :key="sku">
<div class="sa-flex" v-for="level in sku" :key="level">
<template v-for="commission in state.commission_config_temp.level"
:key="commission">
<div v-if="level[commission]" class="col-item commission-item">
<el-input v-model="level[commission].rate" type="number"
:disabled="level[commission].money != ''">
<template #append>%</template>
</el-input>
<el-input v-model="level[commission].money" type="number"
:disabled="level[commission].rate != ''">
<template #append></template>
</el-input>
</div>
</template>
</div>
</div>
</div>
</div>
</template>
<template v-if="state.commission_goods.self_rules == 2">
<div class="commission-header sa-flex">
<div class="col-item">商品规格</div>
<template v-for="commission in state.commission_config_temp.level" :key="commission">
<div class="col-item commission-item">
<template v-if="commission == 1">一级(自购)佣金比例</template>
<template v-if="commission == 2">二级佣金比例</template>
<template v-if="commission == 3">三级佣金比例</template>
<el-popover popper-class="commission-popover"
v-model:visible="commissionPopover.flag[commission]" placement="top"
:width="220" trigger="click">
<div class="commission-item sa-flex">
<el-input v-model="commissionPopover.form.rate" type="number"
:disabled="commissionPopover.form.money != ''">
<template #append>%</template>
</el-input>
</div>
<div class="sa-flex sa-row-right">
<el-button class="is-link" type="primary" size="small"
@click="onCancelCommissionPopover(commission)">取消</el-button>
<el-button size="small" type="primary"
@click="onConfirmCommissionPopover(commission)">确定</el-button>
</div>
<template #reference>
<el-icon class="batch-edit">
<edit />
</el-icon>
</template>
</el-popover>
</div>
</template>
</div>
<div class="commission-content sa-flex">
<div>
<div class="col-item" v-for="level in state.levelData" :key="level">
{{ level.name }}
</div>
</div>
<div>
<div class="sa-flex" v-for="level in state.commission_goods.commission_rules"
:key="level">
<template v-for="commission in state.commission_config_temp.level"
:key="commission">
<div v-if="level[commission]" class="col-item commission-item">
<el-input v-model="level[commission].rate" type="number"
:disabled="level[commission].money != ''">
<template #append>%</template>
</el-input>
</div>
</template>
</div>
</div>
</div>
</template>
</div>
</el-form>
</el-scrollbar>
</el-main>
<el-footer class="sa-footer--submit sa-flex sa-row-right">
<el-button type="primary" @click="onConfirm">确定</el-button>
</el-footer>
</el-container>
</div>

View File

@@ -0,0 +1,116 @@
{include file="/shopro/common/script" /}
<style>
.goods-index .goods-item .goods-title {
height: 20px;
line-height: 20px;
font-size: 14px;
font-weight: 500;
color: var(--sa-font);
}
.goods-index .goods-item .goods-subtitle {
height: 16px;
line-height: 16px;
font-size: 12px;
font-weight: 400;
color: var(--sa-subfont);
margin-bottom: 6px;
}
.goods-index .goods-item .goods-sku {
width: fit-content;
height: 18px;
line-height: 18px;
background: var(--el-color-primary);
border-radius: 10px;
padding: 0 8px;
font-size: 12px;
color: var(--sa-background-assist);
}
</style>
<div id="index" class="goods-index panel panel-default panel-intro" v-cloak>
<el-container class="panel-block">
<el-header class="sa-header">
<div class="sa-title sa-flex sa-row-between">
<div class="sa-title-left">
<div class="left-name">分销商品</div>
<sa-filter-condition v-model="state.filter" @filter-delete="onChangeFilter">
</sa-filter-condition>
</div>
<div class="sa-title-right">
<el-button class="sa-button-refresh" icon="RefreshRight" @click="getData"></el-button>
<el-button class="sa-button-refresh" icon="Search" @click="onOpenFilter"></el-button>
</div>
</div>
</el-header>
<el-main class="sa-main">
<el-table height="100%" class="sa-table" :data="state.data" stripe @selection-change="onChangeSelection">
<el-table-column type="selection" width="48"></el-table-column>
<el-table-column prop="id" label="ID" min-width="90"></el-table-column>
<el-table-column label="商品信息" min-width="300">
<template #default="scope">
<div class="goods-item sa-flex sa-col-top">
<sa-image class="mr-2" :url="scope.row.image" size="64"></sa-image>
<div>
<div class="goods-title sa-table-line-1">{{scope.row.title}}</div>
<div class="goods-subtitle sa-table-line-1">{{scope.row.subtitle}}</div>
<div v-if="scope.row.is_sku==1" class="goods-sku">多规格</div>
</div>
</div>
</template>
</el-table-column>
<el-table-column label="价格" min-width="150">
<template #default="scope">
<div>{{ scope.row.price?.join('~') || 0 }}</div>
</template>
</el-table-column>
<el-table-column label="分销规则" width="100">
<template #default="scope">
<template v-if="scope.row.commission_goods && scope.row.commission_goods.status == 1">
<template v-if="scope.row.commission_goods.self_rules == 0">默认规则</template>
<template v-if="scope.row.commission_goods.self_rules == 1">独立规则</template>
<template v-if="scope.row.commission_goods.self_rules == 2">批量规则</template>
</template>
<template v-else>-</template>
</template>
</el-table-column>
<el-table-column label="商品状态" width="100">
<template #default="scope">
<span :class="`sa-color--${state.statusStyle[scope.row.status]}`">
{{ scope.row.status_text }}
</span>
</template>
</el-table-column>
<el-table-column label="操作" min-width="140" fixed="right">
<template #default="scope">
<div class="sa-flex">
<span class="mr-2"
:class="`sa-color--${state.goodsStatusStyle[scope.row.commission_goods?.status] || 'info'}`">
{{ scope.row.commission_goods?.status_text || '未参与' }}
</span>
{if $auth->check('shopro/commission/goods/edit')}
<el-button type="primary" link @click="onEdit(scope.row.id)">设置佣金</el-button>
{/if}
</div>
</template>
</el-table-column>
</el-table>
</el-main>
<el-footer class="sa-footer sa-flex sa-row-between sa-flex-wrap">
<div class="sa-batch sa-flex">
<div class="tip">
已选择 <span>{{batchHandle.data.length}}</span></div>
<div class="sa-flex">
{if $auth->check('shopro/commission/goods/edit')}
<el-button type="primary" :disabled="!batchHandle.data.length" @click="onBatchHandle('edit')">设置佣金
</el-button>
{/if}
</div>
</div>
<sa-pagination v-model="pagination" @pagination-change="getData"></sa-pagination>
</el-footer>
</el-container>
<sa-filter v-model="state.filter" @filter-change="onChangeFilter"></sa-filter>
</div>

View File

@@ -0,0 +1,187 @@
{include file="/shopro/common/script" /}
<style>
.level-form .title {
height: 32px;
line-height: 32px;
background: var(--sa-background-hex-hover);
padding: 0 16px;
font-size: 12px;
font-weight: 400;
color: var(--sa-subtitle);
border-radius: 4px;
margin-bottom: 16px;
}
.level-form .sa-title.is-line {
margin-bottom: 20px;
}
.level-form .w-120 {
width: 120px;
}
.level-form .item {
height: 32px;
padding: 0 16px;
font-size: 14px;
border: 1px solid var(--sa-border);
border-radius: 4px;
margin: 0 16px 16px 0;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
}
.level-form .item:last-of-type {
margin: 0 0 16px 0;
}
.level-form .item.is-disabled {
background: var(--sa-background-hex-active);
color: #fff;
border: 1px solid var(--sa-background-hex-active);
cursor: not-allowed;
}
.level-form .item.is-active {
background: var(--el-color-primary);
color: #fff;
border: 1px solid var(--el-color-primary);
}
.level-form .item.is-active.is-none {
display: flex;
}
.level-form .item.is-none {
display: none;
}
.level-form .condition-group .condition-item {
padding: 0 12px;
}
</style>
<div id="addEdit" class="level-form" v-cloak>
<el-container class="panel-block">
<el-main>
<el-scrollbar height="100%">
<el-alert class="mb-4" type="warning">
<template #title>
新增或编辑等级后,请及时在分销商品中完善对应的佣金规则
</template>
</el-alert>
<el-form :model="form.model" :rules="form.rules" ref="formRef" label-width="150px">
<div class="sa-title is-line">等级佣金比例</div>
<el-form-item label="等级权重" prop="level">
<div :class="[
'item',
item.level == form.model.level ? 'is-active' : '',
level.existLevel.includes(item.level) ? 'is-disabled' : '',
form.model.level == 1 ? 'is-none' : '',
]" v-for="item in level.data" :key="item" @click="onSelectLevel(item.level)">
{{ item.name }}
</div>
</el-form-item>
<el-form-item label="等级名称" prop="name">
<el-input class="sa-w-360" v-model="form.model.name" placeholder="请输入等级名称"></el-input>
</el-form-item>
<el-form-item label="等级徽章" prop="image">
<sa-uploader v-model="form.model.image"></sa-uploader>
</el-form-item>
<el-form-item label="一级(自购)佣金比例" prop="commission_rules.commission_1"
:rules="form.rules.commission_rules.commission">
<el-input class="sa-w-360" v-model="form.model.commission_rules.commission_1" type="number">
<template #append>%</template>
</el-input>
</el-form-item>
<el-form-item label="二级佣金比例" prop="commission_rules.commission_2"
:rules="form.rules.commission_rules.commission">
<el-input class="sa-w-360" v-model="form.model.commission_rules.commission_2" type="number">
<template #append>%</template>
</el-input>
</el-form-item>
<el-form-item label="三级佣金比例" prop="commission_rules.commission_3"
:rules="form.rules.commission_rules.commission">
<el-input class="sa-w-360" v-model="form.model.commission_rules.commission_3" type="number">
<template #append>%</template>
</el-input>
</el-form-item>
<template v-if="form.model.level != 1">
<div class="sa-title is-line">添加升级条件</div>
<el-form-item label="升级方式" prop="upgrade_rules">
<div>
<el-radio-group class="mb-2" v-model="form.model.upgrade_type">
<el-radio :label="0">满足以下任意条件</el-radio>
<el-radio :label="1">满足以下全部条件</el-radio>
</el-radio-group>
<div>
<div class="sa-flex sa-flex-wrap condition-group" v-for="group in upgradeCondition"
:key="group">
<div :class="[
'item',
'condition-item',
Object.keys(form.model.upgrade_rules).includes(key) ? 'is-active' : '',
]" v-for="(item, key) in group" :key="item"
@click="onSelectUpgradeCondition(key)">
{{ item.name }}
</div>
</div>
</div>
</div>
</el-form-item>
<template v-for="(group, gkey) in upgradeCondition" :key="group">
<template v-for="(item, key) in group" :key="item">
<el-form-item :label="item.name"
v-if="Object.keys(form.model.upgrade_rules).includes(key)"
:prop="`upgrade_rules.${key}`" :rules="form.rules.upgrade_rules_inner.rules">
<template v-if="gkey != 'agent_level'">
<el-input class="w-120" v-model="form.model.upgrade_rules[key]" type="number">
<template #append> {{ initUnit(key) }}</template>
</el-input>
<el-button class="delete" type="danger" link @click="onDeleteRules(key)">
删除
</el-button>
</template>
<div v-if="gkey == 'agent_level'">
<div class="sa-flex sa-flex-wrap mb-4"
v-for="(al, index) in form.model.upgrade_rules[key]" :key="al">
<el-form-item :prop="`upgrade_rules.${key}.${index}.level`"
:rules="form.rules.upgrade_rules_inner.level">
<el-select class="w-120" v-model="al.level" placeholder="请选择分销商等级">
<template v-for="item in level.select" :key="item">
<el-option v-if="item.level < form.model.level"
:label="item.name" :value="item.level+''"></el-option>
</template>
</el-select>
<span class="ml-2 mr-2"></span>
</el-form-item>
<el-form-item :prop="`upgrade_rules.${key}.${index}.count`"
:rules="form.rules.upgrade_rules_inner.rules">
<el-input class="w-120" v-model="al.count" type="number">
<template #append></template>
</el-input>
<el-button class="delete" type="danger" link
@click="onDeleteRules(key, index)">
删除
</el-button>
</el-form-item>
</div>
<el-button type="primary" link size="small" @click="onAddUpgradeRules(key)">
+ 添加</el-button>
</div>
</el-form-item>
</template>
</template>
</template>
</el-form>
</el-scrollbar>
</el-main>
<el-footer class="sa-footer--submit sa-flex sa-row-right">
<el-button type="primary" @click="onConfirm">确定</el-button>
</el-footer>
</el-container>
</div>

View File

@@ -0,0 +1,60 @@
{include file="/shopro/common/script" /}
<div id="index" class="level-index panel panel-default panel-intro" v-cloak>
<el-container class="panel-block">
<el-header class="sa-header">
<div class="sa-title sa-flex sa-row-between">
<div class="sa-title-left">
<div class="left-name">分销商等级</div>
</div>
<div class="sa-title-right">
<el-button class="sa-button-refresh" icon="RefreshRight" @click="getData"></el-button>
{if $auth->check('shopro/commission/level/add')}
<el-button icon="Plus" type="primary" @click="onAdd">添加</el-button>
{/if}
</div>
</div>
</el-header>
<el-main class="sa-main">
<el-table height="100%" class="sa-table" :data="state.data" stripe>
<el-table-column label="等级" min-width="90">
<template #default="scope"> 等级{{ scope.row.level }} </template>
</el-table-column>
<el-table-column label="等级名称" min-width="150">
<template #default="scope">
{{ scope.row.name }}
</template>
</el-table-column>
<el-table-column label="等级徽章" min-width="120">
<template #default="scope">
<sa-image :url="scope.row.image" size="24"></sa-image>
</template>
</el-table-column>
<el-table-column label="一级(自购)佣金比例" min-width="160">
<template #default="scope"> {{ scope.row.commission_rules?.commission_1 }}% </template>
</el-table-column>
<el-table-column label="二级佣金比例" min-width="120">
<template #default="scope"> {{ scope.row.commission_rules?.commission_2 }}% </template>
</el-table-column>
<el-table-column label="三级佣金比例" min-width="120">
<template #default="scope"> {{ scope.row.commission_rules?.commission_3 }}% </template>
</el-table-column>
<el-table-column label="操作" min-width="120" fixed="right">
<template #default="scope">
{if $auth->check('shopro/commission/level/edit')}
<el-button type="primary" link @click="onEdit(scope.row.level)">编辑</el-button>
{/if}
<el-popconfirm v-if="scope.row.level != 1" width="fit-content" confirm-button-text="确认"
cancel-button-text="取消" title="确认删除这条记录?" @confirm="onDelete(scope.row.level)">
<template #reference>
{if $auth->check('shopro/commission/level/delete')}
<el-button type="danger" link>删除</el-button>
{/if}
</template>
</el-popconfirm>
</template>
</el-table-column>
</el-table>
</el-main>
</el-container>
</div>

View File

@@ -0,0 +1,29 @@
{include file="/shopro/common/script" /}
<div id="select" class="level-select" v-cloak>
<el-container class="panel-block">
<el-header class="sa-header">
<el-alert class="mt-4">
<template #title>温馨提示:更换等级后,该用户不会降级</template>
</el-alert>
</el-header>
<el-main>
<el-table height="100%" class="sa-table" :data="state.data" stripe>
<el-table-column prop="name" label="等级信息" min-width="150"></el-table-column>
<el-table-column label="等级权重" min-width="90">
<template #default="scope"> 等级{{ scope.row.level }} </template>
</el-table-column>
<el-table-column label="操作" min-width="80" fixed="right">
<template #default="scope">
<span v-if="scope.row.level == state.level" class="sa-color--info"> 已选择 </span>
<el-button v-else class="is-link" type="primary" @click="onSelect(scope.row.level)">选择
</el-button>
</template>
</el-table-column>
</el-table>
</el-main>
<el-footer class="sa-footer--submit sa-flex sa-row-right">
<el-button type="primary" @click="onConfirm">确定</el-button>
</el-footer>
</el-container>
</div>

View File

@@ -0,0 +1,56 @@
{include file="/shopro/common/script" /}
<div id="index" class="log-index panel panel-default panel-intro" v-cloak>
<el-container class="panel-block">
<el-header class="sa-header">
<div class="sa-title sa-flex sa-row-between">
<div class="sa-title-left">
<div class="left-name">分销动态</div>
<div class="really-status sa-flex ml-4">
实时动态
<el-switch class="ml-2" v-model="really.reallyStatus" :active-value="1" :inactive-value="0"
@change="onChangeReallyStatus"></el-switch>
<span class="ml-1" :class="really.reallyStatus == 1?'sa-color--primary':''">
{{ really.reallyStatus == 1 ? '开启' : '关闭' }}
</span>
<el-popover popper-class="sa-popper" trigger="hover" content="开启后,该页面将实时刷新">
<template #reference>
<el-icon class="sa-color--warning ml-1">
<Warning />
</el-icon>
</template>
</el-popover>
</div>
<sa-filter-condition v-model="state.filter" @filter-delete="onChangeFilter">
</sa-filter-condition>
</div>
<div class="sa-title-right">
<el-button class="sa-button-refresh" icon="RefreshRight" @click="getData"></el-button>
<el-button class="sa-button-refresh" icon="Search" @click="onOpenFilter"></el-button>
</div>
</div>
</el-header>
<el-main class="sa-main">
<el-table height="100%" class="sa-table" :data="state.data" stripe>
<el-table-column prop="id" label="ID" min-width="90"></el-table-column>
<el-table-column prop="event_text" label="动态筛选" min-width="120"></el-table-column>
<el-table-column label="分销商" min-width="160">
<template #default="scope">
<sa-user-profile :user="scope.row.agent" :id="scope.row.agent_id"></sa-user-profile>
</template>
</el-table-column>
<el-table-column prop="remark" label="内容" min-width="300"></el-table-column>
<el-table-column label="操作人" min-width="160">
<template #default="scope">
<sa-user-profile type="oper" :user="scope.row.oper" :id="scope.row.oper_id"></sa-user-profile>
</template>
</el-table-column>
<el-table-column prop="createtime" label="动态时间" width="172"></el-table-column>
</el-table>
</el-main>
<el-footer class="sa-footer sa-flex sa-row-right">
<sa-pagination v-model="pagination" @pagination-change="getData"></sa-pagination>
</el-footer>
</el-container>
<sa-filter v-model="state.filter" @filter-change="onChangeFilter"></sa-filter>
</div>

View File

@@ -0,0 +1,513 @@
{include file="/shopro/common/script" /}
<style>
.order-index .dashboard-content {
padding: 20px 20px 0;
background: var(--sa-table-header-bg);
border-radius: 8px;
margin-bottom: 20px;
}
.order-index .dashboard-content .dashboard-item {
text-align: center;
margin-bottom: 20px;
}
.order-index .dashboard-content .dashboard-item .top {
line-height: 24px;
font-size: 20px;
font-weight: 400;
color: var(--sa-subtitle);
}
.order-index .dashboard-content .dashboard-item .top .unit {
font-size: 12px;
margin-left: 4px;
}
.order-index .dashboard-content .dashboard-item .bottom {
line-height: 16px;
font-size: 12px;
font-weight: 400;
color: var(--sa-font);
}
.order-index .order-content {
font-size: 12px;
font-weight: 400;
color: var(--sa-subtitle);
}
.order-index .goods-item .goods-title {
height: 14px;
line-height: 14px;
font-size: 12px;
font-weight: 500;
margin-bottom: 4px;
}
.order-index .goods-item .goods-title .goods-id {
color: var(--el-color-primary);
cursor: pointer;
}
.order-index .goods-item .goods-sku-text {
height: 14px;
line-height: 14px;
margin-bottom: 10px;
}
.order-index .sa-table-wrap {
height: 100%;
margin-left: -48px;
overflow: hidden;
}
.order-index .sa-table-wrap .sa-table .el-table__header-wrapper {
margin-bottom: 4px;
}
.order-index .sa-table-wrap .sa-table .el-table__row {
background: var(--sa-background-hex-hover);
}
.order-index .sa-table-wrap .sa-table .el-table__expanded-cell {
padding: 0;
}
.order-index .sa-table-wrap .sa-expand-table .el-table__header-wrapper {
margin-bottom: 0;
display: none;
}
.order-index .sa-table-wrap .sa-expand-table .el-table__row {
background: var(--el-table-tr-bg-color);
}
.order-index .rewards-item {
margin-right: 8px;
}
.order-index .rewards-item:last-of-type {
margin-right: 0;
}
.order-index .rewards-item .rewards-agent-id {
line-height: 32px;
}
.rewards-popover {
line-height: 16px;
font-size: 12px;
font-weight: 400;
color: var(--sa-font);
margin-bottom: 4px;
}
.rewards-popover .nickname {
height: 20px;
line-height: 20px;
}
.rewards-popover .id {
line-height: 16px;
font-size: 12px;
font-weight: 400;
color: var(--sa-subfont);
}
.rewards-popover .rewards-status {
height: 16px;
overflow: hidden;
}
.rewards-popover .rewards-commission {
width: 80px;
}
</style>
<div id="index" class="order-index panel panel-default panel-intro" v-cloak>
<el-container class="panel-block">
<el-header class="sa-header">
<div class="sa-title sa-flex sa-row-between">
<div class="sa-title-left">
<div class="left-name">分销订单</div>
<sa-filter-condition v-model="state.filter" @filter-delete="onChangeFilter">
</sa-filter-condition>
</div>
<div class="sa-title-right">
<el-button class="sa-button-refresh" icon="RefreshRight" @click="getData"></el-button>
<el-button class="sa-button-refresh" icon="Search" @click="onOpenFilter"></el-button>
{if $auth->check('shopro/commission/order/export')}
<el-button :loading="exportLoading" :disabled="exportLoading" @click="onExport('export')">订单导出
</el-button>
{/if}
</div>
</div>
<el-row class="dashboard-content">
<el-col class="dashboard-item" :xs="8" :sm="8" :md="6" :lg="6" :xl="6">
<div class="top"> {{ state.count.total }}<span class="unit"></span> </div>
<div class="bottom">商品总订单数</div>
</el-col>
<el-col class="dashboard-item" :xs="8" :sm="8" :md="3" :lg="3" :xl="3">
<div class="top">
{{ state.count.total_amount?.toFixed(2) }}<span class="unit"></span>
</div>
<div class="bottom">商品结算总金额</div>
</el-col>
<el-col class="dashboard-item" :xs="8" :sm="8" :md="3" :lg="3" :xl="3">
<div class="top">
{{ state.count.total_commission?.toFixed(2) }}<span class="unit"></span>
</div>
<div class="bottom">分佣总金额</div>
</el-col>
<el-col class="dashboard-item" :xs="8" :sm="8" :md="3" :lg="3" :xl="3">
<div class="top">
{{ state.count.total_commission_cancel?.toFixed(2) }}<span class="unit"></span>
</div>
<div class="bottom">已取消佣金</div>
</el-col>
<el-col class="dashboard-item" :xs="8" :sm="8" :md="3" :lg="3" :xl="3">
<div class="top">
{{ state.count.total_commission_back?.toFixed(2) }}<span class="unit"></span>
</div>
<div class="bottom">已退回佣金</div>
</el-col>
<el-col class="dashboard-item" :xs="8" :sm="8" :md="3" :lg="3" :xl="3">
<div class="top">
{{ state.count.total_commission_pending?.toFixed(2) }}<span class="unit"></span>
</div>
<div class="bottom">未结算佣金</div>
</el-col>
<el-col class="dashboard-item" :xs="8" :sm="8" :md="3" :lg="3" :xl="3">
<div class="top">
{{ state.count.total_commission_accounted?.toFixed(2) }}<span class="unit"></span>
</div>
<div class="bottom">已结算佣金</div>
</el-col>
</el-row>
</el-header>
<el-main class="sa-main">
<div class="sa-table-wrap">
<el-table height="100%" class="sa-table" :data="state.data" :span-method="arraySpanMethod"
default-expand-all>
<el-table-column type="expand">
<template #default="props">
<el-table class="sa-table sa-expand-table" :data="[props.row]">
<el-table-column width="48"></el-table-column>
<el-table-column min-width="300">
<template #default>
<div v-if="props.row.order_item" class="goods-item sa-flex">
<sa-image class="mr-2" :url="props.row.order_item.goods_image" size="58">
</sa-image>
<div>
<div class="goods-title sa-table-line-1">
<span class="goods-id mr-1"
@click="onOpenGoodsDetail(props.row.order_item.goods_id)">
#{{props.row.order_item.goods_id }}
</span>
{{ props.row.order_item.goods_title }}
</div>
<div class="goods-sku-text sa-table-line-1">
<span v-if="props.row.order_item.goods_sku_text">{{
props.row.order_item.goods_sku_text
}}</span>
</div>
<div class="sa-flex">
<span class="goods-price mr-2">¥{{
props.row.order_item.goods_price }}</span>
<span class="goods-num">x{{
props.row.order_item.goods_num }}</span>
</div>
</div>
</div>
<div v-else>{{ props.row.order_item }}</div>
</template>
</el-table-column>
<el-table-column min-width="100">
<template #default>
<!-- 0=未退款|1=申请退款|2=退款完成 -->
<span
:class="props.row.order_item?.refund_status==0?'sa-color--info':'sa-color--success'">
{{ props.row.order_item?.refund_status_text || '-' }}
</span>
</template>
</el-table-column>
<el-table-column min-width="100" align="center">
<template #default>
<sa-user-profile :user="props.row.buyer" :id="props.row.buyer_id" mode="col">
</sa-user-profile>
</template>
</el-table-column>
<el-table-column min-width="100" align="center">
<template #default>
<sa-user-profile :user="props.row.agent" :id="props.row.agent_id" mode="col">
</sa-user-profile>
</template>
</el-table-column>
<el-table-column min-width="200" align="center">
<template #default>
<el-scrollbar>
<div class="sa-flex sa-row-center">
<template v-for="(rewards, index) in props.row.rewards" :key="rewards">
<el-popover placement="top-start" :width="240" trigger="click">
<div class="rewards-popover">
<div class="mb-2">
<div v-if="rewards.agent" class="sa-flex">
<sa-image :url="rewards.agent.avatar" size="32"
radius="16"></sa-image>
<div class="ml-2">
<div class="nickname sa-table-line-1">
{{ rewards.agent.nickname }}
</div>
<div class="id">#{{ rewards.agent.id }}</div>
</div>
</div>
<div v-else>#{{ rewards.agent_id }}</div>
</div>
<div>用户等级:等级{{ rewards.agent_level }}</div>
<div> 用户层级:{{ rewards.commission_level }}级分销 </div>
<div>
比例/佣金:
<template v-if="rewards.commission_rules">
<template v-if="rewards.commission_rules.rate">
{{ rewards.commission_rules.rate }}%
</template>
<template v-if="rewards.commission_rules.money">
{{ rewards.commission_rules.money }}元
</template>
</template>
</div>
<div class="rewards-status sa-flex">
佣金状态:
<span class="mr-1">{{rewards.status_text}}</span>
<template v-if="rewards.status == 0">
{if $auth->check('shopro/commission/order/confirm')}
<el-button type="primary" link size="small"
@click="onConfirm({commission_reward_id: rewards.id})">
手动结算</el-button>
{/if}
{if $auth->check('shopro/commission/order/cancel')}
<el-button class="ml-1" type="info" link
size="small"
@click="onCancel({commission_reward_id: rewards.id})">
取消
</el-button>
{/if}
</template>
<el-popconfirm v-if="rewards.status == 1"
width="fit-content" confirm-button-text="确认"
cancel-button-text="取消" title="确认?"
@confirm="onBack({commission_reward_id: rewards.id})">
<template #reference>
{if
$auth->check('shopro/commission/order/back')}
<el-button type="danger" link size="small">
手动退回
</el-button>
{/if}
</template>
</el-popconfirm>
</div>
<div>入账方式:{{ rewards.type_text }}</div>
<div class="sa-flex sa-col-top">
<span class="sa-flex-0">佣金金额:</span>
<div class="sa-flex sa-flex-wrap">
<template v-if="!rewardsPopover.flag[index]">
<span>{{ rewards.commission }}元</span>
{if
$auth->check('shopro/commission/order/edit')}
<el-button v-if="rewards.status == 0"
class="ml-1" type="primary" link
size="small"
@click="rewardsPopover.flag[index] = true">
修改
</el-button>
{/if}
</template>
<template v-if="rewardsPopover.flag[index]">
<el-input class="rewards-commission"
v-model="rewardsPopover.commission"
size="small">
<template #append></template>
</el-input>
<el-button class="ml-1" type="info" link
size="small"
@click="onCancelRewardsPopover(index)">取消
</el-button>
<el-button class="ml-1" type="primary" link
size="small"
@click="onConfirmRewardsPopover(index,rewards.id)">
确定</el-button>
</template>
<s v-if="rewards.original_commission != rewards.commission"
class="ml-1">
{{rewards.original_commission}}
</s>
</div>
</div>
</div>
<template #reference>
<div class="rewards-item sa-flex sa-flex-col sa-row-center">
<template v-if="rewards.agent">
<sa-image :url="rewards.agent.avatar" size="32"
radius="16" :ispreview="false"></sa-image>
</template>
<div v-if="!rewards.agent" class="rewards-agent-id">
{{ rewards.agent_id }}
</div>
<div class="commission mt-1"> {{ rewards.commission }}元
</div>
</div>
</template>
</el-popover>
</template>
</div>
</el-scrollbar>
</template>
</el-table-column>
<el-table-column min-width="80">
<template #default>
<!-- commission_reward_status -2=已退回|-1=已取消|0=未结算|1=已结算 -->
<span
:class="`sa-color--${state.statusStyle[props.row.commission_reward_status]}`">
{{ props.row.commission_reward_status_text }}
</span>
</template>
</el-table-column>
<el-table-column min-width="172">
<template #default>
<div>{{ props.row.reward_event_text }}</div>
{{ props.row.commission_time }}
</template>
</el-table-column>
<el-table-column min-width="110">
<template #default>
<div>{{ props.row.reward_type_text }}</div>
{{ props.row.amount }}元
</template>
</el-table-column>
<el-table-column min-width="100">
<template #default>
<!-- commission_order_status -2=已扣除|-1=已取消|0=不计入|1=已计入 -->
<span
:class="`sa-color--${state.statusStyle[props.row.commission_order_status]}`">
{{ props.row.commission_order_status_text }}
</span>
</template>
</el-table-column>
<el-table-column min-width="160">
<template #default>
{{ countRewards(props.row.rewards) }}
</template>
</el-table-column>
<el-table-column min-width="160">
<template #default>
<el-popover v-model:visible="commissionPopover.flag[props.$index]"
placement="top-start" :width="312" trigger="click">
<div class="commission-popover">
<div class="title sa-flex">
<el-icon class="sa-color--warning mr-1">
<question-filled />
</el-icon>
<template v-if="props.row.commission_reward_status == 0">
<template v-if="commissionPopover.type == 'confirm'">
手动提前结算,佣金将不再按结算方式自动执行。
</template>
<template v-if="commissionPopover.type == 'cancel'">
取消结算,佣金将不再结算。
</template>
</template>
<template v-if="props.row.commission_reward_status == 1">
您确定要手动退回佣金?
</template>
</div>
<div class="sa-flex sa-row-between">
<div>
<el-checkbox
v-if="commissionPopover.type == 'back' || commissionPopover.type == 'cancel'"
v-model="commissionPopover.isDelete" true-label="1"
false-label="0">扣除推广分销商业绩
</el-checkbox>
</div>
<div>
<el-button type="info" link size="small"
@click="onCancelCommissionPopover(props.$index)">
取消</el-button>
<el-button size="small" type="primary"
@click="onConfirmCommissionPopover(props.$index,props.row.id)">
确定</el-button>
</div>
</div>
</div>
<template #reference>
<div class="sa-flex">
<template v-if="props.row.commission_reward_status == 0">
{if $auth->check('shopro/commission/order/confirm')}
<el-button type="primary" link
@click="commissionPopover.type = 'confirm'">手动结算</el-button>
{/if}
{if $auth->check('shopro/commission/order/cancel')}
<el-button type="info" link
@click="commissionPopover.type = 'cancel'">
取消结算
</el-button>
{/if}
</template>
{if $auth->check('shopro/commission/order/back')}
<el-button v-if="props.row.commission_reward_status == 1"
type="danger" link @click="commissionPopover.type = 'back'">
手动退回
</el-button>
{/if}
</div>
</template>
</el-popover>
<template v-if="props.row.commission_reward_status < 0">-</template>
</template>
</el-table-column>
</el-table>
</template>
</el-table-column>
<el-table-column label="商品信息" min-width="300">
<template #default="scope">
<div class="order-content sa-flex">
<div class="id mr-4">ID{{ scope.row.id }}</div>
<template v-if="scope.row.order">
<div class="order-sn sa-flex mr-4">
订单号:{{ scope.row.order.order_sn }}
<el-icon class="copy-document" @click="onClipboard(scope.row.order.order_sn)">
<copy-document />
</el-icon>
</div>
<div class="mr-4">下单时间:{{ scope.row.order.createtime }}</div>
<div class="mr-4">订单状态:{{ scope.row.order.status_text }}</div>
</template>
</div>
</template>
</el-table-column>
<el-table-column label="退款状态" min-width="100"></el-table-column>
<el-table-column label="下单用户" min-width="100" align="center"></el-table-column>
<el-table-column label="推广分销商" min-width="100" align="center"></el-table-column>
<el-table-column label="佣金详情" min-width="200" align="center"></el-table-column>
<el-table-column label="佣金状态" min-width="80"></el-table-column>
<el-table-column label="结算方式/结算时间" min-width="172"></el-table-column>
<el-table-column label="商品结算金额" min-width="110"> </el-table-column>
<el-table-column label="分销商业绩" min-width="100"> </el-table-column>
<el-table-column label="分销总金额/到账金额" min-width="160">
</el-table-column>
<el-table-column label="操作" min-width="160">
<template #default="scope">
<el-button type="primary" link @click="onOpenOrderDetail(scope.row.order_id)">订单详情
</el-button>
</template>
</el-table-column>
</el-table>
</div>
</el-main>
<el-footer class="sa-footer sa-flex sa-row-right">
<sa-pagination v-model="pagination" @pagination-change="getData"></sa-pagination>
</el-footer>
</el-container>
<sa-filter v-model="state.filter" @filter-change="onChangeFilter"></sa-filter>
</div>

View File

@@ -0,0 +1,59 @@
{include file="/shopro/common/script" /}
<div id="index" class="reward-index panel panel-default panel-intro" v-cloak>
<el-container class="panel-block">
<el-header class="sa-header">
<div class="sa-title sa-flex sa-row-between">
<div class="sa-title-left">
<div class="left-name">佣金明细</div>
<sa-filter-condition v-model="state.filter" @filter-delete="onChangeFilter">
</sa-filter-condition>
</div>
<div class="sa-title-right">
<el-button class="sa-button-refresh" icon="RefreshRight" @click="getData"></el-button>
<el-button class="sa-button-refresh" icon="Search" @click="onOpenFilter"></el-button>
{if $auth->check('shopro/commission/reward/export')}
<el-button :loading="exportLoading" :disabled="exportLoading" @click="onExport('export')">导出
</el-button>
{/if}
</div>
</div>
</el-header>
<el-main class="sa-main">
<el-table height="100%" class="sa-table" :data="state.data" stripe>
<el-table-column prop="id" label="ID" min-width="90"></el-table-column>
<el-table-column label="订单号" min-width="260">
<template #default="scope">
{{ scope.row.order?.order_sn || scope.row.order_id }}
</template>
</el-table-column>
<el-table-column label="下单用户" min-width="160">
<template #default="scope">
<sa-user-profile :user="scope.row.buyer" :id="scope.row.buyer_id"></sa-user-profile>
</template>
</el-table-column>
<el-table-column label="分销用户" min-width="160">
<template #default="scope">
<sa-user-profile :user="scope.row.agent" :id="scope.row.agent_id"></sa-user-profile>
</template>
</el-table-column>
<el-table-column label="分销金额" min-width="160">
<template #default="scope"> {{ scope.row.commission }}元 </template>
</el-table-column>
<el-table-column label="入账状态" min-width="80">
<template #default="scope">
<span :class="`sa-color--${state.statusStyle[scope.row.status]}`">
{{ scope.row.status_text }}
</span>
</template>
</el-table-column>
<el-table-column prop="type_text" label="入账方式" min-width="80"></el-table-column>
<el-table-column prop="commission_time" label="分佣时间" width="172"></el-table-column>
</el-table>
</el-main>
<el-footer class="sa-footer sa-flex sa-row-right">
<sa-pagination v-model="pagination" @pagination-change="getData"></sa-pagination>
</el-footer>
</el-container>
<sa-filter v-model="state.filter" @filter-change="onChangeFilter"></sa-filter>
</div>

View File

@@ -0,0 +1,25 @@
<link rel="stylesheet" href="//at.alicdn.com/t/c/font_2385137_b8qygb2jne.css?v={$site.version|htmlentities}">
<link rel="stylesheet" href="__CDN__/assets/addons/shopro/css/index.css?v={$site.version|htmlentities}">
{if condition="$DARK_TYPE neq 'none'" }
<link rel="stylesheet" href="__CDN__/assets/addons/shopro/css/dark.css?v={$site.version|htmlentities}" data-render="darktheme" />
{/if}
<link rel="stylesheet" href="__CDN__/assets/addons/shopro/libs/element-plus/index.css?v={$site.version|htmlentities}">
<script src="__CDN__/assets/addons/shopro/libs/vue.js?v={$site.version|htmlentities}"></script>
<script src="__CDN__/assets/addons/shopro/libs/element-plus/index.js?v={$site.version|htmlentities}"></script>
<script src="__CDN__/assets/addons/shopro/libs/element-plus/zh-cn.js?v={$site.version|htmlentities}"></script>
<script src="__CDN__/assets/addons/shopro/libs/element-plus/icons-vue.js?v={$site.version|htmlentities}"></script>
<script src="__CDN__/assets/addons/shopro/libs/sortable.js?v={$site.version|htmlentities}"></script>
<script src="__CDN__/assets/addons/shopro/libs/vuedraggable.js?v={$site.version|htmlentities}"></script>
<script src="__CDN__/assets/addons/shopro/libs/common.js?v={$site.version|htmlentities}"></script>
<script src="__CDN__/assets/addons/shopro/libs/clipboard.min.js?v={$site.version|htmlentities}"></script>
<script src="__CDN__/assets/addons/shopro/components/sa-image.js?v={$site.version|htmlentities}"></script>
<script src="__CDN__/assets/addons/shopro/components/sa-uploader.js?v={$site.version|htmlentities}"></script>
<script src="__CDN__/assets/addons/shopro/components/sa-user-profile.js?v={$site.version|htmlentities}"></script>
<script src="__CDN__/assets/addons/shopro/components/sa-filter.js?v={$site.version|htmlentities}"></script>
<script src="__CDN__/assets/addons/shopro/components/sa-filter-condition.js?v={$site.version|htmlentities}"></script>
<script src="__CDN__/assets/addons/shopro/components/sa-pagination.js?v={$site.version|htmlentities}"></script>

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,182 @@
{include file="/shopro/common/script" /}
<style>
.config-platform .el-select {
flex: 1;
}
.config-platform .title {
width: 100%;
padding: 10px 0 10px 16px;
background: var(--sa-background-hex-hover);
font-weight: 500;
font-size: 14px;
color: var(--sa-subtitle);
margin: 0 0 16px;
display: flex;
align-items: center;
}
.config-platform .title-h5 {
margin-left: 20px;
}
.config-platform .pay-tip {
font-weight: 400;
font-size: 14px;
line-height: 20px;
color: var(--sa-subtitle);
margin-left: 16px;
}
</style>
<div id="platform" class="config-platform" v-cloak>
<el-container class="panel-block">
<el-main>
<el-scrollbar height="100%">
<el-form ref="formRef" :model="form.model" :rules="form.rules" label-width="100px">
<div class="title">状态</div>
<el-form-item label="状态">
<el-switch v-model="form.model.status" :active-value="1" :inactive-value="0"></el-switch>
<span class="label-tip" :class="form.model.status == 1 ? 'sa-color--primary' : ''">
{{form.model.status == 0 ? '关闭' : '开启'}}</span>
</el-form-item>
<div class="title">支付配置<span class="pay-tip">启用货到付款后,请自行安排合作快递完成收款和结算</span> </div>
<el-form-item label="支付方式">
<el-checkbox-group v-model="form.model.payment.methods">
<el-checkbox label="wechat">微信</el-checkbox>
<el-checkbox label="alipay">支付宝</el-checkbox>
<el-checkbox label="money">余额</el-checkbox>
<el-checkbox label="offline">货到付款</el-checkbox>
</el-checkbox-group>
</el-form-item>
<el-form-item v-if="form.model.payment.methods.includes('wechat')" label="微信" prop="payment.wechat">
<div class="sa-w-360">
<el-select v-model="form.model.payment.wechat" placeholder="请选择">
<el-option v-for="item in payConfig.select.wechat" :key="item.id" :label="item.name"
:value="item.id">
</el-option>
</el-select>
<el-button class="label-tip" type="primary" link @click="onAddPayConfig"> 添加支付方式
</el-button>
</div>
</el-form-item>
<el-form-item v-if="form.model.payment.methods.includes('alipay')" label="支付宝"
prop="payment.alipay">
<div class="sa-w-360">
<el-select v-model="form.model.payment.alipay" placeholder="请选择">
<el-option v-for="item in payConfig.select.alipay" :key="item.id" :label="item.name"
:value="item.id">
</el-option>
</el-select>
<el-button class="label-tip" type="primary" link @click="onAddPayConfig"> 添加支付方式
</el-button>
</div>
</el-form-item>
<div class="title">
{{state.platform == 'H5' ? '微信H5' : state.label}}平台设置
<div v-if="state.platform == 'H5'" class="title-h5">
如使用微信支付请在此输入已开通微信H5支付的Appid
</div>
</div>
<el-form-item label="Appid" prop="app_id">
<div class="sa-w-360">
<el-input v-model="form.model.app_id" placeholder="请输入Appid"></el-input>
<el-button v-if="state.platform=='H5' || state.platform=='App'" class="label-tip"
type="primary" link @click="onConfiguration">查看配置引导</el-button>
</div>
</el-form-item>
<el-form-item label="AppSecret" prop="secret" v-if="state.platform != 'H5'">
<el-input class="sa-w-360" v-model="form.model.secret" placeholder="请输入AppSecret"></el-input>
</el-form-item>
<div v-if="state.platform != 'H5'">
<div class="title">微信登录设置</div>
<el-form-item v-if="state.platform != 'App'" label="自动登录">
<div class="sa-flex">
<el-switch v-model="form.model.auto_login" :active-value="1" :inactive-value="0">
</el-switch>
<span class="label-tip" :class="form.model.auto_login == 1 ? 'sa-color--primary' : ''">
{{form.model.auto_login == 0 ? '关闭' : '开启'}}</span>
<div v-if="state.platform == 'WechatMiniProgram'" class="tip label-tip"> 进入应用后,已注册用户将会自动登录,未注册用户需手动授权 </div>
<div v-if="state.platform == 'WechatOfficialAccount'" class="tip label-tip"> 进入应用后,用户将会自动授权登录,未注册用户将会自动注册 </div>
</div>
</el-form-item>
<el-form-item label="绑定手机号">
<div class="sa-flex">
<el-switch v-model="form.model.bind_mobile" :active-value="1" :inactive-value="0">
</el-switch>
<span class="label-tip" :class="form.model.bind_mobile == 1 ? 'sa-color--primary' : ''">
{{form.model.bind_mobile == 0 ? '关闭' : '开启'}}</span>
<div class="tip label-tip"> 授权登录后,未绑定手机号的用户,将会立即提醒绑定手机号 </div>
</div>
</el-form-item>
</div>
<div v-if="state.platform == 'App'">
<div class="title">APP下载</div>
<el-form-item label="Android地址">
<el-input class="sa-w-360" v-model="form.model.download.android"
placeholder="请输入Android下载地址"></el-input>
</el-form-item>
<el-form-item label="IOS地址">
<el-input class="sa-w-360" v-model="form.model.download.ios" placeholder="请输入IOS下载地址">
</el-input>
</el-form-item>
<el-form-item label="本地地址">
<el-input class="sa-w-360" v-model="form.model.download.local" placeholder="请输入本地地址">
</el-input>
</el-form-item>
</div>
<template v-if="form.model.share">
<div class="title">分享设置</div>
<el-form-item label="分享方式">
<el-checkbox-group v-model="form.model.share.methods">
<el-checkbox label="forward" disabled>直接转发</el-checkbox>
<el-checkbox label="poster">分享海报</el-checkbox>
<el-checkbox label="link">复制链接</el-checkbox>
</el-checkbox-group>
</el-form-item>
<template v-if="form.model.share.methods.includes('forward')">
<el-form-item label="标题">
<el-input class="sa-w-360" v-model="form.model.share.forwardInfo.title"
placeholder="请输入分享标题"></el-input>
</el-form-item>
<el-form-item label="副标题">
<el-input class="sa-w-360" v-model="form.model.share.forwardInfo.subtitle"
placeholder="请输入分享副标题">
</el-input>
</el-form-item>
<el-form-item label="分享图片">
<sa-uploader v-model="form.model.share.forwardInfo.image">
</sa-uploader>
</el-form-item>
</template>
<template v-if="form.model.share.methods.includes('poster')">
<el-form-item label="用户海报">
<sa-uploader v-model="form.model.share.posterInfo.user_bg">
</sa-uploader>
</el-form-item>
<el-form-item label="商品海报">
<sa-uploader v-model="form.model.share.posterInfo.goods_bg">
</sa-uploader>
</el-form-item>
<el-form-item label="拼团海报">
<sa-uploader v-model="form.model.share.posterInfo.groupon_bg">
</sa-uploader>
</el-form-item>
</template>
<el-form-item label="分享Url">
<div class="sa-form-wrap">
<el-input class="sa-w-360" v-model="form.model.share.linkAddress"
placeholder="请输入分享Url"></el-input>
<div class="tip">分享链接的默认域名</div>
</div>
</el-form-item>
</template>
</el-form>
</el-scrollbar>
</el-main>
<el-footer class="sa-footer--submit sa-flex sa-row-right">
<el-button type="primary" @click="onConfirm">确定</el-button>
</el-footer>
</el-container>
</div>

View File

@@ -0,0 +1,210 @@
{include file="/shopro/common/script" /}
<style>
.coupon-form .w-120 {
width: 120px;
}
.coupon-form .el-form-item-inner {
--el-form-label-font-size: 12px;
}
.coupon-form .el-form-item-inner .el-form-item__label {
width: fit-content !important;
}
.coupon-form .key .el-form-item__content {
flex-wrap: nowrap;
}
.coupon-form .el-date-editor {
flex: none;
}
</style>
<div id="addEdit" class="coupon-form" v-cloak>
<el-container class="panel-block">
<el-main>
<el-scrollbar height="100%">
<el-form :model="form.model" :rules="form.rules" ref="formRef" label-width="110px">
<el-form-item label="券名称" prop="name">
<el-input class="sa-w-360" v-model="form.model.name" placeholder="例如:国庆优惠券"></el-input>
</el-form-item>
<el-form-item label="名称备注" prop="description">
<el-input class="sa-w-360" v-model="form.model.description" placeholder="请输入名称备注"></el-input>
</el-form-item>
<el-form-item label="券类型" prop="type">
<el-radio-group v-model="form.model.type" :disabled="state.type == 'edit'">
<el-radio label="reduce">满减券</el-radio>
<el-radio label="discount">折扣券</el-radio>
</el-radio-group>
</el-form-item>
<div class="el-form-item-inner">
<el-form-item>
<el-form-item label="消费满" prop="enough">
<el-input class="w-120" type="number" v-model="form.model.enough" :min="0"
:disabled="state.type == 'edit'">
<template #append></template>
</el-input>
</el-form-item>
<el-form-item v-if="form.model.type == 'reduce'" class="is-no-asterisk ml-2" label="立减"
prop="amount">
<el-input class="w-120" type="number" v-model="form.model.amount" :min="0"
:disabled="state.type == 'edit'">
<template #append></template>
</el-input>
</el-form-item>
<el-form-item v-if="form.model.type == 'discount'" class="is-no-asterisk ml-2" label="打"
prop="amount">
<el-input class="w-120" type="number" v-model="form.model.amount" :min="0" :max="10"
:disabled="state.type == 'edit'">
<template #append></template>
</el-input>
</el-form-item>
</el-form-item>
<el-form-item v-if="form.model.type == 'discount'">
<el-form-item label="最多优惠" prop="max_amount">
<el-input class="w-120" type="number" v-model="form.model.max_amount" :min="0"
:disabled="state.type == 'edit'">
<template #append></template>
</el-input>
</el-form-item>
</el-form-item>
</div>
<el-form-item label="发券总量" prop="stock">
<el-input class="w-120" type="number" v-model="form.model.stock" :min="0">
<template #append></template>
</el-input>
</el-form-item>
<el-form-item label="每人限领次数">
<el-input class="w-120" type="number" v-model="form.model.limit_num" :min="0">
<template #append></template>
</el-input>
</el-form-item>
<el-form-item label="领券时间" prop="get_time">
<el-date-picker v-model="form.model.get_time" type="datetimerange"
value-format="YYYY-MM-DD HH:mm:ss" format="YYYY-MM-DD HH:mm:ss"
:default-time="[new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 2, 1, 23, 59, 59)]"
range-separator="至" start-placeholder="开始日期" end-placeholder="结束日期" prefix-icon="Calendar"
:editable="false"></el-date-picker>
</el-form-item>
<el-form-item label="券有效期" prop="use_time_type">
<el-radio-group v-model="form.model.use_time_type">
<el-radio label="days">相对天数</el-radio>
<el-radio label="range">固定区间</el-radio>
</el-radio-group>
</el-form-item>
<div class="el-form-item-inner">
<el-form-item>
<template v-if="form.model.use_time_type == 'days'">
<el-form-item class="is-no-asterisk" label="领券" prop="start_days">
<el-input class="w-120" type="number" v-model="form.model.start_days" :min="0">
<template #append></template>
</el-input>
</el-form-item>
<el-form-item class="is-no-asterisk ml-2" label="后生效,有效期" prop="days">
<el-input class="w-120" type="number" v-model="form.model.days" :min="0">
<template #append></template>
</el-input>
</el-form-item>
</template>
<el-form-item v-if="form.model.use_time_type == 'range'" class="is-no-asterisk" label="固定时间"
prop="useTime">
<el-date-picker v-model="form.model.use_time" type="datetimerange"
value-format="YYYY-MM-DD HH:mm:ss" format="YYYY-MM-DD HH:mm:ss"
:default-time="[new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 2, 1, 23, 59, 59)]"
range-separator="至" start-placeholder="开始日期" end-placeholder="结束日期"
prefix-icon="Calendar" :editable="false"></el-date-picker>
</el-form-item>
</el-form-item>
</div>
<el-form-item label="优惠叠加">
<div>
<div class="sa-flex">
<el-switch v-model="form.model.is_double_discount" :active-value="1"
:inactive-value="0">
</el-switch>
<div class="ml-2" :class="form.model.is_double_discount == 1?'sa-color--primary':''">
{{form.model.is_double_discount == 1?'开启':'关闭'}}
</div>
</div>
<div class="tip"> 开启优惠叠加,优惠券将可以和活动一起使用 </div>
</div>
</el-form-item>
<el-form-item label="券状态" prop="status">
<div>
<el-radio-group v-model="form.model.status">
<el-radio label="normal">公开发放</el-radio>
<el-radio label="hidden">后台发放</el-radio>
<el-radio label="disabled">禁止使用</el-radio>
</el-radio-group>
<div class="tip">
后台发放状态改为别的状态,将导致满赠活动无法赠送该优惠券
</div>
</div>
</el-form-item>
<el-form-item label="可用范围" prop="use_scope">
<el-radio-group v-model="form.model.use_scope" @change="form.model.items_value = []">
<el-radio label="all_use">全场通用</el-radio>
<el-radio label="goods">指定商品可用</el-radio>
<el-radio label="disabled_goods">指定商品不可用</el-radio>
<el-radio label="category">指定分类可用</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item>
<el-button v-if="form.model.use_scope == 'goods' || form.model.use_scope == 'disabled_goods'"
type="primary" link @click="onSelectGoods">选择商品</el-button>
<el-button v-if="form.model.use_scope == 'category'" type="primary" link
@click="onSelectCategory">选择分类
</el-button>
</el-form-item>
<el-form-item>
<div v-if="form.model.use_scope == 'goods' || form.model.use_scope == 'disabled_goods'"
class="sa-template-wrap">
<template v-if="form.model.items_value.length > 0">
<div class="header sa-flex">
<div class="key">商品信息</div>
<div class="oper">操作</div>
</div>
<div class="item" v-for="(element, index) in form.model.items_value" :key="element">
<div class="key">
<sa-image class="mr-2" :url="element.image" size="40"></sa-image>
<div class="sa-table-line-1">
{{ element.title }}
</div>
</div>
<div class="oper">
<el-button type="danger" link @click="onDeleteGoods(index)">
移除
</el-button>
</div>
</div>
</template>
</div>
<div v-if="form.model.use_scope == 'category'" class="sa-template-wrap">
<template v-if="form.model.items_value.length > 0">
<div class="header sa-flex">
<div class="key">分类信息</div>
<div class="oper">操作</div>
</div>
<div class="item" v-for="(element, index) in form.model.items_value" :key="element">
<div class="key">
<div class="goods-title sa-m-b-6">{{ element.name }}</div>
</div>
<div class="oper">
<el-button type="danger" link @click="onDeleteCategory(index)">
移除
</el-button>
</div>
</div>
</template>
</div>
</el-form-item>
</el-form>
</el-scrollbar>
</el-main>
<el-footer class="sa-footer--submit sa-flex sa-row-right">
<el-button type="primary" @click="onConfirm">确定</el-button>
</el-footer>
</el-container>
</div>

View File

@@ -0,0 +1,209 @@
{include file="/shopro/common/script" /}
<style>
.coupon-index .card {
height: 80px;
background: var(--sa-background-assist);
border: 1px solid var(--sa-space);
box-shadow: 0px 2px 6px rgba(140, 140, 140, 0.12);
border-radius: 8px;
padding: 16px;
margin-bottom: 16px;
}
.coupon-index .card .num {
font-weight: 400;
font-size: 24px;
line-height: 26px;
color: var(--sa-subfont);
}
.coupon-index .card .oper {
font-weight: 400;
font-size: 12px;
line-height: 14px;
color: #FAAD14;
cursor: pointer;
}
.coupon-index .card .name {
font-weight: 400;
font-size: 12px;
line-height: 14px;
color: var(--sa-font);
}
.coupon-index .card .tip {
font-size: 14px;
color: var(--sa-subfont);
}
.coupon-index .sa-title {
padding-top: 0;
}
</style>
<div id="index" class="coupon-index panel panel-default panel-intro" v-cloak>
<el-container class="panel-block">
<el-header class="sa-header">
<el-row class="mt-4" :gutter="20">
<el-col v-for="(value,key) in state.dashboard" :xs="24" :sm="12" :md="6" :lg="6" :xl="6">
<div class="card">
<div class="sa-flex sa-row-between mb-1">
<div class="num">{{value.num}}</div>
</div>
<div class="sa-flex sa-row-between">
<div class="name">{{value.name}}</div>
<el-popover popper-class="sa-popper" trigger="hover">
{{value.tip}}
<template #reference>
<el-icon class="tip">
<warning />
</el-icon>
</template>
</el-popover>
</div>
</div>
</el-col>
</el-row>
<div class="sa-title sa-flex sa-row-between">
<div class="sa-title-left">
<div class="left-name">优惠券</div>
<sa-filter-condition v-model="state.filter" @filter-delete="onChangeFilter">
</sa-filter-condition>
</div>
<div class="sa-title-right">
<el-button class="sa-button-refresh" icon="RefreshRight" @click="getData"></el-button>
<el-button class="sa-button-refresh" icon="Search" @click="onOpenFilter"></el-button>
{if $auth->check('shopro/coupon/add')}
<el-button icon="Plus" type="primary" @click="onAdd">添加</el-button>
{/if}
{if $auth->check('shopro/coupon/recyclebin')}
<el-button type="danger" icon="Delete" plain @click="onRecyclebin">回收站</el-button>
{/if}
</div>
</div>
</el-header>
<el-main class="sa-main">
<el-table height="100%" class="sa-table" :data="state.data" stripe @sort-change="onChangeSort">
<el-table-column prop="id" label="ID" min-width="90" sortable="custom"> </el-table-column>
<el-table-column label="优惠券名称" min-width="172">
<template #default="scope">
<div class="sa-table-line-1">{{ scope.row.name }}</div>
</template>
</el-table-column>
<el-table-column label="类型" min-width="74">
<template #default="scope">
<div class="sa-table-line-1">{{ scope.row.type_text }}</div>
</template>
</el-table-column>
<el-table-column label="可用范围" min-width="116">
<template #default="scope">
<div class="sa-table-line-1">{{ scope.row.use_scope_text }}</div>
</template>
</el-table-column>
<el-table-column label="优惠内容" min-width="214">
<template #default="scope">
<div class="sa-table-line-1">{{ scope.row.amount_text }}</div>
</template>
</el-table-column>
<el-table-column label="领取状态" min-width="80">
<template #default="scope">
<el-popover popper-class="sa-popper" placement="bottom" title="优惠券有效期" trigger="hover">
<div v-if="scope.row.use_time_type == 'days'">
领取{{ scope.row.start_days }}天后生效,有效期{{ scope.row.days }}天
</div>
<div v-if="scope.row.use_time_type == 'range'">
<div>开始时间:{{ scope.row.use_start_time }}</div>
<div>结束时间:{{ scope.row.use_end_time }}</div>
</div>
<template #reference>
<div class="sa-table-line-1 get-time-text" :class="
scope.row.get_time_status == 'ing'
? 'sa-color--success'
: scope.row.get_time_status == 'ended'
? 'sa-color--danger'
: 'sa-color--info'
">
{{ scope.row.get_time_text }}
</div>
</template>
</el-popover>
</template>
</el-table-column>
<el-table-column label="已领取" min-width="96">
<template #default="scope">
<div class="sa-table-line-1">{{ scope.row.get_num }}</div>
</template>
</el-table-column>
<el-table-column label="已使用" min-width="96">
<template #default="scope">
<div class="sa-table-line-1">{{ scope.row.use_num }}</div>
</template>
</el-table-column>
<el-table-column label="剩余" min-width="96">
<template #default="scope">
<div class="sa-table-line-1">{{ scope.row.stock }}</div>
</template>
</el-table-column>
<el-table-column label="状态" min-width="130">
<template #default="scope">
{if $auth->check('shopro/coupon/edit')}
<el-dropdown trigger="click" @command="onCommand">
<el-button link>
<el-tag type="info">
{{ scope.row.status_text }}
<el-icon>
<arrow-down />
</el-icon>
</el-tag>
</el-button>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item :command="{
id: scope.row.id,
type: 'normal',
}">公开发放</el-dropdown-item>
<el-dropdown-item :command="{
id: scope.row.id,
type: 'hidden',
}">后台发放</el-dropdown-item>
<el-dropdown-item :command="{
id: scope.row.id,
type: 'disabled',
}">禁止使用</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
{/if}
</template>
</el-table-column>
<el-table-column label="操作" min-width="260" fixed="right">
<template #default="scope">
{if $auth->check('shopro/coupon/send')}
<el-button type="primary" link @click="onSend(scope.row.id)">手动发放</el-button>
{/if}
{if $auth->check('shopro/user/coupon/index')}
<el-button type="primary" link @click="onCoupon(scope.row.id)">领取记录</el-button>
{/if}
{if $auth->check('shopro/coupon/edit')}
<el-button type="primary" link @click="onEdit(scope.row.id)">编辑</el-button>
{/if}
<el-popconfirm width="fit-content" confirm-button-text="确认" cancel-button-text="取消"
title="确认删除这条记录?" @confirm="onDelete(scope.row.id)">
<template #reference>
{if $auth->check('shopro/coupon/delete')}
<el-button type="danger" link>删除</el-button>
{/if}
</template>
</el-popconfirm>
</template>
</el-table-column>
</el-table>
</el-main>
<el-footer class="sa-footer sa-flex sa-row-right">
<sa-pagination v-model="pagination" @pagination-change="getData"></sa-pagination>
</el-footer>
</el-container>
<sa-filter v-model="state.filter" @filter-change="onChangeFilter"></sa-filter>
</div>

View File

@@ -0,0 +1,54 @@
{include file="/shopro/common/script" /}
<div id="recyclebin" class="coupon-recyclebin" v-cloak>
<el-container class="panel-block">
<el-main>
<el-table height="100%" class="sa-table" :data="state.data" stripe @selection-change="onChangeSelection"
@sort-change="onChangeSort">
<el-table-column type="selection" width="48" align="center"></el-table-column>
<el-table-column prop="id" label="ID" min-width="90" sortable="custom"></el-table-column>
<el-table-column label="名称" min-width="100">
<template #default="scope">
<div class="sa-table-line-1">{{ scope.row.name || '-' }}</div>
</template>
</el-table-column>
<el-table-column prop="deletetime" label="删除时间" min-width="172" sortable="custom"></el-table-column>
<el-table-column fixed="right" label="操作" min-width="120">
<template #default="scope">
{if $auth->check('shopro/coupon/restore')}
<el-button type="primary" link @click="onRestore(scope.row.id)">还原</el-button>
{/if}
<el-popconfirm width="fit-content" confirm-button-text="确认" cancel-button-text="取消"
title="确认销毁这条记录?" @confirm="onDestroy(scope.row.id)">
<template #reference>
{if $auth->check('shopro/coupon/destroy')}
<el-button type="danger" link>销毁</el-button>
{/if}
</template>
</el-popconfirm>
</template>
</el-table-column>
</el-table>
</el-main>
<el-footer class="sa-footer sa-flex sa-row-between sa-flex-wrap">
<div class="sa-batch sa-flex">
<div class="tip">
已选择 <span>{{batchHandle.data.length}}</span></div>
<div class="sa-flex">
{if $auth->check('shopro/coupon/restore')}
<el-button type="primary" :disabled="!batchHandle.data.length" @click="onBatchHandle('restore')">还原
</el-button>
{/if}
{if $auth->check('shopro/coupon/destroy')}
<el-button type="danger" :disabled="!batchHandle.data.length" @click="onBatchHandle('destroy')">销毁
</el-button>
{/if}
{if $auth->check('shopro/coupon/destroy')}
<el-button type="danger" @click="onBatchHandle('all')">清空回收站</el-button>
{/if}
</div>
</div>
<sa-pagination class="is-ellipsis" v-model="pagination" @pagination-change="getData"></sa-pagination>
</el-footer>
</el-container>
</div>

View File

@@ -0,0 +1,79 @@
{include file="/shopro/common/script" /}
<div id="select" class="coupon-select" v-cloak>
<el-container class="panel-block">
<el-main>
<el-table class="sa-table" :data="state.data" stripe @selection-change="onChangeSelection">
<el-table-column v-if="state.multiple" type="selection"></el-table-column>
<el-table-column label="优惠券名称" min-width="128">
<template #default="scope">
<div class="sa-table-line-1">
{{ scope.row.name }}
</div>
</template>
</el-table-column>
<el-table-column label="类型" min-width="74">
<template #default="scope">
<div class="sa-table-line-1">
{{ scope.row.type_text }}
</div>
</template>
</el-table-column>
<el-table-column label="可用范围" min-width="88">
<template #default="scope">
<div class="sa-table-line-1">
{{ scope.row.use_scope_text }}
</div>
</template>
</el-table-column>
<el-table-column label="优惠内容" min-width="154">
<template #default="scope">
<div class="sa-table-line-1">
{{ scope.row.amount_text }}
</div>
</template>
</el-table-column>
<el-table-column label="领取状态" min-width="80">
<template #default="scope">
<el-popover popper-class="sa-popper" placement="bottom" title="优惠券有效期" trigger="hover">
<div v-if="scope.row.use_time_type == 'days'">
领取{{ scope.row.start_days }}天后生效,有效期{{ scope.row.days }}天
</div>
<div v-if="scope.row.use_time_type == 'range'">
<div>开始时间:{{ scope.row.use_start_time }}</div>
<div>结束时间:{{ scope.row.use_end_time }}</div>
</div>
<template #reference>
<div class="sa-table-line-1 get-time-text" :class="
scope.row.get_time_status == 'ing'
? 'sa-color--success'
: scope.row.get_time_status == 'ended'
? 'sa-color--danger'
: 'sa-color--info'
">
{{ scope.row.get_time_text }}
</div>
</template>
</el-popover>
</template>
</el-table-column>
<el-table-column label="剩余" min-width="88">
<template #default="scope">
<div class="sa-table-line-1">
{{ scope.row.stock }}
</div>
</template>
</el-table-column>
<el-table-column v-if="!state.multiple" label="操作" min-width="88">
<template #default="scope">
<el-button type="primary" link @click="onSelect(scope.row)">选择</el-button>
</template>
</el-table-column>
</el-table>
</el-main>
<el-footer class="sa-flex" :class="state.multiple ? 'sa-row-between' : 'sa-row-right'">
<sa-pagination class="is-ellipsis" v-model="pagination" @pagination-change="getData"></sa-pagination>
<el-button v-if="state.multiple" type="primary" @click="onConfirm">确 定</el-button>
</el-footer>
</el-container>
</div>

View File

@@ -0,0 +1,382 @@
{include file="/shopro/common/script" /}
<script src="__CDN__/assets/addons/shopro/libs/echarts.min.js?v={$site.version|htmlentities}"></script>
<style>
.dashboard-index .panel-block {
/* background: #f1f4f6; */
}
.dashboard-index .dashboard-index-main {
--el-main-padding: 0;
}
.dashboard-index .el-scrollbar__wrap {
overflow-x: hidden;
}
.dashboard-index .el-scrollbar__bar.is-horizontal {
display: none;
}
.dashboard-index #userTotal,
.dashboard-index #agentTotal,
.dashboard-index #shareTotal {
width: 100%;
height: 66px;
}
.dashboard-index .card {
line-height: 1;
background: var(--sa-background-assist);
border-radius: 8px;
border: 1px solid var(--sa-space);
box-shadow: 0 2px 6px rgb(140 140 140 / 12%);
padding: 12px;
font-size: 12px;
color: var(--sa-font);
margin-bottom: 20px;
}
.dashboard-index .card:hover {
transition: all .2s;
}
@media screen and (min-width: 1200px) {
.dashboard-index .scale-card:hover {
transform: scale(1.05);
}
}
.dashboard-index .card .card-title .left {
font-size: 14px;
color: var(--sa-subtitle);
}
.dashboard-index .card .card-title .left .num {
font-size: 16px;
}
.dashboard-index .card .card-footer {
margin-top: 12px;
}
.dashboard-index .card .card-footer .left {
margin-right: 8px;
}
.dashboard-index .card .card-footer .dot {
width: 6px;
height: 6px;
border-radius: 50%;
display: inline-block;
margin-right: 8px;
}
.dashboard-index .bar-card {
min-height: 358px;
}
.dashboard-index #chartContent {
width: 100%;
height: 296px;
}
.dashboard-index .tab-item {
height: 32px;
line-height: 32px;
margin-right: 20px;
font-size: 14px;
color: var(--sa-subfont);
cursor: pointer;
}
.dashboard-index .tab-item:last-of-type {
margin-right: 0;
}
.dashboard-index .tab-item.is-active {
color: var(--sa-subtitle);
font-weight: bold;
}
@media only screen and (max-width: 768px) {
.dashboard-index .date-time .el-date-editor {
--el-date-editor-datetimerange-width: 320px;
}
}
.dashboard-index .chart-card {
height: 106px;
color: var(--sa-subfont);
}
.dashboard-index .chart-card .card-icon {
width: 24px;
height: 24px;
}
.dashboard-index .chart-card .num {
font-size: 24px;
color: var(--sa-subtitle);
}
.dashboard-index .chart-card .warning {
color: var(--el-color-warning);
}
.dashboard-index .goods-card,
.dashboard-index .hot-search-card {
height: 326px;
}
.dashboard-index .goods-card .header,
.dashboard-index .hot-search-card .header {
line-height: 16px;
font-size: 14px;
color: var(--sa-subtitle);
margin-bottom: 16px;
}
.dashboard-index .top {
width: 18px;
height: 20px;
}
.dashboard-index #rankingContent {
width: 192px;
height: 192px;
}
</style>
<div id="index" class="dashboard-index panel panel-default panel-intro" v-cloak>
<el-container class="panel-block">
<el-main class="dashboard-index-main">
<el-scrollbar height="100%">
{if $auth->check('shopro/dashboard/total')}
<el-row :gutter="20">
<!-- -- commission code start -- -->
<el-col :xs="24" :sm="24" :md="8" :lg="8" :xl="8">
<div class="scale-card card ">
<div class="card-title sa-flex sa-row-between">
<div class="left">{{state.total.user.title}} <span
class="num">{{state.total.user.data.total}}</span> </div>
<div>{{state.total.user.tip}} <span>{{state.total.user.data.today}}</span> </div>
</div>
<div id="userTotal"></div>
<div class="card-footer sa-flex">
<span class="left sa-flex">
<span class="dot" :style="{ background: state.total.user.color }"></span>
<span>{{ state.total.user.footer }}</span>
</span>
<span>{{ state.total.user.data.week }}</span>
</div>
</div>
</el-col>
<el-col :xs="24" :sm="24" :md="8" :lg="8" :xl="8">
<div class="scale-card card ">
<div class="card-title sa-flex sa-row-between">
<div class="left">{{state.total.agent.title}} <span
class="num">{{state.total.agent.data.total}}</span> </div>
<div>{{state.total.agent.tip}} <span>{{state.total.agent.data.today}}</span> </div>
</div>
<div id="agentTotal"></div>
<div class="card-footer sa-flex">
<span class="left sa-flex">
<span class="dot" :style="{ background: state.total.agent.color }"></span>
<span>{{ state.total.agent.footer }}</span>
</span>
<span>{{ state.total.agent.data.week }}</span>
</div>
</div>
</el-col>
<el-col :xs="24" :sm="24" :md="8" :lg="8" :xl="8">
<div class="scale-card card ">
<div class="card-title sa-flex sa-row-between">
<div class="left">{{state.total.share.title}} <span
class="num">{{state.total.share.data.total}}</span> </div>
<div>{{state.total.share.tip}} <span>{{state.total.share.data.today}}</span> </div>
</div>
<div id="shareTotal"></div>
<div class="card-footer sa-flex">
<span class="left sa-flex">
<span class="dot" :style="{ background: state.total.share.color }"></span>
<span>{{ state.total.share.footer }}</span>
</span>
<span>{{ state.total.share.data.week }}</span>
</div>
</div>
</el-col>
<!-- -- commission code end -- -->
<!-- <el-col :xs="24" :sm="24" :md="12" :lg="12" :xl="12">
<div class="scale-card card ">
<div class="card-title sa-flex sa-row-between">
<div class="left">{{state.total.user.title}} <span
class="num">{{state.total.user.data.total}}</span> </div>
<div>{{state.total.user.tip}} <span>{{state.total.user.data.today}}</span> </div>
</div>
<div id="userTotal"></div>
<div class="card-footer sa-flex">
<span class="left sa-flex">
<span class="dot" :style="{ background: state.total.user.color }"></span>
<span>{{ state.total.user.footer }}</span>
</span>
<span>{{ state.total.user.data.week }}</span>
</div>
</div>
</el-col>
<el-col :xs="24" :sm="24" :md="12" :lg="12" :xl="12">
<div class="scale-card card ">
<div class="card-title sa-flex sa-row-between">
<div class="left">{{state.total.share.title}} <span
class="num">{{state.total.share.data.total}}</span> </div>
<div>{{state.total.share.tip}} <span>{{state.total.share.data.today}}</span> </div>
</div>
<div id="shareTotal"></div>
<div class="card-footer sa-flex">
<span class="left sa-flex">
<span class="dot" :style="{ background: state.total.share.color }"></span>
<span>{{ state.total.share.footer }}</span>
</span>
<span>{{ state.total.share.data.week }}</span>
</div>
</div>
</el-col> -->
</el-row>
{/if}
{if $auth->check('shopro/dashboard/chart')}
<el-row :gutter="20">
<el-col :xs="24" :sm="24" :md="24" :lg="16" :xl="16">
<div class="bar-card card">
<div class="sa-flex sa-row-between sa-flex-wrap">
<div class="sa-flex">
<div class="tab-item" :class="chart.tabActive == key ? 'is-active' : ''"
v-for="(value, key) in chart.tabsData" :key="key"
@click="onChangeTabActive(key)">
{{ value }}
</div>
</div>
<div class="date-time">
<el-date-picker v-model="chart.dateTime" type="datetimerange"
value-format="YYYY-MM-DD HH:mm:ss" format="YYYY-MM-DD HH:mm:ss"
:default-time="[new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 2, 1, 23, 59, 59)]"
range-separator="至" start-placeholder="开始日期" end-placeholder="结束日期"
:shortcuts="chart.shortcuts" @change="onChangeDateTime" :editable="false">
</el-date-picker>
</div>
</div>
<div id="chartContent"></div>
</div>
</el-col>
<el-col :xs="24" :sm="24" :md="24" :lg="8" :xl="8">
<el-row :gutter="20">
<el-col :xs="12" :sm="8" :md="12" :lg="12" :xl="12" v-for="(value, key) in statistics"
:key="key">
<div class="chart-card scale-card card">
<div class="sa-flex sa-row-between mb-2">
<img class="card-icon"
:src="`/assets/addons/shopro/img/dashboard/${key}.png`" />
<div class="sa-flex" @click="onOpen(value.status)">
<el-button type="info" link size="small">详情
<el-icon class="ml-1">
<arrow-right />
</el-icon>
</el-button>
</div>
</div>
<div class="num mb-1">{{ value.num }}</div>
<div class="sa-flex sa-row-between">
<span>{{ value.text }}</span>
<el-popover popper-class="sa-popper" placement="top" trigger="hover"
:content="value.tip">
<template #reference>
<el-icon class="warning">
<Warning />
</el-icon>
</template>
</el-popover>
</div>
</div>
</el-col>
</el-row>
</el-col>
</el-row>
{/if}
{if $auth->check('shopro/dashboard/ranking')}
<el-row :gutter="20">
<el-col :xs="24" :sm="24" :md="24" :lg="12" :xl="12">
<div class="goods-card card">
<div class="header">
<span>销量榜</span>
</div>
<el-table class="sa-table" :data="ranking.goods" stripe>
<el-table-column label="排名" width="60" align="center">
<template #default="scope">
<img class="top"
:src="`/assets/addons/shopro/img/dashboard/top${scope.$index + 1}.png`" />
</template>
</el-table-column>
<el-table-column label="名称" min-width="200">
<template #default="scope">
<div class="sa-flex">
<sa-image :url="scope.row.image" size="20"></sa-image>
<div class="ml-2 sa-table-line-1">
{{ scope.row.title || '-' }}
</div>
</div>
</template>
</el-table-column>
<el-table-column label="销量" width="100">
<template #default="scope">
<div class="sa-table-line-1">
{{ scope.row.real_sales || '-' }}
</div>
</template>
</el-table-column>
</el-table>
</div>
</el-col>
<el-col :xs="24" :sm="24" :md="24" :lg="12" :xl="12">
<div class="hot-search-card card">
<div class="header">
<span>热搜榜</span>
</div>
<el-row :gutter="16">
<el-col :xs="24" :sm="24" :md="16" :lg="16" :xl="16">
<el-table class="sa-table" :data="ranking.hot_search" stripe>
<el-table-column label="排名" width="60" align="center">
<template #default="scope">
<img class="top"
:src="`/assets/addons/shopro/img/dashboard/top${scope.$index + 1}.png`" />
</template>
</el-table-column>
<el-table-column label="名称" min-width="200">
<template #default="scope">
<div class="sa-table-line-1">
{{ scope.row.keyword || '-' }}
</div>
</template>
</el-table-column>
<el-table-column label="搜索量(次)" width="100">
<template #default="scope">
<div class="sa-table-line-1">
{{ scope.row.num }}
</div>
</template>
</el-table-column>
</el-table>
</el-col>
<el-col :xs="24" :sm="24" :md="8" :lg="8" :xl="8">
<div class="sa-flex sa-row-center">
<div id="rankingContent"></div>
</div>
</el-col>
</el-row>
</div>
</el-col>
</el-row>
{/if}
</el-scrollbar>
</el-main>
</el-container>
</div>

View File

@@ -0,0 +1,29 @@
{include file="/shopro/common/script" /}
<div id="addEdit" class="area-form" v-cloak>
<el-container class="panel-block">
<el-main>
<el-scrollbar height="100%">
<el-form :model="form.model" :rules="form.rules" ref="formRef" label-width="100px">
<el-form-item label="上级行政区" prop="pid">
<el-cascader class="sa-w-360" v-model="form.model.pid" :options="area.select" :props="{
label: 'name',
value: 'id',
checkStrictly: true,
emitPath: false,
}" clearable placeholder="请选择上级行政区"></el-cascader>
</el-form-item>
<el-form-item label="行政区ID" prop="id">
<el-input class="sa-w-360" v-model="form.model.id" placeholder="请输入行政区ID"></el-input>
</el-form-item>
<el-form-item label="名称" prop="name">
<el-input class="sa-w-360" v-model="form.model.name" placeholder="请输入名称"></el-input>
</el-form-item>
</el-form>
</el-scrollbar>
</el-main>
<el-footer class="sa-footer--submit sa-flex sa-row-right">
<el-button type="primary" @click="onConfirm">确定</el-button>
</el-footer>
</el-container>
</div>

View File

@@ -0,0 +1,108 @@
{include file="/shopro/common/script" /}
<style>
.area-index .sa-title .tip {
margin-left: 8px;
font-weight: 400;
font-size: 12px;
color: var(--sa-subfont);
}
.area-index .sa-title .tip a {
color: var(--sa-subfont);
text-decoration: underline;
}
.area-index .tree-header {
height: 40px;
padding-left: 20px;
background: var(--sa-table-header-bg);
}
.area-index .tree-content .el-tree-node__content {
height: 48px;
}
.area-index .tree-content .el-tree-node__label {
flex: 1;
}
.area-index .tree-header .left,
.area-index .tree-content .left {
flex: 1;
}
.area-index .tree-header .id,
.area-index .tree-content .id {
margin-right: 12px;
color: #999;
}
.area-index .tree-header .level,
.area-index .tree-header .oper,
.area-index .tree-content .level,
.area-index .tree-content .oper {
flex-shrink: 0;
width: 120px;
}
</style>
<div id="index" class="area-index panel panel-default panel-intro" v-cloak>
<el-container class="panel-block">
<el-header class="sa-header">
<div class="sa-title sa-flex sa-flex-wrap sa-row-between">
<div class="sa-title-left">
<div class="left-name">省市区</div>
<div class="tip">
数据来源:
<a href="http://www.stats.gov.cn/sj/tjbz/tjyqhdmhcxhfdm/2022/" target="_blank">
2022年国家统计局区划代码
</a>
更新时间2022-10-31
</div>
</div>
<div class="sa-title-right">
<el-button class="sa-button-refresh" icon="RefreshRight" @click="getData"></el-button>
{if $auth->check('shopro/data/area/add')}
<el-button icon="Plus" type="primary" @click="onAdd">添加</el-button>
{/if}
</div>
</div>
</el-header>
<el-main class="sa-main">
<el-scrollbar height="100%">
<div class="tree-header sa-flex">
<div class="left">名称</div>
<div class="level">级别</div>
<div class="oper">操作</div>
</div>
<el-tree class="tree-content" :data="state.data" node-key="id" ref="accessTree">
<template #default="{ node, data }">
<div class="tree-item sa-flex">
<div class="left sa-flex">
<div class="id"> #{{ data.id }} </div>
<div class="name">{{ data.name }}</div>
</div>
<div class="level">
{{ data.level == 'province' ? '省级' : data.level == 'city' ? '市级' : '区级' }}
</div>
<div class="oper">
{if $auth->check('shopro/data/area/edit')}
<el-button type="primary" link @click.stop="onEdit(node.data.id)">编辑</el-button>
{/if}
<el-popconfirm width="fit-content" confirm-button-text="确认" cancel-button-text="取消"
title="确认删除这条记录?" @confirm="onDelete(node.data.id)">
<template #reference>
{if $auth->check('shopro/data/area/delete')}
<el-button type="danger" link @click.stop>删除</el-button>
{/if}
</template>
</el-popconfirm>
</div>
</div>
</template>
</el-tree>
</el-scrollbar>
</el-main>
</el-container>
</div>

View File

@@ -0,0 +1,19 @@
{include file="/shopro/common/script" /}
<div id="select" class="area-select" v-cloak>
<el-container class="panel-block">
<el-main>
<el-scrollbar height="100%">
<el-checkbox v-model="state.checkedAll" :indeterminate="isIndeterminate" label="全选" @change="onChange">
</el-checkbox>
<el-tree :data="state.data" node-key="id" show-checkbox :default-checked-keys="state.ids"
@check-change="onChangeCheck" ref="treeRef">
<template #default="{ data }">{{ data.name }}</template>
</el-tree>
</el-scrollbar>
</el-main>
<el-footer class="sa-footer--submit sa-flex sa-row-right">
<el-button type="primary" @click="onConfirm">确定</el-button>
</el-footer>
</el-container>
</div>

View File

@@ -0,0 +1,24 @@
{include file="/shopro/common/script" /}
<div id="addEdit" class="express-form" v-cloak>
<el-container class="panel-block">
<el-main>
<el-scrollbar height="100%">
<el-form :model="form.model" :rules="form.rules" ref="formRef" label-width="100px">
<el-form-item label="快递公司" prop="name">
<el-input class="sa-w-360" v-model="form.model.name" placeholder="请输入快递公司"></el-input>
</el-form-item>
<el-form-item label="快递编码" prop="code">
<el-input class="sa-w-360" v-model="form.model.code" placeholder="请输入快递编码"></el-input>
</el-form-item>
<el-form-item label="权重" prop="weigh">
<el-input class="sa-w-360" v-model="form.model.weigh" placeholder="请输入权重" type="number"></el-input>
</el-form-item>
</el-form>
</el-scrollbar>
</el-main>
<el-footer class="sa-footer--submit sa-flex sa-row-right">
<el-button type="primary" @click="onConfirm">确定</el-button>
</el-footer>
</el-container>
</div>

View File

@@ -0,0 +1,77 @@
{include file="/shopro/common/script" /}
<div id="index" class="express-index panel panel-default panel-intro" v-cloak>
<el-container class="panel-block">
<el-header class="sa-header">
<div class="sa-title sa-flex sa-row-between">
<div class="sa-title-left">
<div class="left-name">快递公司</div>
<sa-filter-condition v-model="state.filter" @filter-delete="onChangeFilter">
</sa-filter-condition>
</div>
<div class="sa-title-right">
<el-button class="sa-button-refresh" icon="RefreshRight" @click="getData"></el-button>
<el-button class="sa-button-refresh" icon="Search" @click="onOpenFilter"></el-button>
{if $auth->check('shopro/data/express/add')}
<el-button icon="Plus" type="primary" @click="onAdd">添加</el-button>
{/if}
</div>
</div>
<el-alert class="mb-3" type="warning">
<template #title>快递鸟所有快递公司列表,可以只保留自己需要的,删除多余的快递公司</template>
</el-alert>
</el-header>
<el-main class="sa-main">
<el-table height="100%" class="sa-table" :data="state.data" stripe @selection-change="onChangeSelection"
@sort-change="onChangeSort">
<el-table-column type="selection" width="48" align="center"></el-table-column>
<el-table-column prop="id" label="ID" min-width="90" sortable="custom"> </el-table-column>
<el-table-column label="快递公司" min-width="200">
<template #default="scope">
<div class="sa-table-line-1">
{{ scope.row.name || '-' }}
</div>
</template>
</el-table-column>
<el-table-column label="快递编码" min-width="140">
<template #default="scope">
<div class="sa-table-line-1">
{{ scope.row.code || '-' }}
</div>
</template>
</el-table-column>
<el-table-column prop="weigh" label="权重" min-width="100" sortable="custom">
</el-table-column>
<el-table-column fixed="right" label="操作" min-width="120">
<template #default="scope">
{if $auth->check('shopro/data/express/edit')}
<el-button type="primary" link @click="onEdit(scope.row.id)">编辑</el-button>
{/if}
<el-popconfirm width="fit-content" confirm-button-text="确认" cancel-button-text="取消"
title="确认删除这条记录?" @confirm="onDelete(scope.row.id)">
<template #reference>
{if $auth->check('shopro/data/express/delete')}
<el-button type="danger" link>删除</el-button>
{/if}
</template>
</el-popconfirm>
</template>
</el-table-column>
</el-table>
</el-main>
<el-footer class="sa-footer sa-flex sa-row-between sa-flex-wrap">
<div class="sa-batch sa-flex">
<div class="tip">
已选择 <span>{{batchHandle.data.length}}</span></div>
<div class="sa-flex">
{if $auth->check('shopro/data/express/delete')}
<el-button type="danger" :disabled="!batchHandle.data.length" @click="onBatchHandle('delete')">删除
</el-button>
{/if}
</div>
</div>
<sa-pagination v-model="pagination" @pagination-change="getData"></sa-pagination>
</el-footer>
</el-container>
<sa-filter v-model="state.filter" @filter-change="onChangeFilter"></sa-filter>
</div>

View File

@@ -0,0 +1,45 @@
{include file="/shopro/common/script" /}
<div id="addEdit" class="fake-user-form" v-cloak>
<el-container class="panel-block">
<el-main>
<el-scrollbar height="100%">
<el-form :model="form.model" :rules="form.rules" ref="formRef" label-width="100px">
<el-form-item label="用户头像" prop="avatar">
<sa-uploader v-model="form.model.avatar" fileType="image"></sa-uploader>
</el-form-item>
<el-form-item label="用户名" prop="username">
<el-input class="sa-w-360" v-model="form.model.username" placeholder="请输入用户名"></el-input>
</el-form-item>
<el-form-item label="用户昵称" prop="nickname">
<el-input class="sa-w-360" v-model="form.model.nickname" placeholder="请输入用户昵称"></el-input>
</el-form-item>
<el-form-item label="电子邮箱" prop="email">
<el-input class="sa-w-360" v-model="form.model.email" placeholder="请输入电子邮箱"></el-input>
</el-form-item>
<el-form-item label="手机号" prop="mobile">
<el-input class="sa-w-360" v-model="form.model.mobile" placeholder="请输入手机号"></el-input>
</el-form-item>
<el-form-item label="用户密码">
<el-input class="sa-w-360" v-model="form.model.password" placeholder="不修改请留空"></el-input>
</el-form-item>
<el-form-item label="用户性别">
<el-radio-group v-model="form.model.gender">
<el-radio :label="0"></el-radio>
<el-radio :label="1"></el-radio>
</el-radio-group>
</el-form-item>
<el-form-item v-if="state.type == 'edit'" label="创建时间">
{{ form.model.createtime }}
</el-form-item>
<el-form-item v-if="state.type == 'edit'" label="更新时间">
{{ form.model.updatetime }}
</el-form-item>
</el-form>
</el-scrollbar>
</el-main>
<el-footer class="sa-footer--submit sa-flex sa-row-right">
<el-button type="primary" @click="onConfirm">确定</el-button>
</el-footer>
</el-container>
</div>

View File

@@ -0,0 +1,96 @@
{include file="/shopro/common/script" /}
<div id="index" class="fake-user-index panel panel-default panel-intro" v-cloak>
<el-container class="panel-block">
<el-header class="sa-header">
<div class="sa-title sa-flex sa-row-between">
<div class="sa-title-left">
<div class="left-name">虚拟用户</div>
<sa-filter-condition v-model="state.filter" @filter-delete="onChangeFilter">
</sa-filter-condition>
</div>
<div class="sa-title-right">
<el-button class="sa-button-refresh" icon="RefreshRight" @click="getData"></el-button>
<el-button class="sa-button-refresh" icon="Search" @click="onOpenFilter"></el-button>
{if $auth->check('shopro/data/fake_user/add')}
<el-button icon="Plus" type="primary" @click="onAdd">添加</el-button>
{/if}
{if $auth->check('shopro/data/fake_user/random')}
<el-button @click="onRandom">自动生成</el-button>
{/if}
</div>
</div>
<el-alert class="mb-3" type="warning">
<template #title>
<div>1、可作为虚拟成团时候的虚拟用户和虚拟评价时候的虚拟用户</div>
<div>2、添加完之后可修改虚拟用户信息不要轻易删除虚拟用户</div>
</template>
</el-alert>
</el-header>
<el-main class="sa-main">
<el-table height="100%" class="sa-table" :data="state.data" stripe @selection-change="onChangeSelection"
@sort-change="onChangeSort">
<el-table-column type="selection" width="48" align="center"></el-table-column>
<el-table-column prop="id" label="ID" min-width="90" sortable="custom"> </el-table-column>
<el-table-column label="用户名" min-width="180">
<template #default="scope">
<div class="sa-table-line-1">
{{ scope.row.username || '-' }}
</div>
</template>
</el-table-column>
<el-table-column label="用户信息" min-width="180">
<template #default="scope">
<sa-user-profile :user="scope.row" :id="scope.row.id" />
</template>
</el-table-column>
<el-table-column label="电子邮箱" min-width="170">
<template #default="scope">
<div class="sa-table-line-1">
{{ scope.row.email || '-' }}
</div>
</template>
</el-table-column>
<el-table-column label="创建时间" width="172">
<template #default="scope">
{{ scope.row.createtime || '-' }}
</template>
</el-table-column>
<el-table-column label="更新时间" width="172">
<template #default="scope">
{{ scope.row.updatetime || '-' }}
</template>
</el-table-column>
<el-table-column fixed="right" label="操作" min-width="120">
<template #default="scope">
{if $auth->check('shopro/data/fake_user/edit')}
<el-button type="primary" link @click="onEdit(scope.row.id)">编辑</el-button>
{/if}
<el-popconfirm width="fit-content" confirm-button-text="确认" cancel-button-text="取消"
title="确认删除这条记录?" @confirm="onDelete(scope.row.id)">
<template #reference>
{if $auth->check('shopro/data/fake_user/delete')}
<el-button type="danger" link>删除</el-button>
{/if}
</template>
</el-popconfirm>
</template>
</el-table-column>
</el-table>
</el-main>
<el-footer class="sa-footer sa-flex sa-row-between sa-flex-wrap">
<div class="sa-batch sa-flex">
<div class="tip">
已选择 <span>{{batchHandle.data.length}}</span></div>
<div class="sa-flex">
{if $auth->check('shopro/data/fake_user/delete')}
<el-button type="danger" :disabled="!batchHandle.data.length" @click="onBatchHandle('delete')">删除
</el-button>
{/if}
</div>
</div>
<sa-pagination v-model="pagination" @pagination-change="getData"></sa-pagination>
</el-footer>
</el-container>
<sa-filter v-model="state.filter" @filter-change="onChangeFilter"></sa-filter>
</div>

View File

@@ -0,0 +1,18 @@
{include file="/shopro/common/script" /}
<div id="random" class="fake-user-random" v-cloak>
<el-container class="panel-block">
<el-main>
<el-scrollbar height="100%">
<el-form :model="form.model" :rules="form.rules" ref="formRef" label-width="100px">
<el-form-item label="生成人数" prop="num">
<el-input v-model="form.model.num" placeholder="请输入生成虚拟人数" type="number" min="0"></el-input>
</el-form-item>
</el-form>
</el-scrollbar>
</el-main>
<el-footer class="sa-footer--submit sa-flex sa-row-right">
<el-button type="primary" @click="onConfirm">确定</el-button>
</el-footer>
</el-container>
</div>

View File

@@ -0,0 +1,31 @@
{include file="/shopro/common/script" /}
<div id="select" class="fake-user-select" v-cloak>
<el-container class="panel-block">
<el-main>
<el-table height="100%" class="sa-table" :data="state.data" stripe>
<el-table-column prop="id" label="ID" min-width="90"> </el-table-column>
<el-table-column label="用户名" min-width="180">
<template #default="scope">
<div class="sa-table-line-1">
{{ scope.row.username || '-' }}
</div>
</template>
</el-table-column>
<el-table-column label="用户信息" min-width="180">
<template #default="scope">
<sa-user-profile :user="scope.row" :id="scope.row.id" />
</template>
</el-table-column>
<el-table-column fixed="right" label="操作" min-width="120">
<template #default="scope">
<el-button type="primary" link @click="onSelect(scope.row)">选择</el-button>
</template>
</el-table-column>
</el-table>
</el-main>
<el-footer class="sa-footer sa-flex sa-row-right">
<sa-pagination class="is-ellipsis" v-model="pagination" @pagination-change="getData"></sa-pagination>
</el-footer>
</el-container>
</div>

View File

@@ -0,0 +1,28 @@
{include file="/shopro/common/script" /}
<div id="addEdit" class="faq-form" v-cloak>
<el-container class="panel-block">
<el-main>
<el-scrollbar height="100%">
<el-form :model="form.model" :rules="form.rules" ref="formRef" label-width="100px">
<el-form-item label="标题" prop="title">
<el-input class="sa-w-360" v-model="form.model.title" placeholder="请输入标题"></el-input>
</el-form-item>
<el-form-item label="内容" prop="content">
<el-input class="sa-w-360" type="textarea" v-model="form.model.content" placeholder="请输入内容">
</el-input>
</el-form-item>
<el-form-item label="状态" required>
<el-radio-group v-model="form.model.status">
<el-radio label="normal">正常</el-radio>
<el-radio label="hidden">隐藏</el-radio>
</el-radio-group>
</el-form-item>
</el-form>
</el-scrollbar>
</el-main>
<el-footer class="sa-footer--submit sa-flex sa-row-right">
<el-button type="primary" @click="onConfirm">确定</el-button>
</el-footer>
</el-container>
</div>

View File

@@ -0,0 +1,97 @@
{include file="/shopro/common/script" /}
<div id="index" class="faq-index panel panel-default panel-intro" v-cloak>
<el-container class="panel-block">
<el-header class="sa-header">
<div class="sa-title sa-flex sa-row-between">
<div class="sa-title-left">
<div class="left-name">常见问题</div>
<sa-filter-condition v-model="state.filter" @filter-delete="onChangeFilter">
</sa-filter-condition>
</div>
<div class="sa-title-right">
<el-button class="sa-button-refresh" icon="RefreshRight" @click="getData"></el-button>
<el-button class="sa-button-refresh" icon="Search" @click="onOpenFilter"></el-button>
{if $auth->check('shopro/data/faq/add')}
<el-button icon="Plus" type="primary" @click="onAdd">添加</el-button>
{/if}
</div>
</div>
</el-header>
<el-main class="sa-main">
<el-table height="100%" class="sa-table" :data="state.data" stripe @selection-change="onChangeSelection"
@sort-change="onChangeSort">
<el-table-column type="selection" width="48" align="center"></el-table-column>
<el-table-column prop="id" label="ID" min-width="90" sortable="custom"> </el-table-column>
<el-table-column label="标题" min-width="100">
<template #default="scope">
<div class="sa-table-line-1">
{{ scope.row.title || '-' }}
</div>
</template>
</el-table-column>
<el-table-column label="内容" min-width="140">
<template #default="scope">
<div class="sa-table-line-1">
{{ scope.row.content || '-' }}
</div>
</template>
</el-table-column>
<el-table-column label="状态" min-width="100">
<template #default="scope">
<el-tag :type="scope.row.status == 'normal' ? 'success' : 'info'">
{{ scope.row.status_text }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="创建时间" width="172">
<template #default="scope">
{{ scope.row.createtime || '-' }}
</template>
</el-table-column>
<el-table-column label="更新时间" width="172">
<template #default="scope">
{{ scope.row.updatetime || '-' }}
</template>
</el-table-column>
<el-table-column fixed="right" label="操作" min-width="120">
<template #default="scope">
{if $auth->check('shopro/data/faq/edit')}
<el-button type="primary" link @click="onEdit(scope.row.id)">编辑</el-button>
{/if}
<el-popconfirm width="fit-content" confirm-button-text="确认" cancel-button-text="取消"
title="确认删除这条记录?" @confirm="onDelete(scope.row.id)">
<template #reference>
{if $auth->check('shopro/data/faq/delete')}
<el-button type="danger" link>删除</el-button>
{/if}
</template>
</el-popconfirm>
</template>
</el-table-column>
</el-table>
</el-main>
<el-footer class="sa-footer sa-flex sa-row-between sa-flex-wrap">
<div class="sa-batch sa-flex">
<div class="tip">
已选择 <span>{{batchHandle.data.length}}</span></div>
<div class="sa-flex">
{if $auth->check('shopro/data/faq/delete')}
<el-button type="danger" :disabled="!batchHandle.data.length" @click="onBatchHandle('delete')">删除
</el-button>
{/if}
{if $auth->check('shopro/data/faq/edit')}
<el-button type="success" :disabled="!batchHandle.data.length" @click="onBatchHandle('normal')">正常
</el-button>
{/if}
{if $auth->check('shopro/data/faq/edit')}
<el-button type="info" :disabled="!batchHandle.data.length" @click="onBatchHandle('hidden')">隐藏
</el-button>
{/if}
</div>
</div>
<sa-pagination v-model="pagination" @pagination-change="getData"></sa-pagination>
</el-footer>
</el-container>
<sa-filter v-model="state.filter" @filter-change="onChangeFilter"></sa-filter>
</div>

View File

@@ -0,0 +1,24 @@
{include file="/shopro/common/script" /}
<div id="addEdit" class="page-form" v-cloak>
<el-container class="panel-block">
<el-main>
<el-scrollbar height="100%">
<el-form :model="form.model" :rules="form.rules" ref="formRef" label-width="100px">
<el-form-item label="名称" prop="name">
<el-input class="sa-w-360" v-model="form.model.name" placeholder="请输入名称"></el-input>
</el-form-item>
<el-form-item label="路径" prop="path">
<el-input class="sa-w-360" v-model="form.model.path" placeholder="请输入路径"></el-input>
</el-form-item>
<el-form-item label="分组" prop="group">
<el-input class="sa-w-360" v-model="form.model.group" placeholder="请输入分组"></el-input>
</el-form-item>
</el-form>
</el-scrollbar>
</el-main>
<el-footer class="sa-footer--submit sa-flex sa-row-right">
<el-button type="primary" @click="onConfirm">确定</el-button>
</el-footer>
</el-container>
</div>

View File

@@ -0,0 +1,86 @@
{include file="/shopro/common/script" /}
<div id="index" class="page-index panel panel-default panel-intro" v-cloak>
<el-container class="panel-block">
<el-header class="sa-header">
<div class="sa-title sa-flex sa-row-between">
<div class="sa-title-left">
<div class="left-name">页面链接</div>
</div>
<div class="sa-title-right">
<el-button class="sa-button-refresh" icon="RefreshRight" @click="getData"></el-button>
{if $auth->check('shopro/data/page/add')}
<el-button icon="Plus" type="primary" @click="onAdd">添加</el-button>
{/if}
</div>
</div>
</el-header>
<el-main class="sa-main">
<el-table height="100%" class="sa-table" :data="state.data" stripe @selection-change="onChangeSelection"
@sort-change="onChangeSort">
<el-table-column type="selection" width="48" align="center"></el-table-column>
<el-table-column prop="id" label="ID" min-width="90" sortable="custom"> </el-table-column>
<el-table-column label="名称" min-width="200">
<template #default="scope">
<div class="sa-table-line-1">
{{ scope.row.name || '-' }}
</div>
</template>
</el-table-column>
<el-table-column label="路径" min-width="340">
<template #default="scope">
<div class="sa-table-line-1">
{{ scope.row.path || '-' }}
</div>
</template>
</el-table-column>
<el-table-column label="分组" min-width="100">
<template #default="scope">
<div class="sa-table-line-1">
{{ scope.row.group || '-' }}
</div>
</template>
</el-table-column>
<el-table-column label="创建时间" width="172">
<template #default="scope">
{{ scope.row.createtime || '-' }}
</template>
</el-table-column>
<el-table-column label="更新时间" width="172">
<template #default="scope">
{{ scope.row.updatetime || '-' }}
</template>
</el-table-column>
<el-table-column fixed="right" label="操作" min-width="120">
<template #default="scope">
{if $auth->check('shopro/data/page/edit')}
<el-button type="primary" link @click="onEdit(scope.row.id)">编辑</el-button>
{/if}
<el-popconfirm width="fit-content" confirm-button-text="确认" cancel-button-text="取消"
title="确认删除这条记录?" @confirm="onDelete(scope.row.id)">
<template #reference>
{if $auth->check('shopro/data/page/delete')}
<el-button type="danger" link>删除</el-button>
{/if}
</template>
</el-popconfirm>
</template>
</el-table-column>
</el-table>
</el-main>
<el-footer class="sa-footer sa-flex sa-row-between sa-flex-wrap">
<div class="sa-batch sa-flex">
<div class="tip">
已选择 <span>{{batchHandle.data.length}}</span></div>
<div class="sa-flex">
{if $auth->check('shopro/data/page/delete')}
<el-button type="danger" :disabled="!batchHandle.data.length" @click="onBatchHandle('delete')">删除
</el-button>
{/if}
</div>
</div>
<sa-pagination v-model="pagination" @pagination-change="getData"></sa-pagination>
</el-footer>
</el-container>
<sa-filter v-model="state.filter" @filter-change="onChangeFilter"></sa-filter>
</div>

View File

@@ -0,0 +1,123 @@
{include file="/shopro/common/script" /}
<style>
.page-select .page-select-main {
--el-main-padding: 0;
}
.page-select .el-aside {
--el-aside-width: 140px;
border-right: 1px solid var(--sa-border);
padding: 20px;
}
.page-select .top {
height: 100%;
}
.page-select .group .name {
margin: 0 0 12px 12px;
}
.page-select .group .link {
margin-bottom: 12px;
}
.page-select .group .link .item {
padding: 0 16px;
height: 32px;
display: flex;
align-items: center;
justify-content: center;
border: 1px solid var(--sa-border);
border-radius: 4px;
margin: 0 12px 12px 0;
font-size: 14px;
font-weight: 400;
color: var(--sa-font);
cursor: pointer;
}
.page-select .group .link .item:hover {
color: var(--el-color-primary);
background: var(--t-bg-hover);
}
.page-select .group .link .item.item-active {
color: var(--el-color-primary);
background: var(--t-bg-active);
}
.page-select .left .group {
height: 32px;
line-height: 32px;
border-radius: 4px;
font-size: 14px;
font-weight: 400;
color: var(--sa-subtitle);
margin-bottom: 4px;
cursor: pointer;
}
.page-select .left .group:hover {
color: var(--el-color-primary);
background: var(--t-bg-hover);
}
.page-select .left .group.is-active {
color: var(--el-color-primary);
background: var(--t-bg-active);
}
.page-select .right .name {
line-height: 16px;
font-size: 14px;
font-weight: 600;
color: var(--sa-subtitle);
margin: 0 0 12px 0;
}
.page-select .right-group .link {
border-bottom: 1px dashed var(--sa-border);
}
</style>
<div id="select" class="page-select" v-cloak>
<el-container class="panel-block">
<el-main class="page-select-main">
<el-container class="top">
<el-aside>
<el-scrollbar class="left" height="100%">
<div class="group" :class="state.currentIndex == i ? 'is-active' : ''"
v-for="(g, i) in state.data" :key="g" @click.stop="onChangeIndex(i)">
<div class="name">{{ g.group }}</div>
</div>
</el-scrollbar>
</el-aside>
<el-main>
<el-scrollbar class="right" ref="rightScrollRef" height="100%" @scroll="onRightScroll">
<div class="group right-group" :ref="(el) => setRightRef(el, g, i)" v-for="(g, i) in state.data"
:key="g">
<div class="name">{{ g.group }}</div>
<div class="link sa-flex sa-flex-wrap">
<template v-for="l in g.children" :key="l">
<el-popover popper-class="sa-popper" trigger="hover" :content="l.path">
<template #reference>
<div class="item" :class="state.selected.id == l.id ? 'item-active' : ''"
@click="onSelect(l)">
{{ l.name }}
</div>
</template>
</el-popover>
</template>
</div>
</div>
</el-scrollbar>
</el-main>
</el-container>
</el-main>
<el-footer class="sa-footer--submit sa-flex sa-row-right">
<el-button type="primary" @click="onConfirm">确定</el-button>
</el-footer>
</el-container>
</div>

View File

@@ -0,0 +1,23 @@
{include file="/shopro/common/script" /}
<div id="addEdit" class="richtext-form" v-cloak>
<el-container class="panel-block">
<el-main>
<el-scrollbar height="100%">
<el-form :model="form.model" :rules="form.rules" ref="formRef" label-width="100px">
<el-form-item label="标题" prop="title">
<el-input class="sa-w-360" v-model="form.model.title" placeholder="请输入标题"></el-input>
</el-form-item>
<el-form-item label="内容" prop="content">
<form role="form">
<textarea id="richtextContent" class="editor"></textarea>
</form>
</el-form-item>
</el-form>
</el-scrollbar>
</el-main>
<el-footer class="sa-footer--submit sa-flex sa-row-right">
<el-button type="primary" @click="onConfirm">确定</el-button>
</el-footer>
</el-container>
</div>

View File

@@ -0,0 +1,75 @@
{include file="/shopro/common/script" /}
<div id="index" class="richtext-index panel panel-default panel-intro" v-cloak>
<el-container class="panel-block">
<el-header class="sa-header">
<div class="sa-title sa-flex sa-row-between">
<div class="sa-title-left">
<div class="left-name">富文本</div>
<sa-filter-condition v-model="state.filter" @filter-delete="onChangeFilter">
</sa-filter-condition>
</div>
<div class="sa-title-right">
<el-button class="sa-button-refresh" icon="RefreshRight" @click="getData"></el-button>
<el-button class="sa-button-refresh" icon="Search" @click="onOpenFilter"></el-button>
{if $auth->check('shopro/data/richtext/add')}
<el-button icon="Plus" type="primary" @click="onAdd">添加</el-button>
{/if}
</div>
</div>
</el-header>
<el-main class="sa-main">
<el-table height="100%" class="sa-table" :data="state.data" stripe @selection-change="onChangeSelection"
@sort-change="onChangeSort">
<el-table-column type="selection" width="48" align="center"></el-table-column>
<el-table-column prop="id" label="ID" min-width="90" sortable="custom"> </el-table-column>
<el-table-column label="标题" min-width="120">
<template #default="scope">
<div class="sa-table-line-1">
{{ scope.row.title || '-' }}
</div>
</template>
</el-table-column>
<el-table-column label="创建时间" width="172">
<template #default="scope">
{{ scope.row.createtime || '-' }}
</template>
</el-table-column>
<el-table-column label="更新时间" width="172">
<template #default="scope">
{{ scope.row.updatetime || '-' }}
</template>
</el-table-column>
<el-table-column fixed="right" label="操作" min-width="120">
<template #default="scope">
{if $auth->check('shopro/data/richtext/edit')}
<el-button type="primary" link @click="onEdit(scope.row.id)">编辑</el-button>
{/if}
<el-popconfirm width="fit-content" confirm-button-text="确认" cancel-button-text="取消"
title="确认删除这条记录?" @confirm="onDelete(scope.row.id)">
<template #reference>
{if $auth->check('shopro/data/richtext/delete')}
<el-button type="danger" link>删除</el-button>
{/if}
</template>
</el-popconfirm>
</template>
</el-table-column>
</el-table>
</el-main>
<el-footer class="sa-footer sa-flex sa-row-between sa-flex-wrap">
<div class="sa-batch sa-flex">
<div class="tip">
已选择 <span>{{batchHandle.data.length}}</span></div>
<div class="sa-flex">
{if $auth->check('shopro/data/richtext/delete')}
<el-button type="danger" :disabled="!batchHandle.data.length" @click="onBatchHandle('delete')">删除
</el-button>
{/if}
</div>
</div>
<sa-pagination v-model="pagination" @pagination-change="getData"></sa-pagination>
</el-footer>
</el-container>
<sa-filter v-model="state.filter" @filter-change="onChangeFilter"></sa-filter>
</div>

View File

@@ -0,0 +1,43 @@
{include file="/shopro/common/script" /}
<div id="select" class="richtext-select" v-cloak>
<el-container class="panel-block">
<el-header>
<div class="sa-title sa-flex sa-row-right">
<el-button icon="Plus" type="primary" @click="onAdd">添加</el-button>
</div>
</el-header>
<el-main class="sa-main">
<el-table height="100%" class="sa-table" :data="state.data" stripe @selection-change="onChangeSelection"
@sort-change="onChangeSort">
<el-table-column type="selection" width="48" align="center"></el-table-column>
<el-table-column prop="id" label="ID" min-width="90" sortable="custom"> </el-table-column>
<el-table-column label="标题" min-width="120">
<template #default="scope">
<div class="sa-table-line-1">
{{ scope.row.title || '-' }}
</div>
</template>
</el-table-column>
<el-table-column label="创建时间" width="172">
<template #default="scope">
{{ scope.row.createtime || '-' }}
</template>
</el-table-column>
<el-table-column label="更新时间" width="172">
<template #default="scope">
{{ scope.row.updatetime || '-' }}
</template>
</el-table-column>
<el-table-column fixed="right" label="操作" min-width="120">
<template #default="scope">
<el-button type="primary" link @click="onSelect(scope.row)">选择</el-button>
</template>
</el-table-column>
</el-table>
</el-main>
<el-footer class="sa-footer sa-flex sa-row-right sa-flex-wrap">
<sa-pagination class="is-ellipsis" v-model="pagination" @pagination-change="getData"></sa-pagination>
</el-footer>
</el-container>
</div>

View File

@@ -0,0 +1,118 @@
{include file="/shopro/common/script" /}
<style>
.designer-index .template-item {
width: 246px;
height: 480px;
border: 1px solid var(--sa-space);
box-shadow: 0 0 4px #59595933;
border-radius: 8px;
margin-bottom: 20px;
margin-right: 20px;
position: relative;
overflow: hidden;
}
.designer-index .template-item img {
width: 100%;
}
.designer-index .template-item:hover {
transform: scale(1.02);
box-shadow: 0 4px 16px rgba(89, 89, 89, 0.24);
}
.designer-index .template-item:hover .template-footer {
opacity: 1;
}
.designer-index .template-footer {
position: absolute;
bottom: 0;
width: 100%;
height: fit-content;
background: var(--sa-background-assist);
padding: 10px;
transition: all 0.5s;
opacity: 0;
}
.designer-index .template-footer .name {
font-size: 16px;
color: var(--sa-title);
margin-bottom: 4px;
}
.designer-index .template-footer.platform {
font-size: 14px;
color: var(--sa-subtitle);
margin-bottom: 4px;
}
.designer-index .template-footer.platform .iconfont {
font-size: 20px;
}
.designer-index .template-footer .memo {
font-size: 12px;
color: var(--sa-subfont);
margin-bottom: 4px;
}
.designer-index .template-footer .left {
flex-shrink: 0;
}
</style>
<div id="index" class="designer-index panel panel-default panel-intro" v-cloak>
<el-container class="panel-block">
<el-header class="sa-header">
<div class="sa-title sa-flex sa-row-between">
<div class="sa-title-left">
<div class="left-name">设计师模板</div>
</div>
<div class="sa-title-right">
<el-button class="sa-button-refresh" icon="RefreshRight" @click="getData"></el-button>
</div>
</div>
</el-header>
<el-main>
<el-scrollbar>
<div class="sa-flex sa-flex-wrap">
<div class="template-item" v-for="item in state.data">
<el-carousel trigger="click" height="480px" :autoplay="false" :loop="false"
indicator-position="none">
<el-carousel-item v-for="page in item.page" :key="page">
<img :src="page.image" />
</el-carousel-item>
</el-carousel>
<div class="template-footer">
<div class="name">{{ item.name }}</div>
<div class="platform sa-flex">
<div class="left">支持平台:</div>
<div v-if="item.platform">
<i :class="`iconfont icon${pl} mr-1`" v-for="pl in item.platform" :style="{
color: platformList.find((pf) => {
return pf.type == pl;
})?.color,
}"></i>
</div>
</div>
<div class="memo sa-flex">
<div class="left">备注:</div>
<div>{{ item.memo }}</div>
</div>
<div class="oper sa-flex sa-row-right">
{if $auth->check('shopro/decorate/designer/use')}
<el-button type="primary" link size="small" @click="onUse(item.id)">
使用
</el-button>
{/if}
</div>
</div>
</div>
</div>
</el-scrollbar>
</el-main>
</el-container>
</div>

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,152 @@
{include file="/shopro/common/script" /}
<script src="__CDN__/assets/addons/shopro/libs/qrcode.min.js?v={$site.version|htmlentities}"></script>
<style>
.template-preview {
text-align: center;
}
.template-preview .el-scrollbar__wrap {
overflow-x: hidden;
}
.template-preview .el-scrollbar__bar.is-horizontal {
display: none;
}
.template-preview .preview-title {
color: var(--sa-subtitle);
margin-bottom: 12px;
}
.template-preview .web-preview {
width: 300px;
height: 594px;
padding: 18px;
display: flex;
align-items: center;
justify-content: center;
position: relative;
color: #434343;
}
.template-preview .web-preview .bg {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
}
.template-preview .web-preview #preview {
border: none;
margin: 0 auto;
width: 100%;
height: 100%;
border-radius: 26px;
position: relative;
z-index: 1;
}
.template-preview .web-preview .web-preview-msg {
position: relative;
z-index: 1;
}
.template-preview .name {
font-size: 18px;
color: var(--sa-title);
margin-bottom: 12px;
}
.template-preview .platform .el-icon {
font-size: 20px;
}
.template-preview .copyright {
font-size: 12px;
color: var(--sa-subfont);
margin-bottom: 12px;
}
.template-preview .h5,
.template-preview .wechat {
display: flex;
flex-direction: column;
align-items: center;
}
.template-preview #qrcode {
width: 132px;
height: 132px;
}
.template-preview #qrcode img {
width: 100%;
height: 100%;
}
.template-preview .tip {
font-size: 14px;
color: var(--sa-font);
margin-bottom: 24px;
}
</style>
<div id="preview" class="template-preview" v-cloak>
<el-container class="panel-block">
<el-main>
<el-scrollbar>
<el-row :gutter="20">
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
<div v-if="
state.detail?.type == 'diypage' ||
state.detail?.platform?.includes('H5') ||
state.detail?.platform?.includes('WechatOfficialAccount')
" class="left sa-flex-col sa-col-center">
<div class="preview-title">此为预览效果,实际效果请扫码查看</div>
<div class="web-preview">
<img class="bg" :src="`/assets/addons/shopro/img/decorate/preview_bg.png`" />
<div v-if="isShowIframe" class="web-preview-msg">
<span v-html="isShowIframe"></span>
</div>
<iframe v-else id="preview" :src="urlData.H5" frameborder="1" height="600px"></iframe>
</div>
</div>
</el-col>
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
<div class="name">{{ state.detail?.name }}</div>
<template v-if="
state.detail?.type == 'diypage' || state.detail?.platform?.length > 0
">
<div class="platform mb-4">
<i :class="`iconfont icon${pl} mr-1`" v-for="pl in state.detail?.platform" :style="{
color: platformList.find((pf) => {
return pf.type == pl;
})?.color,
}"></i>
</div>
<div v-if="
state.detail?.type == 'diypage' ||
state.detail?.platform?.includes('H5') ||
state.detail?.platform?.includes('WechatOfficialAccount')
" class="h5">
<div id="qrcode"></div>
<div class="tip mt-2">微信扫描二维码即可预览</div>
</div>
<div v-if="
state.detail?.type == 'diypage' ||
state.detail?.platform?.includes('WechatMiniProgram')
" class="wechat">
<sa-image :url="urlData.WechatMiniProgram" size="132"></sa-image>
<div class="tip mt-2">微信扫描小程序即可预览</div>
</div>
</template>
<div class="copyright">星品科技Shopro版权所有 Copyright 2020-2022</div>
</el-col>
</el-row>
</el-scrollbar>
</el-main>
</el-container>
</div>

View File

@@ -0,0 +1,26 @@
{include file="/shopro/common/script" /}
<div id="addEdit" class="template-form" v-cloak>
<el-container class="panel-block">
<el-main>
<el-scrollbar height="100%">
<el-form :model="form.model" :rules="form.rules" ref="formRef" label-width="100px">
<el-form-item label="模板名称" prop="name">
<el-input v-model="form.model.name" placeholder="请输入模板名称"></el-input>
</el-form-item>
<el-form-item label="备注">
<el-input type="textarea" v-model="form.model.memo" placeholder="请输入备注"></el-input>
</el-form-item>
<el-form-item v-if="state.template == 'template'" label="发布平台">
<el-checkbox-group v-model="form.model.platform">
<el-checkbox v-for="item in platformList" :label="item.type">{{item.label}}</el-checkbox>
</el-checkbox-group>
</el-form-item>
</el-form>
</el-scrollbar>
</el-main>
<el-footer class="sa-footer--submit sa-flex sa-row-right">
<el-button type="primary" @click="onConfirm">确定</el-button>
</el-footer>
</el-container>
</div>

View File

@@ -0,0 +1,167 @@
{include file="/shopro/common/script" /}
<style>
.tempalte-index .template-item {
width: 246px;
height: 480px;
border: 1px solid var(--sa-space);
box-shadow: 0 0 4px #59595933;
border-radius: 8px;
margin-bottom: 20px;
margin-right: 20px;
position: relative;
overflow: hidden;
}
.tempalte-index .template-item img {
width: 100%;
}
.tempalte-index .template-item:hover {
transform: scale(1.02);
box-shadow: 0 4px 16px rgba(89, 89, 89, 0.24);
}
.tempalte-index .template-item:hover .template-footer {
opacity: 1;
}
.tempalte-index .template-footer {
position: absolute;
bottom: 0;
width: 100%;
height: fit-content;
background: var(--sa-background-assist);
padding: 10px;
transition: all 0.5s;
opacity: 0;
}
.tempalte-index .template-footer .name {
font-size: 16px;
color: var(--sa-title);
margin-bottom: 4px;
}
.tempalte-index .template-footer.platform {
font-size: 14px;
color: var(--sa-subtitle);
margin-bottom: 4px;
}
.tempalte-index .template-footer.platform .iconfont {
font-size: 20px;
}
.tempalte-index .template-footer .memo,
.tempalte-index .template-footer .update-time {
font-size: 12px;
color: var(--sa-subfont);
margin-bottom: 4px;
}
.tempalte-index .template-footer .left {
flex-shrink: 0;
}
.tempalte-index .template-footer .oper .el-button+.el-button {
margin-left: 8px;
}
</style>
<div id="index" class="tempalte-index panel panel-default panel-intro" v-cloak>
<el-container class="panel-block">
<el-header class="sa-header">
<el-tabs class="sa-tabs" v-model="state.filter.data.type" @tab-change="getData">
<el-tab-pane v-for="item in type.data.type" :key="item" :label="item.name" :name="item.type">
</el-tab-pane>
</el-tabs>
<div class="sa-title sa-flex sa-row-between">
<div class="sa-title-left">
<div class="left-name">模板管理</div>
</div>
<div class="sa-title-right">
<el-button class="sa-button-refresh" icon="RefreshRight" @click="getData"></el-button>
{if $auth->check('shopro/decorate/template/add')}
<el-button icon="Plus" type="primary" @click="onAdd">添加</el-button>
{/if}
{if $auth->check('shopro/decorate/template/recyclebin')}
<el-button type="danger" icon="Delete" plain @click="onRecyclebin">回收站</el-button>
{/if}
</div>
</div>
</el-header>
<el-main>
<el-scrollbar>
<div class="sa-flex sa-flex-wrap">
<div class="template-item" v-for="item in state.data">
<el-carousel trigger="click" height="480px" :autoplay="false" :loop="false"
indicator-position="none">
<el-carousel-item v-for="page in item.page" :key="page">
<img :src="page.image" />
</el-carousel-item>
</el-carousel>
<div class="template-footer">
<div class="name">{{ item.name }}</div>
<template v-if="state.filter.data.type == 'template'">
<div class="platform sa-flex">
<div class="left">支持平台:</div>
<div v-if="item.platform">
<i :class="`iconfont icon${pl} mr-1`" v-for="pl in item.platform" :style="{
color: platformList.find((pf) => {
return pf.type == pl;
})?.color,
}"></i>
</div>
</div>
</template>
<div class="memo sa-flex">
<div class="left">备注:</div>
<div>{{ item.memo }}</div>
</div>
<div class="update-time sa-flex">
<div class="left">更新时间:</div>
<div>{{ item.updatetime }}</div>
</div>
<div class="oper sa-flex sa-row-between">
{if $auth->check('shopro/decorate/page/index')}
<el-button type="primary" link size="small" @click="onDecorate(item.id)">
装修
</el-button>
{/if}
<div class="sa-flex">
{if $auth->check('shopro/decorate/template/edit')}
<el-button type="primary" link size="small" @click="onEdit(item.id)">
编辑
</el-button>
{/if}
<template v-if="state.filter.data.type == 'template'">
{if $auth->check('shopro/decorate/template/copy')}
<el-button type="info" link size="small" @click="onCopy(item.id)">
复制
</el-button>
{/if}
{if $auth->check('shopro/decorate/template/status')}
<el-button :type="item.status == 'enable' ? 'success' : 'info'" link
size="small" @click="onChangeStatus(item)">
{{ item.status_text }}
</el-button>
{/if}
</template>
<el-popconfirm width="fit-content" confirm-button-text="确认" cancel-button-text="取消"
title="确认删除这条记录?" @confirm="onDelete(item.id)">
<template #reference>
{if $auth->check('shopro/decorate/template/delete')}
<el-button type="danger" link size="small">删除</el-button>
{/if}
</template>
</el-popconfirm>
</div>
</div>
</div>
</div>
</div>
</el-scrollbar>
</el-main>
</el-container>
</div>

View File

@@ -0,0 +1,54 @@
{include file="/shopro/common/script" /}
<div id="recyclebin" class="template-recyclebin" v-cloak>
<el-container class="panel-block">
<el-main>
<el-table height="100%" class="sa-table" :data="state.data" stripe @selection-change="onChangeSelection"
@sort-change="onChangeSort">
<el-table-column type="selection" width="48" align="center"></el-table-column>
<el-table-column prop="id" label="ID" min-width="90" sortable="custom"></el-table-column>
<el-table-column label="名称" min-width="100">
<template #default="scope">
<div class="sa-table-line-1">{{ scope.row.name || '-' }}</div>
</template>
</el-table-column>
<el-table-column prop="deletetime" label="删除时间" width="172" sortable="custom"></el-table-column>
<el-table-column fixed="right" label="操作" min-width="120">
<template #default="scope">
{if $auth->check('shopro/decorate/template/restore')}
<el-button type="primary" link @click="onRestore(scope.row.id)">还原</el-button>
{/if}
<el-popconfirm width="fit-content" confirm-button-text="确认" cancel-button-text="取消"
title="确认销毁这条记录?" @confirm="onDestroy(scope.row.id)">
<template #reference>
{if $auth->check('shopro/decorate/template/destroy')}
<el-button type="danger" link>销毁</el-button>
{/if}
</template>
</el-popconfirm>
</template>
</el-table-column>
</el-table>
</el-main>
<el-footer class="sa-footer sa-flex sa-row-between sa-flex-wrap">
<div class="sa-batch sa-flex">
<div class="tip">
已选择 <span>{{batchHandle.data.length}}</span></div>
<div class="sa-flex">
{if $auth->check('shopro/decorate/template/restore')}
<el-button type="primary" :disabled="!batchHandle.data.length" @click="onBatchHandle('restore')">还原
</el-button>
{/if}
{if $auth->check('shopro/decorate/template/destroy')}
<el-button type="danger" :disabled="!batchHandle.data.length" @click="onBatchHandle('destroy')">销毁
</el-button>
{/if}
{if $auth->check('shopro/decorate/template/destroy')}
<el-button type="danger" @click="onBatchHandle('all')">清空回收站</el-button>
{/if}
</div>
</div>
<sa-pagination class="is-ellipsis" v-model="pagination" @pagination-change="getData"></sa-pagination>
</el-footer>
</el-container>
</div>

View File

@@ -0,0 +1,24 @@
{include file="/shopro/common/script" /}
<div id="select" class="template-select" v-cloak>
<el-container class="panel-block">
<el-main>
<el-table height="100%" class="sa-table" :data="state.data" stripe>
<el-table-column prop="id" label="ID" min-width="90"></el-table-column>
<el-table-column label="名称" min-width="180">
<template #default="scope">
<div class="sa-line-1">
{{ scope.row.name }}
</div>
</template>
</el-table-column>
<el-table-column prop="type_text" label="类型" min-width="80"></el-table-column>
<el-table-column label="操作" min-width="100" fixed="right">
<template #default="scope">
<el-button type="primary" link @click="onSelect(scope.row)">选择</el-button>
</template>
</el-table-column>
</el-table>
</el-main>
</el-container>
</div>

View File

@@ -0,0 +1,178 @@
{include file="/shopro/common/script" /}
<style>
.dispatch-form .sa-template-wrap {
width: 100%;
max-width: unset;
}
.dispatch-form .sa-template-wrap .item {
align-items: flex-start;
}
.dispatch-form .sa-template-wrap .el-form-item .el-form-item__content {
margin-left: 0 !important;
}
.dispatch-form .sa-template-wrap .express {
flex: unset !important;
width: 110px;
}
</style>
<div id="addEdit" class="dispatch-form" v-cloak>
<el-container class="panel-block">
<el-main>
<el-scrollbar height="100%">
<el-form :model="form.model" :rules="form.rules" ref="formRef" label-width="100px">
<el-form-item label="模板名称" prop="name">
<el-input class="sa-w-360" v-model="form.model.name" placeholder="请输入模板名称"></el-input>
</el-form-item>
<template v-if="form.model.type=='express'">
<el-form-item label="计价方式">
<el-radio-group v-model="state.priceType">
<el-radio label="number">按件数</el-radio>
<el-radio label="weight">按重量</el-radio>
</el-radio-group>
</el-form-item>
<div class="sa-template-wrap">
<div class="header sa-flex">
<div class="key area">可配送区域</div>
<div v-if="state.priceType == 'number'" class="express key">首件</div>
<div v-if="state.priceType == 'weight'" class="express key">首重(kg)</div>
<div class="express key">运费(元)</div>
<div v-if="state.priceType == 'number'" class="express key">续件</div>
<div v-if="state.priceType == 'weight'" class="express key">续重(kg)</div>
<div class="express key">续费(元)</div>
<div class="oper">操作</div>
</div>
<draggable v-model="form.model.express" :animation="300" handle=".sortable-drag"
item-key="element">
<template #item="{ element, index }">
<div class="item">
<el-form-item class="key area" :prop="'express.' + index + '.district_text'"
:rules="form.rules.express.district_text">
<el-button v-if="!element.district_text" type="primary"
@click="onSelectArea(index)">选择地址</el-button>
<div v-if="element.district_text" class="sa-flex sa-row-between area-edit">
<div>{{ element.district_text }}</div>
<el-button class="ml-1" type="primary" link
@click="onSelectArea(index)">选择
</el-button>
</div>
</el-form-item>
<el-form-item v-if="state.priceType == 'number'" class="express key"
:prop="'express.' + index + '.first_num'"
:rules="form.rules.express.first_num">
<el-input placeholder="请输入首件" type="number" min="0"
v-model="element.first_num">
</el-input>
</el-form-item>
<el-form-item v-if="state.priceType == 'weight'" class="express key"
:prop="'express.' + index + '.first_num'"
:rules="form.rules.express.first_num">
<el-input placeholder="请输入首重" type="number" min="0"
v-model="element.first_num">
</el-input>
</el-form-item>
<el-form-item class="express key" :prop="'express.' + index + '.first_price'"
:rules="form.rules.express.first_price">
<el-input placeholder="请输入运费" type="number" min="0" :step="0.01"
v-model="element.first_price">
</el-input>
</el-form-item>
<el-form-item v-if="state.priceType == 'number'" class="express key"
:prop="'express.' + index + '.additional_num'"
:rules="form.rules.express.additional_num">
<el-input placeholder="请输入续件" type="number" min="0"
v-model="element.additional_num">
</el-input>
</el-form-item>
<el-form-item v-if="state.priceType == 'weight'" class="express key"
:prop="'express.' + index + '.additional_num'"
:rules="form.rules.express.additional_num">
<el-input placeholder="请输入续重" type="number" min="0"
v-model="element.additional_num">
</el-input>
</el-form-item>
<el-form-item class="express key"
:prop="'express.' + index + '.additional_price'"
:rules="form.rules.express.additional_price">
<el-input placeholder="请输入续费" type="number" min="0" :step="0.01"
v-model="element.additional_price">
</el-input>
</el-form-item>
<el-form-item class="oper">
<el-popconfirm width="fit-content" confirm-button-text="确认"
cancel-button-text="取消" title="确认删除这条记录?"
@confirm="onDeleteTemplate(index)">
<template #reference>
<el-button type="danger" link @click.stop>删除
</el-button>
</template>
</el-popconfirm>
<i class="iconfont iconmove sortable-drag"></i>
</el-form-item>
</div>
</template>
</draggable>
<el-button class="add-params" type="primary" plain icon="Plus" @click="onAddTemplate">添加
</el-button>
</div>
</template>
<template v-if="form.model.type=='autosend'">
<el-form-item label="发货类型:">
<el-radio-group v-model="form.model.autosend.type" @change="onChangeAutosendType">
<el-radio label="text">固定内容</el-radio>
<el-radio label="params">自定义内容</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item v-if="form.model.autosend.type=='text'" label="发货内容:">
<el-input v-model="form.model.autosend.content" placeholder="请输入自动发货内容"></el-input>
</el-form-item>
<el-form-item v-if="form.model.autosend.type=='params'" label="发货内容:">
<div class="sa-template-wrap">
<div class="header sa-flex">
<div class="key">参数名称</div>
<div class="key">内容</div>
<div class="oper">操作</div>
</div>
<draggable v-model="form.model.autosend.content" :animation="300"
handle=".sortable-drag" item-key="element">
<template #item="{ element, index }">
<div class="item">
<el-form-item class="key">
<el-input placeholder="请输入" v-model="element.title">
</el-input>
</el-form-item>
<el-form-item class="key">
<el-input placeholder="请输入" v-model="element.content">
</el-input>
</el-form-item>
<el-form-item class="oper">
<el-popconfirm width="fit-content" confirm-button-text="确认"
cancel-button-text="取消" title="确认删除这条记录?"
@confirm="onDeleteContent(index)">
<template #reference>
<el-button type="danger" link @click.stop>删除
</el-button>
</template>
</el-popconfirm>
<i class="iconfont iconmove sortable-drag"></i>
</el-form-item>
</div>
</template>
</draggable>
<el-button class="add-params" type="primary" plain icon="Plus" @click="onAddContent">添加
</el-button>
</div>
</el-form-item>
</template>
</el-form>
</el-scrollbar>
</el-main>
<el-footer class="sa-footer--submit sa-flex sa-row-right">
<el-button type="primary" @click="onConfirm">确定</el-button>
</el-footer>
</el-container>
</div>

View File

@@ -0,0 +1,180 @@
{include file="/shopro/common/script" /}
<style>
.dispatch-index {
font-size: 14px;
color: var(--sa-font);
}
.dispatch-index .dispatch-item {
min-width: 100%;
display: inline-block;
border-radius: 4px;
border: 1px solid var(--sa-space);
margin-bottom: 20px;
}
.dispatch-index .template-header {
height: 40px;
background: var(--t-bg-disabled);
border-radius: 4px;
padding-left: 20px;
}
.dispatch-index .template-header .name {
min-width: 570px;
}
.dispatch-index .template-header .right {
flex-shrink: 0;
padding-right: 20px;
}
.dispatch-index .template-body .template-item {
border-bottom: 1px solid var(--sa-space);
padding: 10px 0 10px 16px;
font-size: 14px;
color: var(--sa-font);
}
.dispatch-index .template-body .template-item:first-of-type {
border-bottom: none;
box-shadow: 0 2px 6px #8c8c8c1f;
}
.dispatch-index .template-body .template-item .area {
min-width: 600px;
font-size: 12px;
}
.dispatch-index .template-body .template-item .district {
min-width: 88px;
padding: 0 18px;
text-align: center;
}
</style>
<div id="index" class="dispatch-index panel panel-default panel-intro" v-cloak>
<el-container class="panel-block">
<el-header class="sa-header">
<el-tabs class="sa-tabs" v-model="state.dispatch_type" @tab-change="onChangeTab">
<el-tab-pane label="物流快递" name="express"></el-tab-pane>
<el-tab-pane label="自动发货" name="autosend"></el-tab-pane>
</el-tabs>
<div class="sa-title sa-flex sa-row-between">
<div class="sa-title-left">
<div class="left-name">配送设置</div>
</div>
<div class="sa-title-right">
<el-button class="sa-button-refresh" icon="RefreshRight" @click="getData"></el-button>
{if $auth->check('shopro/dispatch/dispatch/add')}
<el-button icon="Plus" type="primary" @click="onAdd">添加</el-button>
{/if}
</div>
</div>
</el-header>
<el-main class="sa-main">
<el-scrollbar v-if="state.dispatch_type=='express'">
<div class="dispatch-item" v-for="item in state.data" :key="item">
<div class="template-header sa-flex sa-row-between">
<div class="name sa-flex">
<div class="mr-2">#{{ item.id }}</div>
<div>{{ item.name }}</div>
</div>
<div class="right sa-flex">
<div class="mr-1">最后编辑时间:{{ item.updatetime }}</div>
{if $auth->check('shopro/dispatch/dispatch/edit')}
<el-button type="primary" class="is-link" @click="onEdit(item.id)">编辑</el-button>
{/if}
{if $auth->check('shopro/dispatch/dispatch/add')}
<el-button type="info" link @click="onCopy(item.id)">复制</el-button>
{/if}
<el-popconfirm width="fit-content" confirm-button-text="确认" cancel-button-text="取消"
title="确认删除这条记录?" @confirm="onDelete(item.id)">
<template #reference>
{if $auth->check('shopro/dispatch/dispatch/delete')}
<el-button type="danger" link> 删除</el-button>
{/if}
</template>
</el-popconfirm>
</div>
</div>
<div class="template-body">
<template v-for="(inneritem, index) in item.express" :key="index">
<div v-if="index == 0" class="template-item sa-flex sa-row-between">
<div class="area">可配送区域</div>
<div class="sa-flex">
<div class="district">
{{ inneritem.type == 'weight' ? '首重(kg)' : '首件' }}
</div>
<div class="district">运费(元)</div>
<div class="district">
{{ inneritem.type == 'weight' ? '续重(kg)' : '续件' }}
</div>
<div class="district">续费(元)</div>
</div>
</div>
<div class="template-item sa-flex sa-row-between">
<div class="area">{{ inneritem.district_text || '-' }}</div>
<div class="sa-flex">
<div class="district">{{ inneritem.first_num }}</div>
<div class="district">{{ inneritem.first_price }}</div>
<div class="district">{{ inneritem.additional_num }}</div>
<div class="district">{{ inneritem.additional_price }}</div>
</div>
</div>
</template>
</div>
</div>
</el-scrollbar>
<el-table v-if="state.dispatch_type=='autosend'" class="sa-table" :data="state.data">
<el-table-column prop="id" label="ID" min-width="90">
</el-table-column>
<el-table-column label="模板名称" min-width="140">
<template #default="scope">
<div class="sa-line-1">
{{scope.row.name}}
</div>
</template>
</el-table-column>
<el-table-column label="自动发货内容" min-width="400">
<template #default="scope">
<div>
<div v-if="scope.row.autosend?.type=='text'">
{{scope.row.autosend?.content}}</div>
<div v-else>
<template v-for="(item,index) in scope.row.autosend?.content">
{{item.title}}:{{item.content}}
<span v-if="index!=scope.row.autosend?.content.length-1" class="sa-m-r-4">;</span>
</template>
</div>
</div>
</template>
</el-table-column>
<el-table-column prop="updatetime" label="最后编辑时间" min-width="172">
</el-table-column>
<el-table-column label="操作" min-width="180">
<template #default="scope">
{if $auth->check('shopro/dispatch/dispatch/edit')}
<el-button type="primary" class="is-link" @click="onEdit(scope.row.id)">编辑</el-button>
{/if}
{if $auth->check('shopro/dispatch/dispatch/add')}
<el-button type="info" link @click="onCopy(scope.row.id)">复制</el-button>
{/if}
<el-popconfirm width="fit-content" confirm-button-text="确认" cancel-button-text="取消"
title="确认删除这条记录?" @confirm="onDelete(scope.row.id)">
<template #reference>
{if $auth->check('shopro/dispatch/dispatch/delete')}
<el-button type="danger" link> 删除</el-button>
{/if}
</template>
</el-popconfirm>
</template>
</el-table-column>
</el-table>
</el-main>
<el-footer class="sa-footer sa-flex sa-row-right">
<sa-pagination v-model="pagination" @pagination-change="getData"></sa-pagination>
</el-footer>
</el-container>
</div>

View File

@@ -0,0 +1,46 @@
{include file="/shopro/common/script" /}
<div id="detail" class="feedback-detail" v-cloak>
<el-container class="panel-block">
<el-main>
<el-scrollbar height="100%">
<el-form :model="form.model" :rules="form.rules" ref="formRef" label-width="100px">
<el-form-item label="反馈用户">
<sa-user-profile :user="form.model.user" :id="form.model.user_id"></sa-user-profile>
</el-form-item>
<el-form-item label="反馈类型">
{{ form.model.type }}
</el-form-item>
<el-form-item label="反馈内容">
{{ form.model.content }}
</el-form-item>
<el-form-item label="截图">
<el-scrollbar>
<div class="sa-flex">
<sa-image class="mr-1" v-for="item in form.model.images" :url="item" size="30">
</sa-image>
</div>
</el-scrollbar>
</el-form-item>
<el-form-item label="联系电话">
{{ form.model.phone }}
</el-form-item>
<el-form-item label="是否处理">
<el-radio-group v-model="form.model.status">
<el-radio label="0">待处理</el-radio>
<el-radio label="1">已处理</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="系统备注">
<el-input v-model="form.model.remark" placeholder="请输入系统备注"></el-input>
</el-form-item>
</el-form>
</el-scrollbar>
</el-main>
<el-footer class="sa-footer--submit sa-flex sa-row-right">
{if $auth->check('shopro/feedback/edit')}
<el-button type="primary" @click="onConfirm">确定</el-button>
{/if}
</el-footer>
</el-container>
</div>

View File

@@ -0,0 +1,123 @@
{include file="/shopro/common/script" /}
<div id="index" class="feedback-index panel panel-default panel-intro" v-cloak>
<el-container class="panel-block">
<el-header class="sa-header">
<div class="sa-title sa-flex sa-row-between">
<div class="sa-title-left">
<div class="left-name">意见反馈</div>
<sa-filter-condition v-model="state.filter" @filter-delete="onChangeFilter">
</sa-filter-condition>
</div>
<div class="sa-title-right">
<el-button class="sa-button-refresh" icon="RefreshRight" @click="getData"></el-button>
<el-button class="sa-button-refresh" icon="Search" @click="onOpenFilter"></el-button>
</div>
</div>
</el-header>
<el-main class="sa-main">
<el-table height="100%" class="sa-table" :data="state.data" stripe @selection-change="onChangeSelection"
@sort-change="onChangeSort">
<el-table-column type="selection" width="48"> </el-table-column>
<el-table-column prop="id" label="ID" min-width="90" sortable="custom"> </el-table-column>
<el-table-column label="反馈用户" min-width="180">
<template #default="scope">
<sa-user-profile :user="scope.row.user" :id="scope.row.user_id"></sa-user-profile>
</template>
</el-table-column>
<el-table-column label="反馈类型" min-width="140">
<template #default="scope">
<div class="sa-table-line-1">
{{ scope.row.type || '-' }}
</div>
</template>
</el-table-column>
<el-table-column prop="content" label="反馈内容" min-width="260">
<template #default="scope">
<div class="sa-table-line-1">
{{ scope.row.content || '-' }}
</div>
</template>
</el-table-column>
<el-table-column label="截图" min-width="146">
<template #default="scope">
<el-scrollbar>
<div class="sa-flex">
<sa-image class="mr-1" v-for="item in scope.row.images" :url="item" size="30">
</sa-image>
</div>
</el-scrollbar>
</template>
</el-table-column>
<el-table-column prop="phone" label="联系电话" min-width="160">
<template #default="scope">
<div class="sa-table-line-1">
{{ scope.row.phone || '-' }}
</div>
</template>
</el-table-column>
<el-table-column prop="status" label="处理状态" min-width="100">
<template #default="scope">
<el-tag :type="scope.row.status == '1' ? 'success' : 'info'">
{{ scope.row.status_text }}
</el-tag>
</template>
</el-table-column>
<el-table-column prop="remark" label="系统备注" min-width="260">
<template #default="scope">
<div class="sa-table-line-1">
{{ scope.row.remark || '-' }}
</div>
</template>
</el-table-column>
<el-table-column label="创建时间" width="172">
<template #default="scope">
{{ scope.row.createtime || '-' }}
</template>
</el-table-column>
<el-table-column label="更新时间" width="172">
<template #default="scope">
{{ scope.row.updatetime || '-' }}
</template>
</el-table-column>
<el-table-column fixed="right" label="操作" min-width="120">
<template #default="scope">
{if $auth->check('shopro/feedback/detail')}
<el-button type="primary" link @click="onDetail(scope.row.id)">查看</el-button>
{/if}
<el-popconfirm width="fit-content" confirm-button-text="确认" cancel-button-text="取消"
title="确认删除这条记录?" @confirm="onDelete(scope.row.id)">
<template #reference>
{if $auth->check('shopro/feedback/delete')}
<el-button type="danger" link>删除</el-button>
{/if}
</template>
</el-popconfirm>
</template>
</el-table-column>
</el-table>
</el-main>
<el-footer class="sa-footer sa-flex sa-row-between sa-flex-wrap">
<div class="sa-batch sa-flex">
<div class="tip">
已选择 <span>{{batchHandle.data.length}}</span></div>
<div class="sa-flex">
{if $auth->check('shopro/feedback/delete')}
<el-button type="danger" :disabled="!batchHandle.data.length" @click="onBatchHandle('delete')">删除
</el-button>
{/if}
{if $auth->check('shopro/feedback/edit')}
<el-button type="success" :disabled="!batchHandle.data.length" @click="onBatchHandle('1')">已处理
</el-button>
{/if}
{if $auth->check('shopro/feedback/edit')}
<el-button type="info" :disabled="!batchHandle.data.length" @click="onBatchHandle('0')">未处理
</el-button>
{/if}
</div>
</div>
<sa-pagination v-model="pagination" @pagination-change="getData"></sa-pagination>
</el-footer>
</el-container>
<sa-filter v-model="state.filter" @filter-change="onChangeFilter"></sa-filter>
</div>

View File

@@ -0,0 +1,248 @@
{include file="/shopro/common/script" /}
<style>
.comment-form .sa-template-wrap .item {
border-bottom: none
}
.comment-form .goods-image {
margin-right: 8px;
}
.comment-form .goods-price {
color: var(--el-color-danger);
}
.comment-form .top {
background: var(--sa-table-header-bg);
padding: 20px 24px 0;
font-size: 12px;
color: #8c8c8c;
}
.comment-form .top .el-col {
margin-bottom: 20px;
}
.comment-form .top .title {
font-size: 14px;
line-height: 18px;
font-weight: 500;
color: var(--sa-title);
margin-bottom: 8px;
}
.comment-form .top .goods-title {
color: var(--el-color-primary);
margin-bottom: 8px;
}
.comment-form .left {
flex-shrink: 0;
}
.comment-form .bottom {
margin: 32px 20px 0;
}
.comment-form .avatar {
margin-right: 12px;
}
.comment-form .list {
padding: 20px 0;
border-bottom: 1px solid var(--sa-space);
}
.comment-form .nickname {
font-weight: 500;
font-size: 12px;
color: var(--sa-subfont);
margin-bottom: 4px;
}
.comment-form .reply-time {
font-weight: 400;
font-size: 12px;
color: var(--sa-subfont);
margin-bottom: 8px;
}
.comment-form .reply-content {
color: var(--sa-subtitle);
font-weight: 500;
font-size: 12px;
margin-bottom: 8px;
}
.comment-form .list-image {
margin-right: 8px;
}
.comment-form .list-image:last-of-type {
margin-right: 0;
}
</style>
<div id="addEdit" class="comment-form" v-cloak>
<el-container v-if="state.type=='add'" class="panel-block">
<el-main>
<el-scrollbar height="100%">
<el-form :model="form.model" :rules="form.rules" ref="formRef" label-width="100px">
<el-form-item label="评价内容" prop="content">
<el-input class="sa-w-360" v-model="form.model.content" autosize type="textarea"
placeholder="请输入评价内容">
</el-input>
</el-form-item>
<el-form-item label="评价图片">
<sa-uploader v-model="form.model.images" :multiple="true"></sa-uploader>
</el-form-item>
<el-form-item label="评价星级" prop="level">
<el-rate v-model="form.model.level"></el-rate>
</el-form-item>
<el-form-item label="评价用户" prop="user_id">
<el-button v-if="!form.model.user_id" type="primary" link @click="onSelectFakeUser">
选择虚拟用户
</el-button>
<div v-if="form.model.user_id" class="sa-template-wrap">
<div class="item">
<div class="key id">{{ state.fakeUserData?.id }}</div>
<div class="key">{{ state.fakeUserData?.nickname }}</div>
<div class="oper">
<el-button type="danger" link @click="onDeleteFakeUser">
移除
</el-button>
</div>
</div>
</div>
</el-form-item>
<el-form-item label="商品选择" prop="goods_id">
<el-button v-if="!form.model.goods_id" type="primary" link @click="onSelectGoods">选择商品
</el-button>
<div v-if="form.model.goods_id" class="sa-template-wrap">
<div class="item">
<div class="key id">{{ form.model.goods_id }}</div>
<div class="key">
<sa-image class="goods-image" :url="state.goodsData?.image" size="40"></sa-image>
<div class="right">
<div class="goods-title sa-table-line-1">
{{ state.goodsData?.title }}
</div>
<div class="goods-price">
¥{{ state.goodsData?.price.join('~') || 0 }}
</div>
</div>
</div>
<div class="oper">
<el-button type="danger" link @click="onDeleteGoods">移除</el-button>
</div>
</div>
</div>
</el-form-item>
<el-form-item label="状态" prop="status">
<el-radio-group v-model="form.model.status">
<el-radio label="normal">显示</el-radio>
<el-radio label="hidden">隐藏</el-radio>
</el-radio-group>
</el-form-item>
</el-form>
</el-scrollbar>
</el-main>
<el-footer class="sa-footer--submit sa-flex sa-row-right">
<el-button type="primary" @click="onConfirm">确定</el-button>
</el-footer>
</el-container>
<el-container v-if="state.type=='edit'" class="panel-block">
<el-main>
<el-row class="top" :gutter="10">
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
<div class="title">评价信息</div>
<div class="item sa-flex">
<div class="left">用户昵称:</div>
<div class="right">{{form.model.user?.nickname || form.model.user_id}}</div>
</div>
<div class="item sa-flex">
<div class="left">评价星级:</div>
<div class="right">
<el-rate v-model="form.model.level" disabled></el-rate>
</div>
</div>
<div class="item sa-flex">
<div class="left">显示状态:</div>
<div class="right">
<el-radio-group v-model="form.model.status" @change="onChangeStatus">
<el-radio label="normal">正常</el-radio>
<el-radio label="hidden">隐藏</el-radio>
</el-radio-group>
</div>
</div>
</el-col>
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
<div class="title">商品信息</div>
<div v-if="form.model.order_item" class="sa-flex">
<sa-image class="mr-2" :url="form.model.order_item.goods_image" size="64"></sa-image>
<div class="right">
<div class="goods-title sa-table-line-1">
{{ form.model.order_item.goods_title }}
</div>
<div class="sa-flex mb-2">
<div class="left">单价:</div>
<div class="right goods-num">{{ form.model.order_item.goods_price }}×{{
form.model.order_item.goods_num }}</div>
</div>
<div v-if="form.model.order_item.goods_sku_text" class="sa-flex">
<div class="left">规格:</div>
<div class="right goods-num">{{ form.model.order_item.goods_sku_text }},</div>
</div>
</div>
</div>
<div v-else-if="form.model.goods" class="sa-flex">
<sa-image class="mr-2" :url="form.model.goods.image" size="64"></sa-image>
<div class="right">
<div class="goods-title sa-table-line-1">{{form.model.goods.title}}</div>
<div class="item sa-flex">
<div class="left">单价:</div>
<div class="right goods-num">
{{form.model.goods.price.join(',')}}
</div>
</div>
<div v-if="form.model.goods.sku_text" class="item sa-flex">
<div class="left">规格:</div>
<div class="right goods-num">{{form.model.goods.sku_text }}</div>
</div>
</div>
</div>
</el-col>
</el-row>
<div class="bottom">
<div class="title sa-flex sa-row-between">
<div>评价记录</div>
{if $auth->check('shopro/goods/comment/reply')}
<el-button v-if="!form.model.reply_time" type="primary" link @click="onReply">点击回复</el-button>
{/if}
</div>
<div v-if="form.model.admin" class="list sa-flex sa-col-top">
<sa-image class="avatar" :url="form.model.admin.avatar" size="48"></sa-image>
<div>
<div class="nickname">{{ form.model.admin.nickname }}</div>
<div class="reply-time">{{ form.model.reply_time }}</div>
<div class="reply-content">{{ form.model.reply_content }}</div>
</div>
</div>
<div v-if="form.model.user" class="list sa-flex sa-col-top">
<sa-image class="avatar" :url="form.model.user.avatar" size="48"></sa-image>
<div>
<div class="nickname">{{ form.model.user.nickname }}</div>
<div class="reply-time">{{ form.model.createtime }}</div>
<div class="reply-content">{{ form.model.content }}</div>
<div class="sa-flex">
<template v-for="item in form.model.images">
<sa-image class="list-image" :url="item" size="48"></sa-image>
</template>
</div>
</div>
</div>
</div>
</el-main>
</el-container>
</div>

View File

@@ -0,0 +1,178 @@
{include file="/shopro/common/script" /}
<style>
.comment-index .image {
margin-right: 4px;
}
.comment-index .goods-item .goods-image {
margin-right: 8px;
}
.comment-index .goods-item .goods-title {
color: var(--el-color-primary);
cursor: pointer;
}
</style>
<div id="index" class="comment-index panel panel-default panel-intro" v-cloak>
<el-container class="panel-block">
<el-header class="sa-header">
<div class="sa-title sa-flex sa-row-between">
<div class="sa-title-left">
<div class="left-name">评价管理</div>
<sa-filter-condition v-model="state.filter" @filter-delete="onChangeFilter">
</sa-filter-condition>
</div>
<div class="sa-title-right">
<el-button class="sa-button-refresh" icon="RefreshRight" @click="getData"></el-button>
<el-button class="sa-button-refresh" icon="Search" @click="onOpenFilter"></el-button>
{if $auth->check('shopro/goods/comment/add')}
<el-button plain @click="onAdd">添加虚拟评价</el-button>
{/if}
{if $auth->check('shopro/goods/comment/recyclebin')}
<el-button type="danger" icon="Delete" plain @click="onRecyclebin">回收站</el-button>
{/if}
</div>
</div>
</el-header>
<el-main class="sa-main">
<el-table height="100%" class="sa-table" :data="state.data" stripe @selection-change="onChangeSelection">
<el-table-column type="selection" width="48"></el-table-column>
<el-table-column label="商品信息" min-width="310">
<template #default="scope">
<div v-if="scope.row.order_item" class="goods-item sa-flex">
<sa-image class="goods-image" :url="scope.row.order_item.goods_image" size="40"></sa-image>
<div class="right">
<span class="goods-title sa-table-line-1"
@click="onOpenGoodsDetail(scope.row.order_item.goods_id)">
{{ scope.row.order_item.goods_title || '-' }}
</span>
<span v-if="scope.row.order" class="sa-table-line-1">
订单号:{{ scope.row.order.order_sn }}
<el-icon class="copy-document" @click="onClipboard(scope.row.order.order_sn)">
<copy-document />
</el-icon>
</span>
<span v-else>订单号:-</span>
</div>
</div>
<div v-else-if="scope.row.goods" class="goods-item sa-flex">
<sa-image class="goods-image" :url="scope.row.goods.image" size="40"></sa-image>
<div class="right">
<span class=" goods-title sa-table-line-1"
@click="onOpenGoodsDetail(scope.row.goods.id)">
{{ scope.row.goods.title || '-' }}
</span>
<span>虚拟评价</span>
</div>
</div>
</template>
</el-table-column>
<el-table-column label="用户信息" min-width="96" align="center">
<template #default="scope">
<sa-user-profile :user="scope.row.user" :id="scope.row.user_id" mode="col"
:ishover="scope.row.user_type != 'fake_user'"></sa-user-profile>
</template>
</el-table-column>
<el-table-column label="评价星级" min-width="146">
<template #default="scope">
<el-rate v-model="scope.row.level" disabled></el-rate>
</template>
</el-table-column>
<el-table-column label="评价图片" width="200">
<template #default="scope">
<el-scrollbar>
<div class="sa-flex">
<template v-for="item in scope.row.images" :key="item">
<sa-image class="image" :url="item" size="30"></sa-image>
</template>
</div>
</el-scrollbar>
</template>
</el-table-column>
<el-table-column label="评价内容" min-width="162">
<template #default="scope">
<div class="sa-table-line-1">
{{ scope.row.content || '-' }}
</div>
</template>
</el-table-column>
<el-table-column label="评价时间" width="172">
<template #default="scope">
{{ scope.row.createtime || '-' }}
</template>
</el-table-column>
<el-table-column label="显示状态" min-width="130">
<template #default="scope">
{if $auth->check('shopro/goods/comment/edit')}
<el-dropdown @command="onCommand">
<el-button link>
<el-tag :type="scope.row.status == 'normal' ? 'success' : 'info'">
{{ scope.row.status_text }}
<el-icon>
<arrow-down />
</el-icon>
</el-tag>
</el-button>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item :command="{
id: scope.row.id,
type: 'normal',
}">
<span class="status-normal">正常</span>
</el-dropdown-item>
<el-dropdown-item :command="{
id: scope.row.id,
type: 'hidden',
}">
<span class="status-hidden">隐藏</span>
</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
{/if}
</template>
</el-table-column>
<el-table-column fixed="right" label="操作" min-width="120">
<template #default="scope">
{if $auth->check('shopro/goods/comment/edit')}
<el-button type="primary" link @click="onEdit(scope.row.id)">编辑</el-button>
{/if}
<el-popconfirm width="fit-content" confirm-button-text="确认" cancel-button-text="取消"
title="确认删除这条记录?" @confirm="onDelete(scope.row.id)">
<template #reference>
{if $auth->check('shopro/goods/comment/delete')}
<el-button type="danger" link>删除</el-button>
{/if}
</template>
</el-popconfirm>
</template>
</el-table-column>
</el-table>
</el-main>
<el-footer class="sa-footer sa-flex sa-row-between sa-flex-wrap">
<div class="sa-batch sa-flex">
<div class="tip">
已选择 <span>{{batchHandle.data.length}}</span></div>
<div class="sa-flex">
{if $auth->check('shopro/goods/comment/delete')}
<el-button type="danger" :disabled="!batchHandle.data.length" @click="onBatchHandle('delete')">删除
</el-button>
{/if}
{if $auth->check('shopro/goods/comment/edit')}
<el-button type="success" :disabled="!batchHandle.data.length" @click="onBatchHandle('normal')">正常
</el-button>
{/if}
{if $auth->check('shopro/goods/comment/edit')}
<el-button type="info" :disabled="!batchHandle.data.length" @click="onBatchHandle('hidden')">隐藏
</el-button>
{/if}
</div>
</div>
<sa-pagination v-model="pagination" @pagination-change="getData"></sa-pagination>
</el-footer>
</el-container>
<sa-filter v-model="state.filter" @filter-change="onChangeFilter"></sa-filter>
</div>

View File

@@ -0,0 +1,54 @@
{include file="/shopro/common/script" /}
<div id="recyclebin" class="comment-recyclebin panel panel-default panel-intro" v-cloak>
<el-container class="panel-block">
<el-main>
<el-table height="100%" class="sa-table" :data="state.data" stripe @selection-change="onChangeSelection"
@sort-change="onChangeSort">
<el-table-column type="selection" width="48" align="center"></el-table-column>
<el-table-column prop="id" label="ID" width="90" sortable="custom"></el-table-column>
<el-table-column label="名称" min-width="100">
<template #default="scope">
<div class="sa-table-line-1">{{ scope.row.content || '-' }}</div>
</template>
</el-table-column>
<el-table-column prop="deletetime" label="删除时间" width="172" sortable="custom"></el-table-column>
<el-table-column fixed="right" label="操作" min-width="120">
<template #default="scope">
{if $auth->check('shopro/goods/comment/restore')}
<el-button type="primary" link @click="onRestore(scope.row.id)">还原</el-button>
{/if}
<el-popconfirm width="fit-content" confirm-button-text="确认" cancel-button-text="取消"
title="确认销毁这条记录?" @confirm="onDestroy(scope.row.id)">
<template #reference>
{if $auth->check('shopro/goods/comment/destroy')}
<el-button type="danger" link>销毁</el-button>
{/if}
</template>
</el-popconfirm>
</template>
</el-table-column>
</el-table>
</el-main>
<el-footer class="sa-footer sa-flex sa-row-between sa-flex-wrap">
<div class="sa-batch sa-flex">
<div class="tip">
已选择 <span>{{batchHandle.data.length}}</span></div>
<div class="sa-flex">
{if $auth->check('shopro/goods/comment/restore')}
<el-button type="primary" :disabled="!batchHandle.data.length" @click="onBatchHandle('restore')">还原
</el-button>
{/if}
{if $auth->check('shopro/goods/comment/destroy')}
<el-button type="danger" :disabled="!batchHandle.data.length" @click="onBatchHandle('destroy')">销毁
</el-button>
{/if}
{if $auth->check('shopro/goods/comment/destroy')}
<el-button type="danger" @click="onBatchHandle('all')">清空回收站</el-button>
{/if}
</div>
</div>
<sa-pagination class="is-ellipsis" v-model="pagination" @pagination-change="getData"></sa-pagination>
</el-footer>
</el-container>
</div>

View File

@@ -0,0 +1,18 @@
{include file="/shopro/common/script" /}
<div id="reply" class="comment-reply" v-cloak>
<el-container class="panel-block">
<el-main>
<el-scrollbar height="100%">
<el-form :model="form.model" :rules="form.rules" ref="formRef" label-width="100px">
<el-form-item label="回复内容" prop="content">
<el-input class="sa-w-360" v-model="form.model.content" placeholder="请输入回复内容"></el-input>
</el-form-item>
</el-form>
</el-scrollbar>
</el-main>
<el-footer class="sa-footer--submit sa-flex sa-row-right">
<el-button type="primary" @click="onConfirm">确定</el-button>
</el-footer>
</el-container>
</div>

View File

@@ -0,0 +1,889 @@
{include file="/shopro/common/script" /}
<style>
.goods-form .el-header {
--el-header-padding: 10px 20px 0;
--el-header-height: fit-content;
}
.goods-form .el-header .el-tabs__header {
margin: 0;
}
.goods-form .goods-type {
width: 140px;
height: 56px;
border: 1px solid rgb(230, 230, 230);
border-radius: 4px;
margin-left: 16px;
cursor: pointer;
}
.goods-form .goods-type.is-active {
border: 1px solid var(--el-color-primary);
}
.goods-form .title {
width: 100%;
height: 40px;
line-height: 40px;
padding-left: 16px;
background: var(--sa-table-striped);
margin: 24px 0 16px;
font-weight: 500;
font-size: 14px;
color: #434343;
}
.goods-form .sku-wrap {
width: 100%;
border: 1px solid var(--sa-border);
padding: 8px;
box-sizing: border-box;
}
.goods-form .sku-wrap .sku {
width: 100%;
min-height: 100px;
}
.goods-form .sku-wrap .sku .sku-key {
width: 100%;
height: 40px;
color: var(--sa-subtitle);
padding: 0 16px;
background: var(--sa-table-header-bg);
font-size: 14px;
}
.goods-form .sku-wrap .sku .sku-key .sku-value-title {
margin-right: 16px;
}
.goods-form .sku-wrap .sku .sku-key .sku-key-input {
width: 120px;
}
.goods-form .sku-wrap .sku .sku-key .sku-key-icon {
color: var(--el-color-primary);
cursor: pointer;
}
.goods-form .sku-wrap .sku .sku-value {
padding: 12px 0 0 30px;
font-size: 14px;
color: var(--sa-subtitle);
}
.goods-form .sku-wrap .sku .sku-value .sku-value-title {
height: 32px;
margin-right: 16px;
margin-bottom: 16px;
}
.goods-form .sku-wrap .sku .sku-value .sku-value-box {
position: relative;
margin-right: 24px;
margin-bottom: 16px;
}
.goods-form .sku-wrap .sku .sku-value .sku-value-box .sku-value-input {
width: 104px;
}
.goods-form .sku-wrap .sku .sku-value .sku-value-box .sku-value-icon {
position: absolute;
right: -8px;
top: -8px;
width: 16px;
height: 16px;
color: var(--el-color-primary);
}
.goods-form .sku-wrap .sku .sku-value .sku-value-add {
margin-right: 24px;
margin-bottom: 16px;
}
.goods-form .sku-wrap .sku-tools {
width: 100%;
height: 40px;
color: #434343;
padding-left: 16px;
background: var(--sa-table-header-bg);
font-size: 12px;
}
.goods-form .sku-table-wrap {
width: 100%;
overflow: auto;
margin-top: 16px;
}
.goods-form .sku-table-wrap .sku-table {
width: 100%;
border: 1px solid var(--sa-border);
}
.goods-form .sku-table-wrap .sku-table tbody {
font-size: 12px;
}
.goods-form .sku-table-wrap .sku-table th {
font-size: 12px;
color: var(--subtitle);
height: 32px;
line-height: 1;
padding-left: 12px;
box-sizing: border-box;
text-align: left;
}
.goods-form .sku-table-wrap .sku-table th .sku-table-header-title {
margin-right: 10px;
}
.goods-form .sku-table-wrap .sku-table th .th-title {
font-size: 12px;
color: var(--subtitle);
font-weight: bold;
}
.goods-form .sku-table-wrap .sku-table td {
min-width: 88px;
padding: 0 10px;
height: 40px;
box-sizing: border-box;
}
.goods-form .sku-table-wrap .sku-table td.image {
min-width: 48px;
}
.goods-form .sku-table-wrap .sku-table td.stock {
min-width: 138px;
}
.goods-form .sku-table-wrap .sku-table td.stock_warning {
min-width: 168px;
}
.goods-form .sku-table-wrap .sku-table td.stock_warning .sku-stock-switch {
margin-right: 10px;
}
.goods-form .sku-table-wrap .sku-table td.sn {
min-width: 116px;
}
.goods-form .batch-icon {
font-size: 12px;
color: var(--el-color-primary);
margin-left: 8px;
cursor: pointer;
}
.sales-show-type .exact,
.sales-show-type .sketchy {
width: 220px;
height: 98px;
}
.stock-show-type .exact,
.stock-show-type .sketchy {
width: 220px;
height: 74px;
}
.goods-form .el-select {
flex: 1;
}
.goods-form .category-tag-wrap {
flex: 1;
min-height: 32px;
padding-right: 12px;
border-radius: 4px;
border: 1px solid var(--sa-border);
cursor: pointer;
position: relative;
}
.goods-form .category-tag-wrap .el-tag {
display: inline-flex;
align-items: center;
max-width: 100%;
margin: 2px 0 2px 6px;
text-overflow: ellipsis;
}
.goods-form .category-tag-wrap-suffix {
width: 12px;
height: 100%;
position: absolute;
right: 6px;
top: 0;
display: flex;
align-items: center;
justify-content: center;
}
.goods-form .category-tag-wrap-suffix .circle-close {
display: none;
}
.goods-form .category-tag-wrap-suffix.is-active:hover .circle-close {
display: block;
}
.goods-form .category-tag-wrap-suffix.is-active:hover .arrow-down {
display: none;
}
.category-tooltip {}
.goods-form .is-error {
color: #FF4D4F;
}
.goods-form .el-affix, .goods-form .el-tabs{
width: 100%;
}
.editor-form-item .el-form-item__content {
margin-left: 16px !important;
}
.note-editable {
height: 300px !important;
}
</style>
<div id="addEdit" class="goods-form" v-cloak>
<el-container class="panel-block">
<el-header>
<el-tabs v-model="state.activeStep" @tab-click="isValidate">
<el-tab-pane :name="0">
<template #label>
<div class="sa-flex" :class="validateData['0']?'is-error':''">
基本信息
<el-icon v-if="validateData['0']" class="ml-1">
<warning-filled />
</el-icon>
</div>
</template>
</el-tab-pane>
<el-tab-pane :name="1">
<template #label>
<div class="sa-flex" :class="validateData['1']?'is-error':''">
价格/库存
<el-icon v-if="validateData['1']" class="ml-1">
<warning-filled />
</el-icon>
</div>
</template>
</el-tab-pane>
<el-tab-pane :name="2">
<template #label>
<div class="sa-flex" :class="validateData['2']?'is-error':''">
发货设置
<el-icon v-if="validateData['2']" class="ml-1">
<warning-filled />
</el-icon>
</div>
</template>
</el-tab-pane>
<el-tab-pane :name="3">
<template #label>
<div class="sa-flex" :class="validateData['3']?'is-error':''">
商品参数
<el-icon v-if="validateData['3']" class="ml-1">
<warning-filled />
</el-icon>
</div>
</template>
</el-tab-pane>
<el-tab-pane :name="4">
<template #label>
<div class="sa-flex" :class="validateData['4']?'is-error':''">
商品详情
<el-icon v-if="validateData['4']" class="ml-1">
<warning-filled />
</el-icon>
</div>
</template>
</el-tab-pane>
</el-tabs>
</el-header>
<el-main>
<el-scrollbar height="100%">
<el-form :model="form.model" :rules="form.rules" ref="formRef0" label-width="100px">
<div v-show="state.activeStep==0">
<div class="sa-flex mb-4">
<img v-if="!(state.type=='edit' && form.model.type=='virtual')" class="goods-type" :class="form.model.type=='normal'?'is-active':''"
src="/assets/addons/shopro/img/goods/normal.png" @click="onChangeGoodsType('normal')" />
<img v-if="!(state.type=='edit' && form.model.type=='normal')" class="goods-type" :class="form.model.type=='virtual'?'is-active':''"
src="/assets/addons/shopro/img/goods/virtual.png"
@click="onChangeGoodsType('virtual')" />
</div>
<el-form-item label="商品标题" prop="title">
<el-input class="sa-w-360" v-model="form.model.title" placeholder="请输入商品标题"></el-input>
</el-form-item>
<el-form-item label="副标题">
<el-input class="sa-w-360" v-model="form.model.subtitle" placeholder="请输入副标题"></el-input>
</el-form-item>
<el-form-item label="商品主图" prop="image">
<sa-uploader v-model="form.model.image" type="size" @success="onSuccess"></sa-uploader>
<div class="warning"> 作用于商城列表、分享图片建议尺寸750*750 px </div>
</el-form-item>
<el-form-item label="轮播图" prop="images">
<sa-uploader v-model="form.model.images" :multiple="true"></sa-uploader>
<div class="warning">
作用于商品详情顶部轮播显示,<br />轮播图可以拖拽调整顺序
</div>
</el-form-item>
<el-form-item label="商品分类">
<div class="sa-w-360">
<el-popover popper-class="category-tooltip sa-popper" effect="light"
placement="top-start" trigger="click">
<el-tabs v-model="tempCategory.tabActive">
<el-tab-pane v-for="tab in category.select" :key="tab" :label="tab.name"
:name="tab.id + ''">
<el-cascader-panel v-model="tempCategory.idsArr[tab.id]"
:ref="(el) => setCategoryRef(el, tab)" :options="tab.children" :props="{
multiple: true,
checkStrictly: true,
value: 'id',
label: 'name',
children: 'children',
emitPath: false,
}" @change="onChangeCategoryIds"></el-cascader-panel>
</el-tab-pane>
</el-tabs>
<template #reference>
<div class="category-tag-wrap">
<el-tag v-for="(value, key) in tempCategory.label" :key="key" type="info"
closable @close.stop="onDeleteCategoryIds(key)">{{ value }}</el-tag>
<div class="category-tag-wrap-suffix"
:class="JSON.stringify(tempCategory.label) == '{}'?'':'is-active'">
<el-icon class="arrow-down">
<arrow-down />
</el-icon>
<el-icon class="circle-close" @click.stop="onClearCategoryIds">
<circle-close />
</el-icon>
</div>
</div>
</template>
</el-popover>
{if $auth->check('shopro/category/add')}
<el-button class="label-tip" type="primary" link @click="onAddCategory">添加商品分类</el-button>
{/if}
</div>
</el-form-item>
<el-form-item label="商品排序">
<el-input class="sa-w-360" v-model="form.model.weigh" placeholder="请输入商品排序" type="number"
:min="0">
</el-input>
</el-form-item>
<el-form-item label="限购类型">
<el-radio-group v-model="form.model.limit_type">
<el-radio label="none">不限购</el-radio>
<el-radio label="daily">每日</el-radio>
<el-radio label="all">累计</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item v-if="form.model.limit_type != 'none'" label="限购数量">
<el-input class="sa-w-360" v-model="form.model.limit_num" placeholder="请输入限购数量" :min="0"
type="number">
</el-input>
</el-input>
</el-form-item>
<el-form-item label="商品状态">
<el-radio-group v-model="form.model.status">
<el-radio label="up">上架</el-radio>
<el-radio label="hidden">隐藏</el-radio>
<el-radio label="down">下架</el-radio>
</el-radio-group>
</el-form-item>
</div>
</el-form>
<el-form :model="form.model" :rules="form.rules" ref="formRef1" label-width="100px">
<div v-show="state.activeStep==1">
<el-form-item label="商品规格">
<div class="sa-flex">
<el-radio-group :disabled="state.type == 'edit'" v-model="form.model.is_sku">
<el-radio :label="0">单规格</el-radio>
<el-radio :label="1">多规格</el-radio>
</el-radio-group>
<div class="warning">
如商品参与了拼团、秒杀、积分等活动,切换规格,可能导致活动规格不可用
</div>
</div>
</el-form-item>
<template v-if="form.model.is_sku == 1">
<div class="sku-wrap">
<div class="sku" v-for="(s, k) in form.model.skus" :key="k">
<div class="sku-key sa-flex sa-row-between">
<div class="sa-flex">
<div class="sku-value-title">规格名称</div>
<el-input class="sku-key-input" v-model="s.name" placeholder="请输入规格名称">
</el-input>
</div>
<el-icon class="sku-key-icon" @click="deleteMainSku(k)">
<circle-close-filled />
</el-icon>
</div>
<div class="sku-value sa-flex sa-flex-wrap">
<div class="sku-value-title sa-flex"> 规格值 </div>
<div class="sku-value-box" v-for="(sc, c) in s.children" :key="c">
<el-input class="sku-value-input" v-model="sc.name" placeholder="请输入规格值">
</el-input>
<el-icon class="sku-value-icon" @click="deleteChildrenSku(k, c)">
<circle-close-filled />
</el-icon>
</div>
<el-button class="sku-value-add" type="primary" link @click="addChildrenSku(k)">
添加规格值
</el-button>
</div>
</div>
<div class="sku-tools sa-flex">
<el-button class="add" type="primary" @click="addMainSku">+ 添加规格</el-button>
</div>
</div>
<!-- 表格 -->
<div class="sku-table-wrap mb-4">
<table class="sku-table" rules="all">
<thead>
<tr>
<template v-for="(item, i) in form.model.skus" :key="i">
<th v-if="item.children.length">{{ item.name }}</th>
</template>
<th>图片</th>
<th>
<div class="sa-flex">
<div class="th-title">价格(元)</div>
<el-popover placement="top" width="160"
v-model:visible="batchPopover.flag.price" trigger="click">
<template #reference>
<el-icon class="batch-icon">
<Edit />
</el-icon>
</template>
<el-input class="mb-2" v-model="batchPopover.value"
placeholder="请输入价格" size="small" type="number" :step="0.01"
:min="0" :precision="2"></el-input>
<div class="sa-flex sa-row-right">
<el-button type="primary" link size="small"
@click="onbatchPopover('price', 'cancel')">取消
</el-button>
<el-button type="primary" size="small"
@click="onbatchPopover('price', 'confirm')">确定
</el-button>
</div>
</el-popover>
</div>
</th>
<th>
<div class="sa-flex">
<div class="th-title">划线价格</div>
<el-popover placement="top" width="160"
v-model:visible="batchPopover.flag.original_price"
trigger="click">
<template #reference>
<el-icon class="batch-icon">
<Edit />
</el-icon>
</template>
<el-input class="mb-2" v-model="batchPopover.value"
placeholder="请输入划线价格" size="small" type="number"
:step="0.01" :min="0" :precision="2"></el-input>
<div class="sa-flex sa-row-right">
<el-button type="primary" link size="small"
@click="onbatchPopover('original_price', 'cancel')">取消
</el-button>
<el-button type="primary" size="small"
@click="onbatchPopover('original_price', 'confirm')">确定
</el-button>
</div>
</el-popover>
</div>
</th>
<th>
<div class="sa-flex">
<div class="th-title">成本价</div>
<el-popover placement="top" width="160"
v-model:visible="batchPopover.flag.cost_price" trigger="click">
<template #reference>
<el-icon class="batch-icon">
<Edit />
</el-icon>
</template>
<el-input class="mb-2" v-model="batchPopover.value"
placeholder="请输入成本价" size="small" type="number" :step="0.01"
:min="0" :precision="2"></el-input>
<div class="sa-flex sa-row-right">
<el-button type="primary" link size="small"
@click="onbatchPopover('cost_price', 'cancel')">取消
</el-button>
<el-button type="primary" size="small"
@click="onbatchPopover('cost_price', 'confirm')">确定
</el-button>
</div>
</el-popover>
</div>
</th>
<th>库存(件)</th>
<th>库存预警(件)</th>
<th>
<div class="sa-flex">
<div class="th-title">重量(kg)</div>
<el-popover placement="top" width="160"
v-model:visible="batchPopover.flag.weight" trigger="click">
<template #reference>
<el-icon class="batch-icon">
<Edit />
</el-icon>
</template>
<el-input class="mb-2" v-model="batchPopover.value"
placeholder="请输入重量" size="small" type="number" :step="0.01"
:min="0" :precision="2"></el-input>
<div class="sa-flex sa-row-right">
<el-button type="primary" link size="small"
@click="onbatchPopover('weight', 'cancel')">取消
</el-button>
<el-button type="primary" size="small"
@click="onbatchPopover('weight', 'confirm')">确定
</el-button>
</div>
</el-popover>
</div>
</th>
<th>
<div class="sa-flex">
<div class="th-title">规格编码</div>
<el-popover placement="top" width="160"
v-model:visible="batchPopover.flag.sn" trigger="click">
<template #reference>
<el-icon class="batch-icon">
<Edit />
</el-icon>
</template>
<el-input class="mb-2" v-model="batchPopover.value"
placeholder="请输入规格编码" size="small" type="number"></el-input>
<div class="sa-flex sa-row-right">
<el-button type="primary" link size="small"
@click="onbatchPopover('sn', 'cancel')">取消</el-button>
<el-button type="primary" size="small"
@click="onbatchPopover('sn', 'confirm')">确定</el-button>
</div>
</el-popover>
</div>
</th>
<th>商品状态</th>
</tr>
</thead>
<tbody>
<tr v-for="(item, i) in form.model.sku_prices" :key="i">
<template v-for="(v, j) in item.goods_sku_text" :key="j">
<td>
<span class="th-center">{{ v }}</span>
</td>
</template>
<td class="image">
<sa-uploader v-model="item.image" size="28">
</sa-uploader>
</td>
<td>
<el-input v-model="item.price" placeholder="请输入价格" size="small"
type="number" :step="0.01" :min="0" :precision="2"></el-input>
</td>
<td>
<el-input v-model="item.original_price" placeholder="请输入划线价格"
size="small" type="number" :step="0.01" :min="0" :precision="2">
</el-input>
</td>
<td>
<el-input v-model="item.cost_price" placeholder="请输入成本价" size="small"
type="number" :step="0.01" :min="0" :precision="2"></el-input>
</td>
<td class="stock">
<el-input v-if="state.type == 'add'" v-model="item.stock"
placeholder="请输入库存" size="small" type="number" :step="1" :min="0">
</el-input>
</el-input>
<span v-if="state.type == 'edit'">
{{ item.stock }}
</span>
</td>
<td class="stock_warning">
<div class="sa-flex">
<el-switch class="sku-stock-switch"
v-model="item.stock_warning_switch"
@change="onChangeStockWarningSwitch(i)"></el-switch>
<span v-if="!item.stock_warning_switch">使用默认库存预警</span>
<el-input v-if="item.stock_warning_switch"
v-model="item.stock_warning" placeholder="请输入" size="small"
type="number" :step="1" :min="0"></el-input>
</div>
</td>
<td>
<el-input v-model="item.weight" placeholder="请输入" size="small"
type="number" :step="0.01" :min="0" :precision="2"></el-input>
</td>
<td class="sn">
<el-input v-model="item.sn" placeholder="请输入" size="small"></el-input>
</td>
<td>
<el-select v-model="item.status" placeholder="请选择" size="small">
<el-option label="上架" value="up"></el-option>
<el-option label="下架" value="down"></el-option>
</el-select>
</td>
</tr>
</tbody>
</table>
</div>
</template>
<template v-if="form.model.is_sku == 0">
<el-form-item label="售卖价格" prop="price">
<el-input class="sa-w-360" v-model="form.model.price" placeholder="请输入售卖价格" type="number">
<template #append></template>
</el-input>
</el-form-item>
<el-form-item label="划线价格">
<el-input class="sa-w-360" v-model="form.model.original_price" placeholder="请输入划线价格"
type="number" :step="0.01" :min="0" :precision="2">
<template #append></template>
</el-input>
</el-form-item>
<el-form-item label="成本价格">
<el-input class="sa-w-360" v-model="form.model.cost_price" placeholder="请输入成本价格"
type="number" :step="0.01" :min="0" :precision="2">
<template #append></template>
</el-input>
</el-form-item>
<el-form-item label="库存类型">
<el-radio-group v-model="form.model.stock_show_type">
<el-radio label="exact">
<div class="sa-flex">
<div>精确显示</div>
<el-popover popper-class="stock-show-type sa-popper" trigger="hover">
<img class="exact"
src="/assets/addons/shopro/img/goods/stock-exact.png" />
<template #reference>
<el-icon class="warning">
<warning />
</el-icon>
</template>
</el-popover>
</div>
</el-radio>
<el-radio label="sketchy">
<div class="sa-flex">
<div>粗略显示</div>
<el-popover popper-class="stock-show-type sa-popper" trigger="hover">
<img class="sketchy"
src="/assets/addons/shopro/img/goods/stock-sketchy.png" />
<template #reference>
<el-icon class="warning">
<warning />
</el-icon>
</template>
</el-popover>
</div>
</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="商品库存">
<el-input class="sa-w-360" v-model="form.model.stock" placeholder="请输入商品库存"
type="number" :step="1" :min="0" :disabled="state.type == 'edit'">
<template #append></template>
</el-input>
</el-form-item>
<el-form-item label="库存预警">
<el-switch v-model="state.tempData.isStockWarning"></el-switch>
<div class="warning"> 库存预警在未开启的状态下,使用默认库存预警 </div>
</el-form-item>
<el-form-item v-if="state.tempData.isStockWarning" label="预警数量">
<el-input class="sa-w-360" v-model="form.model.stock_warning" placeholder="请输入库存预警数量">
<template #append></template>
</el-input>
</el-form-item>
</template>
<el-form-item label="销量类型">
<el-radio-group v-model="form.model.sales_show_type">
<el-radio label="exact">
<div class="sa-flex">
<div>精确显示</div>
<el-popover popper-class="sales-show-type sa-popper" trigger="hover">
<img class="exact" src="/assets/addons/shopro/img/goods/sales-exact.png" />
<template #reference>
<el-icon class="warning">
<warning />
</el-icon>
</template>
</el-popover>
</div>
</el-radio>
<el-radio label="sketchy">
<div class="sa-flex">
<div>粗略显示</div>
<el-popover popper-class="sales-show-type sa-popper" trigger="hover">
<img class="sketchy"
src="/assets/addons/shopro/img/goods/sales-sketchy.png" />
<template #reference>
<el-icon class="warning">
<warning />
</el-icon>
</template>
</el-popover>
</div>
</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="虚拟销量">
<div class="sa-form-wrap">
<el-input class="sa-w-360" v-model="form.model.show_sales" placeholder="请输入虚拟销量"
type="number" :min="0">
</el-input>
<div class="warning"> 可以提高商品的销量排行榜,鼓励用户下单 </div>
</div>
</el-form-item>
<template v-if="form.model.is_sku == 0">
<el-form-item label="商品重量">
<el-input class="sa-w-360" v-model="form.model.weight" placeholder="请输入商品重量"
type="number" :step="0.01" :min="0" :precision="2">
<template #append>kg</template>
</el-input>
</el-form-item>
<el-form-item label="商品编号">
<el-input class="sa-w-360" v-model="form.model.sn" placeholder="请输入商品编号"></el-input>
</el-form-item>
</template>
</div>
</el-form>
<el-form :model="form.model" :rules="form.rules" ref="formRef2" label-width="100px">
<div v-show="state.activeStep==2">
<template v-if="form.model.type=='normal'">
<el-form-item label="配送方式">
<el-radio-group v-model="form.model.dispatch_type">
<el-radio label="express">物流快递</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item v-if="form.model.dispatch_type" label="物流快递" prop="dispatch_id">
<div class="sa-w-360">
<el-select v-model="form.model.dispatch_id" placeholder="请选择物流快递">
<el-option v-for="item in dispatch.select" :key="item.id" :label="item.name"
:value="item.id"></el-option>
</el-select>
{if $auth->check('shopro/dispatch/dispatch/add')}
<el-button class="label-tip" type="primary" link @click="onAddDispatch('express')">
添加物流快递
</el-button>
{/if}
</div>
</el-form-item>
<el-form-item label="货到付款">
<el-switch v-model="form.model.is_offline" :active-value="1" :inactive-value="0"></el-switch>
</el-form-item>
</template>
<template v-if="form.model.type=='virtual'">
<el-form-item label="配送方式">
<el-radio-group v-model="form.model.dispatch_type" @change="onChangeDispatchType">
<el-radio label="autosend">自动发货</el-radio>
<el-radio label="custom">手动发货
<el-popover popper-class="sa-popper" trigger="hover">
在订单管理,手动对订单进行发货,发货时填写自定义发货内容
<template #reference>
<el-icon class="warning">
<warning />
</el-icon>
</template>
</el-popover>
</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item v-if="form.model.dispatch_type=='autosend'" label="自动发货" prop="dispatch_id">
<div class="sa-w-360">
<el-select v-model="form.model.dispatch_id" placeholder="请选择自动发货">
<el-option v-for="item in dispatch.select" :key="item.id" :label="item.name"
:value="item.id"></el-option>
</el-select>
{if $auth->check('shopro/dispatch/dispatch/add')}
<el-button class="label-tip" type="primary" link @click="onAddDispatch('autosend')">
添加自动发货
</el-button>
{/if}
</div>
</el-form-item>
</template>
</div>
</el-form>
<el-form :model="form.model" :rules="form.rules" ref="formRef3" label-width="100px">
<div v-show="state.activeStep==3">
<el-form-item label="服务保障" prop="service_ids">
<div class="sa-w-360">
<el-select v-model="form.model.service_ids" placeholder="请选择服务保障" multiple>
<el-option v-for="item in service.select" :key="item.id" :label="item.name"
:value="item.id"></el-option>
</el-select>
{if $auth->check('shopro/goods/service/add')}
<el-button class="label-tip" type="primary" link @click="onAddService">
添加服务保障
</el-button>
{/if}
</div>
</el-form-item>
<el-form-item label="参数详情">
<div class="sa-template-wrap">
<div class="header">
<div class="key">参数名称</div>
<div class="key">内容</div>
<div class="oper">操作</div>
</div>
<draggable v-model="form.model.params" :animation="300" handle=".sortable-drag"
item-key="element">
<template #item="{ element, index }">
<div class="item">
<el-form-item class="key" :prop="'params.' + index + '.title'"
:rules="paramsRules.title">
<el-input placeholder="请输入名称" v-model="element.title"></el-input>
</el-form-item>
<el-form-item class="key" :prop="'params.' + index + '.content'"
:rules="paramsRules.content">
<el-input placeholder="请输入内容" v-model="element.content"></el-input>
</el-form-item>
<el-form-item class="oper">
<el-button type="danger" link @click="onDeleteParams(index)">删除
</el-button>
<i class="iconfont iconmove sortable-drag"></i>
</el-form-item>
</div>
</template>
</draggable>
<el-button class="add-params" icon="Plus" @click="onAddParams">添加
</el-button>
</div>
</el-form-item>
</div>
</el-form>
<el-form :model="form.model" :rules="form.rules" ref="formRef4" label-width="100px">
<div v-show="state.activeStep==4">
<el-form-item class="editor-form-item" label="">
<form role="form">
<textarea id="goodsContent" class="editor"></textarea>
</form>
</el-form-item>
</div>
</el-form>
</el-scrollbar>
</el-main>
<el-footer class="sa-footer--submit sa-flex sa-row-right">
<!-- <el-button plain v-if="state.activeStep > 0" @click="onBack">上一步</el-button>
<el-button v-if="state.activeStep < 4" type="primary" @click="onNext">下一步</el-button> -->
<el-button type="primary" @click="onConfirm">确定</el-button>
</el-footer>
</el-container>
</div>

View File

@@ -0,0 +1,153 @@
{include file="/shopro/common/script" /}
<style>
.goods-add-stock .sku-table-wrap {
width: 100%;
overflow: auto;
}
.goods-add-stock .sku-table-wrap .sku-table {
width: 100%;
border: 1px solid var(--sa-border);
}
.goods-add-stock .sku-table-wrap .sku-table th {
font-size: 12px;
color: var(--subtitle);
height: 32px;
line-height: 1;
padding-left: 12px;
box-sizing: border-box;
text-align: left;
}
.goods-add-stock .sku-table-wrap .sku-table th .th-title {
font-size: 12px;
color: var(--subtitle);
font-weight: bold;
}
.goods-add-stock .sku-table-wrap .sku-table td {
min-width: 88px;
padding: 0 10px;
height: 40px;
box-sizing: border-box;
}
.goods-add-stock .sku-table-wrap .sku-table td.image {
min-width: 48px;
}
.goods-add-stock .sku-table-wrap .sku-table td.stock {
min-width: 190px;
}
.goods-add-stock .sku-table-wrap .sku-table td.stock .addsku-input {
width: 80px;
}
.goods-add-stock .sku-table-wrap .sku-table td.stock_warning {
min-width: 168px;
}
.goods-add-stock .sku-table-wrap .sku-table td.sn {
min-width: 116px;
}
.sku-table-wrap .sku-table .up {
color: var(--el-color-success);
}
.goods-add-stock .sku-table-wrap .sku-table .down {
color: var(--el-color-danger);
}
.goods-add-stock .sku-table-wrap .sku-table .hidden {
color: var(--el-color-info);
}
</style>
<div id="addStock" class="goods-add-stock" v-cloak>
<el-container class="panel-block">
<el-main>
<el-scrollbar height="100%">
<el-form :model="form.model" :rules="form.rules" ref="formRef" label-width="100px">
<el-form-item v-if="state.is_sku == 0" label="商品库存:" prop="add_stock">
<div class="sa-w-360">
<div class="mr-2">{{ state.stock }}</div>
<el-input type="number" v-model="form.model.add_stock" placeholder="补充库存"><template
#append></template></el-input>
</div>
</el-form-item>
<div v-if="state.is_sku == 1" class="sku-table-wrap">
<table class="sku-table" rules="all">
<thead>
<tr>
<th>规格值</th>
<th>图片</th>
<th>价格(元)</th>
<th>划线价格</th>
<th>成本价</th>
<th>
<div class="sa-flex">
<div class="th-title">库存(件)</div>
<el-popover placement="top" width="160" trigger="click"
v-model:visible="batchPopover.flag">
<template #reference>
<el-icon class="sa-color--primary ml-1">
<Edit />
</el-icon>
</template>
<el-input class="mb-2" v-model="batchPopover.add_stock"
placeholder="请输入内容" size="small"></el-input>
<div class="sa-flex sa-row-right">
<el-button type="primary" link size="small"
@click="onBatchPopover('cancel')">取消</el-button>
<el-button type="primary" size="small"
@click="onBatchPopover('define')">确定</el-button>
</div>
</el-popover>
</div>
</th>
<th>库存预警(件)</th>
<th>重量(kg)</th>
<th>规格编码</th>
<th>商品状态</th>
</tr>
</thead>
<tbody>
<tr v-for="(item, i) in form.model.sku_prices" :key="i">
<td>{{ item.goods_sku_text.join('/') }}</td>
<td class="image">
<sa-image :url="item.image" size="28"></sa-image>
</td>
<td>{{ item.price }}</td>
<td>{{ item.original_price }}</td>
<td>{{ item.cost_price }}</td>
<td class="stock">
<div class="sa-flex sa-row-between">
<div class="stock-title">{{ item.stock }}</div>
<el-input v-model="item.add_stock" placeholder="补充库存量" size="small"
class="addsku-input"
οnkeyup="value=value.replace(/[^\d]/g, '').replace(/^0{1,}/g,'')">
</el-input>
</div>
</td>
<td class="stock_warning">{{ item.stock_warning }}</td>
<td>{{ item.weight }}</td>
<td>{{ item.sn }}</td>
<td :class="item.status">
{{ item.status == 'up' ? `${item.status_text}中` : `已${item.status_text}` }}
</td>
</tr>
</tbody>
</table>
</div>
</el-form>
</el-scrollbar>
</el-main>
<el-footer class="sa-footer--submit sa-flex sa-row-right">
<el-button type="primary" @click="onConfirm">确定</el-button>
</el-footer>
</el-container>
</div>

View File

@@ -0,0 +1,494 @@
{include file="/shopro/common/script" /}
<style>
.goods-index .goods-index-main {
overflow: hidden;
}
.goods-index .el-aside {
--el-aside-width: 161px;
border-right: 1px solid var(--sa-border);
padding: 0 3px;
}
.goods-index .el-aside .category-all {
line-height: 48px;
border-radius: 4px;
padding: 0 12px;
position: relative;
cursor: pointer;
font-size: 14px;
color: var(--sa-title);
}
.goods-index .el-aside .category-all span:last-child {
color: var(--el-color-primary);
}
.goods-index .el-aside .category-all:hover {
background: var(--t-bg-hover);
}
.goods-index .el-aside .category-all.is-active {
background: var(--t-bg-active);
color: var(--el-color-primary);
}
.goods-index .el-aside .category-all::after {
content: '';
position: absolute;
right: 9px;
bottom: 0;
width: 138px;
height: 1px;
background: var(--sa-space);
}
.goods-index .el-aside .el-tree {
--el-tree-node-content-height: 40px;
--el-tree-node-hover-bg-color: var(--t-bg-hover);
}
.goods-index .el-aside .el-tree>.el-tree-node>.el-tree-node__content {
--el-tree-node-content-height: 54px;
align-items: flex-start;
position: relative;
}
.goods-index .el-aside .el-tree>.el-tree-node>.el-tree-node__content::after {
content: '';
position: absolute;
right: 9px;
bottom: 0;
width: 138px;
height: 1px;
background: var(--sa-space);
}
.goods-index .el-aside .el-tree .el-tree-node__content {
/* align-items: flex-start; */
padding-top: 6px;
border-radius: 4px;
}
.goods-index .el-aside .el-tree .name {
line-height: 20px;
font-size: 12px;
color: var(--sa-font);
}
.goods-index .el-aside .el-tree .goods {
line-height: 16px;
font-size: 12px;
color: var(--sa-subfont);
}
.goods-index .el-aside .el-tree:not(.all) .el-tree-node.is-current>.el-tree-node__content {
background: var(--t-bg-active);
}
.goods-index .el-aside .el-tree:not(.all) .el-tree-node.is-current>.el-tree-node__content .el-tree-node__expand-icon {
color: var(--el-color-primary);
}
.goods-index .el-aside .el-tree:not(.all) .el-tree-node.is-current>.el-tree-node__content .name {
color: var(--el-color-primary);
}
.goods-index .el-aside .el-tree:not(.all) .el-tree-node.is-current>.el-tree-node__content .goods {
color: var(--el-color-primary);
}
.goods-index .goods-item .goods-image {
margin-right: 12px;
}
.goods-index .goods-item .goods-title {
height: 20px;
line-height: 20px;
font-size: 14px;
font-weight: 500;
color: var(--sa-font);
}
.goods-index .goods-item .goods-subtitle {
height: 16px;
line-height: 16px;
font-size: 12px;
font-weight: 400;
color: var(--sa-subfont);
margin-bottom: 6px;
}
.goods-index .activity-tag {
padding: 3px 8px;
border-radius: 10px;
line-height: 14px;
font-size: 12px;
font-weight: 400;
margin-right: 8px;
cursor: pointer;
}
.goods-index .activity-tag:last-of-type {
margin-right: 0;
}
.goods-index .activity-tag.groupon,
.goods-index .activity-tag.groupon_ladder {
color: var(--el-color-primary);
background: var(--t-bg-active);
}
.goods-index .activity-tag.seckill {
color: #ff4d4f;
background: rgba(255, 77, 79, .16);
}
.goods-index .activity-tag.promos {
color: #faad14;
background: rgba(250, 173, 20, 0.16);
}
.goods-index .sku {
width: fit-content;
height: 20px;
line-height: 1;
padding: 0 8px;
font-size: 12px;
color: #fff;
background: var(--el-color-primary);
border-radius: 10px;
cursor: pointer;
}
.goods-index .sku .el-icon {
margin-left: 4px;
}
.goods-index .add-stock {
margin-left: 8px;
}
.goods-index .add-stock .iconfont {
font-size: 12px;
color: var(--el-color-primary);
}
.goods-index .sku-image {
margin-left: 16px;
margin-right: 28px;
}
.goods-index .sku-text {
font-size: 12px;
color: var(--sa-font);
}
.goods-index .price .el-input,
.goods-index .sales .el-input {
flex: 1;
}
.goods-index .price span,
.goods-index .sales span {
margin: 0 8px;
}
.goods-index .sa-table-wrap {
height: 100%;
margin-left: -48px;
overflow: hidden;
}
.goods-index .sa-table-wrap .sa-expand-table .el-table__header-wrapper {
display: none;
}
</style>
<div id="index" class="goods-index panel panel-default panel-intro" v-cloak>
<el-container class="panel-block">
<el-container class="goods-index-main">
<el-aside>
<el-scrollbar height="100%">
<div class="category-all sa-flex sa-row-between"
:class="state.filter.data.category_ids == 'all'?'is-active':''"
@click.stop="onChangeCategoryIds()">
<span>全部商品</span>
<span @click.stop="onFold">折叠</span>
</div>
<el-tree ref="treeRef" :class="state.filter.data.category_ids" :data="category.select" :props="{
label:'name'
}" :expand-on-click-node="false" node-key="id" :current-node-key="state.filter.data.category_ids"
:indent="12" :default-expanded-keys="defaultExpandedKeys" @node-click="onChangeCategoryIds">
<template #default="{ node, data }">
<div>
<div class="name">{{ node.label }}</div>
<div v-if="node.level = 1" class="goods mt-1">
<span v-if="data.children?.length">
子分类{{data.children.length}}
</span>
</div>
</div>
</template>
</el-tree>
</el-scrollbar>
</el-aside>
<el-container>
<el-header class="sa-header">
<el-tabs class="sa-tabs" v-model="state.filter.data.status" @tab-change="onChangeTab">
<el-tab-pane v-for="sl in type.data.status" :key="sl" :label="sl.name" :name="sl.type">
</el-tab-pane>
</el-tabs>
<div class="sa-title sa-flex sa-row-between">
<div class="sa-title-left">
<div class="left-name">商品库</div>
<sa-filter-condition v-model="state.filter" @filter-delete="onChangeFilter">
</sa-filter-condition>
</div>
<div class="sa-title-right">
<el-button class="sa-button-refresh" icon="RefreshRight" @click="getData"></el-button>
<el-button class="sa-button-refresh" icon="Search" @click="onOpenFilter"></el-button>
{if $auth->check('shopro/goods/goods/add')}
<el-button icon="Plus" type="primary" @click="onAdd">添加</el-button>
{/if}
{if $auth->check('shopro/goods/goods/recyclebin')}
<el-button type="danger" icon="Delete" plain @click="onRecyclebin">回收站</el-button>
{/if}
</div>
</div>
</el-header>
<el-main class="sa-main">
<div class="sa-table-wrap">
<el-table height="100%" class="sa-table" :data="state.data"
@selection-change="onChangeSelection" @sort-change="onChangeSort"
:expand-row-keys="expandRowKeys" row-key="id" stripe>
<el-table-column type="expand">
<template #default="props">
<el-table class="sa-table sa-expand-table" :data="skuPrice.data" stripe>
<el-table-column width="96"></el-table-column>
<el-table-column prop="id" label="ID" min-width="90"></el-table-column>
<el-table-column label="商品" min-width="440">
<template #default="scope">
<div class="sa-flex">
<sa-image class="sku-image"
:url="scope.row.image || props.row.image" size="32"></sa-image>
<div class="sku-text">
{{ scope.row.goods_sku_text?.join('/') }}
</div>
</div>
</template>
</el-table-column>
<el-table-column prop="price" label="价格" min-width="150"></el-table-column>
<el-table-column prop="sales" label="销量" min-width="100"></el-table-column>
<el-table-column label="浏览量" min-width="100">
<template #default="scope">
{{ scope.row.views || '-' }}</template>
</el-table-column>
<el-table-column prop="stock" label="库存" min-width="100"></el-table-column>
<el-table-column label="更新时间" width="172">
<template #default>-</template>
</el-table-column>
<el-table-column label="操作" min-width="240">
<template #default="scope">
{if $auth->check('shopro/goods/sku_price/edit')}
<el-dropdown popper-class="goods-dropdown" @command="onSkuCommand">
<el-button link>
<el-tag :type="state.statusData.type[scope.row.status]">
{{ scope.row.status_text }}
<el-icon>
<arrow-down />
</el-icon>
</el-tag>
</el-button>
<template #dropdown>
<el-dropdown-menu>
<template v-for="item in type.data.status">
<el-dropdown-item
v-if="item.type!='all' && item.type!='hidden'"
:command="{
goods_id: props.row.id,
id: scope.row.id,
type: item.type,
}">
<span
:style="{color:state.statusData.color[item.type]}">
{{item.name}}
</span>
</el-dropdown-item>
</template>
</el-dropdown-menu>
</template>
</el-dropdown>
{/if}
</template>
</el-table-column>
</el-table>
</template>
</el-table-column>
<el-table-column type="selection" width="48" align="center"></el-table-column>
<el-table-column sortable="custom" prop="id" label="ID" min-width="90"></el-table-column>
<el-table-column label="商品" min-width="440">
<template #default="scope">
<div class="goods-item sa-flex sa-col-top">
<sa-image class="goods-image" :url="scope.row.image" size="64"></sa-image>
<div class="right">
<div class="goods-title sa-table-line-1">{{scope.row.title}}</div>
<div class="goods-subtitle sa-table-line-1">{{scope.row.subtitle}}</div>
<el-scrollbar>
<div class="sa-flex">
<template v-for="activity in scope.row.activities">
<el-popover popper-class="sa-popper" trigger="hover">
<el-button type="primary" link
@click="onOpenActivityDetail(activity)">
{{ activity.title }}
</el-button>
<template #reference>
<div class="activity-tag" :class="activity.type">
{{ activity.type_text }}
</div>
</template>
</el-popover>
</template>
<template v-for="promo in scope.row.promos">
<el-popover popper-class="sa-popper" trigger="hover">
<el-button type="primary" link
@click="onOpenActivityDetail(activity)">
{{ promo.title }}
</el-button>
<template #reference>
<div class="activity-tag promos">
{{ promo.type_text }}
</div>
</template>
</el-popover>
</template>
</div>
</el-scrollbar>
</div>
</div>
</template>
</el-table-column>
<el-table-column sortable="custom" prop="price" label="价格" min-width="150">
<template #default="scope">
<div>{{ scope.row.price?.join('~') || 0 }}</div>
<div v-if="scope.row.is_sku" class="sku sa-flex sa-row-center"
@click.stop="onExpand(scope.row.id)">
<span>多规格</span>
<el-icon
:class="[ 'expand-arrow', expandRowKeys.includes(scope.row.id) ? 'expand-arrow-up' : 'expand-arrow-down',]">
<arrow-down />
</el-icon>
</div>
</template>
</el-table-column>
<el-table-column sortable="custom" prop="sales" label="销量" min-width="100">
</el-table-column>
<el-table-column sortable="custom" prop="views" label="浏览量" min-width="100">
</el-table-column>
<el-table-column label="库存" min-width="100">
<template #default="scope">
<div class="sa-flex">
<span>{{ scope.row.stock || 0 }}</span>
{if $auth->check('shopro/goods/goods/addStock')}
<el-button class="add-stock" link @click="onEditStock(scope.row)">
<i class="iconfont iconadd-stock"></i>
</el-button>
{/if}
</div>
</template>
</el-table-column>
<el-table-column label="更新时间" width="172">
<template #default="scope">{{ scope.row.createtime || '-' }}</template>
</el-table-column>
<el-table-column label="操作" min-width="240" fixed="right">
<template #default="scope">
<div class="sa-flex">
{if $auth->check('shopro/goods/goods/edit')}
<el-dropdown popper-class="goods-dropdown" @command="onCommand">
<el-button link>
<el-tag :type="state.statusData.type[scope.row.status]">
{{ scope.row.status_text }}
<el-icon>
<arrow-down />
</el-icon>
</el-tag>
</el-button>
<template #dropdown>
<el-dropdown-menu>
<template v-for="item in type.data.status">
<el-dropdown-item v-if="item.type!='all'" :command="{
id: scope.row.id,
type: item.type,
}">
<span :style="{color:state.statusData.color[item.type]}">
{{item.name}}
</span>
</el-dropdown-item>
</template>
</el-dropdown-menu>
</template>
</el-dropdown>
<el-button type="primary" link @click="onEdit(scope.row.id)">编辑</el-button>
{/if}
{if $auth->check('shopro/goods/goods/add')}
<el-button type="primary" link @click="onCopy(scope.row.id)">复制
</el-button>
{/if}
<el-popconfirm width="fit-content" confirm-button-text="确认"
cancel-button-text="取消" title="确认删除这条记录?" @confirm="onDelete(scope.row.id)">
<template #reference>
{if $auth->check('shopro/goods/goods/delete')}
<el-button type="danger" link>删除</el-button>
{/if}
</template>
</el-popconfirm>
</div>
</template>
</el-table-column>
</el-table>
</div>
</el-main>
</el-container>
</el-container>
<el-footer class="sa-footer sa-flex sa-row-between sa-flex-wrap">
<div class="sa-batch sa-flex">
<div class="tip">
已选择 <span>{{batchHandle.data.length}}</span></div>
<div class="sa-flex">
{if $auth->check('shopro/goods/goods/delete')}
<el-button type="danger" :disabled="!batchHandle.data.length" @click="onBatchHandle('delete')">删除
</el-button>
{/if}
{if $auth->check('shopro/goods/goods/edit')}
<el-button type="success" :disabled="!batchHandle.data.length" @click="onBatchHandle('up')">上架
</el-button>
{/if}
{if $auth->check('shopro/goods/goods/edit')}
<el-button type="danger" :disabled="!batchHandle.data.length" @click="onBatchHandle('down')">下架
</el-button>
{/if}
{if $auth->check('shopro/goods/goods/edit')}
<el-button type="info" :disabled="!batchHandle.data.length" @click="onBatchHandle('hidden')">隐藏
</el-button>
{/if}
</div>
</div>
<sa-pagination v-model="pagination" @pagination-change="getData"></sa-pagination>
</el-footer>
</el-container>
<sa-filter v-model="state.filter" @filter-change="onChangeFilter">
<template #supplement>
<el-form-item class="price" label="价格区间">
<el-input v-model="state.filter.data.price.min" placeholder="最低价格"></el-input>
<span></span>
<el-input v-model="state.filter.data.price.max" placeholder="最高价格"></el-input>
</el-form-item>
<el-form-item class="sales" label="销量区间">
<el-input v-model="state.filter.data.sales.min" placeholder="最低销量"></el-input>
<span></span>
<el-input v-model="state.filter.data.sales.max" placeholder="最高销量"></el-input>
</el-form-item>
</template>
</sa-filter>
</div>

View File

@@ -0,0 +1,54 @@
{include file="/shopro/common/script" /}
<div id="recyclebin" class="goods-recyclebin" v-cloak>
<el-container class="panel-block">
<el-main>
<el-table height="100%" class="sa-table" :data="state.data" stripe @selection-change="onChangeSelection"
@sort-change="onChangeSort">
<el-table-column type="selection" width="48" align="center"></el-table-column>
<el-table-column prop="id" label="ID" min-width="90" sortable="custom"></el-table-column>
<el-table-column label="名称" min-width="100">
<template #default="scope">
<div class="sa-table-line-1">{{ scope.row.title || '-' }}</div>
</template>
</el-table-column>
<el-table-column prop="deletetime" label="删除时间" min-width="172" sortable="custom"></el-table-column>
<el-table-column fixed="right" label="操作" min-width="120">
<template #default="scope">
{if $auth->check('shopro/goods/goods/restore')}
<el-button type="primary" link @click="onRestore(scope.row.id)">还原</el-button>
{/if}
<el-popconfirm width="fit-content" confirm-button-text="确认" cancel-button-text="取消"
title="确认销毁这条记录?" @confirm="onDestroy(scope.row.id)">
<template #reference>
{if $auth->check('shopro/goods/goods/destroy')}
<el-button type="danger" link>销毁</el-button>
{/if}
</template>
</el-popconfirm>
</template>
</el-table-column>
</el-table>
</el-main>
<el-footer class="sa-footer sa-flex sa-row-between sa-flex-wrap">
<div class="sa-batch sa-flex">
<div class="tip">
已选择 <span>{{batchHandle.data.length}}</span></div>
<div class="sa-flex">
{if $auth->check('shopro/goods/goods/restore')}
<el-button type="primary" :disabled="!batchHandle.data.length" @click="onBatchHandle('restore')">还原
</el-button>
{/if}
{if $auth->check('shopro/goods/goods/destroy')}
<el-button type="danger" :disabled="!batchHandle.data.length" @click="onBatchHandle('destroy')">销毁
</el-button>
{/if}
{if $auth->check('shopro/goods/goods/destroy')}
<el-button type="danger" @click="onBatchHandle('all')">清空回收站</el-button>
{/if}
</div>
</div>
<sa-pagination class="is-ellipsis" v-model="pagination" @pagination-change="getData"></sa-pagination>
</el-footer>
</el-container>
</div>

View File

@@ -0,0 +1,168 @@
{include file="/shopro/common/script" /}
<style>
.goods-select .el-aside {
--el-aside-width: 180px;
border-right: 1px solid var(--sa-border);
padding: 20px;
}
.goods-select .category-select {
margin-bottom: 16px;
}
.goods-select .el-tree-node__expand-icon {
display: none;
}
.goods-select .el-tree-node__content {
height: 32px;
}
.goods-select .el-tree-node__label {
width: 100%;
}
.goods-select .custom-tree-node {
width: 100%;
height: 32px;
line-height: 32px;
border-radius: 4px;
}
.goods-select .custom-tree-node.is-active {
background: var(--t-bg-active);
color: var(--el-color-primary);
}
.goods-select .expand-arrow {
margin-left: 8px;
}
.goods-select .search-wrap {
--el-header-height: auto;
padding-top: var(--sa-padding);
}
.goods-select .search-price span {
margin-right: 12px;
}
.goods-select .search-price .search-price-min,
.goods-select .search-price .search-price-max {
width: 88px;
}
.goods-select .search-price .search-price-min {
margin-right: 12px;
}
.goods-select .search-keyword {
width: 180px;
}
.goods-select .goods-item {}
.goods-select .goods-item .goods-image {
margin-right: 8px;
}
.goods-select .goods-item .goods-title {
height: 16px;
line-height: 16px;
font-size: 12px;
font-weight: 400;
color: var(--sa-subtitle);
margin-bottom: 6px;
}
.goods-select .goods-item .goods-price {
line-height: 16px;
font-size: 12px;
font-weight: 400;
color: #ff4d4f;
}
</style>
<div id="select" class="goods-select" v-cloak>
<el-container class="panel-block">
<el-aside>
<el-scrollbar height="100%">
<el-select class="category-select" v-model="category.id" placeholder="Select"
@change="getCategoryDetail">
<el-option v-for="item in category.select" :key="item.id" :label="item.name" :value="item.id">
</el-option>
</el-select>
<el-tree :data="category.detail" empty-text="" :props="{
children: 'children',
label: 'name',
}" :indent="0" :accordion="true">
<template #default="{ node, data }">
<span class="custom-tree-node sa-flex"
:class="data.id == state.filter.data.category_ids ? 'is-active' : ''"
:style="{ 'padding-left': `${node.level * 16}px` }" @click.stop="changeCategoryIds(data)">
<div class="sa-table-line-1">{{ data.name }}</div>
<el-icon v-if="data.children && data.children.length"
:class="['expand-arrow',node.expanded ? 'expand-arrow-up' : 'expand-arrow-down']"
@click.stop="node.expanded = !node.expanded">
<arrow-down />
</el-icon>
</span>
</template>
</el-tree>
</el-scrollbar>
</el-aside>
<el-container>
<el-header class="search-wrap sa-flex sa-flex-wrap sa-row-between">
<div class="sa-flex sa-flex-wrap search-price">
<span>商品价格</span>
<el-input class="search-price-min" v-model="state.filter.data.price.min" placeholder="最低价格">
</el-input>
<span></span>
<el-input class="search-price-max" v-model="state.filter.data.price.max" placeholder="最高价格">
</el-input>
</div>
<el-input class="search-keyword" v-model="state.filter.data.keyword" prefix-icon="Search"
placeholder="请输入搜索内容"></el-input>
</el-header>
<el-main>
<el-table height="100%" class="sa-table" ref="multipleTableRef" :data="state.data" stripe
@select="onSelect" @select-all="onSelectAll">
<el-table-column v-if="state.multiple" type="selection" width="48"></el-table-column>
<el-table-column prop="id" label="ID" min-width="90"></el-table-column>
<el-table-column label="商品信息" min-width="310">
<template #default="scoped">
<div class="goods-item sa-flex sa-col-top">
<sa-image class="goods-image" :url="scoped.row.image" size="40"></sa-image>
<div>
<div class="goods-title sa-m-b-6 sa-table-line-1">
{{ scoped.row.title }}
</div>
<div class="goods-price">¥{{ scoped.row.price.join('~¥') }}</div>
</div>
</div>
</template>
</el-table-column>
<el-table-column prop="stock" label="库存" min-width="120"></el-table-column>
<el-table-column v-if="!state.multiple" label="操作" width="80">
<template #default="scope">
<template v-if="state.data_type == 'score_shop'">
<span v-if="scope.row.is_score_shop">已参加</span>
<el-button v-if="!scope.row.is_score_shop" type="primary" link
@click="onSingleSelect(scope.row)">参加</el-button>
</template>
<template v-else>
<el-button type="primary" link @click="onSingleSelect(scope.row)">选择
</el-button>
</template>
</template>
</el-table-column>
</el-table>
</el-main>
<el-footer class="sa-flex" :class="state.multiple ? 'sa-row-between' : 'sa-row-right'">
<sa-pagination class="is-ellipsis" v-model="pagination" @pagination-change="getData"></sa-pagination>
<el-button v-if="state.multiple" type="primary" @click="onConfirm">确 定</el-button>
</el-footer>
</el-container>
</el-container>
</div>

View File

@@ -0,0 +1,24 @@
{include file="/shopro/common/script" /}
<div id="addEdit" class="service-form" v-cloak>
<el-container class="panel-block">
<el-main>
<el-scrollbar height="100%">
<el-form :model="form.model" :rules="form.rules" ref="formRef" label-width="100px">
<el-form-item label="名称" prop="name">
<el-input class="sa-w-360" v-model="form.model.name" placeholder="请输入名称"></el-input>
</el-form-item>
<el-form-item label="服务标识">
<sa-uploader v-model="form.model.image"></sa-uploader>
</el-form-item>
<el-form-item label="说明">
<el-input class="sa-w-360" v-model="form.model.description" placeholder="请输入说明"></el-input>
</el-form-item>
</el-form>
</el-scrollbar>
</el-main>
<el-footer class="sa-footer--submit sa-flex sa-row-right">
<el-button type="primary" @click="onConfirm">确定</el-button>
</el-footer>
</el-container>
</div>

View File

@@ -0,0 +1,83 @@
{include file="/shopro/common/script" /}
<div id="index" class="service-index panel panel-default panel-intro" v-cloak>
<el-container class="panel-block">
<el-header class="sa-header">
<div class="sa-title sa-flex sa-row-between">
<div class="sa-title-left">
<div class="left-name">服务保障</div>
</div>
<div class="sa-title-right">
<el-button class="sa-button-refresh" icon="RefreshRight" @click="getData"></el-button>
{if $auth->check('shopro/goods/service/add')}
<el-button icon="Plus" type="primary" @click="onAdd">添加</el-button>
{/if}
</div>
</div>
</el-header>
<el-main class="sa-main">
<el-table height="100%" class="sa-table" :data="state.data" stripe @selection-change="onChangeSelection"
@sort-change="onChangeSort">
<el-table-column type="selection" width="48" align="center"></el-table-column>
<el-table-column prop="id" label="ID" min-width="90" sortable="custom"> </el-table-column>
<el-table-column label="名称" min-width="120">
<template #default="scope">
<div class="sa-table-line-1">
{{ scope.row.name || '-' }}
</div>
</template>
</el-table-column>
<el-table-column label="服务标识" min-width="100">
<template #default="scope">
<sa-image :url="scope.row.image" size="30"></sa-image>
</template>
</el-table-column>
<el-table-column label="说明" min-width="170">
<template #default="scope">
<div class="sa-table-line-1">
{{ scope.row.description || '-' }}
</div>
</template>
</el-table-column>
<el-table-column label="创建时间" width="172">
<template #default="scope">
{{ scope.row.createtime || '-' }}
</template>
</el-table-column>
<el-table-column label="更新时间" width="172">
<template #default="scope">
{{ scope.row.updatetime || '-' }}
</template>
</el-table-column>
<el-table-column fixed="right" label="操作" min-width="120">
<template #default="scope">
{if $auth->check('shopro/goods/service/edit')}
<el-button type="primary" link @click="onEdit(scope.row.id)">编辑</el-button>
{/if}
<el-popconfirm width="fit-content" confirm-button-text="确认" cancel-button-text="取消"
title="确认删除这条记录?" @confirm="onDelete(scope.row.id)">
<template #reference>
{if $auth->check('shopro/goods/service/delete')}
<el-button type="danger" link>删除</el-button>
{/if}
</template>
</el-popconfirm>
</template>
</el-table-column>
</el-table>
</el-main>
<el-footer class="sa-footer sa-flex sa-row-between sa-flex-wrap">
<div class="sa-batch sa-flex">
<div class="tip">
已选择 <span>{{batchHandle.data.length}}</span></div>
<div class="sa-flex">
{if $auth->check('shopro/goods/service/delete')}
<el-button type="danger" :disabled="!batchHandle.data.length" @click="onBatchHandle('delete')">删除
</el-button>
{/if}
</div>
</div>
<sa-pagination v-model="pagination" @pagination-change="getData"></sa-pagination>
</el-footer>
</el-container>
</div>

View File

@@ -0,0 +1,51 @@
{include file="/shopro/common/script" /}
<div id="index" class="stock-log-index panel panel-default panel-intro" v-cloak>
<el-container class="panel-block">
<el-header class="sa-header">
<div class="sa-title sa-flex sa-row-between">
<div class="sa-title-left">
<div class="left-name">补货记录</div>
<sa-filter-condition v-model="state.filter" @filter-delete="onChangeFilter">
</sa-filter-condition>
</div>
<div class="sa-title-right">
<el-button class="sa-button-refresh" icon="RefreshRight" @click="getData"></el-button>
<el-button class="sa-button-refresh" icon="Search" @click="onOpenFilter"></el-button>
</div>
</div>
</el-header>
<el-main class="sa-main">
<el-table height="100%" class="sa-table" :data="state.data" stripe @sort-change="onChangeSort">
<el-table-column prop="id" label="ID" min-width="90" sortable="custom"> </el-table-column>
<el-table-column label="商品" min-width="400">
<template #default="scope">
<div v-if="scope.row.goods" class="sa-goods-item sa-flex sa-col-top">
<sa-image class="goods-image" :url="scope.row.goods.image" size="48"></sa-image>
<div class="right">
<div class="goods-title sa-table-line-1">{{scope.row.goods.title}}</div>
<div v-if="scope.row.goods_sku_text" class="goods-sku-text">{{scope.row.goods_sku_text}}
</div>
</div>
</div>
<div v-else>{{scope.row.goods_id}}</div>
</template>
</el-table-column>
<el-table-column prop="before" label="补货前" min-width="106"></el-table-column>
<el-table-column prop="stock" label="补货库存" min-width="106"></el-table-column>
<el-table-column prop="msg" label="补货备注" min-width="124"></el-table-column>
<el-table-column prop="createtime" label="创建时间" width="172"></el-table-column>
<el-table-column prop="updatetime" label="更新时间" width="172"></el-table-column>
<el-table-column label="操作人" min-width="140" fixed="right">
<template #default="scope">
<sa-user-profile type="oper" :user="scope.row.oper" :id="scope.row.admin_id" />
</template>
</el-table-column>
</el-table>
</el-main>
<el-footer class="sa-footer sa-flex sa-row-right">
<sa-pagination v-model="pagination" @pagination-change="getData"></sa-pagination>
</el-footer>
</el-container>
<sa-filter v-model="state.filter" @filter-change="onChangeFilter"></sa-filter>
</div>

View File

@@ -0,0 +1,23 @@
{include file="/shopro/common/script" /}
<div id="addStock" class="stock-warning-add-stock" v-cloak>
<el-container class="panel-block">
<el-main>
<el-scrollbar height="100%">
<el-form :model="form.model" :rules="form.rules" ref="formRef" label-width="100px">
<el-form-item label="商品库存:" prop="stock">
<div class="sa-w-360">
<div class="mr-2">{{ state.stock }}</div>
<el-input v-model="form.model.stock" placeholder="补充库存" type="number">
<template #append></template>
</el-input>
</div>
</el-form-item>
</el-form>
</el-scrollbar>
</el-main>
<el-footer class="sa-footer--submit sa-flex sa-row-right">
<el-button type="primary" @click="onConfirm">确定</el-button>
</el-footer>
</el-container>
</div>

View File

@@ -0,0 +1,60 @@
{include file="/shopro/common/script" /}
<div id="index" class="stock-warning-index panel panel-default panel-intro" v-cloak>
<el-container class="panel-block">
<el-header class="sa-header">
<el-tabs class="sa-tabs" v-model="state.filter.data.stock_type" @tab-change="onChangeTab">
<el-tab-pane v-for="(value, key) in type.data.stock_type" :key="key"
:label="`${value.name}${value.num ? '(' + value.num + ')' : ''}`" :name="key"></el-tab-pane>
</el-tabs>
<div class="sa-title sa-flex sa-row-between">
<div class="sa-title-left">
<div class="left-name">库存预警</div>
<sa-filter-condition v-model="state.filter" @filter-delete="onChangeFilter">
</sa-filter-condition>
</div>
<div class="sa-title-right">
<el-button class="sa-button-refresh" icon="RefreshRight" @click="getData"></el-button>
<el-button class="sa-button-refresh" icon="Search" @click="onOpenFilter"></el-button>
{if $auth->check('shopro/goods/stock_warning/recyclebin')}
<el-button type="danger" plain @click="onRecyclebin">历史记录</el-button>
{/if}
</div>
</div>
</el-header>
<el-main class="sa-main">
<el-table height="100%" class="sa-table" :data="state.data" stripe @sort-change="onChangeSort">
<el-table-column prop="id" label="ID" min-width="90" sortable="custom"> </el-table-column>
<el-table-column label="商品" min-width="440">
<template #default="scope">
<div v-if="scope.row.goods" class="sa-goods-item sa-flex sa-col-top">
<sa-image class="goods-image" :url="scope.row.goods.image" size="48"></sa-image>
<div>
<div class="goods-title sa-table-line-1">{{scope.row.goods.title}}</div>
<div v-if="scope.row.goods_sku_text" class="goods-sku-text">{{scope.row.goods_sku_text}}
</div>
</div>
</div>
<div v-else>{{scope.row.goods_id}}</div>
</template>
</el-table-column>
<el-table-column prop="stock" label="库存" min-width="100"></el-table-column>
<el-table-column prop="stock_warning" label="预警库存" min-width="100"></el-table-column>
<el-table-column label="更新时间" width="172">
<template #default="scope">{{ scope.row.createtime || '-' }}</template>
</el-table-column>
<el-table-column label="操作" min-width="100" fixed="right">
<template #default="scope">
{if $auth->check('shopro/goods/stock_warning/addStock')}
<el-button type="primary" link @click="onAddStock(scope.row)">补货</el-button>
{/if}
</template>
</el-table-column>
</el-table>
</el-main>
<el-footer class="sa-footer sa-flex sa-row-right">
<sa-pagination v-model="pagination" @pagination-change="getData"></sa-pagination>
</el-footer>
</el-container>
<sa-filter v-model="state.filter" @filter-change="onChangeFilter"></sa-filter>
</div>

View File

@@ -0,0 +1,20 @@
{include file="/shopro/common/script" /}
<div id="recyclebin" class="stock-warning-recyclebin" v-cloak>
<el-container class="panel-block">
<el-main>
<el-table height="100%" class="sa-table" :data="state.data" stripe @sort-change="onChangeSort">
<el-table-column prop="id" label="ID" width="90" sortable="custom"></el-table-column>
<el-table-column label="名称" min-width="120">
<template #default="scope">
<div class="sa-table-line-1">{{ scope.row.goods?.title || scope.row.goods_id }}</div>
</template>
</el-table-column>
<el-table-column prop="deletetime" label="补货时间" width="172" sortable="custom"></el-table-column>
</el-table>
</el-main>
<el-footer class="sa-footer sa-flex sa-row-right">
<sa-pagination class="is-ellipsis" v-model="pagination" @pagination-change="getData"></sa-pagination>
</el-footer>
</el-container>
</div>

View File

@@ -0,0 +1,154 @@
{include file="/shopro/common/script" /}
<style>
.template-id-popover .question-filled {
color: var(--el-color-warning);
margin-right: 8px;
}
.notification-config-form .field .el-form-item__content {
display: block;
border: 1px solid var(--sa-border);
max-width: 360px;
background: var(--sa-background-hex-hover);
border-radius: 4px;
padding: 6px 0 2px 12px;
color: var(--sa-place);
}
.notification-config-form .field-item {
margin-bottom: 18px;
}
.notification-config-form .field-item .field-name {
flex-shrink: 0;
width: 100px;
height: 32px;
padding-right: 12px;
}
.notification-config-form .field-item .el-input {
flex: 1;
}
.notification-config-form .field-item .el-input {
flex: 1;
}
.notification-config-form .field-item .field-delete {
margin-left: 8px;
}
.notification-config-form .field-tip {
color: #ff5959;
margin-bottom: 12px;
}
</style>
<div id="addEdit" class="notification-config-form" v-cloak>
<el-container class="panel-block">
<el-main>
<el-scrollbar height="100%">
<el-form :model="form.model" :rules="form.rules" ref="formRef" label-width="100px">
<el-form-item v-if="
state.channel == 'WechatOfficialAccount' ||
state.channel == 'WechatMiniProgram'
" label="模板类型">
<el-radio-group v-model="form.model.type">
<el-radio label="default">默认配置</el-radio>
<el-radio label="custom">自定义配置</el-radio>
</el-radio-group>
</el-form-item>
<template v-if="
(form.model.type == 'default' &&
state.channel == 'WechatOfficialAccount') ||
(form.model.type == 'default' && state.channel == 'WechatMiniProgram')
">
<el-form-item label="通知标题">
<el-input v-model="form.model.name" placeholder="注册完成给上级发送" disabled></el-input>
</el-form-item>
<el-form-item label="模板编号" v-if="state.channel != 'WechatMiniProgram'">
<el-input v-model="form.model.wechat.temp_no" placeholder="" disabled></el-input>
</el-form-item>
<el-form-item label="模板Id">
<el-input v-model="form.model.content.template_id" disabled>
<template #append>
<span v-if="!form.model.content.template_id" class="cursor-pointer"
@click="getTemplateId('0')">立即获取</span>
<el-popover v-if="form.model.content.template_id" popper-class="template-id-popover"
v-model:visible="templateIdPopover.flag" :width="250" trigger="click">
<div class="sa-flex mb-2">
<el-icon class="question-filled">
<question-filled />
</el-icon>
<div>确定要重新获取模板Id吗</div>
</div>
<div class="sa-flex">
<el-checkbox v-model="templateIdPopover.is_delete" label="删除旧模板"
class="mr-4" true-label="1" false-label="0"></el-checkbox>
<el-button size="small" @click="templateIdPopover.flag = false">取消
</el-button>
<el-button size="small" type="primary"
@click="getTemplateId(templateIdPopover.is_delete)">确定
</el-button>
</div>
<template #reference>
{if $auth->check('shopro/notification/config/getTemplateId')}
<span class="cursor-pointer">重新获取</span>
{/if}
</template>
</el-popover>
</template>
</el-input>
</el-form-item>
<el-form-item label="模板" class="field">
<div v-for="i in form.model.wechat.fields" :key="i" class="sa-flex">
<div v-if="i.name">{{ i.name }}</div>
<div>{{ `{{${i.template_field}.DATA` }}}}</div>
</div>
</el-form-item>
</template>
<template v-if="form.model.type == 'custom' || state.channel == 'Sms'">
<template v-if="form.model.content">
<el-form-item label="模板消息Id">
<el-input v-model="form.model.content.template_id" placeholder="请输入模版消息Id"></el-input>
</el-form-item>
<div class="field-item sa-flex" v-for="(item, index) in form.model.content.fields"
:key="item">
<div class="field-name sa-flex sa-row-right">
<span v-if="item.field">{{ item.name }}</span>
<el-input v-else v-model="item.name" placeholder="请输入名称"></el-input>
</div>
<el-input class="mr-4" v-model="item.template_field" placeholder="请输入模版名称">
</el-input>
<el-input v-model="item.value" placeholder="请输入默认值"></el-input>
<el-button v-if="!item.field" class="field-delete" type="danger" link
@click="onDeleteField(index)">
删除
</el-button>
</div>
<el-form-item>
<el-button icon="Plus" @click="onAddField">添加</el-button>
</el-form-item>
</template>
</template>
<template v-if="state.channel == 'Email'">
<div class="field-item sa-flex" v-for="item in fieldList.data.fields" :key="item">
<div class="field-name sa-flex sa-row-right">
<span v-if="item.field">{{ item.name }}</span>
</div>
<el-input v-model="item.field" placeholder="请输入模版名称" disabled></el-input>
</div>
<div class="field-tip"> 请按照如下格式在文档中插入要显示的字段 p:{字段名} </div>
<form role="form">
<textarea id="emailContent" class="editor"></textarea>
</form>
</template>
</el-form>
</el-scrollbar>
</el-main>
<el-footer class="sa-footer--submit sa-flex sa-row-right">
<el-button type="primary" @click="onConfirm">确定</el-button>
</el-footer>
</el-container>
</div>

View File

@@ -0,0 +1,286 @@
{include file="/shopro/common/script" /}
<style>
.notification-config-index .icon {
width: 16px;
height: 16px;
margin-right: 8px;
}
.notification-config-index .edit-button {
border-radius: 4px 0 0 4px;
color: var(--sa-background-assist);
}
.notification-config-index .num {
width: 140px;
height: 32px;
border-radius: 0 4px 4px 0;
margin-right: 8px;
}
.notification-config-index .num.WechatOfficialAccount {
background: rgba(7, 193, 96, .1);
color: #07c160;
}
.notification-config-index .num.WechatMiniProgram {
background: rgba(111, 116, 233, .1);
color: #6f74e9;
}
.notification-config-index .num.Sms {
background: rgba(128, 106, 246, .1);
color: #806af6;
}
.notification-config-index .num.Email {
background: rgba(64, 158, 255, .1);
color: #409eff;
}
.notification-config-index .tip {
margin-left: 8px;
}
.notification-config-index .tip.is-active {
color: var(--el-color-primary);
}
.qrcode-popover{
width: fit-content !important;
min-width: unset !important;
font-weight: 400;
font-size: 12px;
line-height: 16px;
color: #595959;
}
.qrcode-mask{
position: absolute;
top: 12px;
right: 12px;
width: 80px;
height: 80px;
background: rgba(253, 253, 253, 0.8);
backdrop-filter: blur(2px);
}
.qrcode-popover #qrcode {
width: 80px;
height: 80px;
margin-bottom: 4px;
}
.qrcode-popover #qrcode img {
width: 100%;
height: 100%;
}
</style>
<div id="index" class="notification-config-index panel panel-default panel-intro" v-cloak>
<el-container class="panel-block">
<el-header class="sa-header">
<el-tabs class="sa-tabs" v-model="state.receiver_type" @tab-change="getData">
<el-tab-pane label="通知用户" name="user"></el-tab-pane>
<el-tab-pane label="通知管理员" name="admin"></el-tab-pane>
</el-tabs>
<div class="sa-title sa-flex sa-row-between">
<div class="sa-title-left">
<div class="left-name">消息配置</div>
</div>
<div class="sa-title-right">
<el-button class="sa-button-refresh" icon="RefreshRight" @click="getData"></el-button>
</div>
</div>
<el-alert class="mb-4" type="warning">
<template #title>
<div>
1、消息通知仅用于向用户发送重要的服务通知只能用于符合其要求的服务场景如拼团成功通知、商品发货通知等。不支持广告等营销类消息以及其它所有可能对用户造成骚扰的消息
</div>
<div>
2、小程序和公众号需要选择 生活服务/百货/超市/便利店 类目;
</div>
<div>3、公众号和小程序必须选择上面对应的类目才可以自动获取模板。</div>
<div>4、目前公众号类目模板库有待完善部分模板无法自动获取请自行在公众号后台->模板消息->挑选模板,并在商城后台->消息通知->对应消息的自定义配置处配置</div>
</template>
</el-alert>
</el-header>
<el-main class="sa-main">
<el-table height="100%" class="sa-table" :data="state.data" row-key="id" stripe>
<el-table-column label="消息类别" min-width="160" align="center">
<template #default="scope">
<span class="sa-table-line-1">
{{ scope.row.name || '-' }}
</span>
</template>
</el-table-column>
<el-table-column min-width="344">
<template #header>
<div class="sa-flex sa-row-center">
<img class="icon" src="/assets/addons/shopro/img/notification/officialAccount.png" />
<div>公众号模版通知</div>
<el-popover ref="qrcodePopoverRef" popper-class="qrcode-popover" placement="bottom-start" trigger="click" :show-after="200" @hide="onHideQrcode">
<image v-if="state.qrcodeUrl" id="qrcode" :src="state.qrcodeUrl"></image>
<div v-if="state.scanStatus === 'expired'" class="qrcode-mask"></div>
<div v-if="state.scanStatus === 'pending'" class="sa-flex sa-row-center">等待扫码</div>
<div v-if="state.scanStatus === 'scanned'" class="sa-flex sa-row-center">已扫码</div>
<div v-if="state.scanStatus === 'expired'" class="sa-flex sa-row-center">已过期</div>
<div v-if="state.scanStatus === 'binded'" class="sa-flex">
<span>{{state.oauthInfo.openid}}</span>
<el-button class="ml-1" type="danger" link @click="onUnbind">解除绑定</el-button>
</div>
<template #reference>
<el-button v-if="state.receiver_type=='admin'" class="ml-1" type="primary" link @click="onQrcode">绑定微信</el-button>
</template>
</el-popover>
</div>
</template>
<template #default="scope">
<div class="sa-flex sa-row-center">
{if $auth->check('shopro/notification/config/edit')}
<div v-if="scope.row.channels">
<el-button class="edit-button" type="primary" color="#07C160"
:disabled="!scope.row.channels.includes('WechatOfficialAccount')"
@click="onEdit(scope.row.event, 'WechatOfficialAccount')">编辑配置</el-button>
</div>
{/if}
<div v-if="scope.row.configs" class="sa-flex">
<div class="num WechatOfficialAccount sa-flex sa-row-center">
已发送{{ scope.row.configs.WechatOfficialAccount?.send_num || 0 }}次
</div>
{if $auth->check('shopro/notification/config/setStatus')}
<el-button link>
<el-switch v-if="scope.row.channels.includes('WechatOfficialAccount')"
v-model="scope.row.configs.WechatOfficialAccount.status" active-value="enable"
inactive-value="disabled"
@change="onSetStatus($event,scope.row.event, 'WechatOfficialAccount')">
</el-switch>
<el-switch v-else model-value="false" disabled></el-switch>
<span class="tip"
:class="scope.row.configs.WechatOfficialAccount?.status == 'enable' && 'is-active'">
{{scope.row.configs.WechatOfficialAccount?.status == 'enable'? '开启': '关闭'}}
</span>
</el-button>
{/if}
</div>
</div>
</template>
</el-table-column>
<el-table-column min-width="344">
<template #header>
<div class="sa-flex sa-row-center">
<img class="icon" src="/assets/addons/shopro/img/notification/miniProgram.png" />
<div>微信小程序通知</div>
</div>
</template>
<template #default="scope">
<div class="sa-flex sa-row-center">
{if $auth->check('shopro/notification/config/edit')}
<div v-if="scope.row.channels">
<el-button class="edit-btn" type="primary" color="#6F74E9"
:disabled="!scope.row.channels.includes('WechatMiniProgram')"
@click="onEdit(scope.row.event, 'WechatMiniProgram')">编辑配置</el-button>
</div>
{/if}
<div v-if="scope.row.configs" class="sa-flex">
<div class="num WechatMiniProgram sa-flex sa-row-center">
已发送{{ scope.row.configs.WechatMiniProgram?.send_num || 0 }}次
</div>
{if $auth->check('shopro/notification/config/setStatus')}
<el-button link>
<el-switch v-if="scope.row.channels.includes('WechatMiniProgram')"
v-model="scope.row.configs.WechatMiniProgram.status" active-value="enable"
inactive-value="disabled"
@change="onSetStatus($event,scope.row.event, 'WechatMiniProgram')">
</el-switch>
<el-switch v-else model-value="false" disabled></el-switch>
<span class="tip"
:class="scope.row.configs.WechatMiniProgram?.status == 'enable' && 'is-active'">
{{scope.row.configs.WechatMiniProgram?.status == 'enable' ? '开启' : '关闭'}}
</span>
</el-button>
{/if}
</div>
</div>
</template>
</el-table-column>
<el-table-column min-width="344">
<template #header>
<div class="sa-flex sa-row-center">
<img class="icon" src="/assets/addons/shopro/img/notification/sms.png" />
<div>短信通知</div>
</div>
</template>
<template #default="scope">
<div class="sa-flex sa-row-center">
{if $auth->check('shopro/notification/config/edit')}
<div v-if="scope.row.channels">
<el-button class="edit-button" type="primary" color="#806AF6"
:disabled="!scope.row.channels.includes('Sms')"
@click="onEdit(scope.row.event, 'Sms')">编辑配置</el-button>
</div>
{/if}
<div v-if="scope.row.configs" class="sa-flex">
<div class="num Sms sa-flex sa-row-center">
已发送{{ scope.row.configs.Sms?.send_num || 0 }}次
</div>
{if $auth->check('shopro/notification/config/setStatus')}
<el-button link>
<el-switch v-if="scope.row.channels.includes('Sms')"
v-model="scope.row.configs.Sms.status" active-value="enable"
inactive-value="disabled" @change="onSetStatus($event,scope.row.event, 'Sms')">
</el-switch>
<el-switch v-else model-value="false" disabled></el-switch>
<span class="tip" :class="scope.row.configs.Sms?.status == 'enable' && 'is-active'">
{{ scope.row.configs.Sms?.status == 'enable' ? '开启' : '关闭' }}
</span>
</el-button>
{/if}
</div>
</div>
</template>
</el-table-column>
<el-table-column min-width="344">
<template #header>
<div class="sa-flex sa-row-center">
<img class="icon" src="/assets/addons/shopro/img/notification/email.png" />
<div>邮件通知</div>
</div>
</template>
<template #default="scope">
<div class="sa-flex sa-row-center">
{if $auth->check('shopro/notification/config/edit')}
<div v-if="scope.row.channels">
<el-button class="edit-button" type="primary" color="#409EFF"
:disabled="!scope.row.channels.includes('Email')"
@click="onEdit(scope.row.event, 'Email')">编辑配置</el-button>
</div>
{/if}
<div v-if="scope.row.configs" class="sa-flex">
<div class="num Email sa-flex sa-row-center">
已发送{{ scope.row.configs.Email?.send_num || 0 }}次
</div>
{if $auth->check('shopro/notification/config/setStatus')}
<el-button link>
<el-switch v-if="scope.row.channels.includes('Email')"
v-model="scope.row.configs.Email.status" active-value="enable"
inactive-value="disabled"
@change="onSetStatus($event,scope.row.event, 'Email')">
</el-switch>
<el-switch v-else model-value="false" disabled></el-switch>
<span class="tip"
:class="scope.row.configs.Email?.status == 'enable' && 'is-active'">
{{scope.row.configs.Email?.status == 'enable' ? '开启' : '关闭' }}
</span>
</el-button>
{/if}
</div>
</div>
</template>
</el-table-column>
</el-table>
</el-main>
</el-container>
</div>

View File

@@ -0,0 +1,22 @@
{include file="/shopro/common/script" /}
<div id="addLog" class="aftersale-add-log" v-cloak>
<el-container class="panel-block">
<el-main>
<el-scrollbar height="100%">
<el-form :model="form.model" :rules="form.rules" ref="formRef" label-width="100px">
<el-form-item label="回复内容" prop="content">
<el-input type="textarea" v-model="form.model.content" placeholder="请输入"></el-input>
</el-form-item>
<el-form-item label="选择图片">
<sa-uploader v-model="form.model.images" :multiple="true" max="9">
</sa-uploader>
</el-form-item>
</el-form>
</el-scrollbar>
</el-main>
<el-footer class="sa-footer--submit sa-flex sa-row-right">
<el-button type="primary" @click="onConfirm">确定</el-button>
</el-footer>
</el-container>
</div>

View File

@@ -0,0 +1,417 @@
{include file="/shopro/common/script" /}
<style>
.aftersale-detail .el-scrollbar__wrap {
overflow-x: hidden;
}
.aftersale-detail .el-scrollbar__bar.is-horizontal {
display: none;
}
.aftersale-detail .tip {
margin-bottom: 16px;
}
.aftersale-detail .status-text {
line-height: 24px;
font-size: 18px;
font-weight: 600;
color: var(--sa-title);
margin-bottom: 4px;
}
.aftersale-detail .status-desc {
line-height: 16px;
font-size: 12px;
color: var(--sa-subfont);
margin-bottom: 16px;
}
.aftersale-detail .el-step__head .el-step__line {
top: 15px;
}
.aftersale-detail .el-step__head .el-step__icon {
width: 32px;
height: 32px;
color: var(--sa-background-assist);
background: var(--sa-place);
border: 2px solid var(--sa-table-header-bg);
}
.aftersale-detail .el-step__head.is-finish .el-step__icon {
color: var(--sa-background-assist);
background: var(--el-color-primary);
}
.aftersale-detail .el-step__title {
color: var(--sa-subfont);
font-size: 14px;
font-weight: 400;
}
.aftersale-detail .el-step__title.is-finish {
color: var(--sa-subtitle);
}
.aftersale-detail .el-step__description {
padding: 0;
color: var(--sa-subfont);
}
.aftersale-detail .el-step__description.is-finish .step-status {
color: var(--el-color-primary);
}
.aftersale-detail .step-status {
color: var(--sa-font);
font-size: 14px;
}
.aftersale-detail .status-steps-mobile {
margin-top: 32px;
display: none;
@media only screen and (max-width: 768px) {
display: flex;
}
}
.aftersale-detail .status-steps-mobile .el-step__head {
width: fit-content;
}
.aftersale-detail .status-steps-mobile .el-step__head .el-step__line {
left: 15px;
}
.aftersale-detail .status-steps-pc {
display: flex;
margin-top: 32px;
@media only screen and (max-width: 768px) {
display: none;
}
}
.aftersale-detail .status-steps-pc .step-status {
position: absolute;
top: -12px;
right: -30px;
width: 60px;
}
.aftersale-content {
padding: var(--sa-padding) var(--sa-padding) 0;
background: var(--sa-background-hex-hover);
border-radius: 8px;
margin-bottom: 16px;
}
.aftersale-detail .el-col {
margin-bottom: var(--sa-padding);
}
.aftersale-detail .title {
line-height: 20px;
font-size: 16px;
font-weight: 600;
color: var(--sa-title);
margin-bottom: 16px;
}
.aftersale-detail .subtitle {
line-height: 18px;
font-size: 14px;
font-weight: 500;
color: var(--sa-title);
margin-bottom: 12px;
}
.aftersale-detail .item {
display: flex;
align-items: center;
margin-bottom: 8px;
}
.aftersale-detail .left {
line-height: 16px;
font-size: 12px;
color: var(--sa-subfont);
}
.aftersale-detail .right {
line-height: 16px;
font-size: 12px;
color: var(--sa-subtitle);
display: flex;
align-items: center;
}
.aftersale-detail .goods-item .goods-title {
height: 14px;
line-height: 14px;
font-size: 12px;
font-weight: 500;
margin-bottom: 6px;
}
.aftersale-detail .goods-item .goods-price {
flex-shrink: 0;
line-height: 14px;
font-size: 12px;
color: var(--sa-font);
margin-bottom: 12px;
}
.aftersale-detail .goods-item .goods-sku-text {
width: fit-content;
height: 18px;
line-height: 18px;
padding: 0 8px;
font-size: 12px;
color: var(--sa-subfont);
background: var(--sa-space);
border-radius: 10px;
}
.aftersale-detail .log-item {
line-height: 16px;
font-size: 12px;
color: var(--sa-subfont);
}
.aftersale-detail .log-oper {
margin-right: 12px;
}
.aftersale-detail .name {
font-weight: 500;
margin-bottom: 4px;
}
.aftersale-detail .create-time {
font-weight: 400;
margin-bottom: 8px;
}
.aftersale-detail .log-content {
margin-bottom: 8px;
}
.aftersale-detail .log-image {
margin-right: 4px;
}
.aftersale-detail .log-imageZ:last-of-type {
margin-right: 0;
}
.aftersale-detail .log-type-text,
.aftersale-detail .log-content {
font-weight: 500;
color: var(--sa-subtitle);
margin-bottom: 8px;
}
</style>
<div id="detail" class="aftersale-detail" v-cloak>
<el-container class="panel-block">
<el-main>
<el-scrollbar height="100%">
<div class="tip">
<div>温馨提示</div>
<div>1、如果同意申请请发送正确的退货地址给买家</div>
<div>2、如果拒绝申请请发送给买家拒绝理由</div>
</div>
<el-row class="aftersale-content sa-m-b-16" :gutter="10">
<el-col :xs="24" :sm="8" :md="8" :lg="8" :xl="8">
<div class="status-text sa-m-b-4">
{{ state.data.aftersale_status_text }}
</div>
<div class="status-desc sa-m-b-16">
{{ state.data.aftersale_status_desc }}
</div>
<div class="tools">
<template v-if="state.data.aftersale_status == 0 || state.data.aftersale_status == 1">
{if $auth->check('shopro/order/aftersale/refund')}
<el-button type="primary" link @click="onRefund">售后退款</el-button>
{/if}
{if $auth->check('shopro/order/aftersale/refuse')}
<el-button @click="onRefuse">拒绝售后</el-button>
{/if}
{if $auth->check('shopro/order/aftersale/completed')}
<el-button type="primary" link @click="onCompleted">售后完成</el-button>
{/if}
</template>
</div>
</el-col>
<el-col :xs="24" :sm="16" :md="16" :lg="16" :xl="16">
<el-steps class="status-steps-mobile" direction="vertical" :active="state.stepActive"
:align-center="true" :space="80">
<el-step title="买家申请售后" :description="state.data.create_time"></el-step>
<el-step title="售后申请处理中" :description="
state.stepActive >= 2
? state.data.logs.length > 0
? state.data.logs[0].updatetime
: ''
: ''
"></el-step>
<el-step title="处理完成" :description="state.stepActive == 3 ? state.data.updatetime : ''">
</el-step>
</el-steps>
<el-steps class="status-steps-pc" direction="horizontal" :active="state.stepActive"
:align-center="true">
<el-step title="买家申请售后" :description="state.data.create_time"></el-step>
<el-step title="售后申请处理中" :description="
state.stepActive >= 2
? state.data.logs.length > 0
? state.data.logs[0].updatetime
: ''
: ''
"></el-step>
<el-step title="处理完成" :description="state.stepActive == 3 ? state.data.updatetime : ''">
</el-step>
</el-steps>
</el-col>
</el-row>
<div class="refund-content aftersale-content sa-m-b-26">
<div class="title sa-m-b-16">售后详情</div>
<el-row :gutter="10">
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
<div class="subtitle">交易信息</div>
<div class="item">
<div class="left">用户信息:</div>
<div class="right">
<sa-user-profile :user="state.data.user" :id="state.data.user_id" :isavatar="false">
</sa-user-profile>
</div>
</div>
<div class="item">
<div class="left">订单编号:</div>
<div class="right">
<template v-if="state.data.order">
{{ state.data.order.order_sn }}
<el-icon class="copy-document" @click="onClipboard(state.data.order.order_sn)">
<copy-document />
</el-icon>
</template>
<template v-else>{{ state.data.order_id }}</template>
</div>
</div>
<div class="item">
<div class="left">物流状态:</div>
<div class="right">{{ state.data.dispatch_status_text }}</div>
</div>
<div class="item">
<div class="left">订单实付:</div>
<div class="right">¥{{ state.data?.order?.pay_fee }}</div>
</div>
<div class="item">
<div class="left">订单运费:</div>
<div class="right"> ¥{{ state.data?.order?.dispatch_amount }} </div>
</div>
<div class="item">
<div class="left">订单优惠:</div>
<div class="right"> ¥{{ state.data?.order?.total_discount_fee }} </div>
</div>
<div class="item">
<div class="left">商品运费:</div>
<div class="right">¥{{ state.data.dispatch_fee }}</div>
</div>
<div class="item">
<div class="left">商品优惠:</div>
<div class="right">¥{{ state.data.discount_fee }}</div>
</div>
<div class="item">
<div class="left">建议退款:</div>
<div class="right">¥{{ state.data.suggest_refund_fee }}</div>
</div>
</el-col>
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
<div class="subtitle">售后信息</div>
<div class="item">
<div class="left">售后单号:</div>
<div class="right">
{{ state.data.aftersale_sn }}
<el-icon class="copy-document" @click="onClipboard(state.data.aftersale_sn)">
<copy-document />
</el-icon>
</div>
</div>
<div class="item">
<div class="left">申请时间:</div>
<div class="right">{{ state.data.createtime }}</div>
</div>
<div class="item">
<div class="left">联系电话:</div>
<div class="right">{{ state.data.mobile || '-' }}</div>
</div>
<div class="item">
<div class="left">售后类型:</div>
<div class="right">
<span class="sa-color--danger">{{ state.data.type_text }}</span>
</div>
</div>
<div class="item">
<div class="left">实际退款:</div>
<div class="right">
<span class="sa-color--danger">¥{{ state.data.refund_fee }}</span>
</div>
</div>
<div class="item">
<div class="left">申请原因:</div>
<div class="right"> {{ state.data.reason }} </div>
</div>
<div class="item">
<div class="left">相关描述:</div>
<div class="right" v-html="state.data.content"></div>
</div>
</el-col>
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
<div class="subtitle">商品信息</div>
<div class="goods-item sa-flex sa-col-top">
<sa-image class="mr-2" :url="state.data.goods_image" size="64"></sa-image>
<div>
<div class="goods-title sa-table-line-1">
{{state.data.goods_title}}</div>
<div class="goods-price">
¥{{state.data.goods_price}} <span class="ml-1">x{{state.data.goods_num}}</span>
</div>
<div v-if="state.data.goods_sku_text" class="goods-sku-text">
{{state.data.goods_sku_text}}
</div>
</div>
</div>
</el-col>
</el-row>
</div>
<div class="log-content aftersale-content">
<div class="title sa-flex sa-row-between">
<div class="left">协商记录</div>
{if $auth->check('shopro/order/aftersale/addLog')}
<el-button type="primary" link @click="onAddLog">回复买家</el-button>
{/if}
</div>
<div class="log-item sa-flex sa-col-top" v-for="(log, index) in state.data.logs" :key="log">
<sa-image v-if="log.oper" class="log-oper" :url="log.oper.avatar" size="48" radius="24">
</sa-image>
<div>
<div v-if="log.oper" class="name">{{ log.oper.name }}</div>
<div class="create-time">{{ log.createtime }}</div>
<div class="log-type-text">{{ log.log_type_text }}</div>
<div v-if="index < state.data.logs.length - 1" class="log-content" v-html="log.content">
</div>
<div class="sa-flex mb-2">
<template v-for="item in log.images" :key="img">
<sa-image class="log-image" :url="item" size="48"></sa-image>
</template>
</div>
</div>
</div>
</div>
</el-scrollbar>
</el-main>
</el-container>
</div>

View File

@@ -0,0 +1,200 @@
{include file="/shopro/common/script" /}
<style>
.aftersale-index .sa-table {
font-size: 12px;
}
.aftersale-index .sa-table-wrap {
height: 100%;
margin-left: -48px;
overflow: hidden;
}
.aftersale-index .sa-table-wrap .sa-table .el-table__header-wrapper {
margin-bottom: 4px;
}
.aftersale-index .sa-table-wrap .sa-table .el-table__row {
background: var(--sa-background-hex-hover);
}
.aftersale-index .sa-table-wrap .sa-table .el-table__expanded-cell {
padding: 0;
}
.aftersale-index .sa-table-wrap .sa-expand-table .el-table__header-wrapper {
margin-bottom: 0;
display: none;
}
.aftersale-index .sa-table-wrap .sa-expand-table .el-table__row {
background: var(--el-table-tr-bg-color);
}
.aftersale-index .sa-expand-table tr:hover>td.el-table__cell {
background-color: var(--el-table-tr-bg-color) !important;
}
.aftersale-index .order-detail {
margin-left: 4px;
}
.aftersale-index .goods-item {
line-height: 1;
}
.aftersale-index .goods-item .goods-image {
margin-right: 12px;
}
.aftersale-index .goods-item .goods-title {
height: 14px;
line-height: 14px;
font-size: 12px;
font-weight: 600;
color: var(--el-color-primary);
cursor: pointer;
margin-bottom: 6px;
}
.aftersale-index .goods-item .goods-price {
flex-shrink: 0;
line-height: 14px;
font-size: 12px;
color: var(--sa-font);
margin-bottom: 12px;
}
.aftersale-index .goods-item .goods-num {
margin-left: 8px;
}
.aftersale-index .goods-item .goods-sku-text {
width: fit-content;
height: 18px;
line-height: 18px;
padding: 0 8px;
font-size: 12px;
color: var(--sa-subfont);
background: var(--sa-space);
border-radius: 10px;
}
.aftersale-index .status--1 {
color: var(--el-color-danger);
}
</style>
<div id="index" class="aftersale-index panel panel-default panel-intro" v-cloak>
<el-container class="panel-block">
<el-header class="sa-header">
<el-tabs class="sa-tabs" v-model="state.filter.data['aftersale_list.aftersale_status']"
@tab-change="onChangeTab">
<el-tab-pane v-for="item in type.data.aftersale_status" :key="item"
:label="`${item.name}${item.num ? '(' + item.num + ')' : ''}`" :name="item.type"></el-tab-pane>
</el-tabs>
<div class="sa-title sa-flex sa-row-between">
<div class="sa-title-left">
<div class="left-name">售后管理</div>
<sa-filter-condition v-model="state.filter" @filter-delete="onChangeFilter">
</sa-filter-condition>
</div>
<div class="sa-title-right">
<el-button class="sa-button-refresh" icon="RefreshRight" @click="getData"></el-button>
<el-button class="sa-button-refresh" icon="Search" @click="onOpenFilter"></el-button>
</div>
</div>
</el-header>
<el-main class="sa-main">
<div class="sa-table-wrap">
<el-table height="100%" class="sa-table" :data="state.data" stripe default-expand-all>
<el-table-column type="expand">
<template #default="props">
<el-table class="sa-table sa-expand-table" :data="props.row.aftersales" stripe>
<el-table-column width="48"></el-table-column>
<el-table-column min-width="280">
<template #default="scope">
<div class="aftersale-sn">
售后单号:{{ scope.row.aftersale_sn }}
<el-icon class="copy-document" @click="onClipboard(scope.row.aftersale_sn)">
<copy-document />
</el-icon>
</div>
<div class="create-time"> 申请时间:{{ scope.row.createtime }} </div>
</template>
</el-table-column>
<el-table-column min-width="300">
<template #default="scope">
<div class="goods-item sa-flex sa-col-top">
<sa-image class="mr-2" :url="scope.row.goods_image" size="64"></sa-image>
<div>
<div class="goods-title sa-table-line-1"
@click="onOpenGoods(scope.row.goods_id)">
{{scope.row.goods_title}}</div>
<div class="goods-price">
¥{{scope.row.goods_price}} <span
class="goods-num">x{{scope.row.goods_num}}</span>
</div>
<div v-if="scope.row.goods_sku_text" class="goods-sku-text">
{{scope.row.goods_sku_text}}
</div>
</div>
</div>
</template>
</el-table-column>
<el-table-column min-width="130">
<template #default>{{ props.row.pay_fee }}</template>
</el-table-column>
<el-table-column prop="refund_fee" min-width="100"></el-table-column>
<el-table-column min-width="80">
<template #default="scope">
<div :class="scope.row.aftersale_status == '-1' ? 'status--1' : ''">
{{ scope.row.aftersale_status_text }}
</div>
</template>
</el-table-column>
<el-table-column prop="type_text" min-width="80"></el-table-column>
<el-table-column min-width="80">
<template #default="scope">
{if $auth->check('shopro/order/aftersale/detail')}
<el-button type="primary" link @click="onDetail(scope.row.id)">详情</el-button>
{/if}
</template>
</el-table-column>
</el-table>
</template>
</el-table-column>
<el-table-column label="售后信息" min-width="280">
<template #default="scope">
<div class="order-sn sa-flex">
订单号:{{ scope.row.order_sn }}
<el-button class="order-detail" type="primary" link size="small"
@click="onOpenOrderDetail(scope.row.id)">详情</el-button>
</div>
</template>
</el-table-column>
<el-table-column label="商品信息" min-width="300">
<template #default="scope">
<div class="create-time"> 下单时间:{{ scope.row.createtime }} </div>
</template>
</el-table-column>
<el-table-column label="订单实付金额" min-width="130">
<template #default="scope">
<sa-user-profile :user="scope.row.user" :id="scope.row.user_id" :isavatar="false">
</sa-user-profile>
</template>
</el-table-column>
<el-table-column label="已退款金额" min-width="100"></el-table-column>
<el-table-column label="处理状态" min-width="80"></el-table-column>
<el-table-column label="售后类型" min-width="80"></el-table-column>
<el-table-column label="操作" min-width="80"></el-table-column>
</el-table>
</div>
</el-main>
<el-footer class="sa-footer sa-flex sa-row-right">
<sa-pagination v-model="pagination" @pagination-change="getData"></sa-pagination>
</el-footer>
</el-container>
<sa-filter v-model="state.filter" @filter-change="onChangeFilter"></sa-filter>
</div>

View File

@@ -0,0 +1,28 @@
{include file="/shopro/common/script" /}
<div id="refund" class="aftersale-refund" v-cloak>
<el-container class="panel-block">
<el-main>
<el-scrollbar height="100%">
<el-form :model="form.model" :rules="form.rules" ref="formRef" label-width="100px">
<el-form-item label="退款方式">
<div>
<el-radio-group v-model="form.model.refund_type">
<el-radio label="back">原路退回</el-radio>
<el-radio label="money">退回余额</el-radio>
</el-radio-group>
</div>
</el-form-item>
<el-form-item label="退款金额" prop="refund_money">
<el-input v-model="form.model.refund_money"
:placeholder="`建议退款金额${state.suggest_refund_fee}元`" />
<div class="tip"> 退款时请与买家协商好,退款之后不可撤回 </div>
</el-form-item>
</el-form>
</el-scrollbar>
</el-main>
<el-footer class="sa-footer--submit sa-flex sa-row-right">
<el-button type="primary" @click="onConfirm">确定</el-button>
</el-footer>
</el-container>
</div>

View File

@@ -0,0 +1,18 @@
{include file="/shopro/common/script" /}
<div id="refuse" class="aftersale-refuse" v-cloak>
<el-container class="panel-block">
<el-main>
<el-scrollbar height="100%">
<el-form :model="form.model" :rules="form.rules" ref="formRef" label-width="100px">
<el-form-item label="拒绝原因" prop="refuse_msg">
<el-input v-model="form.model.refuse_msg" placeholder="请输入拒绝原因" />
</el-form-item>
</el-form>
</el-scrollbar>
</el-main>
<el-footer class="sa-footer--submit sa-flex sa-row-right">
<el-button type="primary" @click="onConfirm">确定</el-button>
</el-footer>
</el-container>
</div>

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