mirror of
https://github.com/crmeb/CRMEB.git
synced 2026-10-28 21:40:50 +00:00
Merge branch 'v8.0' of https://gitee.com/ZhongBangKeJi/CRMEB into v8.0
This commit is contained in:
commit
639b4d1800
@ -527,6 +527,12 @@ function del(row, tit, num) {
|
||||
|
||||
### 13.2 巡检整改记录(2026-09-09)
|
||||
|
||||
**已修复**(2026-09-23,全站页面标题头补充描述):
|
||||
|
||||
- 全站带标题头页面统一补充 `description` 说明文字:`<pages-header>` 用法直接加 `description` 属性(44 处,含存量模型管理、小程序一键上传共 46 处),直写 `.i-layout-page-header.header-title` 的 16 处改为「`.header-main` 包裹标题 + `.header-description`(前置 `<el-icon>` + `InfoFilled`)」结构,与组件渲染结果一致。仅 setApp 占位页(空壳)与 SchemaPage DetailTemplate(标题由后端 config 下发)未加。
|
||||
- `.header-main` / `.header-description` / `.header-description-icon` 三类样式真源由 `pagesHeader/index.vue` scoped 迁移至 `styles/style.scss` 全局(组件内定义已删),直写页面直接复用全局类与全局注册的 `InfoFilled` 图标,页面无需自带样式。
|
||||
- 注意 `header-title` 是 flex space-between,直写时描述必须与标题同包在 `.header-main` 内,否则会被推到容器最右侧。
|
||||
|
||||
**已修复**(2026-09-23,表单数字输入框宽度与对齐):
|
||||
|
||||
- 「添加优惠券」数字框(面值/天数/领取数量等)挂了为文本框设计的 `content_width`(414px),且 EP 数字默认居中显示。同类问题全站共 6 文件 17 处(优惠券 ×5、拼团 ×7、砍价 ×3、秒杀 ×1、渠道码 ×1)。
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
direction="rtl"
|
||||
size="720"
|
||||
:wrapper-closable="false"
|
||||
custom-class="schema-drawer"
|
||||
class="schema-drawer"
|
||||
@closed="emit('closed')"
|
||||
>
|
||||
<div class="schema-drawer__content">
|
||||
|
||||
@ -822,9 +822,6 @@ defineExpose({ modals, handleCheckChange });
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
:deep(.el-dialog__body) {
|
||||
}
|
||||
|
||||
:deep(.el-tree-node__content) {
|
||||
height: 30px;
|
||||
}
|
||||
|
||||
@ -51,24 +51,7 @@ function goBack() {
|
||||
.header-title {
|
||||
justify-content: space-between;
|
||||
}
|
||||
/* 标题行:返回钮 + 标题 + 描述,基线对齐(描述字号小于标题,用 baseline 不用 flex-end) */
|
||||
.header-main {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
min-width: 0;
|
||||
gap: 16px;
|
||||
}
|
||||
.header-description {
|
||||
color: var(--prev-color-text-secondary);
|
||||
font-size: 12px;
|
||||
line-height: 18px;
|
||||
}
|
||||
.header-description-icon {
|
||||
font-size: 14px;
|
||||
color: var(--prev-color-primary);
|
||||
vertical-align: -2px;
|
||||
margin-right: 2px;
|
||||
}
|
||||
/* .header-main / .header-description / .header-description-icon 全局定义见 styles/style.scss */
|
||||
.after-line {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
|
||||
@ -15,7 +15,7 @@
|
||||
|
||||
<!-- <rightBtn :activeIndex="activeIndex" :configObj="configObj"></rightBtn> -->
|
||||
<el-dialog
|
||||
custom-class="custom-design-dialog"
|
||||
class="custom-design-dialog"
|
||||
v-model="modals"
|
||||
width="100%"
|
||||
fullscreen
|
||||
|
||||
@ -1,7 +1,13 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="i-layout-page-header header-title">
|
||||
<span class="ivu-page-header-title mr20">{{ $route.meta.title }}</span>
|
||||
<div class="header-main">
|
||||
<span class="ivu-page-header-title mr20">{{ $route.meta.title }}</span>
|
||||
<span class="header-description">
|
||||
<el-icon class="header-description-icon"><InfoFilled /></el-icon>
|
||||
装修页面与模板列表,支持新增页面、导入模板、编辑设计与设为默认。
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
<div style="float: right" v-if="cardShow == 1 || cardShow == 2">
|
||||
<el-button class="bnt" type="primary" v-db-click @click="submit" :loading="loadingExist">保存</el-button>
|
||||
|
||||
@ -1,6 +1,11 @@
|
||||
<template>
|
||||
<div>
|
||||
<pages-header ref="pageHeader" title="页面设计" :backUrl="routePre + '/setting/pages/devise/0'"></pages-header>
|
||||
<pages-header
|
||||
ref="pageHeader"
|
||||
title="页面设计"
|
||||
:backUrl="routePre + '/setting/pages/devise/0'"
|
||||
description="配置页面组件与属性,实时预览移动端效果,保存后同步到前台。"
|
||||
></pages-header>
|
||||
<el-card :bordered="false" shadow="never" class="ivu-mt mt15">
|
||||
<div class="flex-wrapper">
|
||||
<!-- :src="iframeUrl" -->
|
||||
|
||||
@ -1,7 +1,13 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="i-layout-page-header header-title">
|
||||
<span class="ivu-page-header-title mr20">{{ $route.meta.title }}</span>
|
||||
<div class="header-main">
|
||||
<span class="ivu-page-header-title mr20">{{ $route.meta.title }}</span>
|
||||
<span class="header-description">
|
||||
<el-icon class="header-description-icon"><InfoFilled /></el-icon>
|
||||
切换移动端商城主题色系,保存后前台立即生效。
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
<div style="float: right">
|
||||
<el-button class="bnt" type="primary" v-db-click @click="submit">保存</el-button>
|
||||
|
||||
@ -7,7 +7,6 @@
|
||||
:show-close="false"
|
||||
append-to-body
|
||||
:modal="true"
|
||||
:modal-append-to-body="true"
|
||||
:lock-scroll="true"
|
||||
@close="handleClose"
|
||||
>
|
||||
|
||||
@ -68,11 +68,10 @@
|
||||
v-model="styleDialogVisible"
|
||||
width="1188px"
|
||||
top="9vh"
|
||||
custom-class="theme-dialog"
|
||||
class="theme-dialog"
|
||||
:show-close="false"
|
||||
append-to-body
|
||||
:modal="true"
|
||||
:modal-append-to-body="true"
|
||||
:lock-scroll="true"
|
||||
@close="handleClose"
|
||||
>
|
||||
@ -576,34 +575,13 @@ function saveAndClose() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 弹窗样式
|
||||
:deep(.theme-dialog) {
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
margin-top: 50px !important;
|
||||
margin-bottom: 50px !important;
|
||||
width: calc(100vw - 140px) !important;
|
||||
height: calc(100vh - 100px) !important;
|
||||
margin-left: 70px !important;
|
||||
margin-right: 70px !important;
|
||||
|
||||
.el-dialog__header {
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
padding: 0px 20px !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
:deep(.el-dialog__body) {
|
||||
max-height: max-content;
|
||||
padding: 0px !important;
|
||||
overflow-y: auto;
|
||||
}
|
||||
.dialog-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
padding: 15px 24px;
|
||||
.dialog-header-tabs {
|
||||
background: #fff;
|
||||
|
||||
@ -634,7 +612,6 @@ function saveAndClose() {
|
||||
.dialog-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: calc(100% - 20px);
|
||||
background-color: #f5f7fa;
|
||||
|
||||
.content-wrapper {
|
||||
@ -666,6 +643,7 @@ function saveAndClose() {
|
||||
overflow-y: auto;
|
||||
padding-right: 5px;
|
||||
flex: 1;
|
||||
max-height: calc(100vh - 340px);
|
||||
|
||||
.theme-item {
|
||||
background: #fff;
|
||||
@ -1033,3 +1011,24 @@ function saveAndClose() {
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<style lang="scss">
|
||||
/* 弹窗壳层覆盖(非 scoped):append-to-body 弹窗 teleport 到 body 后
|
||||
脱离组件样式作用域,scoped :deep 无法命中,必须用业务前缀全局类。
|
||||
高度随内容自适应,滚动交给内部网格/详情区,避免内容少时大片空白 */
|
||||
.theme-dialog {
|
||||
border-radius: 6px;
|
||||
overflow: hidden;
|
||||
|
||||
/* header 内边距归零,留白由内部 .dialog-header(15px 24px)提供 */
|
||||
.el-dialog__header {
|
||||
padding: 0 !important;
|
||||
border-bottom: 1px solid var(--prev-border-color-lighter);
|
||||
}
|
||||
|
||||
.el-dialog__body {
|
||||
padding: 0 !important;
|
||||
max-height: calc(100vh - 100px);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -1,8 +1,12 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="i-layout-page-header header-title">
|
||||
<div class="fl_header">
|
||||
<div class="header-main">
|
||||
<span class="ivu-page-header-title">{{ $route.meta.title }}</span>
|
||||
<span class="header-description">
|
||||
<el-icon class="header-description-icon"><InfoFilled /></el-icon>
|
||||
自定义移动端页面,添加后可通过链接在菜单、广告位等场景跳转使用。
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<el-card :bordered="false" shadow="never" class="ivu-mt">
|
||||
|
||||
@ -2,8 +2,12 @@
|
||||
<div class="my-theme-page">
|
||||
<!-- 顶部标题栏 -->
|
||||
<div class="i-layout-page-header header-title">
|
||||
<div class="fl_header">
|
||||
<div class="header-main">
|
||||
<span class="ivu-page-header-title">我的主题</span>
|
||||
<span class="header-description">
|
||||
<el-icon class="header-description-icon"><InfoFilled /></el-icon>
|
||||
新建或导入商城主题,支持导出备份、扫码预览与一键启用。
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@ -87,17 +87,7 @@ service.interceptors.response.use(
|
||||
case 401:
|
||||
redirectToLogin();
|
||||
return Promise.reject({ ...obj, msg: obj.msg || '未登录' });
|
||||
case 402:
|
||||
removeCookies('kefuInfo');
|
||||
removeCookies('kefu_token');
|
||||
removeCookies('kefu_expires_time');
|
||||
removeCookies('kefu_uuid');
|
||||
router.replace({ path: Setting.routePre + '/kefu' }).catch(() => {});
|
||||
return Promise.reject({ msg: '未登录' });
|
||||
case 403:
|
||||
// 403 仅由 AdminEditorTokenMiddleware(文件编辑 token 过期)抛出,跳转文件管理登录页
|
||||
// 路由名见 pages/plugin/system_file_manage/routes.js:pre('system_file_') + opendir_login
|
||||
router.replace({ name: 'system_file_opendir_login' }).catch(() => {});
|
||||
return Promise.reject({ msg: '没有权限' });
|
||||
default:
|
||||
return Promise.reject(obj || { msg: '未知错误' });
|
||||
|
||||
@ -1,7 +1,13 @@
|
||||
<template>
|
||||
<div :style="bgcolors">
|
||||
<div class="i-layout-page-header header-title">
|
||||
<span class="ivu-page-header-title mr20">{{ $route.meta.title }}</span>
|
||||
<div class="header-main">
|
||||
<span class="ivu-page-header-title mr20">{{ $route.meta.title }}</span>
|
||||
<span class="header-description">
|
||||
<el-icon class="header-description-icon"><InfoFilled /></el-icon>
|
||||
维护 APP 服务协议与隐私政策内容,右侧实时预览移动端弹窗效果。
|
||||
</span>
|
||||
</div>
|
||||
<div style="float: right">
|
||||
<el-button class="bnt" type="primary" v-db-click @click="onsubmit('formValidate')">保存</el-button>
|
||||
</div>
|
||||
|
||||
@ -4,6 +4,7 @@
|
||||
ref="pageHeader"
|
||||
:title="route.params.id ? '编辑文章' : '添加文章'"
|
||||
:backUrl="Setting.routePre + '/cms/article/index'"
|
||||
description="填写文章标题、分类、封面与正文,保存后在前台文章模块展示。"
|
||||
></pages-header>
|
||||
<el-card :bordered="false" shadow="never" class="mt16">
|
||||
<el-form
|
||||
|
||||
@ -1,6 +1,10 @@
|
||||
<template>
|
||||
<div>
|
||||
<pages-header class="mb16" :title="$route.meta.title"></pages-header>
|
||||
<pages-header
|
||||
class="mb16"
|
||||
:title="$route.meta.title"
|
||||
description="配置 IM 机器人通知渠道并启停驱动,系统告警与业务消息推送经此发送。"
|
||||
></pages-header>
|
||||
<el-card :bordered="false" shadow="never" class="ivu-mt mt16">
|
||||
<el-table :data="list" ref="table" v-loading="loading" highlight-current-row row-key="id">
|
||||
<el-table-column label="排序" width="80" prop="sort">
|
||||
|
||||
@ -1,6 +1,10 @@
|
||||
<template>
|
||||
<div>
|
||||
<pages-header class="mb16" :title="$route.meta.title"></pages-header>
|
||||
<pages-header
|
||||
class="mb16"
|
||||
:title="$route.meta.title"
|
||||
description="接入商品采集服务商,按支持平台启用并填写账号密钥,采集商品时自动调用。"
|
||||
></pages-header>
|
||||
<el-card :bordered="false" shadow="never" class="ivu-mt mt16">
|
||||
<el-table :data="list" ref="table" v-loading="loading" highlight-current-row row-key="id">
|
||||
<el-table-column label="排序" width="80" prop="sort">
|
||||
|
||||
@ -1,6 +1,10 @@
|
||||
<template>
|
||||
<div>
|
||||
<pages-header class="mb16" :title="$route.meta.title"></pages-header>
|
||||
<pages-header
|
||||
class="mb16"
|
||||
:title="$route.meta.title"
|
||||
description="配置邮件服务器参数并启停驱动,邮箱验证与通知邮件经此发送。"
|
||||
></pages-header>
|
||||
<el-card :bordered="false" shadow="never" class="ivu-mt mt16">
|
||||
<el-table :data="list" ref="table" v-loading="loading" highlight-current-row row-key="id">
|
||||
<el-table-column label="排序" width="80" prop="sort">
|
||||
|
||||
@ -1,6 +1,10 @@
|
||||
<template>
|
||||
<div>
|
||||
<pages-header class="mb16" :title="$route.meta.title"></pages-header>
|
||||
<pages-header
|
||||
class="mb16"
|
||||
:title="$route.meta.title"
|
||||
description="配置电子面单服务商账号并启停驱动,面单模板与寄件信息在电子面单设置中维护。"
|
||||
></pages-header>
|
||||
<el-card :bordered="false" shadow="never" class="ivu-mt mt16">
|
||||
<el-alert
|
||||
title="这里仅管理电子面单服务商驱动;物流公司、打印机编号和寄件信息请到“设置 > 电子面单设置”配置。"
|
||||
|
||||
@ -1,6 +1,10 @@
|
||||
<template>
|
||||
<div>
|
||||
<pages-header class="mb16" :title="$route.meta.title"></pages-header>
|
||||
<pages-header
|
||||
class="mb16"
|
||||
:title="$route.meta.title"
|
||||
description="对接电子发票服务商并启停驱动,开票请求由启用驱动统一处理。"
|
||||
></pages-header>
|
||||
<el-card :bordered="false" shadow="never" class="ivu-mt mt16">
|
||||
<el-table :data="list" ref="table" v-loading="loading" highlight-current-row row-key="id">
|
||||
<el-table-column label="排序" width="80" prop="sort">
|
||||
|
||||
@ -1,6 +1,10 @@
|
||||
<template>
|
||||
<div>
|
||||
<pages-header class="mb16" :title="$route.meta.title"></pages-header>
|
||||
<pages-header
|
||||
class="mb16"
|
||||
:title="$route.meta.title"
|
||||
description="配置物流查询服务商并启停驱动,订单物流轨迹经此获取。"
|
||||
></pages-header>
|
||||
<el-card :bordered="false" shadow="never" class="ivu-mt mt16">
|
||||
<el-table :data="list" ref="table" v-loading="loading" highlight-current-row row-key="id">
|
||||
<el-table-column label="排序" width="80" prop="sort">
|
||||
|
||||
@ -1,6 +1,10 @@
|
||||
<template>
|
||||
<div>
|
||||
<pages-header class="mb16" :title="$route.meta.title"></pages-header>
|
||||
<pages-header
|
||||
class="mb16"
|
||||
:title="$route.meta.title"
|
||||
description="查看各支付方式的支持端与驱动状态并启停,支付参数在各驱动的配置中维护。"
|
||||
></pages-header>
|
||||
<el-card :bordered="false" shadow="never" class="ivu-mt mt16">
|
||||
<el-table :data="list" ref="table" v-loading="loading" highlight-current-row row-key="id">
|
||||
<el-table-column label="排序" width="80" prop="sort">
|
||||
|
||||
@ -1,6 +1,11 @@
|
||||
<template>
|
||||
<div class="printer-content-page">
|
||||
<pages-header ref="pageHeader" title="小票配置" :backUrl="$routeProStr + '/setting/printer'"></pages-header>
|
||||
<pages-header
|
||||
ref="pageHeader"
|
||||
title="小票配置"
|
||||
:backUrl="$routeProStr + '/setting/printer'"
|
||||
description="勾选小票需打印的商家、商品、支付等信息项,保存后打印即时生效。"
|
||||
></pages-header>
|
||||
<el-card :bordered="false" shadow="never" class="mt16">
|
||||
<div class="flex justify-between warpper" v-loading="loading">
|
||||
<el-form
|
||||
|
||||
@ -1,6 +1,10 @@
|
||||
<template>
|
||||
<div>
|
||||
<pages-header class="mb16" :title="$route.meta.title"></pages-header>
|
||||
<pages-header
|
||||
class="mb16"
|
||||
:title="$route.meta.title"
|
||||
description="添加并维护打印机设备,绑定驱动、设置打印时机与打印联数。"
|
||||
></pages-header>
|
||||
<el-card :bordered="false" shadow="never" class="ivu-mt mt16">
|
||||
<el-row class="action-row mb14">
|
||||
<el-col :span="24">
|
||||
|
||||
@ -1,6 +1,10 @@
|
||||
<template>
|
||||
<div>
|
||||
<pages-header class="mb16" :title="$route.meta.title"></pages-header>
|
||||
<pages-header
|
||||
class="mb16"
|
||||
:title="$route.meta.title"
|
||||
description="配置打印服务商账号并启停驱动,具体打印机设备在打印设置中维护。"
|
||||
></pages-header>
|
||||
<el-card :bordered="false" shadow="never" class="ivu-mt mt16">
|
||||
<el-alert
|
||||
title="在这里配置打印服务商账号和密钥;具体设备只在“设置 > 打印设置”中填写打印机 ID。"
|
||||
|
||||
@ -1,6 +1,10 @@
|
||||
<template>
|
||||
<div>
|
||||
<pages-header class="mb16" :title="$route.meta.title"></pages-header>
|
||||
<pages-header
|
||||
class="mb16"
|
||||
:title="$route.meta.title"
|
||||
description="配置短信服务商参数并启停驱动,驱动为互斥模式,同时仅一个生效。"
|
||||
></pages-header>
|
||||
<el-card :bordered="false" shadow="never" class="ivu-mt mt16">
|
||||
<el-table :data="list" ref="table" v-loading="loading" highlight-current-row row-key="id">
|
||||
<el-table-column label="排序" width="80" prop="sort">
|
||||
|
||||
@ -1,6 +1,10 @@
|
||||
<template>
|
||||
<div>
|
||||
<pages-header class="mb16" :title="$route.meta.title"></pages-header>
|
||||
<pages-header
|
||||
class="mb16"
|
||||
:title="$route.meta.title"
|
||||
description="管理本地与云存储驱动并切换启用,图片附件将上传至启用的存储平台。"
|
||||
></pages-header>
|
||||
<el-card :bordered="false" shadow="never" class="ivu-mt mt16">
|
||||
<el-table :data="list" ref="table" v-loading="loading" highlight-current-row row-key="id">
|
||||
<el-table-column label="排序" width="80" prop="sort">
|
||||
|
||||
@ -1,7 +1,13 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="i-layout-page-header header-title">
|
||||
<span class="ivu-page-header-title">{{ $route.meta.title }}</span>
|
||||
<div class="header-main">
|
||||
<span class="ivu-page-header-title">{{ $route.meta.title }}</span>
|
||||
<span class="header-description">
|
||||
<el-icon class="header-description-icon"><InfoFilled /></el-icon>
|
||||
用户资金流水明细,按类型与时间筛选,支持导出对账。
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<el-card :bordered="false" shadow="never">
|
||||
<el-form
|
||||
|
||||
@ -4,6 +4,7 @@
|
||||
ref="pageHeader"
|
||||
:title="route.params.id && isEdit ? '编辑优惠券' : '添加优惠券'"
|
||||
:backUrl="Setting.routePre + '/marketing/store_coupon_issue/index'"
|
||||
description="设置优惠券名称、面值、领取与有效期等规则,保存后可发放给用户。"
|
||||
></pages-header>
|
||||
<el-card :bordered="false" shadow="never" class="mt16">
|
||||
<el-form :model="formData" label-width="160px">
|
||||
|
||||
@ -5,7 +5,6 @@
|
||||
@close="$emit('update:visible', false)"
|
||||
title="物流查询"
|
||||
size="420px"
|
||||
:modal-append-to-body="true"
|
||||
:wrapper-closable="true"
|
||||
class="order_box2"
|
||||
>
|
||||
@ -76,19 +75,6 @@ function copyNum() {
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.order_box2 {
|
||||
:deep(.el-drawer__wrapper) {
|
||||
z-index: 3000 !important;
|
||||
}
|
||||
|
||||
:deep(.el-drawer__body) {
|
||||
padding: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
/* 快递单号信息区域 */
|
||||
.express-header {
|
||||
display: flex;
|
||||
@ -201,3 +187,15 @@ function copyNum() {
|
||||
font-size: 14px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<style lang="scss">
|
||||
/* 抽屉壳层覆盖(非 scoped):抽屉根类自锚的 scoped :deep 在组件作用域外无法命中;
|
||||
body 满高 flex 布局供底部滚动区使用。原 .el-drawer__wrapper z-index 覆盖为
|
||||
iView 遗留死规则(选择器结构写反且 EP 层级由弹层管理),不再保留 */
|
||||
.order_box2 .el-drawer__body {
|
||||
padding: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -954,11 +954,6 @@ function formatFullTime(timestamp) {
|
||||
}
|
||||
|
||||
/* 运行详情回放 */
|
||||
.run-detail-dialog {
|
||||
:deep(.el-dialog__body) {
|
||||
padding-top: 10px;
|
||||
}
|
||||
}
|
||||
.run-detail-head {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@ -1039,3 +1034,11 @@ function formatFullTime(timestamp) {
|
||||
color: #f56c6c;
|
||||
}
|
||||
</style>
|
||||
|
||||
<style lang="scss">
|
||||
/* 运行详情弹窗壳层(非 scoped):append-to-body 弹窗 teleport 到 body 后
|
||||
脱离组件样式作用域,scoped :deep 无法命中,必须用全局类 */
|
||||
.run-detail-dialog .el-dialog__body {
|
||||
padding-top: 10px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -1,970 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
<pages-header
|
||||
:title="$route.params.id ? '编辑砍价商品' : '添加砍价商品'"
|
||||
:backUrl="routePre + '/marketing/bargain/product'"
|
||||
></pages-header>
|
||||
<el-card :bordered="false" shadow="never" class="mt16">
|
||||
<el-row class="mt30 acea-row row-middle row-center">
|
||||
<el-col :span="20">
|
||||
<steps :stepList="stepList" :isActive="current"></steps>
|
||||
</el-col>
|
||||
<el-col :span="23" v-loading="spinShow">
|
||||
<el-form
|
||||
class="form mt30"
|
||||
ref="formValidateRef"
|
||||
:rules="ruleValidate"
|
||||
:model="formValidate"
|
||||
@on-validate="validate"
|
||||
:label-width="labelWidth"
|
||||
:label-position="labelPosition"
|
||||
@submit.prevent
|
||||
>
|
||||
<el-form-item label="选择商品:" prop="image_input" v-show="current === 0">
|
||||
<div class="picBox" v-db-click @click="changeGoods">
|
||||
<div class="pictrue" v-if="formValidate.image">
|
||||
<img v-lazy="formValidate.image" />
|
||||
</div>
|
||||
<div class="upLoad acea-row row-center-wrapper" v-else>
|
||||
<i class="el-icon-goods" style="font-size: 24px"></i>
|
||||
</div>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-row v-show="current === 1">
|
||||
<el-col :span="24">
|
||||
<el-form-item label="商品主图:" prop="image">
|
||||
<div class="picBox" v-db-click @click="modalPicTap('dan', 'danFrom')">
|
||||
<div class="pictrue" v-if="formValidate.image">
|
||||
<img v-lazy="formValidate.image" />
|
||||
</div>
|
||||
<div class="upLoad acea-row row-center-wrapper" v-else>
|
||||
<i class="el-icon-picture-outline" style="font-size: 24px"></i>
|
||||
</div>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="商品轮播图:" prop="images">
|
||||
<div class="acea-row">
|
||||
<div
|
||||
class="pictrue"
|
||||
v-for="(item, index) in formValidate.images"
|
||||
:key="index"
|
||||
draggable="true"
|
||||
@dragstart="handleDragStart($event, item)"
|
||||
@dragover.prevent="handleDragOver($event, item)"
|
||||
@dragenter="handleDragEnter($event, item)"
|
||||
@dragend="handleDragEnd($event, item)"
|
||||
>
|
||||
<img v-lazy="item" />
|
||||
<i class="el-icon-circle-close btndel" v-db-click @click="handleRemove(index)"></i>
|
||||
</div>
|
||||
<div
|
||||
v-if="formValidate.images.length < 10"
|
||||
class="upLoad acea-row row-center-wrapper"
|
||||
v-db-click
|
||||
@click="modalPicTap('duo')"
|
||||
>
|
||||
<i class="el-icon-picture-outline" style="font-size: 24px"></i>
|
||||
</div>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24">
|
||||
<el-col v-bind="grid">
|
||||
<el-form-item label="砍价活动名称:" prop="title" label-for="title">
|
||||
<el-input
|
||||
placeholder="请输入砍价活动名称"
|
||||
v-model="formValidate.title"
|
||||
class="content_width"
|
||||
maxlength="30"
|
||||
show-word-limit
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-col>
|
||||
<el-col :span="24">
|
||||
<el-col v-bind="grid">
|
||||
<el-form-item label="砍价活动简介:" prop="info" label-for="info">
|
||||
<el-input
|
||||
placeholder="请输入砍价活动简介"
|
||||
type="textarea"
|
||||
:rows="4"
|
||||
v-model="formValidate.info"
|
||||
class="content_width"
|
||||
maxlength="100"
|
||||
show-word-limit
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-col>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="活动时间:" prop="section_time">
|
||||
<div>
|
||||
<el-date-picker
|
||||
clearable
|
||||
:editable="false"
|
||||
type="datetimerange"
|
||||
format="YYYY-MM-DD HH:mm"
|
||||
value-format="YYYY-MM-DD HH:mm"
|
||||
range-separator="-"
|
||||
start-placeholder="开始日期"
|
||||
end-placeholder="结束日期"
|
||||
@change="onchangeTime"
|
||||
style="width: 460px"
|
||||
v-model="formValidate.section_time"
|
||||
></el-date-picker>
|
||||
<div class="grey">设置活动开启结束时间,用户可以在设置时间内发起参与砍价</div>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24" v-if="formValidate.virtual_type == 0">
|
||||
<el-form-item label="物流方式:" prop="logistics">
|
||||
<el-checkbox-group v-model="formValidate.logistics">
|
||||
<el-checkbox label="1">快递</el-checkbox>
|
||||
<el-checkbox label="2">到店</el-checkbox>
|
||||
</el-checkbox-group>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24" v-if="formValidate.virtual_type == 0 && formValidate.logistics.includes('1')">
|
||||
<el-form-item label="运费设置:" :prop="formValidate.freight != 1 ? 'freight' : ''">
|
||||
<el-radio-group v-model="formValidate.freight">
|
||||
<el-radio :label="2" :value="2">固定邮费</el-radio>
|
||||
<el-radio :label="3" :value="3">运费模板</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col
|
||||
:span="24"
|
||||
v-if="
|
||||
formValidate.freight != 3 &&
|
||||
formValidate.freight != 1 &&
|
||||
formValidate.virtual_type == 0 &&
|
||||
formValidate.logistics.includes('1')
|
||||
"
|
||||
>
|
||||
<el-form-item label="">
|
||||
<div class="acea-row">
|
||||
<el-input-number
|
||||
:controls="false"
|
||||
:min="0"
|
||||
:max="9999999999"
|
||||
v-model="formValidate.postage"
|
||||
placeholder="请输入金额"
|
||||
class="content_width"
|
||||
/>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24" v-if="formValidate.freight == 3 && formValidate.virtual_type == 0">
|
||||
<el-form-item label="" prop="temp_id">
|
||||
<div class="acea-row">
|
||||
<el-select
|
||||
v-model="formValidate.temp_id"
|
||||
clearable
|
||||
placeholder="请选择运费模板"
|
||||
class="content_width"
|
||||
>
|
||||
<el-option
|
||||
v-for="(item, index) in templateList"
|
||||
:value="item.id"
|
||||
:key="index"
|
||||
:label="item.name"
|
||||
></el-option>
|
||||
</el-select>
|
||||
<span class="addfont" v-db-click @click="freight">新增运费模板</span>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="砍价人数:" prop="people_num" label-for="people_num">
|
||||
<div>
|
||||
<el-input-number
|
||||
:controls="false"
|
||||
placeholder="请输入砍价人数"
|
||||
element-id="people_num"
|
||||
:min="2"
|
||||
:max="10000"
|
||||
:precision="0"
|
||||
v-model="formValidate.people_num"
|
||||
class="input-number-unit-class"
|
||||
class-unit="人"
|
||||
/>
|
||||
<div class="grey">需要多少人砍价成功</div>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="帮砍次数:" prop="bargain_num" label-for="bargain_num">
|
||||
<div>
|
||||
<el-input-number
|
||||
:controls="false"
|
||||
placeholder="请输入帮砍次数"
|
||||
:min="1"
|
||||
:max="10000"
|
||||
:precision="0"
|
||||
v-model="formValidate.bargain_num"
|
||||
class="input-number-unit-class"
|
||||
class-unit="次"
|
||||
/>
|
||||
<div class="grey">
|
||||
单个商品用户可以帮砍的次数,例:次数设置为1,甲和乙同时将商品A的砍价链接发给丙,丙只能帮甲或乙其中一个人砍价
|
||||
</div>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="单位:" prop="unit_name" label-for="unit_name">
|
||||
<el-input
|
||||
placeholder="请输入单位"
|
||||
element-id="unit_name"
|
||||
v-model="formValidate.unit_name"
|
||||
class="content_width"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="购买数量限制:" prop="num">
|
||||
<div>
|
||||
<el-input-number
|
||||
:controls="false"
|
||||
placeholder="购买数量限制"
|
||||
:min="1"
|
||||
:max="10000"
|
||||
:precision="0"
|
||||
v-model="formValidate.num"
|
||||
class="input-number-unit-class"
|
||||
:class-unit="formValidate.unit_name || '件'"
|
||||
/>
|
||||
<div class="grey">单个活动每个用户发起砍价次数限制</div>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="排序:">
|
||||
<el-input-number
|
||||
:controls="false"
|
||||
placeholder="请输入排序"
|
||||
element-id="sort"
|
||||
:min="0"
|
||||
:max="10000"
|
||||
:precision="0"
|
||||
v-model="formValidate.sort"
|
||||
class="content_width"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="砍价是否参与分销:" props="is_commission" label-for="is_commission">
|
||||
<div>
|
||||
<el-switch
|
||||
class="defineSwitch"
|
||||
:active-value="1"
|
||||
:inactive-value="0"
|
||||
v-model="formValidate.is_commission"
|
||||
size="large"
|
||||
active-text="开启"
|
||||
inactive-text="关闭"
|
||||
>
|
||||
</el-switch>
|
||||
<div class="grey">商品是否参与商城分销返佣</div>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="活动状态:" props="status" label-for="status">
|
||||
<el-switch
|
||||
class="defineSwitch"
|
||||
:active-value="1"
|
||||
:inactive-value="0"
|
||||
v-model="formValidate.status"
|
||||
size="large"
|
||||
active-text="开启"
|
||||
inactive-text="关闭"
|
||||
>
|
||||
</el-switch>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="规格选择:">
|
||||
<el-table :data="specsData" border>
|
||||
<el-table-column width="50">
|
||||
<template #default="scope">
|
||||
<el-radio
|
||||
type="index"
|
||||
v-model="templateRadio"
|
||||
:label="scope.$index"
|
||||
:value="scope.$index"
|
||||
@change="getTemplateRow"
|
||||
> </el-radio
|
||||
>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
:label="item.title"
|
||||
:min-width="item.minWidth"
|
||||
v-for="(item, index) in columns"
|
||||
:key="index"
|
||||
>
|
||||
<template #default="scope">
|
||||
<template v-if="item.key">
|
||||
<div>
|
||||
<span>{{ scope.row[item.key] }}</span>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else-if="item.slot === 'pic'">
|
||||
<div
|
||||
class="acea-row row-middle row-center-wrapper"
|
||||
v-db-click
|
||||
@click="modalPicTap('dan', 'danTable', scope.$index)"
|
||||
>
|
||||
<div class="pictrue pictrueTab" v-if="scope.row.pic">
|
||||
<img v-lazy="scope.row.pic" />
|
||||
</div>
|
||||
<div class="upLoad pictrueTab acea-row row-center-wrapper" v-else>
|
||||
<i class="el-icon-picture-outline" style="font-size: 24px"></i>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else-if="item.slot === 'price'">
|
||||
<el-input-number
|
||||
:controls="false"
|
||||
v-model="scope.row.price"
|
||||
:min="0"
|
||||
:precision="2"
|
||||
class="priceBox"
|
||||
:active-change="false"
|
||||
></el-input-number>
|
||||
</template>
|
||||
<template v-else-if="item.slot === 'min_price'">
|
||||
<el-input-number
|
||||
:controls="false"
|
||||
v-model="scope.row.min_price"
|
||||
:min="0"
|
||||
:precision="2"
|
||||
class="priceBox"
|
||||
:active-change="false"
|
||||
></el-input-number>
|
||||
</template>
|
||||
<template v-else-if="item.slot === 'quota'">
|
||||
<el-input-number
|
||||
:controls="false"
|
||||
v-model="scope.row.quota"
|
||||
:min="1"
|
||||
active-change
|
||||
class="priceBox"
|
||||
></el-input-number>
|
||||
</template>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<div v-if="current === 2">
|
||||
<el-form-item label="内容:">
|
||||
<WangEditor
|
||||
style="width: 90%"
|
||||
:content="formValidate.description"
|
||||
:ai-default-prompt="aiDefaultPrompt"
|
||||
@editorContent="getEditorContent"
|
||||
></WangEditor>
|
||||
</el-form-item>
|
||||
</div>
|
||||
<div v-if="current === 3">
|
||||
<el-form-item label="规则:">
|
||||
<WangEditor
|
||||
style="width: 90%"
|
||||
:content="formValidate.rule"
|
||||
@editorContent="getEditorContent2"
|
||||
></WangEditor>
|
||||
</el-form-item>
|
||||
</div>
|
||||
<el-form-item>
|
||||
<el-button
|
||||
v-if="current !== 0"
|
||||
class="submission"
|
||||
v-db-click
|
||||
@click="step"
|
||||
:disabled="($route.params.id && $route.params.id !== '0' && current === 1) || current === 0"
|
||||
>上一步</el-button
|
||||
>
|
||||
<el-button
|
||||
type="primary"
|
||||
:disabled="submitOpen && current === 3"
|
||||
class="submission"
|
||||
v-db-click
|
||||
@click="next"
|
||||
>{{ current === 3 ? '提交' : '下一步' }}</el-button
|
||||
>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-card>
|
||||
<!-- 选择商品-->
|
||||
<el-dialog v-model="modals" title="商品列表" class="paymentFooter" width="1000px">
|
||||
<goods-list ref="goodslist" @getProductId="getProductId"></goods-list>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 上传图片-->
|
||||
<el-dialog v-model="modalPic" width="950px" title="上传商品图" :close-on-click-modal="false">
|
||||
<uploadPictures
|
||||
:isChoice="isChoice"
|
||||
@getPic="getPic"
|
||||
@getPicD="getPicD"
|
||||
:gridBtn="gridBtn"
|
||||
:gridPic="gridPic"
|
||||
v-if="modalPic"
|
||||
></uploadPictures>
|
||||
</el-dialog>
|
||||
<!-- 运费模板-->
|
||||
<freight-template ref="template" @addSuccess="productGetTemplate"></freight-template>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed, nextTick, onMounted, ref } from 'vue';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
import { ElMessage } from 'element-plus';
|
||||
import goodsList from '@/components/goodsList/index';
|
||||
import uploadPictures from '@/components/uploadPictures';
|
||||
import { bargainInfoApi, bargainCreatApi, productAttrsApi } from '@/api/marketing';
|
||||
import { productGetTemplateApi } from '@/api/product';
|
||||
import freightTemplate from '@/components/freightTemplate/index';
|
||||
import WangEditor from '@/components/wangEditor/index.vue';
|
||||
import steps from '@/components/steps/index';
|
||||
import setting from '@/setting';
|
||||
import { useMediaStore } from '@/store/module/media';
|
||||
|
||||
defineOptions({ name: 'bargainCreate' });
|
||||
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
const routePre = setting.routePre;
|
||||
const { isMobile } = storeToRefs(useMediaStore());
|
||||
|
||||
const labelWidth = computed(() => (isMobile.value ? undefined : '140px'));
|
||||
const labelPosition = computed(() => (isMobile.value ? 'top' : 'right'));
|
||||
|
||||
const formValidateRef = ref(null);
|
||||
const goodslist = ref(null);
|
||||
const template = ref(null);
|
||||
|
||||
const templateRadio = ref(0);
|
||||
const submitOpen = ref(false);
|
||||
const spinShow = ref(false);
|
||||
const myConfig = {
|
||||
autoHeightEnabled: false,
|
||||
initialFrameHeight: 500,
|
||||
initialFrameWidth: '100%',
|
||||
UEDITOR_HOME_URL: '/UEditor/',
|
||||
serverUrl: '',
|
||||
};
|
||||
const stepList = ['选择砍价商品', '填写基础信息', '修改商品详情', '修改商品规则'];
|
||||
const isChoice = ref('');
|
||||
const current = ref(0);
|
||||
const modalPic = ref(false);
|
||||
const grid = {
|
||||
xl: 12,
|
||||
lg: 20,
|
||||
md: 24,
|
||||
sm: 24,
|
||||
xs: 24,
|
||||
};
|
||||
const grid2 = {
|
||||
xl: 8,
|
||||
lg: 8,
|
||||
md: 12,
|
||||
sm: 24,
|
||||
xs: 24,
|
||||
};
|
||||
const gridPic = {
|
||||
xl: 6,
|
||||
lg: 8,
|
||||
md: 12,
|
||||
sm: 12,
|
||||
xs: 12,
|
||||
};
|
||||
const gridBtn = {
|
||||
xl: 4,
|
||||
lg: 8,
|
||||
md: 8,
|
||||
sm: 8,
|
||||
xs: 8,
|
||||
};
|
||||
const modals = ref(false);
|
||||
const modal_loading = ref(false);
|
||||
const images = ref([]);
|
||||
const templateList = ref([]);
|
||||
const columns = ref([]);
|
||||
const specsData = ref([]);
|
||||
const formValidate = ref({
|
||||
images: [],
|
||||
info: '',
|
||||
title: '',
|
||||
store_name: '',
|
||||
image: '',
|
||||
unit_name: '',
|
||||
price: 0,
|
||||
min_price: 0,
|
||||
bargain_max_price: 10,
|
||||
bargain_min_price: 0.01,
|
||||
cost: 0,
|
||||
bargain_num: 1,
|
||||
people_num: 2,
|
||||
stock: 1,
|
||||
sales: 0,
|
||||
sort: 0,
|
||||
num: 1,
|
||||
give_integral: 0,
|
||||
is_postage: 0,
|
||||
is_hot: 0,
|
||||
status: 0,
|
||||
section_time: [],
|
||||
description: '',
|
||||
rule: '',
|
||||
id: 0,
|
||||
product_id: 0,
|
||||
temp_id: '',
|
||||
attrs: [],
|
||||
items: [],
|
||||
logistics: [],
|
||||
freight: 2,
|
||||
postage: 1,
|
||||
is_commission: 0,
|
||||
});
|
||||
// AI 写作默认提示词:优先带入当前商品名称(弹窗内未被用户修改过的提示词会跟随刷新)
|
||||
const aiDefaultPrompt = computed(() => {
|
||||
const title = (formValidate.value.store_name || formValidate.value.title || '').trim();
|
||||
return title
|
||||
? `请围绕商品《${title}》撰写一篇产品推广文章,介绍产品亮点、使用场景与适用人群,结构清晰,800字左右。`
|
||||
: '写一篇产品推广文章,介绍产品亮点、使用场景与适用人群,结构清晰,800字左右。';
|
||||
});
|
||||
const description = ref('');
|
||||
const rule = ref('');
|
||||
const ruleValidate = {
|
||||
image: [{ required: true, message: '请选择主图', trigger: 'change' }],
|
||||
images: [
|
||||
{
|
||||
required: true,
|
||||
type: 'array',
|
||||
message: '请选择主图',
|
||||
trigger: 'change',
|
||||
},
|
||||
{
|
||||
type: 'array',
|
||||
min: 1,
|
||||
message: 'Choose two hobbies at best',
|
||||
trigger: 'change',
|
||||
},
|
||||
],
|
||||
title: [{ required: true, message: '请输入砍价活动名称', trigger: 'blur' }],
|
||||
info: [{ required: true, message: '请输入砍价活动简介', trigger: 'blur' }],
|
||||
store_name: [{ required: true, message: '请输入砍价商品名称', trigger: 'blur' }],
|
||||
section_time: [
|
||||
{
|
||||
required: true,
|
||||
type: 'array',
|
||||
message: '请选择活动时间',
|
||||
trigger: 'change',
|
||||
},
|
||||
],
|
||||
unit_name: [{ required: true, message: '请输入单位', trigger: 'blur' }],
|
||||
price: [
|
||||
{
|
||||
required: true,
|
||||
type: 'number',
|
||||
message: '请输入原价',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
min_price: [
|
||||
{
|
||||
required: true,
|
||||
type: 'number',
|
||||
message: '请输入最低购买价',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
cost: [
|
||||
{
|
||||
required: true,
|
||||
type: 'number',
|
||||
message: '请输入成本价',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
bargain_num: [
|
||||
{
|
||||
required: true,
|
||||
type: 'number',
|
||||
message: '请输入帮砍次数',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
people_num: [
|
||||
{
|
||||
required: true,
|
||||
type: 'number',
|
||||
message: '请输入砍价人数',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
stock: [
|
||||
{
|
||||
required: true,
|
||||
type: 'number',
|
||||
message: '请输入库存',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
num: [
|
||||
{
|
||||
required: true,
|
||||
type: 'number',
|
||||
message: '请输入单次允许购买数量',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
temp_id: [
|
||||
{
|
||||
required: true,
|
||||
message: '请选择运费模板',
|
||||
trigger: 'change',
|
||||
type: 'number',
|
||||
},
|
||||
],
|
||||
};
|
||||
const currentid = ref(0);
|
||||
const picTit = ref('');
|
||||
const tableIndex = ref(0);
|
||||
const copy = ref(0);
|
||||
const dragging = ref(null);
|
||||
|
||||
onMounted(() => {
|
||||
if (route.params.id !== '0' && route.params.id) {
|
||||
copy.value = route.params.copy;
|
||||
current.value = 1;
|
||||
getInfo();
|
||||
}
|
||||
productGetTemplate();
|
||||
});
|
||||
|
||||
function getEditorContent(data) {
|
||||
description.value = data;
|
||||
}
|
||||
function getEditorContent2(data) {
|
||||
rule.value = data;
|
||||
}
|
||||
function freight() {
|
||||
template.value.id = 0;
|
||||
template.value.isTemplate = true;
|
||||
}
|
||||
function productAttrs(row) {
|
||||
productAttrsApi(row.id, 2)
|
||||
.then((res) => {
|
||||
let data = res.data.info;
|
||||
columns.value = data.header;
|
||||
specsData.value = data.attrs;
|
||||
formValidate.value.items = data.items;
|
||||
formValidate.value['attrs'] = [specsData.value[0]];
|
||||
})
|
||||
.catch((res) => {
|
||||
ElMessage.error(res.msg);
|
||||
});
|
||||
}
|
||||
function getTemplateRow(index) {
|
||||
currentid.value = index;
|
||||
formValidate.value['attrs'] = [specsData.value[index]];
|
||||
}
|
||||
function productGetTemplate() {
|
||||
productGetTemplateApi().then((res) => {
|
||||
templateList.value = res.data;
|
||||
});
|
||||
}
|
||||
function getProductId(row) {
|
||||
modal_loading.value = false;
|
||||
modals.value = false;
|
||||
setTimeout(() => {
|
||||
formValidate.value = {
|
||||
images: row.slider_image,
|
||||
info: row.store_info,
|
||||
title: row.store_name,
|
||||
store_name: row.store_name,
|
||||
image: row.image,
|
||||
unit_name: row.unit_name,
|
||||
price: 0,
|
||||
min_price: 0,
|
||||
bargain_max_price: 10,
|
||||
bargain_min_price: 0.01,
|
||||
cost: row.cost,
|
||||
bargain_num: 1,
|
||||
people_num: 2,
|
||||
stock: row.stock,
|
||||
sales: row.sales,
|
||||
sort: row.sort,
|
||||
num: 1,
|
||||
give_integral: row.give_integral,
|
||||
is_postage: row.is_postage,
|
||||
is_hot: row.is_hot,
|
||||
status: 0,
|
||||
section_time: [],
|
||||
description: '',
|
||||
rule: '',
|
||||
id: 0,
|
||||
product_id: row.id,
|
||||
temp_id: row.temp_id,
|
||||
logistics: row.temp_id ? ['2'] : ['1'],
|
||||
freight: row.freight,
|
||||
postage: row.postage,
|
||||
custom_form: row.custom_form,
|
||||
virtual_type: row.virtual_type,
|
||||
is_commission: row.is_commission,
|
||||
description: row.description,
|
||||
};
|
||||
productAttrs(row);
|
||||
}, 500);
|
||||
}
|
||||
function cancel() {
|
||||
modals.value = false;
|
||||
}
|
||||
function handleDragStart(e, item) {
|
||||
dragging.value = item;
|
||||
}
|
||||
function handleDragEnd(e, item) {
|
||||
dragging.value = null;
|
||||
}
|
||||
function handleDragOver(e) {
|
||||
e.dataTransfer.dropEffect = 'move';
|
||||
}
|
||||
function handleDragEnter(e, item) {
|
||||
e.dataTransfer.effectAllowed = 'move';
|
||||
if (item === dragging.value) {
|
||||
return;
|
||||
}
|
||||
const newItems = [...formValidate.value.images];
|
||||
const src = newItems.indexOf(dragging.value);
|
||||
const dst = newItems.indexOf(item);
|
||||
newItems.splice(dst, 0, ...newItems.splice(src, 1));
|
||||
formValidate.value.images = newItems;
|
||||
}
|
||||
function onchangeTime(e) {
|
||||
formValidate.value.section_time = e;
|
||||
}
|
||||
function getInfo() {
|
||||
spinShow.value = true;
|
||||
bargainInfoApi(route.params.id)
|
||||
.then(async (res) => {
|
||||
let info = res.data.info;
|
||||
formValidate.value = info;
|
||||
formValidate.value.rule = info.rule === null ? '' : info.rule;
|
||||
formValidate.value['items'] = info.attrs.items;
|
||||
description.value = formValidate.value.description;
|
||||
columns.value = info.attrs.header;
|
||||
specsData.value = info.attrs.value;
|
||||
let defaultAttrs = [];
|
||||
info.attrs.value.forEach(function (item, index) {
|
||||
if (item.opt) {
|
||||
defaultAttrs.push(item);
|
||||
currentid.value = index;
|
||||
templateRadio.value = index;
|
||||
formValidate.value['attrs'] = defaultAttrs;
|
||||
}
|
||||
});
|
||||
spinShow.value = false;
|
||||
})
|
||||
.catch((res) => {
|
||||
spinShow.value = false;
|
||||
ElMessage.error(res.msg);
|
||||
});
|
||||
}
|
||||
function next() {
|
||||
if (current.value === 3) {
|
||||
formValidate.value.description = description.value;
|
||||
formValidate.value.rule = rule.value;
|
||||
formValidateRef.value.validate((valid) => {
|
||||
if (valid) {
|
||||
if (copy.value == 1) formValidate.value.copy = 1;
|
||||
formValidate.value.id = route.params.id || 0;
|
||||
submitOpen.value = true;
|
||||
bargainCreatApi(formValidate.value)
|
||||
.then(async (res) => {
|
||||
submitOpen.value = false;
|
||||
ElMessage.success(res.msg);
|
||||
setTimeout(() => {
|
||||
router.push({
|
||||
path: routePre + '/marketing/bargain/product',
|
||||
});
|
||||
}, 500);
|
||||
})
|
||||
.catch((res) => {
|
||||
submitOpen.value = false;
|
||||
ElMessage.error(res.msg);
|
||||
});
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
} else if (current.value === 1) {
|
||||
formValidateRef.value.validate((valid) => {
|
||||
if (valid) {
|
||||
if (currentid.value === '') {
|
||||
return ElMessage.error('请选择属性规格');
|
||||
} else {
|
||||
if (formValidate.value.attrs[0].quota <= 0) {
|
||||
return ElMessage.error('砍价限量必须大于0');
|
||||
}
|
||||
if (formValidate.value.attrs[0].quota > formValidate.value.attrs[0]['stock']) {
|
||||
return ElMessage.error('砍价限量不能超过规格库存');
|
||||
}
|
||||
}
|
||||
current.value += 1;
|
||||
} else {
|
||||
return ElMessage.warning('请完善您的信息');
|
||||
}
|
||||
});
|
||||
} else {
|
||||
if (formValidate.value.image) {
|
||||
current.value += 1;
|
||||
if (current.value == 3) {
|
||||
setTimeout((e) => {
|
||||
formValidate.value.rule += ' ';
|
||||
}, 0);
|
||||
}
|
||||
} else {
|
||||
ElMessage.warning('请选择商品');
|
||||
}
|
||||
}
|
||||
}
|
||||
function step() {
|
||||
current.value--;
|
||||
}
|
||||
function getContent(val) {
|
||||
formValidate.value.description = val;
|
||||
}
|
||||
function getRole(val) {
|
||||
formValidate.value.rule = val;
|
||||
}
|
||||
function modalPicTap(tit, picTitVal, index) {
|
||||
modalPic.value = true;
|
||||
isChoice.value = tit === 'dan' ? '单选' : '多选';
|
||||
picTit.value = picTitVal;
|
||||
tableIndex.value = index;
|
||||
}
|
||||
function getPic(pc) {
|
||||
switch (picTit.value) {
|
||||
case 'danFrom':
|
||||
formValidate.value.image = pc.att_dir;
|
||||
break;
|
||||
default:
|
||||
specsData.value[tableIndex.value].pic = pc.att_dir;
|
||||
formValidate.value.attrs[0].pic = pc.att_dir;
|
||||
}
|
||||
modalPic.value = false;
|
||||
}
|
||||
function getPicD(pc) {
|
||||
images.value = pc;
|
||||
images.value.map((item) => {
|
||||
formValidate.value.images.push(item.att_dir);
|
||||
formValidate.value.images = formValidate.value.images.splice(0, 10);
|
||||
});
|
||||
modalPic.value = false;
|
||||
}
|
||||
function handleRemove(i) {
|
||||
images.value.splice(i, 1);
|
||||
formValidate.value.images.splice(i, 1);
|
||||
}
|
||||
function changeGoods() {
|
||||
modals.value = true;
|
||||
nextTick((e) => {
|
||||
goodslist.value.formValidate.is_show = -1;
|
||||
goodslist.value.formValidate.type = 3;
|
||||
goodslist.value.getList();
|
||||
goodslist.value.goodsCategory();
|
||||
});
|
||||
}
|
||||
function validate(prop, status, error) {
|
||||
if (status === false) {
|
||||
ElMessage.error(error);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.content_width {
|
||||
width: 460px;
|
||||
}
|
||||
.grey {
|
||||
color: #999;
|
||||
font-size: 12px;
|
||||
}
|
||||
.maxW :deep(.ivu-select-dropdown) {
|
||||
max-width: 600px;
|
||||
}
|
||||
.ivu-table-wrapper {
|
||||
border-left: 1px solid #dcdee2;
|
||||
border-top: 1px solid #dcdee2;
|
||||
}
|
||||
.tabBox_img {
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
}
|
||||
.tabBox_img img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
.priceBox {
|
||||
width: 100%;
|
||||
}
|
||||
.form {
|
||||
.picBox {
|
||||
display: inline-block;
|
||||
cursor: pointer;
|
||||
}
|
||||
.pictrue {
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
border: 1px dotted rgba(0, 0, 0, 0.1);
|
||||
margin-right: 15px;
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
|
||||
img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
.btndel {
|
||||
position: absolute;
|
||||
z-index: 9;
|
||||
width: 20px !important;
|
||||
height: 20px !important;
|
||||
left: 46px;
|
||||
top: -4px;
|
||||
}
|
||||
}
|
||||
.upLoad {
|
||||
width: 58px;
|
||||
height: 58px;
|
||||
line-height: 58px;
|
||||
border: 1px dotted rgba(0, 0, 0, 0.1);
|
||||
border-radius: 4px;
|
||||
background: rgba(0, 0, 0, 0.02);
|
||||
cursor: pointer;
|
||||
}
|
||||
.col {
|
||||
color: #2d8cf0;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
.addfont {
|
||||
font-size: 12px;
|
||||
color: var(--prev-color-primary);
|
||||
margin-left: 14px;
|
||||
cursor: pointer;
|
||||
margin-left: 10px;
|
||||
cursor: pointer;
|
||||
}
|
||||
</style>
|
||||
@ -1,258 +0,0 @@
|
||||
<template>
|
||||
<div class="article-manager">
|
||||
<el-card :bordered="false" shadow="never" :body-style="{ padding: 0 }">
|
||||
<div class="padding-add">
|
||||
<el-form :model="formValidate" :label-width="labelWidth" label-position="right" @submit.prevent inline>
|
||||
<el-form-item label="时间选择:">
|
||||
<date-range-picker
|
||||
clearable
|
||||
v-model="timeVal"
|
||||
:editable="false"
|
||||
@change="onchangeTime"
|
||||
format="YYYY/MM/DD"
|
||||
value-format="YYYY/MM/DD"
|
||||
class="mr20"
|
||||
></date-range-picker>
|
||||
</el-form-item>
|
||||
<el-form-item label="砍价状态:">
|
||||
<el-select
|
||||
v-model="formValidate.status"
|
||||
placeholder="请选择"
|
||||
clearable
|
||||
@change="userSearchs"
|
||||
class="form_content_width"
|
||||
>
|
||||
<el-option :value="1" label="进行中"></el-option>
|
||||
<el-option :value="2" label="已失败"></el-option>
|
||||
<el-option :value="3" label="已成功"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
</el-card>
|
||||
<el-card :bordered="false" shadow="never" class="ivu-mt mt16">
|
||||
<el-table
|
||||
:data="tableList"
|
||||
v-loading="loading"
|
||||
highlight-current-row
|
||||
no-userFrom-text="暂无数据"
|
||||
no-filtered-userFrom-text="暂无筛选结果"
|
||||
>
|
||||
<el-table-column label="头像" width="80">
|
||||
<template #default="scope">
|
||||
<div class="tabBox_img" v-viewer>
|
||||
<img v-lazy="scope.row.avatar" />
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="发起用户" min-width="100">
|
||||
<template #default="scope">
|
||||
<span> {{ scope.row.nickname + ' / ' + scope.row.uid }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="开启时间" min-width="110">
|
||||
<template #default="scope">
|
||||
<span> {{ scope.row.add_time }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="砍价商品" min-width="300">
|
||||
<template #default="scope">
|
||||
<span> {{ scope.row.title }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="最低价" min-width="60">
|
||||
<template #default="scope">
|
||||
<span> {{ scope.row.bargain_price_min }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="当前价" min-width="60">
|
||||
<template #default="scope">
|
||||
<span> {{ scope.row.now_price }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="总砍价次数" min-width="70">
|
||||
<template #default="scope">
|
||||
<span> {{ scope.row.people_num }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="剩余砍价次数" min-width="100">
|
||||
<template #default="scope">
|
||||
<span> {{ scope.row.num }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="结束时间" min-width="150">
|
||||
<template #default="scope">
|
||||
<span> {{ scope.row.datatime }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="状态" min-width="100">
|
||||
<template #default="scope">
|
||||
<el-tag size="default" type="info" v-show="scope.row.status === 1">进行中</el-tag>
|
||||
<el-tag size="default" type="danger" v-show="scope.row.status === 2">已失败</el-tag>
|
||||
<el-tag size="default" v-show="scope.row.status === 3">已成功</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" fixed="right" width="100">
|
||||
<template #default="scope">
|
||||
<a v-db-click @click="Info(scope.row)">查看详情</a>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<div class="acea-row row-right page">
|
||||
<pagination
|
||||
v-if="total"
|
||||
:total="total"
|
||||
v-model:page="formValidate.page"
|
||||
v-model:limit="formValidate.limit"
|
||||
@pagination="getList"
|
||||
/>
|
||||
</div>
|
||||
</el-card>
|
||||
|
||||
<!-- 详情模态框-->
|
||||
<el-dialog v-model="modals" class="tableBox" title="查看详情" :close-on-click-modal="false" width="720px">
|
||||
<el-table :data="tabList3" v-loading="loading2" empty-text="暂无数据" highlight-current-row max-height="600">
|
||||
<el-table-column label="用户ID" width="80">
|
||||
<template #default="scope">
|
||||
<span>{{ scope.row.uid }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="用户头像" min-width="100">
|
||||
<template #default="scope">
|
||||
<div class="tabBox_img" v-viewer>
|
||||
<img v-lazy="scope.row.avatar" />
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="用户名称" min-width="100">
|
||||
<template #default="scope">
|
||||
<span> {{ scope.row.nickname }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="砍价金额" min-width="100">
|
||||
<template #default="scope">
|
||||
<span>{{ scope.row.price }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="砍价时间" min-width="130">
|
||||
<template #default="scope">
|
||||
<span>{{ scope.row.add_time }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed, ref } from 'vue';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { ElMessage } from 'element-plus';
|
||||
import { formatDate } from '@/utils/validate';
|
||||
import { bargainUserListApi, bargainUserInfoApi } from '@/api/marketing';
|
||||
import { useMediaStore } from '@/store/module/media';
|
||||
|
||||
defineOptions({ name: 'bargainPink' });
|
||||
|
||||
const { isMobile } = storeToRefs(useMediaStore());
|
||||
|
||||
const labelWidth = computed(() => (isMobile.value ? undefined : '80px'));
|
||||
const labelPosition = computed(() => (isMobile.value ? 'top' : 'right'));
|
||||
|
||||
const cardLists = ref([]);
|
||||
const modals = ref(false);
|
||||
const loading = ref(false);
|
||||
const formValidate = ref({
|
||||
status: '',
|
||||
data: '',
|
||||
page: 1,
|
||||
limit: 15,
|
||||
});
|
||||
const tableList = ref([]);
|
||||
const total = ref(0);
|
||||
const timeVal = ref([]);
|
||||
const loading2 = ref(false);
|
||||
const tabList3 = ref([]);
|
||||
const rows = ref({});
|
||||
|
||||
// 原 filters:转为普通 function
|
||||
function formatDateFilter(time) {
|
||||
if (time !== 0) {
|
||||
let date = new Date(time * 1000);
|
||||
return formatDate(date, 'yyyy-MM-dd hh:mm');
|
||||
}
|
||||
}
|
||||
|
||||
getList();
|
||||
|
||||
// 查看详情
|
||||
function Info(row) {
|
||||
modals.value = true;
|
||||
rows.value = row;
|
||||
bargainUserInfoApi(row.id)
|
||||
.then(async (res) => {
|
||||
let data = res.data;
|
||||
tabList3.value = data.list;
|
||||
loading.value = false;
|
||||
})
|
||||
.catch((res) => {
|
||||
loading.value = false;
|
||||
ElMessage.error(res.msg);
|
||||
});
|
||||
}
|
||||
// 具体日期
|
||||
function onchangeTime(e) {
|
||||
timeVal.value = e || [];
|
||||
formValidate.value.data = timeVal.value[0] ? (timeVal.value ? timeVal.value.join('-') : '') : '';
|
||||
formValidate.value.page = 1;
|
||||
getList();
|
||||
}
|
||||
// 选择时间
|
||||
function selectChange(tab) {
|
||||
formValidate.value.page = 1;
|
||||
formValidate.value.data = tab;
|
||||
timeVal.value = [];
|
||||
getList();
|
||||
}
|
||||
// 列表
|
||||
function getList() {
|
||||
loading.value = true;
|
||||
formValidate.value.status = formValidate.value.status || '';
|
||||
bargainUserListApi(formValidate.value)
|
||||
.then(async (res) => {
|
||||
let data = res.data;
|
||||
tableList.value = data.list;
|
||||
total.value = res.data.count;
|
||||
loading.value = false;
|
||||
})
|
||||
.catch((res) => {
|
||||
loading.value = false;
|
||||
ElMessage.error(res.msg);
|
||||
});
|
||||
}
|
||||
// 表格搜索
|
||||
function userSearchs() {
|
||||
formValidate.value.page = 1;
|
||||
getList();
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
:deep(.ivu-tag-cyan .ivu-tag-text) {
|
||||
color: #19be6b !important;
|
||||
}
|
||||
.ivu-tag-cyan {
|
||||
background: rgba(25, 190, 170, 0.1);
|
||||
border-color: #19be6b !important;
|
||||
}
|
||||
.tabBox_img {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@ -1,337 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-card :bordered="false" shadow="never" :body-style="{ padding: 0 }">
|
||||
<div class="padding-add">
|
||||
<el-form :model="tableFrom" :label-width="labelWidth" :label-position="labelPosition" @submit.prevent inline>
|
||||
<el-form-item label="上架状态:">
|
||||
<el-select
|
||||
placeholder="请选择"
|
||||
v-model="tableFrom.status"
|
||||
clearable
|
||||
@change="userSearchs"
|
||||
class="form_content_width"
|
||||
>
|
||||
<el-option value="1" label="上架"></el-option>
|
||||
<el-option value="0" label="下架"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="商品搜索:" label-for="store_name">
|
||||
<el-input
|
||||
clearable
|
||||
placeholder="请输入砍价名称,ID"
|
||||
v-model="tableFrom.store_name"
|
||||
class="form_content_width"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" v-db-click @click="userSearchs">查询</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
</el-card>
|
||||
<el-card :bordered="false" shadow="never" class="ivu-mt mt16">
|
||||
<el-button v-auth="['marketing-store_bargain-create']" type="primary" class="action-row" v-db-click @click="add"
|
||||
>添加砍价商品</el-button
|
||||
>
|
||||
<el-button
|
||||
v-auth="['export-storeBargain']"
|
||||
class="action-row export"
|
||||
icon="ios-share-outline"
|
||||
v-db-click
|
||||
@click="exportList"
|
||||
>导出</el-button
|
||||
>
|
||||
<el-table
|
||||
:data="tableList"
|
||||
v-loading="loading"
|
||||
highlight-current-row
|
||||
no-userFrom-text="暂无数据"
|
||||
no-filtered-userFrom-text="暂无筛选结果"
|
||||
class="mt14"
|
||||
>
|
||||
<el-table-column label="ID" width="80">
|
||||
<template #default="scope">
|
||||
<div>{{ scope.row.id }}</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="砍价图片" min-width="80">
|
||||
<template #default="scope">
|
||||
<div class="tabBox_img" v-viewer>
|
||||
<img v-lazy="scope.row.image" />
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="砍价名称" min-width="150">
|
||||
<template #default="scope">
|
||||
<el-tooltip placement="top" :open-delay="600">
|
||||
<template #content
|
||||
><div>{{ scope.row.title }}</div></template
|
||||
>
|
||||
<span class="line2">{{ scope.row.title }}</span>
|
||||
</el-tooltip>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="砍价价格" min-width="100">
|
||||
<template #default="scope">
|
||||
<div>{{ scope.row.price }}</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="最低价" min-width="100">
|
||||
<template #default="scope">
|
||||
<div>{{ scope.row.min_price }}</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="参与人数" min-width="100">
|
||||
<template #default="scope">
|
||||
<div>{{ scope.row.count_people_all }}</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="帮忙砍价人数" min-width="100">
|
||||
<template #default="scope">
|
||||
<div>{{ scope.row.count_people_help }}</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="砍价成功人数" min-width="100">
|
||||
<template #default="scope">
|
||||
<div>{{ scope.row.count_people_success }}</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="限量" min-width="80">
|
||||
<template #default="scope">
|
||||
<div>{{ scope.row.quota_show }}</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="限量剩余" min-width="80">
|
||||
<template #default="scope">
|
||||
<div>{{ scope.row.quota }}</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="活动状态" min-width="100">
|
||||
<template #default="scope">
|
||||
<el-tag size="default" v-show="scope.row.start_name === '进行中'">进行中</el-tag>
|
||||
<el-tag size="default" type="warning" v-show="scope.row.start_name === '未开始'">未开始</el-tag>
|
||||
<el-tag size="default" type="info" v-show="scope.row.start_name === '已结束'">已结束</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="活动时间" min-width="180">
|
||||
<template #default="scope">
|
||||
<p>开始:{{ scope.row.start_time }}</p>
|
||||
<p>结束:{{ scope.row.stop_time }}</p>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="上架状态" min-width="100">
|
||||
<template #default="scope">
|
||||
<el-switch
|
||||
class="defineSwitch"
|
||||
:active-value="1"
|
||||
:inactive-value="0"
|
||||
v-model="scope.row.status"
|
||||
:value="scope.row.status"
|
||||
@change="onchangeIsShow(scope.row)"
|
||||
size="large"
|
||||
active-text="上架"
|
||||
inactive-text="下架"
|
||||
>
|
||||
</el-switch>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" fixed="right" width="170">
|
||||
<template #default="scope">
|
||||
<a v-if="scope.row.stop_status === 0" v-db-click @click="edit(scope.row, 0)">编辑</a>
|
||||
<el-divider v-if="scope.row.stop_status === 0" direction="vertical" />
|
||||
<a v-db-click @click="edit(scope.row, 1)">复制</a>
|
||||
<el-divider direction="vertical"></el-divider>
|
||||
<a v-db-click @click="del(scope.row, '删除砍价商品', scope.$index)">删除</a>
|
||||
<el-divider direction="vertical"></el-divider>
|
||||
<a v-db-click @click="viewInfo(scope.row)">统计</a>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<div class="acea-row row-right page">
|
||||
<pagination
|
||||
v-if="total"
|
||||
:total="total"
|
||||
v-model:page="tableFrom.page"
|
||||
v-model:limit="tableFrom.limit"
|
||||
@pagination="getList"
|
||||
/>
|
||||
</div>
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed, onActivated, ref } from 'vue';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
import { ElMessage } from 'element-plus';
|
||||
import { bargainListApi, bargainSetStatusApi } from '@/api/marketing';
|
||||
import { formatDate } from '@/utils/validate';
|
||||
import { exportBargainList } from '@/api/export';
|
||||
import { modalSure } from '@/utils/public';
|
||||
import exportExcel from '@/utils/newToExcel.js';
|
||||
import setting from '@/setting';
|
||||
import { useMediaStore } from '@/store/module/media';
|
||||
|
||||
defineOptions({ name: 'bargainProduct' });
|
||||
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
const routePre = setting.routePre;
|
||||
const { isMobile } = storeToRefs(useMediaStore());
|
||||
|
||||
const labelWidth = computed(() => (isMobile.value ? undefined : '80px'));
|
||||
const labelPosition = computed(() => (isMobile.value ? 'top' : 'right'));
|
||||
|
||||
const loading = ref(false);
|
||||
const tableList = ref([]);
|
||||
const grid = {
|
||||
xl: 7,
|
||||
lg: 10,
|
||||
md: 12,
|
||||
sm: 24,
|
||||
xs: 24,
|
||||
};
|
||||
const tableFrom = ref({
|
||||
status: '',
|
||||
store_name: '',
|
||||
page: 1,
|
||||
limit: 15,
|
||||
});
|
||||
const tableFrom2 = ref({
|
||||
status: '',
|
||||
store_name: '',
|
||||
export: 1,
|
||||
});
|
||||
const total = ref(0);
|
||||
|
||||
// 原 filters:转为普通 function
|
||||
function formatDateFilter(time) {
|
||||
if (time !== 0) {
|
||||
let date = new Date(time * 1000);
|
||||
return formatDate(date, 'yyyy-MM-dd hh:mm:ss');
|
||||
}
|
||||
}
|
||||
|
||||
getList();
|
||||
|
||||
onActivated(() => {
|
||||
getList();
|
||||
});
|
||||
|
||||
// 添加
|
||||
function add() {
|
||||
router.push({ path: routePre + '/marketing/bargain/create' });
|
||||
}
|
||||
// 用户导出
|
||||
async function exportList() {
|
||||
tableFrom.value.status = tableFrom.value.status || '';
|
||||
let [th, filekey, data, fileName] = [[], [], [], ''];
|
||||
let excelData = JSON.parse(JSON.stringify(tableFrom.value));
|
||||
excelData.page = 1;
|
||||
excelData.limit = 50;
|
||||
for (let i = 0; i < excelData.page + 1; i++) {
|
||||
let lebData = await getExcelData(excelData);
|
||||
if (!fileName) fileName = lebData.filename;
|
||||
if (!filekey.length) {
|
||||
filekey = lebData.fileKey;
|
||||
}
|
||||
if (!th.length) th = lebData.header;
|
||||
if (lebData.export.length) {
|
||||
data = data.concat(lebData.export);
|
||||
excelData.page++;
|
||||
} else {
|
||||
exportExcel(th, filekey, fileName, data);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
function getExcelData(excelData) {
|
||||
return new Promise((resolve, reject) => {
|
||||
exportBargainList(excelData).then((res) => {
|
||||
resolve(res.data);
|
||||
});
|
||||
});
|
||||
}
|
||||
// 编辑 / 复制 type 0 编辑 1 复制
|
||||
function edit(row, type) {
|
||||
router.push({
|
||||
path: routePre + `/marketing/bargain/create/${row.id}/${type}`,
|
||||
});
|
||||
}
|
||||
// 删除
|
||||
function del(row, tit, num) {
|
||||
let delfromData = {
|
||||
title: tit,
|
||||
num: num,
|
||||
url: `marketing/bargain/${row.id}`,
|
||||
method: 'DELETE',
|
||||
ids: '',
|
||||
};
|
||||
modalSure(delfromData)
|
||||
.then((res) => {
|
||||
ElMessage.success(res.msg);
|
||||
tableList.value.splice(num, 1);
|
||||
})
|
||||
.catch((res) => {
|
||||
ElMessage.error(res.msg);
|
||||
});
|
||||
}
|
||||
function viewInfo(row) {
|
||||
router.push({
|
||||
path: routePre + '/marketing/bargain/statistics/' + row.id,
|
||||
});
|
||||
}
|
||||
// 列表
|
||||
function getList() {
|
||||
loading.value = true;
|
||||
tableFrom.value.status = tableFrom.value.status || '';
|
||||
tableFrom.value.product_id = route.params.product_id || '';
|
||||
bargainListApi(tableFrom.value)
|
||||
.then(async (res) => {
|
||||
let data = res.data;
|
||||
tableList.value = data.list;
|
||||
total.value = res.data.count;
|
||||
loading.value = false;
|
||||
})
|
||||
.catch((res) => {
|
||||
loading.value = false;
|
||||
ElMessage.error(res.msg);
|
||||
});
|
||||
}
|
||||
// 表格搜索
|
||||
function userSearchs() {
|
||||
tableFrom.value.page = 1;
|
||||
getList();
|
||||
}
|
||||
// 修改是否显示
|
||||
function onchangeIsShow(row) {
|
||||
let data = {
|
||||
id: row.id,
|
||||
status: row.status,
|
||||
};
|
||||
bargainSetStatusApi(data)
|
||||
.then(async (res) => {
|
||||
ElMessage.success(res.msg);
|
||||
getList();
|
||||
})
|
||||
.catch((res) => {
|
||||
ElMessage.error(res.msg);
|
||||
row.status = !row.status;
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.tabBox_img {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
|
||||
img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@ -1,361 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
<pages-header :title="$route.meta.title" :backUrl="routePre + '/marketing/bargain/product'"></pages-header>
|
||||
<cards-data :cardLists="cardLists" v-if="cardLists.length" class="ivu-mt-16"></cards-data>
|
||||
<el-card :bordered="false" shadow="never">
|
||||
<el-form :model="pagination" :label-width="labelWidth" label-position="right" @submit.prevent inline>
|
||||
<el-form-item v-if="type == 1" label="订单状态:" label-for="status">
|
||||
<el-select
|
||||
v-model="pagination.status"
|
||||
placeholder="请选择订单状态"
|
||||
clearable
|
||||
@change="searchList"
|
||||
class="form_content_width"
|
||||
>
|
||||
<el-option value="1" label="待发货"></el-option>
|
||||
<el-option value="2" label="待收货"></el-option>
|
||||
<el-option value="3" label="待评价"></el-option>
|
||||
<el-option value="4" label="交易完成"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="搜索:" label-for="title">
|
||||
<el-input
|
||||
v-model="pagination.real_name"
|
||||
:placeholder="type == 1 ? '请输入用户姓名|订单号|UID' : '请输入用户UID'"
|
||||
class="form_content_width"
|
||||
clearable
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" v-db-click @click="searchList">查询</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<el-tabs v-model="type" @tab-change="onClickTab">
|
||||
<el-tab-pane v-for="(item, index) in tabs" :label="item.label" :name="item.type" :key="index" />
|
||||
</el-tabs>
|
||||
<el-table
|
||||
:data="tbody"
|
||||
v-loading="loading"
|
||||
highlight-current-row
|
||||
no-userFrom-text="暂无数据"
|
||||
no-filtered-userFrom-text="暂无筛选结果"
|
||||
>
|
||||
<el-table-column
|
||||
:label="item.title"
|
||||
:min-width="item.minWidth"
|
||||
v-for="(item, index) in type == 1 ? thead2 : thead"
|
||||
:key="index"
|
||||
>
|
||||
<template #default="scope">
|
||||
<template v-if="item.key">
|
||||
<div>
|
||||
<span>{{ scope.row[item.key] }}</span>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else-if="item.slot === 'avatar'">
|
||||
<div class="tabBox_img" v-viewer>
|
||||
<img v-lazy="scope.row.avatar" />
|
||||
</div>
|
||||
</template>
|
||||
<template v-else-if="item.slot === 'status'">
|
||||
<el-tag size="default" type="info" v-show="scope.row.status === 1">进行中</el-tag>
|
||||
<el-tag size="default" type="danger" v-show="scope.row.status === 2">已失败</el-tag>
|
||||
<el-tag size="default" v-show="scope.row.status === 3">已成功</el-tag>
|
||||
</template>
|
||||
<template v-else-if="item.slot === 'action'">
|
||||
<a v-db-click @click="Info(scope.row)">查看详情</a>
|
||||
</template>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<div class="acea-row row-right page">
|
||||
<pagination
|
||||
v-if="total"
|
||||
:total="total"
|
||||
v-model:page="pagination.page"
|
||||
v-model:limit="pagination.limit"
|
||||
@pagination="getList"
|
||||
/>
|
||||
</div>
|
||||
</el-card>
|
||||
<!-- 详情模态框-->
|
||||
<el-dialog v-model="modals" class="tableBox" title="查看详情" :close-on-click-modal="false" width="720px">
|
||||
<el-table :data="tabList3" v-loading="loading2" empty-text="暂无数据" highlight-current-row max-height="600">
|
||||
<el-table-column label="用户ID" width="80">
|
||||
<template #default="scope">
|
||||
<span>{{ scope.row.uid }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="用户头像" min-width="90">
|
||||
<template #default="scope">
|
||||
<div class="tabBox_img" v-viewer>
|
||||
<img v-lazy="scope.row.avatar" />
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="砍价金额" min-width="130">
|
||||
<template #default="scope">
|
||||
<span>{{ scope.row.price }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="砍价时间" min-width="130">
|
||||
<template #default="scope">
|
||||
<span>{{ scope.row.add_time }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue';
|
||||
import { useRoute } from 'vue-router';
|
||||
import { ElMessage } from 'element-plus';
|
||||
import cardsData from '@/components/cards/cards';
|
||||
import {
|
||||
getbargainStatistics,
|
||||
getbargainStatisticsPeople,
|
||||
getbargainStatisticsOrder,
|
||||
bargainUserInfoApi,
|
||||
} from '@/api/marketing';
|
||||
import setting from '@/setting';
|
||||
|
||||
defineOptions({ name: 'bargainStatistics' });
|
||||
|
||||
const route = useRoute();
|
||||
const routePre = setting.routePre;
|
||||
|
||||
const modals = ref(false);
|
||||
const tabList3 = ref([]);
|
||||
const loading2 = ref(false);
|
||||
const grid = {
|
||||
xl: 7,
|
||||
lg: 7,
|
||||
md: 12,
|
||||
sm: 24,
|
||||
xs: 24,
|
||||
};
|
||||
const id = ref(0);
|
||||
const tbody = ref([]);
|
||||
const labelWidth = '80px';
|
||||
const total = ref(0);
|
||||
const tabs = [
|
||||
{
|
||||
type: '0',
|
||||
label: '发起砍价',
|
||||
},
|
||||
{
|
||||
type: '1',
|
||||
label: '活动订单',
|
||||
},
|
||||
];
|
||||
const currentTab = ref(0);
|
||||
const loading = ref(false);
|
||||
const thead = [
|
||||
{
|
||||
title: '头像',
|
||||
slot: 'avatar',
|
||||
},
|
||||
{
|
||||
title: '发起用户',
|
||||
key: 'nickname',
|
||||
},
|
||||
{
|
||||
title: '发起时间',
|
||||
key: 'add_time',
|
||||
},
|
||||
{
|
||||
title: '帮砍人数',
|
||||
key: 'already_num',
|
||||
},
|
||||
{
|
||||
title: '结束时间',
|
||||
key: 'datatime',
|
||||
},
|
||||
{
|
||||
title: '砍价状态',
|
||||
slot: 'status',
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
slot: 'action',
|
||||
},
|
||||
];
|
||||
const thead2 = [
|
||||
{
|
||||
title: '订单号',
|
||||
key: 'order_id',
|
||||
},
|
||||
{
|
||||
title: '用户',
|
||||
key: 'real_name',
|
||||
},
|
||||
{
|
||||
title: '订单状态',
|
||||
key: 'status',
|
||||
},
|
||||
{
|
||||
title: '订单支付金额',
|
||||
key: 'pay_price',
|
||||
},
|
||||
{
|
||||
title: '订单商品数',
|
||||
key: 'total_num',
|
||||
},
|
||||
{
|
||||
title: '下单时间',
|
||||
key: 'add_time',
|
||||
},
|
||||
{
|
||||
title: '支付时间',
|
||||
key: 'pay_time',
|
||||
},
|
||||
];
|
||||
const cardLists = ref([
|
||||
{
|
||||
col: 4,
|
||||
count: 0,
|
||||
name: '活动参与人数(人)',
|
||||
className: 'iconcanyurenshu',
|
||||
},
|
||||
{
|
||||
col: 4,
|
||||
count: 0,
|
||||
name: '砍价人数(人)',
|
||||
className: 'iconxiadanrenshu',
|
||||
},
|
||||
{
|
||||
col: 4,
|
||||
count: 0,
|
||||
name: '发起砍价数',
|
||||
className: 'icontuiguangrenshu',
|
||||
},
|
||||
{
|
||||
col: 4,
|
||||
count: 0,
|
||||
name: '砍价成功数',
|
||||
className: 'iconkanjiachenggong',
|
||||
},
|
||||
{
|
||||
col: 4,
|
||||
count: 0,
|
||||
name: '支付订单额(元)',
|
||||
className: 'iconzhifudingdan',
|
||||
},
|
||||
{
|
||||
col: 4,
|
||||
count: 0,
|
||||
name: '支付人数(人)',
|
||||
className: 'iconzhifurenshu',
|
||||
},
|
||||
]);
|
||||
const pagination = ref({
|
||||
page: 1,
|
||||
limit: 15,
|
||||
real_name: '',
|
||||
status: '',
|
||||
});
|
||||
const type = ref('0');
|
||||
const rows = ref({});
|
||||
|
||||
id.value = route.params.id;
|
||||
getStatistics(id.value);
|
||||
getList();
|
||||
|
||||
function getStatistics(id) {
|
||||
getbargainStatistics(id).then((res) => {
|
||||
let arr = ['people_count', 'spread_count', 'start_count', 'success_count', 'pay_price', 'pay_count', 'pay_rate'];
|
||||
cardLists.value.map((i, index) => {
|
||||
i.count = res.data[arr[index]];
|
||||
});
|
||||
});
|
||||
}
|
||||
function getList() {
|
||||
loading.value = true;
|
||||
if (type.value == 0) {
|
||||
getbargainStatisticsPeople(id.value, pagination.value).then((res) => {
|
||||
loading.value = false;
|
||||
const { count, list } = res.data;
|
||||
total.value = count;
|
||||
tbody.value = list;
|
||||
});
|
||||
} else {
|
||||
getbargainStatisticsOrder(id.value, pagination.value).then((res) => {
|
||||
loading.value = false;
|
||||
const { count, list } = res.data;
|
||||
total.value = count;
|
||||
tbody.value = list;
|
||||
});
|
||||
}
|
||||
}
|
||||
function onClickTab() {
|
||||
pagination.value.page = 1;
|
||||
pagination.value.real_name = '';
|
||||
pagination.value.status = '';
|
||||
getList();
|
||||
}
|
||||
function searchList() {
|
||||
pagination.value.page = 1;
|
||||
getList();
|
||||
}
|
||||
function Info(row) {
|
||||
modals.value = true;
|
||||
rows.value = row;
|
||||
bargainUserInfoApi(row.id)
|
||||
.then(async (res) => {
|
||||
let data = res.data;
|
||||
tabList3.value = data.list;
|
||||
loading.value = false;
|
||||
})
|
||||
.catch((res) => {
|
||||
loading.value = false;
|
||||
ElMessage.error(res.msg);
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.cl {
|
||||
margin-right: 20px;
|
||||
}
|
||||
.code-row-bg {
|
||||
display: flex;
|
||||
flex-wrap: nowrap;
|
||||
}
|
||||
.code-row-bg .ivu-mt {
|
||||
width: 100%;
|
||||
margin: 0 5px;
|
||||
}
|
||||
.ech-box {
|
||||
margin-top: 10px;
|
||||
}
|
||||
.change-style {
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 15px;
|
||||
padding: 0px 10px;
|
||||
cursor: pointer;
|
||||
}
|
||||
.table-head {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
.return {
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
:deep(.ivu-tabs-nav-scroll) {
|
||||
background-color: #fff;
|
||||
padding-top: 5px;
|
||||
}
|
||||
.tabBox_img {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@ -1,125 +0,0 @@
|
||||
/**
|
||||
* 砍价扩展路由
|
||||
*/
|
||||
import setting from '@/setting';
|
||||
const routePre = setting.routePre;
|
||||
const pre = 'bargain_';
|
||||
|
||||
export default [
|
||||
// ===== 新路径 =====
|
||||
{
|
||||
path: routePre + '/marketing/bargain/product',
|
||||
section: 'bargain',
|
||||
action: 'product',
|
||||
meta: {
|
||||
auth: ['marketing-store_bargain'],
|
||||
title: '砍价商品',
|
||||
},
|
||||
component: () => import('@/layout'),
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
name: `${pre}product`,
|
||||
component: () => import('./pages/product/index.vue'),
|
||||
meta: {
|
||||
auth: ['marketing-store_bargain'],
|
||||
title: '砍价商品',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: routePre + '/marketing/bargain/create/:id?/:copy?',
|
||||
section: 'bargain',
|
||||
action: 'create',
|
||||
meta: {
|
||||
auth: ['marketing-store_bargain-create'],
|
||||
title: '添加/编辑砍价商品',
|
||||
},
|
||||
component: () => import('@/layout'),
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
name: `${pre}create`,
|
||||
component: () => import('./pages/create/index.vue'),
|
||||
meta: {
|
||||
auth: ['marketing-store_bargain-create'],
|
||||
title: '添加/编辑砍价商品',
|
||||
activeMenu: routePre + '/marketing/bargain/product',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: routePre + '/marketing/bargain/pink',
|
||||
section: 'bargain',
|
||||
action: 'pink',
|
||||
meta: {
|
||||
auth: ['marketing-store_bargain-bargain_list'],
|
||||
title: '砍价列表',
|
||||
},
|
||||
component: () => import('@/layout'),
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
name: `${pre}pink`,
|
||||
component: () => import('./pages/pink/index.vue'),
|
||||
meta: {
|
||||
auth: ['marketing-store_bargain-bargain_list'],
|
||||
title: '砍价列表',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: routePre + '/marketing/bargain/statistics/:id',
|
||||
section: 'bargain',
|
||||
action: 'statistics',
|
||||
meta: {
|
||||
auth: ['marketing-store_bargain-statistics'],
|
||||
title: '砍价统计',
|
||||
},
|
||||
component: () => import('@/layout'),
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
name: `${pre}statistics`,
|
||||
component: () => import('./pages/statistics/index.vue'),
|
||||
meta: {
|
||||
auth: ['marketing-store_bargain-statistics'],
|
||||
title: '砍价统计',
|
||||
activeMenu: routePre + '/marketing/bargain/product',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
// ===== 兼容旧路由(无组件,仅用于菜单选中) =====
|
||||
{
|
||||
path: routePre + '/marketing/store_bargain/index',
|
||||
section: 'bargain',
|
||||
action: 'product',
|
||||
name: `${pre}legacyIndex`,
|
||||
meta: { title: '砍价商品' },
|
||||
},
|
||||
{
|
||||
path: routePre + '/marketing/store_bargain/bargain_list',
|
||||
section: 'bargain',
|
||||
action: 'pink',
|
||||
name: `${pre}legacyPink`,
|
||||
meta: { title: '砍价列表' },
|
||||
},
|
||||
{
|
||||
path: routePre + '/marketing/store_bargain/create/:id?/:copy?',
|
||||
section: 'bargain',
|
||||
action: 'create',
|
||||
name: `${pre}legacyCreate`,
|
||||
meta: { title: '添加/编辑砍价商品' },
|
||||
},
|
||||
{
|
||||
path: routePre + '/marketing/store_bargain/statistics/:id',
|
||||
section: 'bargain',
|
||||
action: 'statistics',
|
||||
name: `${pre}legacyStatistics`,
|
||||
meta: { title: '砍价统计' },
|
||||
},
|
||||
];
|
||||
@ -1,45 +0,0 @@
|
||||
<template>
|
||||
<div class="cardkey-app">
|
||||
<div class="section-content">
|
||||
<component :is="actionComponent" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
/**
|
||||
* 卡密商品扩展根组件
|
||||
* 由 PageContainer 动态加载,根据 action 切换子页面。
|
||||
* 路由参数(editId/orderNo)由子页面从 $route.params 自行读取,路由 path 保持不变。
|
||||
*/
|
||||
import { computed } from 'vue';
|
||||
import ProductList from './index.vue';
|
||||
import ProductAdd from './add/index.vue';
|
||||
import StockList from './stock/List.vue';
|
||||
import OrderList from './order/List.vue';
|
||||
import OrderDetail from './order/Detail.vue';
|
||||
|
||||
const actionComponents = {
|
||||
list: ProductList,
|
||||
add: ProductAdd,
|
||||
stock: StockList,
|
||||
order: OrderList,
|
||||
order_detail: OrderDetail,
|
||||
};
|
||||
|
||||
defineOptions({ name: 'CardkeyApp' });
|
||||
|
||||
const props = defineProps({
|
||||
section: { type: String, default: 'cardkey' },
|
||||
action: { type: String, default: 'list' },
|
||||
params: { type: Object, default: () => ({}) },
|
||||
});
|
||||
|
||||
const actionComponent = computed(() => actionComponents[props.action] || ProductList);
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.cardkey-app {
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
@ -1,73 +0,0 @@
|
||||
<template>
|
||||
<div class="cardkey-setting">
|
||||
<el-form label-width="120px" label-position="right">
|
||||
<el-form-item label="卡密类型:" prop="card_type">
|
||||
<el-radio-group v-model="formValidate.card_type">
|
||||
<el-radio label="single" value="single">单卡密</el-radio>
|
||||
<el-radio label="combo" value="combo">组合卡密</el-radio>
|
||||
</el-radio-group>
|
||||
<div class="tip">单卡密:一个卡密对应一个密码;组合卡密:卡号 + 密码组合</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="卡密有效期:" prop="valid_days">
|
||||
<el-input-number v-model="formValidate.valid_days" :min="0" :precision="0" :controls="false" />
|
||||
<span class="tip"> 天(0 表示永久有效)</span>
|
||||
</el-form-item>
|
||||
<el-form-item label="使用说明:" prop="usage_tip">
|
||||
<el-input
|
||||
type="textarea"
|
||||
:rows="5"
|
||||
v-model="formValidate.usage_tip"
|
||||
placeholder="填写卡密的使用方法说明,下单后展示给买家"
|
||||
></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="卡密库存:">
|
||||
<span class="tip">当前可用卡密 {{ cardCount }} 条,请在商品列表页导入卡密内容</span>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue';
|
||||
import request from '@/libs/request';
|
||||
|
||||
defineOptions({ name: 'cardkeySetting' });
|
||||
|
||||
const props = defineProps({
|
||||
formValidate: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
// 当前商品ID,用于展示卡密库存数量
|
||||
productId: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
});
|
||||
|
||||
const cardCount = ref(0);
|
||||
|
||||
// 加载当前商品的卡密库存数量(编辑时展示)
|
||||
async function loadCardCount() {
|
||||
try {
|
||||
const res = await request({
|
||||
url: `cardkey/product/${props.productId}/card_list`,
|
||||
method: 'get',
|
||||
});
|
||||
cardCount.value = Array.isArray(res.data) ? res.data.length : 0;
|
||||
} catch (e) {
|
||||
cardCount.value = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// created:编辑时加载卡密库存
|
||||
if (props.productId) {
|
||||
loadCardCount();
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.cardkey-setting {
|
||||
padding: 20px;
|
||||
}
|
||||
</style>
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,69 +0,0 @@
|
||||
import request from '@/libs/request';
|
||||
|
||||
export function cardkeyProductList(params) {
|
||||
return request({
|
||||
url: 'cardkey/product/list',
|
||||
method: 'get',
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
export function cardkeyProductDetail(id) {
|
||||
return request({
|
||||
url: `cardkey/product/${id}`,
|
||||
method: 'get',
|
||||
});
|
||||
}
|
||||
|
||||
export function cardkeyProductSave(data) {
|
||||
return request({
|
||||
url: 'cardkey/product',
|
||||
method: 'post',
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
export function cardkeyProductUpdate(id, data) {
|
||||
return request({
|
||||
url: `cardkey/product/${id}`,
|
||||
method: 'put',
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
export function cardkeyProductDelete(id) {
|
||||
return request({
|
||||
url: `cardkey/product/${id}`,
|
||||
method: 'delete',
|
||||
});
|
||||
}
|
||||
|
||||
export function cardkeyProductCardList(id) {
|
||||
return request({
|
||||
url: `cardkey/product/${id}/card_list`,
|
||||
method: 'get',
|
||||
});
|
||||
}
|
||||
|
||||
export function cardkeyProductImportCard(id, cards) {
|
||||
return request({
|
||||
url: `cardkey/product/${id}/import_card`,
|
||||
method: 'post',
|
||||
data: { cards },
|
||||
});
|
||||
}
|
||||
|
||||
export function cardkeyOrderList(params) {
|
||||
return request({
|
||||
url: 'cardkey/order/list',
|
||||
method: 'get',
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
export function cardkeyOrderDetail(orderNo) {
|
||||
return request({
|
||||
url: `cardkey/order/${orderNo}`,
|
||||
method: 'get',
|
||||
});
|
||||
}
|
||||
@ -1,12 +0,0 @@
|
||||
{
|
||||
"key": "cardkey",
|
||||
"title": "卡密商品",
|
||||
"version": "1.0.0",
|
||||
"pages": [
|
||||
{ "path": "list", "title": "卡密商品列表" },
|
||||
{ "path": "add", "title": "添加/编辑卡密商品" },
|
||||
{ "path": "stock", "title": "卡密库存" },
|
||||
{ "path": "order", "title": "卡密订单" },
|
||||
{ "path": "order_detail", "title": "卡密订单详情" }
|
||||
]
|
||||
}
|
||||
@ -1,9 +0,0 @@
|
||||
/**
|
||||
* 卡密商品扩展 UMD 入口
|
||||
* 构建后通过 PageContainer 动态加载(window.__ext_cardkey)
|
||||
*/
|
||||
import CardkeyApp from './App.vue';
|
||||
import routes from './routes.js';
|
||||
|
||||
export default CardkeyApp;
|
||||
export { routes };
|
||||
@ -1,778 +0,0 @@
|
||||
<template>
|
||||
<div class="article-manager">
|
||||
<el-card :bordered="false" shadow="never" :body-style="{ padding: 0 }">
|
||||
<div class="padding-add">
|
||||
<el-form :model="artFrom" label-width="80px" label-position="right" inline @submit.prevent>
|
||||
<div class="acea-row search-form">
|
||||
<div class="search-form-box">
|
||||
<el-form-item label="商品搜索:" label-for="store_name">
|
||||
<el-input
|
||||
clearable
|
||||
placeholder="请输入商品名称/关键字/ID"
|
||||
v-model="artFrom.store_name"
|
||||
class="form_content_width"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="商品分类:" label-for="pid">
|
||||
<el-cascader
|
||||
v-model="artFrom.cate_id"
|
||||
:options="treeSelect"
|
||||
:props="{ multiple: false, emitPath: false, checkStrictly: true }"
|
||||
clearable
|
||||
class="form_content_width"
|
||||
></el-cascader>
|
||||
</el-form-item>
|
||||
<template v-if="collapse">
|
||||
<el-form-item label="会员专属:">
|
||||
<el-select v-model="artFrom.vip_product" clearable placeholder="全部" class="form_content_width">
|
||||
<el-option label="全部" value="" />
|
||||
<el-option label="不限制" value="0" />
|
||||
<el-option label="仅会员可见可买" value="1" />
|
||||
<el-option label="所有人可见仅会员可买" value="2" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="添加时间:">
|
||||
<date-range-picker
|
||||
class="form_range_content_width"
|
||||
clearable
|
||||
v-model="timeVal"
|
||||
:editable="false"
|
||||
@change="onchangeTime"
|
||||
format="YYYY/MM/DD"
|
||||
value-format="YYYY/MM/DD"
|
||||
></date-range-picker>
|
||||
</el-form-item>
|
||||
<el-form-item label="库存:" label-for="store_name">
|
||||
<el-input
|
||||
clearable
|
||||
placeholder="最小值"
|
||||
v-model="artFrom.stock_s[0]"
|
||||
class="form_range_content_width"
|
||||
/>
|
||||
~
|
||||
<el-input
|
||||
clearable
|
||||
placeholder="最大值"
|
||||
v-model="artFrom.stock_s[1]"
|
||||
class="form_range_content_width"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="价格:" label-for="store_name">
|
||||
<el-input
|
||||
clearable
|
||||
placeholder="最小值"
|
||||
v-model="artFrom.price_s[0]"
|
||||
class="form_range_content_width"
|
||||
/>
|
||||
~
|
||||
<el-input
|
||||
clearable
|
||||
placeholder="最大值"
|
||||
v-model="artFrom.price_s[1]"
|
||||
class="form_range_content_width"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="销量:" label-for="store_name">
|
||||
<el-input
|
||||
clearable
|
||||
placeholder="最小值"
|
||||
v-model="artFrom.sales_s[0]"
|
||||
class="form_range_content_width"
|
||||
/>
|
||||
~
|
||||
<el-input
|
||||
clearable
|
||||
placeholder="最大值"
|
||||
v-model="artFrom.sales_s[1]"
|
||||
class="form_range_content_width"
|
||||
/>
|
||||
</el-form-item>
|
||||
</template>
|
||||
</div>
|
||||
<div class="search-form-sub">
|
||||
<el-button type="primary" v-db-click @click="userSearchs">查询</el-button>
|
||||
<el-button class="ResetSearch" v-db-click @click="reset">重置</el-button>
|
||||
<a class="ivu-ml-8 font12 ml10" v-db-click @click="collapse = !collapse">
|
||||
<template v-if="!collapse"> 展开 <i class="el-icon-arrow-down" /> </template>
|
||||
<template v-else> 收起 <i class="el-icon-arrow-up" /> </template>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</el-form>
|
||||
</div>
|
||||
</el-card>
|
||||
<el-card :bordered="false" shadow="never" class="ivu-mt mt16" :body-style="{ padding: '20px 20px 20px' }">
|
||||
<div class="Button">
|
||||
<router-link v-auth="['admin-cardkey-product-save']" :to="$routeProStr + '/product/cardkey/add'"
|
||||
><el-button type="primary" class="mr14">添加卡密商品</el-button></router-link
|
||||
>
|
||||
<el-dropdown class="bnt mr14" @command="batchSelect">
|
||||
<el-button>批量修改<i class="el-icon-arrow-down el-icon--right"></i></el-button>
|
||||
<template #dropdown
|
||||
><el-dropdown-menu>
|
||||
<el-dropdown-item :command="1">商品分类</el-dropdown-item>
|
||||
<el-dropdown-item :command="3">购买送积分</el-dropdown-item>
|
||||
<el-dropdown-item :command="4">购买送优惠券</el-dropdown-item>
|
||||
<el-dropdown-item :command="5">关联用户标签</el-dropdown-item>
|
||||
<el-dropdown-item v-if="artFrom.type === '1'" :command="7">批量下架</el-dropdown-item>
|
||||
<el-dropdown-item v-if="artFrom.type === '2'" :command="8">批量上架</el-dropdown-item>
|
||||
<el-dropdown-item :command="9">设置商品标签</el-dropdown-item>
|
||||
<el-dropdown-item v-if="artFrom.type !== '6'" :command="11">移到回收站</el-dropdown-item>
|
||||
<el-dropdown-item v-if="artFrom.type == '6'" :command="12">恢复商品</el-dropdown-item>
|
||||
</el-dropdown-menu></template
|
||||
>
|
||||
</el-dropdown>
|
||||
</div>
|
||||
<el-table
|
||||
ref="table"
|
||||
:data="tableList"
|
||||
class="mt14"
|
||||
v-loading="loading"
|
||||
highlight-current-row
|
||||
:row-key="getRowKey"
|
||||
@selection-change="handleSelectRow"
|
||||
empty-text="暂无数据"
|
||||
>
|
||||
<el-table-column type="selection" width="60" :reserve-selection="true"> </el-table-column>
|
||||
<el-table-column label="商品ID" width="80">
|
||||
<template #default="scope">
|
||||
<span>{{ scope.row.id }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="商品图" min-width="90">
|
||||
<template #default="scope">
|
||||
<div class="tabBox_img" v-viewer>
|
||||
<img v-lazy="scope.row.image" />
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="商品名称" min-width="250">
|
||||
<template #default="scope">
|
||||
<span>{{ scope.row.store_name }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="卡密类型" min-width="100">
|
||||
<template #default="scope">
|
||||
<span>{{ scope.row.card_type === 'combo' ? '组合卡密' : '单卡密' }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="卡密数量" min-width="100">
|
||||
<template #default="scope">
|
||||
<span>{{ scope.row.card_count || 0 }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="商品售价" min-width="100">
|
||||
<template #default="scope">
|
||||
<span>{{ scope.row.price }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="销量" min-width="100">
|
||||
<template #default="scope">
|
||||
<span>{{ scope.row.sales }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="排序" min-width="100">
|
||||
<template #default="scope">
|
||||
<span>{{ scope.row.sort }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="状态" min-width="100">
|
||||
<template #default="scope">
|
||||
<el-switch
|
||||
class="defineSwitch"
|
||||
:active-value="1"
|
||||
:inactive-value="0"
|
||||
v-model="scope.row.is_show"
|
||||
:value="scope.row.is_show"
|
||||
:disabled="scope.row.stop_status ? true : false"
|
||||
@change="changeSwitch(scope.row)"
|
||||
size="large"
|
||||
active-text="上架"
|
||||
inactive-text="下架"
|
||||
>
|
||||
</el-switch>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" fixed="right" minWidth="100">
|
||||
<template #default="scope">
|
||||
<a v-db-click @click="edit(scope.row)">编辑</a>
|
||||
<el-divider direction="vertical"></el-divider>
|
||||
<el-dropdown>
|
||||
<span class="el-dropdown-link">更多<i class="el-icon-arrow-down el-icon--right"></i> </span>
|
||||
<template #dropdown
|
||||
><el-dropdown-menu>
|
||||
<el-dropdown-item>
|
||||
<router-link :to="{ path: $routeProStr + '/product/product_reply/' + scope.row.id }"
|
||||
><a>查看评论</a></router-link
|
||||
>
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item @click="openModal(scope.row, 'vipPriceSet')">会员价管理</el-dropdown-item>
|
||||
<el-dropdown-item @click="openModal(scope.row, 'brokerageSet')">佣金管理</el-dropdown-item>
|
||||
<el-dropdown-item v-if="artFrom.type === '6'" @click="del(scope.row, '恢复商品', scope.$index)"
|
||||
>恢复商品</el-dropdown-item
|
||||
>
|
||||
<el-dropdown-item v-if="artFrom.type === '6'" @click="fullDel(scope.row, '彻底删除', scope.$index)"
|
||||
>彻底删除</el-dropdown-item
|
||||
>
|
||||
<el-dropdown-item v-else @click="del(scope.row, '移入回收站', scope.$index)"
|
||||
>移到回收站</el-dropdown-item
|
||||
>
|
||||
</el-dropdown-menu></template
|
||||
>
|
||||
</el-dropdown>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<div class="acea-row row-right page">
|
||||
<pagination
|
||||
v-if="total"
|
||||
:total="total"
|
||||
v-model:page="artFrom.page"
|
||||
v-model:limit="artFrom.limit"
|
||||
@pagination="getDataList"
|
||||
/>
|
||||
</div>
|
||||
</el-card>
|
||||
<brokerageSet ref="brokerageSetRef" :productId="productId"></brokerageSet>
|
||||
<vipPriceSet ref="vipPriceSetRef" :productId="productId"></vipPriceSet>
|
||||
<el-dialog
|
||||
v-model="batchModal"
|
||||
class="batch-box"
|
||||
title="批量设置"
|
||||
:show-close="true"
|
||||
:close-on-click-modal="false"
|
||||
width="540px"
|
||||
>
|
||||
<el-form
|
||||
class="batchFormData"
|
||||
:rules="ruleBatch"
|
||||
:model="batchFormData"
|
||||
label-width="90px"
|
||||
label-position="right"
|
||||
@submit.prevent
|
||||
>
|
||||
<el-row :gutter="24">
|
||||
<el-col :span="24" v-if="batchType == 1">
|
||||
<el-form-item label="商品分类:" prop="cate_id">
|
||||
<el-cascader
|
||||
v-model="batchFormData.cate_id"
|
||||
:options="treeSelect"
|
||||
:props="{ multiple: true, emitPath: false, checkStrictly: true }"
|
||||
clearable
|
||||
style="width: 400px"
|
||||
></el-cascader>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24" v-if="[3, 4, 5].includes(batchType)">
|
||||
<el-form-item label="赠送积分:" prop="give_integral" v-if="batchType == 3">
|
||||
<el-input-number
|
||||
:controls="false"
|
||||
v-model="batchFormData.give_integral"
|
||||
:min="0"
|
||||
:max="9999999999"
|
||||
placeholder="请输入积分"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="赠送优惠券:" v-if="batchType == 4">
|
||||
<div v-if="couponName.length" class="mb20">
|
||||
<el-tag closable v-for="(item, index) in couponName" :key="index" @close="handleClose(item)">{{
|
||||
item.title
|
||||
}}</el-tag>
|
||||
</div>
|
||||
<el-button type="primary" v-db-click @click="addCoupon">添加优惠券</el-button>
|
||||
</el-form-item>
|
||||
<el-form-item label="关联标签:" prop="label_id" v-if="batchType == 5">
|
||||
<div class="acea-row label_width">
|
||||
<div class="labelInput acea-row row-between-wrapper" v-db-click @click="openLabel">
|
||||
<div style="width: auto">
|
||||
<div v-if="dataLabel.length">
|
||||
<el-tag
|
||||
class="m-r-2"
|
||||
closable
|
||||
v-for="(item, index) in dataLabel"
|
||||
@close="closeLabel(item)"
|
||||
:key="index"
|
||||
>{{ item.label_name }}</el-tag
|
||||
>
|
||||
</div>
|
||||
<span class="span" v-else>选择用户关联标签</span>
|
||||
</div>
|
||||
<div class="iconfont iconxiayi"></div>
|
||||
</div>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
<template #footer
|
||||
><span class="dialog-footer">
|
||||
<el-button v-db-click @click="clearBatchData">取 消</el-button>
|
||||
<el-button type="primary" v-db-click @click="batchSub">确 定</el-button>
|
||||
</span></template
|
||||
>
|
||||
</el-dialog>
|
||||
<el-dialog
|
||||
v-model="labelShow"
|
||||
title="请选择用户标签"
|
||||
width="540px"
|
||||
:show-close="true"
|
||||
:close-on-click-modal="false"
|
||||
>
|
||||
<userLabel @activeData="activeData" @close="labelClose"></userLabel>
|
||||
</el-dialog>
|
||||
<el-dialog v-model="tagShow" title="请选择商品标签" :show-close="true" width="540px" :close-on-click-modal="false">
|
||||
<goodsLabel :defaultLabelList="goodsLabelList" @activeLabel="activeGoodsLabel" @close="labelClose"></goodsLabel>
|
||||
</el-dialog>
|
||||
<coupon-list ref="couponTemplates" @nameId="nameId" :couponids="batchFormData.coupon_ids"></coupon-list>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { nextTick, onActivated, onMounted, ref } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { ElMessage } from 'element-plus';
|
||||
import { cardkeyProductList } from '@/pages/plugin/cardkey/cardkeyProduct';
|
||||
import {
|
||||
PostgoodsIsShow,
|
||||
cascaderListApi,
|
||||
productShowApi,
|
||||
productUnshowApi,
|
||||
batchSetting,
|
||||
productLabelUseListApi,
|
||||
} from '@/api/product';
|
||||
import userLabel from '@/components/labelList';
|
||||
import goodsLabel from '@/components/goodsLabel';
|
||||
import couponList from '@/components/couponList';
|
||||
import brokerageSet from '../../../pages/product/components/brokerageSet.vue';
|
||||
import vipPriceSet from '../../../pages/product/components/vipPriceSet.vue';
|
||||
import { modalSure } from '@/utils/public';
|
||||
import setting from '@/setting';
|
||||
|
||||
defineOptions({ name: 'cardkeyProduct' });
|
||||
|
||||
const router = useRouter();
|
||||
const routePre = setting.routePre;
|
||||
|
||||
const table = ref(null);
|
||||
const brokerageSetRef = ref(null);
|
||||
const vipPriceSetRef = ref(null);
|
||||
const couponTemplates = ref(null);
|
||||
|
||||
const batchModal = ref(false);
|
||||
const labelShow = ref(false);
|
||||
const tagShow = ref(false);
|
||||
const batchType = ref(1);
|
||||
const batchFormData = ref({
|
||||
cate_id: [],
|
||||
give_integral: 0,
|
||||
label_id: [],
|
||||
coupon_ids: [],
|
||||
});
|
||||
const ruleBatch = ref({});
|
||||
const couponName = ref([]);
|
||||
const dataLabel = ref([]);
|
||||
const artFrom = ref({
|
||||
page: 1,
|
||||
limit: 15,
|
||||
store_name: '',
|
||||
cate_id: '',
|
||||
vip_product: '',
|
||||
sales_s: ['', ''],
|
||||
stock_s: ['', ''],
|
||||
price_s: ['', ''],
|
||||
time: '',
|
||||
type: '1',
|
||||
});
|
||||
const tableList = ref([]);
|
||||
const total = ref(0);
|
||||
const loading = ref(false);
|
||||
const treeSelect = ref([]);
|
||||
const ids = ref([]);
|
||||
const multipleSelection = ref([]);
|
||||
const productId = ref(0);
|
||||
const goodsLabelList = ref([]);
|
||||
const timeVal = ref([]);
|
||||
const collapse = ref(false);
|
||||
|
||||
function refreshAll() {
|
||||
goodsCategory();
|
||||
getLabelList();
|
||||
getDataList();
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
// 首次挂载加载数据(activated 依赖 keep-alive 缓存,未缓存时不会触发)
|
||||
refreshAll();
|
||||
});
|
||||
|
||||
onActivated(() => {
|
||||
// keep-alive 缓存后再次进入时刷新数据
|
||||
refreshAll();
|
||||
});
|
||||
|
||||
function onchangeTime(e) {
|
||||
timeVal.value = e;
|
||||
artFrom.value.time = timeVal.value ? timeVal.value.join('-') : '';
|
||||
artFrom.value.page = 1;
|
||||
getDataList();
|
||||
}
|
||||
function getLabelList() {
|
||||
productLabelUseListApi()
|
||||
.then((res) => {
|
||||
res.data.map((el) => {
|
||||
if (el.list && el.list.length) {
|
||||
el.list.map((label) => {
|
||||
label.active = false;
|
||||
});
|
||||
}
|
||||
});
|
||||
goodsLabelList.value = res.data;
|
||||
})
|
||||
.catch((res) => {
|
||||
ElMessage.error(res.msg);
|
||||
});
|
||||
}
|
||||
function openModal(row, type) {
|
||||
productId.value = row.id;
|
||||
if (type === 'vipPriceSet') {
|
||||
vipPriceSetRef.value.visible = true;
|
||||
} else {
|
||||
brokerageSetRef.value.visible = true;
|
||||
}
|
||||
}
|
||||
function batchSub() {
|
||||
let data = batchFormData.value;
|
||||
data.ids = ids.value;
|
||||
data.type = batchType.value;
|
||||
let activeIds = [];
|
||||
dataLabel.value.forEach((item) => {
|
||||
activeIds.push(item.id);
|
||||
});
|
||||
data.label_id = activeIds;
|
||||
batchSetting(data)
|
||||
.then((res) => {
|
||||
ElMessage.success(res.msg);
|
||||
getDataList();
|
||||
clearBatchData(false);
|
||||
ids.value = [];
|
||||
})
|
||||
.catch((err) => {
|
||||
ElMessage.error(err.msg);
|
||||
});
|
||||
}
|
||||
function clearBatchData(status) {
|
||||
if (!status) {
|
||||
batchFormData.value = {
|
||||
cate_id: [],
|
||||
give_integral: null,
|
||||
label_id: [],
|
||||
coupon_ids: [],
|
||||
label_list: [],
|
||||
};
|
||||
dataLabel.value = [];
|
||||
}
|
||||
batchModal.value = false;
|
||||
table.value.clearSelection();
|
||||
}
|
||||
function batchSelect(type) {
|
||||
if (!ids.value.length) {
|
||||
ElMessage.warning('请选择要修改的商品');
|
||||
} else if (type === 7) {
|
||||
onDismount();
|
||||
} else if (type === 8) {
|
||||
onShelves();
|
||||
} else if (type === 9) {
|
||||
batchType.value = type;
|
||||
tagShow.value = true;
|
||||
} else if (type === 11) {
|
||||
batchGoodsSetting('全部移到回收站', 1);
|
||||
} else if (type === 12) {
|
||||
batchGoodsSetting('恢复选中商品', 2);
|
||||
} else {
|
||||
batchType.value = type;
|
||||
batchModal.value = true;
|
||||
}
|
||||
}
|
||||
function batchGoodsSetting(tit, type) {
|
||||
let url = type == 1 ? 'product/product/batch_delete' : 'product/product/batch_recover';
|
||||
let delfromData = {
|
||||
title: tit,
|
||||
url,
|
||||
method: 'post',
|
||||
ids: {
|
||||
ids: ids.value,
|
||||
},
|
||||
un: 1,
|
||||
};
|
||||
modalSure(delfromData)
|
||||
.then((res) => {
|
||||
ElMessage.success(res.msg);
|
||||
getDataList();
|
||||
})
|
||||
.catch((res) => {
|
||||
ElMessage.error(res.msg);
|
||||
});
|
||||
}
|
||||
function activeData(dataLabelVal) {
|
||||
labelShow.value = false;
|
||||
dataLabel.value = dataLabelVal;
|
||||
}
|
||||
function nameId(id, names) {
|
||||
batchFormData.value.coupon_ids = id;
|
||||
couponName.value = unique(names);
|
||||
}
|
||||
function handleClose(name) {
|
||||
let index = couponName.value.indexOf(name);
|
||||
couponName.value.splice(index, 1);
|
||||
batchFormData.value.coupon_ids.splice(index, 1);
|
||||
}
|
||||
function unique(arr) {
|
||||
const res = new Map();
|
||||
return arr.filter((arr) => !res.has(arr.id) && res.set(arr.id, 1));
|
||||
}
|
||||
function labelClose() {
|
||||
labelShow.value = false;
|
||||
tagShow.value = false;
|
||||
}
|
||||
function activeGoodsLabel(data) {
|
||||
tagShow.value = false;
|
||||
batchFormData.value.label_list = Array.from(new Set(data));
|
||||
batchSub();
|
||||
}
|
||||
function openLabel() {
|
||||
labelShow.value = true;
|
||||
}
|
||||
function closeLabel(label) {
|
||||
let index = dataLabel.value.indexOf(dataLabel.value.filter((d) => d.id == label.id)[0]);
|
||||
dataLabel.value.splice(index, 1);
|
||||
}
|
||||
function addCoupon() {
|
||||
couponTemplates.value.isTemplate = true;
|
||||
couponTemplates.value.tableList();
|
||||
}
|
||||
function onShelves() {
|
||||
if (ids.value.length === 0) {
|
||||
ElMessage.warning('请选择要上架的商品');
|
||||
} else {
|
||||
let data = {
|
||||
ids: ids.value,
|
||||
};
|
||||
productShowApi(data)
|
||||
.then((res) => {
|
||||
ElMessage.success(res.msg);
|
||||
getDataList();
|
||||
})
|
||||
.catch((res) => {
|
||||
ElMessage.error(res.msg);
|
||||
});
|
||||
}
|
||||
}
|
||||
function onDismount() {
|
||||
if (ids.value.length === 0) {
|
||||
ElMessage.warning('请选择要下架的商品');
|
||||
} else {
|
||||
let data = {
|
||||
ids: ids.value,
|
||||
};
|
||||
productUnshowApi(data)
|
||||
.then((res) => {
|
||||
ElMessage.success(res.msg);
|
||||
artFrom.value.page = 1;
|
||||
getDataList();
|
||||
})
|
||||
.catch((res) => {
|
||||
ElMessage.error(res.msg);
|
||||
});
|
||||
}
|
||||
}
|
||||
function getRowKey(row) {
|
||||
return row.id;
|
||||
}
|
||||
function handleSelectRow(selection) {
|
||||
const uniqueArr = [];
|
||||
const idArr = [];
|
||||
for (let i = 0; i < selection.length; i++) {
|
||||
const item = selection[i];
|
||||
if (!idArr.includes(item.id)) {
|
||||
uniqueArr.push(item);
|
||||
idArr.push(item.id);
|
||||
}
|
||||
}
|
||||
ids.value = idArr;
|
||||
multipleSelection.value = uniqueArr;
|
||||
}
|
||||
function goodsCategory() {
|
||||
cascaderListApi(1)
|
||||
.then((res) => {
|
||||
treeSelect.value = res.data;
|
||||
})
|
||||
.catch((res) => {
|
||||
ElMessage.error(res.msg);
|
||||
});
|
||||
}
|
||||
function getDataList() {
|
||||
loading.value = true;
|
||||
artFrom.value.cate_id = artFrom.value.cate_id || '';
|
||||
cardkeyProductList(artFrom.value)
|
||||
.then((res) => {
|
||||
tableList.value = res.data.list || [];
|
||||
total.value = res.data.count || 0;
|
||||
nextTick(() => {
|
||||
showSelectData();
|
||||
});
|
||||
loading.value = false;
|
||||
})
|
||||
.catch((res) => {
|
||||
loading.value = false;
|
||||
ElMessage.error(res.msg || '获取列表失败');
|
||||
});
|
||||
}
|
||||
function showSelectData() {
|
||||
if (multipleSelection.value.length > 0) {
|
||||
tableList.value.forEach((row) => {
|
||||
multipleSelection.value.forEach((item) => {
|
||||
if (row.id === item.id) {
|
||||
table.value.toggleRowSelection(item, true);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
function userSearchs() {
|
||||
artFrom.value.page = 1;
|
||||
getDataList();
|
||||
}
|
||||
function changeSwitch(row) {
|
||||
PostgoodsIsShow(row.id, row.is_show)
|
||||
.then((res) => {
|
||||
ElMessage.success(res.msg);
|
||||
getDataList();
|
||||
})
|
||||
.catch((res) => {
|
||||
row.is_show = !row.is_show ? 1 : 0;
|
||||
ElMessage.error(res.msg);
|
||||
});
|
||||
}
|
||||
function edit(row) {
|
||||
router.push({ path: routePre + '/product/cardkey/add/' + row.id });
|
||||
}
|
||||
function del(row, tit, num) {
|
||||
let delfromData = {
|
||||
title: tit,
|
||||
num: num,
|
||||
url: `product/product/${row.id}`,
|
||||
method: 'DELETE',
|
||||
ids: '',
|
||||
un: 1,
|
||||
};
|
||||
modalSure(delfromData)
|
||||
.then((res) => {
|
||||
ElMessage.success(res.msg);
|
||||
tableList.value.splice(num, 1);
|
||||
getDataList();
|
||||
})
|
||||
.catch((res) => {
|
||||
ElMessage.error(res.msg);
|
||||
});
|
||||
}
|
||||
function fullDel(row, tit, num) {
|
||||
let delfromData = {
|
||||
title: tit,
|
||||
num: num,
|
||||
url: `product/full_del/${row.id}`,
|
||||
method: 'DELETE',
|
||||
};
|
||||
modalSure(delfromData)
|
||||
.then((res) => {
|
||||
ElMessage.success(res.msg);
|
||||
tableList.value.splice(num, 1);
|
||||
getDataList();
|
||||
})
|
||||
.catch((res) => {
|
||||
ElMessage.error(res.msg);
|
||||
});
|
||||
}
|
||||
function reset() {
|
||||
artFrom.value = {
|
||||
page: 1,
|
||||
limit: 15,
|
||||
store_name: '',
|
||||
cate_id: '',
|
||||
vip_product: '',
|
||||
sales_s: ['', ''],
|
||||
stock_s: ['', ''],
|
||||
price_s: ['', ''],
|
||||
time: '',
|
||||
type: '1',
|
||||
};
|
||||
timeVal.value = [];
|
||||
getDataList();
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.mt16 {
|
||||
margin-top: 16px;
|
||||
}
|
||||
.tabBox_img {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
.labelInput {
|
||||
border: 1px solid #dcdee2;
|
||||
padding: 0 15px 0 10px;
|
||||
border-radius: 5px;
|
||||
min-height: 30px;
|
||||
cursor: pointer;
|
||||
font-size: 12px;
|
||||
.span {
|
||||
color: #c5c8ce;
|
||||
}
|
||||
.iconxiayi {
|
||||
margin-left: 5px;
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
.el-dropdown-link {
|
||||
cursor: pointer;
|
||||
color: var(--prev-color-primary);
|
||||
font-size: 12px;
|
||||
}
|
||||
.el-icon-arrow-down {
|
||||
font-size: 12px;
|
||||
}
|
||||
.el-dropdown-menu__item {
|
||||
a {
|
||||
color: #606266;
|
||||
}
|
||||
}
|
||||
.label_width {
|
||||
width: 400px;
|
||||
}
|
||||
.search-form {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
.search-form-box {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
flex: 1;
|
||||
}
|
||||
.search-form-sub {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
}
|
||||
}
|
||||
.batch-box {
|
||||
:deep(.ivu-modal-body) {
|
||||
overflow: auto;
|
||||
min-height: 350px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@ -1,627 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
<div v-loading="detailLoading">
|
||||
<div v-if="detailData" class="order-detail">
|
||||
<div class="head">
|
||||
<div class="full">
|
||||
<img class="order_icon" :src="orderIcon" alt="" />
|
||||
<div class="text">
|
||||
<div class="title">卡密商品订单</div>
|
||||
<div>订单号:{{ detailData.order_no }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<ul class="list">
|
||||
<li class="item">
|
||||
<div class="title">订单状态</div>
|
||||
<div>
|
||||
{{ getStatusLabel(detailData.status_code) }}
|
||||
<span v-if="detailData.refund_status == 1" style="color: #ed4014">
|
||||
{{ detailData.is_all_refund ? '退款中' : '部分退款中' }}
|
||||
</span>
|
||||
</div>
|
||||
</li>
|
||||
<li class="item">
|
||||
<div class="title">订单金额</div>
|
||||
<div class="value1">¥{{ detailData.total_price || '0.00' }}</div>
|
||||
</li>
|
||||
<li class="item" v-if="detailData.refund_status == 2">
|
||||
<div class="title">实际退款</div>
|
||||
<div>¥{{ detailData.refunded_price || '0.00' }}</div>
|
||||
</li>
|
||||
<li class="item">
|
||||
<div class="title">支付方式</div>
|
||||
<div>{{ payType(detailData.pay_type) }}</div>
|
||||
</li>
|
||||
<li class="item">
|
||||
<div class="title">支付时间</div>
|
||||
<div>{{ detailData.pay_time ? formatDate(detailData.pay_time) : '--' }}</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<el-tabs type="border-card" v-model="activeTab">
|
||||
<el-tab-pane label="订单信息" name="detail">
|
||||
<div class="section" v-if="orderItems.length">
|
||||
<div class="section-title">商品信息</div>
|
||||
<el-table :data="orderItems" stripe class="goods-table">
|
||||
<el-table-column label="商品" min-width="300">
|
||||
<template #default="{ row }">
|
||||
<div class="goods-cell">
|
||||
<el-image :src="row.image" class="goods-img" />
|
||||
<div class="goods-meta">
|
||||
<p class="goods-name">{{ row.store_name }}</p>
|
||||
<p v-if="row.sku" class="goods-sku">{{ row.sku }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="单价" width="100">
|
||||
<template #default="{ row }">¥{{ row.true_price || row.price }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="数量" width="80" prop="cart_num" />
|
||||
<el-table-column label="小计" width="120">
|
||||
<template #default="{ row }"
|
||||
>¥{{ (parseFloat(row.true_price || row.price) * row.cart_num).toFixed(2) }}</template
|
||||
>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
|
||||
<div class="section" v-if="detailData.card_info && detailData.card_info.length">
|
||||
<div class="section-title">卡密信息</div>
|
||||
<el-table :data="detailData.card_info" stripe class="goods-table">
|
||||
<el-table-column label="卡号" min-width="200">
|
||||
<template #default="{ row }">{{ row.card_no || '--' }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="卡密" min-width="200">
|
||||
<template #default="{ row }">
|
||||
<div class="card-key-wrapper">
|
||||
<span class="card-key">{{ row.card_key || '--' }}</span>
|
||||
<a v-db-click @click="copyCardKey(row.card_key)">复制</a>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="有效期" width="150">
|
||||
<template #default="{ row }">{{
|
||||
row.expire_time ? formatDate(row.expire_time) : '永久有效'
|
||||
}}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="状态" width="100">
|
||||
<template #default="{ row }">
|
||||
<el-tag :type="row.status == 1 ? 'success' : 'warning'">{{
|
||||
row.status == 1 ? '已使用' : '未使用'
|
||||
}}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<div class="section-title">用户信息</div>
|
||||
<el-row :gutter="24" class="detail-grid">
|
||||
<el-col :span="8"
|
||||
><div class="detail-item">
|
||||
<span class="label">用户名称:</span
|
||||
><span class="value">{{ detailData.real_name || detailData.contact?.name || '--' }}</span>
|
||||
</div></el-col
|
||||
>
|
||||
<el-col :span="8"
|
||||
><div class="detail-item">
|
||||
<span class="label">联系电话:</span
|
||||
><span class="value">{{ detailData.user_phone || detailData.contact?.phone || '--' }}</span>
|
||||
</div></el-col
|
||||
>
|
||||
</el-row>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<div class="section-title">订单信息</div>
|
||||
<el-row :gutter="24" class="detail-grid">
|
||||
<el-col :span="8"
|
||||
><div class="detail-item">
|
||||
<span class="label">创建时间:</span
|
||||
><span class="value">{{ formatDate(detailData.add_time) }}</span>
|
||||
</div></el-col
|
||||
>
|
||||
<el-col :span="8"
|
||||
><div class="detail-item">
|
||||
<span class="label">商品总数:</span><span class="value">{{ detailData.total_num }}</span>
|
||||
</div></el-col
|
||||
>
|
||||
<el-col :span="8"
|
||||
><div class="detail-item">
|
||||
<span class="label">商品总价:</span><span class="value">¥{{ detailData.total_price }}</span>
|
||||
</div></el-col
|
||||
>
|
||||
<el-col :span="8"
|
||||
><div class="detail-item">
|
||||
<span class="label">优惠券金额:</span
|
||||
><span class="value">-¥{{ detailData.coupon_price || '0.00' }}</span>
|
||||
</div></el-col
|
||||
>
|
||||
<el-col :span="8"
|
||||
><div class="detail-item">
|
||||
<span class="label">积分抵扣:</span
|
||||
><span class="value">-¥{{ detailData.deduction_price || '0.00' }}</span>
|
||||
</div></el-col
|
||||
>
|
||||
<el-col :span="8"
|
||||
><div class="detail-item">
|
||||
<span class="label">会员等级优惠:</span
|
||||
><span class="value">-¥{{ detailData.member_level_discount || '0.00' }}</span>
|
||||
</div></el-col
|
||||
>
|
||||
<el-col :span="8"
|
||||
><div class="detail-item">
|
||||
<span class="label">付费会员优惠:</span
|
||||
><span class="value">-¥{{ detailData.vip_discount || '0.00' }}</span>
|
||||
</div></el-col
|
||||
>
|
||||
<el-col :span="8"
|
||||
><div class="detail-item">
|
||||
<span class="label price-label">实际支付:</span
|
||||
><span class="value price-value">¥{{ detailData.pay_price || '0.00' }}</span>
|
||||
</div></el-col
|
||||
>
|
||||
</el-row>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="section"
|
||||
v-if="
|
||||
detailData.one_brokerage ||
|
||||
detailData.two_brokerage ||
|
||||
detailData.staff_brokerage ||
|
||||
detailData.agent_brokerage ||
|
||||
detailData.division_brokerage
|
||||
"
|
||||
>
|
||||
<div class="section-title">返佣信息(金额|用户UID)</div>
|
||||
<el-row :gutter="24" class="detail-grid">
|
||||
<el-col :span="8"
|
||||
><div class="detail-item">
|
||||
<span class="label">一级佣金:</span
|
||||
><span class="value"
|
||||
>{{ detailData.one_brokerage || '0.00' }} | {{ detailData.spread_uid || '0' }}</span
|
||||
>
|
||||
</div></el-col
|
||||
>
|
||||
<el-col :span="8"
|
||||
><div class="detail-item">
|
||||
<span class="label">二级佣金:</span
|
||||
><span class="value"
|
||||
>{{ detailData.two_brokerage || '0.00' }} | {{ detailData.spread_two_uid || '0' }}</span
|
||||
>
|
||||
</div></el-col
|
||||
>
|
||||
<el-col :span="8"
|
||||
><div class="detail-item">
|
||||
<span class="label">员工返佣:</span
|
||||
><span class="value"
|
||||
>{{ detailData.staff_brokerage || '0.00' }} | {{ detailData.staff_id || '0' }}</span
|
||||
>
|
||||
</div></el-col
|
||||
>
|
||||
<el-col :span="8"
|
||||
><div class="detail-item">
|
||||
<span class="label">代理商佣金:</span
|
||||
><span class="value"
|
||||
>{{ detailData.agent_brokerage || '0.00' }} | {{ detailData.agent_id || '0' }}</span
|
||||
>
|
||||
</div></el-col
|
||||
>
|
||||
<el-col :span="8"
|
||||
><div class="detail-item">
|
||||
<span class="label">事业部佣金:</span
|
||||
><span class="value"
|
||||
>{{ detailData.division_brokerage || '0.00' }} | {{ detailData.division_id || '0' }}</span
|
||||
>
|
||||
</div></el-col
|
||||
>
|
||||
</el-row>
|
||||
</div>
|
||||
|
||||
<div class="section" v-if="detailData.invoice && Object.keys(detailData.invoice).length">
|
||||
<div class="section-title">发票信息</div>
|
||||
<el-row :gutter="24" class="detail-grid">
|
||||
<el-col :span="8"
|
||||
><div class="detail-item">
|
||||
<span class="label">发票抬头:</span
|
||||
><span class="value">{{ detailData.invoice.name || '--' }}</span>
|
||||
</div></el-col
|
||||
>
|
||||
<el-col :span="8" v-if="detailData.invoice.header_type === 2 && detailData.invoice.type === 1"
|
||||
><div class="detail-item">
|
||||
<span class="label">企业税号:</span
|
||||
><span class="value">{{ detailData.invoice.duty_number || '--' }}</span>
|
||||
</div></el-col
|
||||
>
|
||||
<el-col :span="8"
|
||||
><div class="detail-item">
|
||||
<span class="label">开票状态:</span
|
||||
><span class="value">{{ detailData.invoice.is_invoice ? '已开票' : '未开票' }}</span>
|
||||
</div></el-col
|
||||
>
|
||||
</el-row>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<div class="section-title">买家留言</div>
|
||||
<el-row :gutter="24" class="detail-grid">
|
||||
<el-col :span="24"
|
||||
><div class="detail-item">
|
||||
<span class="value">{{ detailData.mark || '--' }}</span>
|
||||
</div></el-col
|
||||
>
|
||||
</el-row>
|
||||
</div>
|
||||
|
||||
<div class="section" v-if="detailData.custom_form && detailData.custom_form.length">
|
||||
<div class="section-title">表单信息</div>
|
||||
<el-row :gutter="24" class="detail-grid">
|
||||
<template v-for="(item, idx) in detailData.custom_form" :key="idx">
|
||||
<el-col :span="8" v-if="item.label !== 'img'">
|
||||
<div class="detail-item">
|
||||
<span class="label">{{ item.title }}:</span><span class="value">{{ item.value }}</span>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="24" v-else>
|
||||
<div class="detail-item">
|
||||
<span class="label">{{ item.title }}:</span>
|
||||
<span class="value">
|
||||
<img v-for="(img, i) in item.value" :key="i" :src="img" class="form-img" v-viewer />
|
||||
</span>
|
||||
</div>
|
||||
</el-col>
|
||||
</template>
|
||||
</el-row>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<div class="section-title">订单备注</div>
|
||||
<el-row :gutter="24" class="detail-grid">
|
||||
<el-col :span="24"
|
||||
><div class="detail-item">
|
||||
<span class="value">{{ detailData.remark || '--' }}</span>
|
||||
</div></el-col
|
||||
>
|
||||
</el-row>
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
|
||||
<el-tab-pane label="订单进度" name="timeline">
|
||||
<div class="tl-section" v-if="detailData.timeline && detailData.timeline.length">
|
||||
<el-timeline>
|
||||
<el-timeline-item
|
||||
v-for="(item, index) in detailData.timeline"
|
||||
:key="index"
|
||||
:timestamp="item.time"
|
||||
:color="index === 0 ? '#409eff' : '#e4e7ed'"
|
||||
>
|
||||
<span class="tl-title">{{ item.title }}</span>
|
||||
<span class="tl-desc">{{ item.desc }}</span>
|
||||
</el-timeline-item>
|
||||
</el-timeline>
|
||||
</div>
|
||||
<div v-else class="empty-tips">暂无订单进度</div>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</div>
|
||||
<div v-else-if="!detailLoading" class="empty-tip">
|
||||
<el-empty description="暂无订单数据"></el-empty>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed, onMounted, ref } from 'vue';
|
||||
import { useRoute } from 'vue-router';
|
||||
import { ElMessage } from 'element-plus';
|
||||
import __asset_order_icon_0 from '@/assets/images/order_icon.png';
|
||||
|
||||
import request from '@/libs/request';
|
||||
|
||||
defineOptions({ name: 'cardkeyOrderDetail' });
|
||||
|
||||
const route = useRoute();
|
||||
|
||||
const detailData = ref(null);
|
||||
const detailLoading = ref(false);
|
||||
const activeTab = ref('detail');
|
||||
const orderIcon = __asset_order_icon_0;
|
||||
|
||||
const orderItems = computed(() => {
|
||||
if (!detailData.value) return [];
|
||||
return detailData.value.order_items || detailData.value.cartInfo || [];
|
||||
});
|
||||
|
||||
function loadDetail() {
|
||||
const orderNo = route.params.orderNo;
|
||||
if (!orderNo) return;
|
||||
detailLoading.value = true;
|
||||
request
|
||||
.get('cardkey/order/' + orderNo)
|
||||
.then((res) => {
|
||||
detailData.value = res.data;
|
||||
detailLoading.value = false;
|
||||
})
|
||||
.catch((res) => {
|
||||
detailLoading.value = false;
|
||||
ElMessage.error(res.msg || '加载订单详情失败');
|
||||
});
|
||||
}
|
||||
function copyCardKey(key) {
|
||||
if (!key) return;
|
||||
const input = document.createElement('input');
|
||||
input.value = key;
|
||||
document.body.appendChild(input);
|
||||
input.select();
|
||||
document.execCommand('copy');
|
||||
document.body.removeChild(input);
|
||||
ElMessage.success('复制成功');
|
||||
}
|
||||
function getStatusLabel(code) {
|
||||
const map = {
|
||||
pending_payment: '待支付',
|
||||
processing: '待处理',
|
||||
completed: '已完成',
|
||||
canceled: '已取消',
|
||||
refunding: '退款中',
|
||||
refunded: '已退款',
|
||||
};
|
||||
return map[code] || code || '--';
|
||||
}
|
||||
// 原 filters.payType
|
||||
function payType(val) {
|
||||
const obj = {
|
||||
yue: '余额',
|
||||
weixin: '微信支付',
|
||||
alipay: '支付宝支付',
|
||||
offline: '线下支付',
|
||||
balance: '余额支付',
|
||||
integral: '积分支付',
|
||||
};
|
||||
return obj[val] || val || '--';
|
||||
}
|
||||
function formatDate(ts) {
|
||||
if (!ts) return '--';
|
||||
const d = new Date(ts * 1000);
|
||||
return `${d.getFullYear()}/${(d.getMonth() + 1).toString().padStart(2, '0')}/${d
|
||||
.getDate()
|
||||
.toString()
|
||||
.padStart(2, '0')} ${d.getHours().toString().padStart(2, '0')}:${d.getMinutes().toString().padStart(2, '0')}:${d
|
||||
.getSeconds()
|
||||
.toString()
|
||||
.padStart(2, '0')}`;
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
loadDetail();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
:deep(.el-tabs--border-card > .el-tabs__header .el-tabs__item.is-active) {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
:deep(.el-tabs__item) {
|
||||
height: 40px !important;
|
||||
line-height: 40px !important;
|
||||
}
|
||||
|
||||
.head {
|
||||
padding: 0 30px 24px;
|
||||
|
||||
.full {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.order_icon {
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
}
|
||||
|
||||
.text {
|
||||
align-self: center;
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
padding-left: 12px;
|
||||
font-size: 13px;
|
||||
color: #606266;
|
||||
|
||||
.title {
|
||||
margin-bottom: 10px;
|
||||
font-weight: 500;
|
||||
font-size: 16px;
|
||||
line-height: 16px;
|
||||
color: rgba(0, 0, 0, 0.85);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.list {
|
||||
display: flex;
|
||||
margin-top: 20px;
|
||||
overflow: hidden;
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
|
||||
.item {
|
||||
flex: none;
|
||||
width: 200px;
|
||||
font-size: 14px;
|
||||
line-height: 14px;
|
||||
color: rgba(0, 0, 0, 0.85);
|
||||
|
||||
.title {
|
||||
margin-bottom: 12px;
|
||||
font-size: 13px;
|
||||
line-height: 13px;
|
||||
color: #666666;
|
||||
}
|
||||
|
||||
.value1 {
|
||||
color: #f56022;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.el-tabs--border-card > .el-tabs__content) {
|
||||
padding: 0 35px;
|
||||
}
|
||||
|
||||
:deep(.el-tabs--border-card > .el-tabs__header),
|
||||
:deep(.el-tabs--border-card > .el-tabs__header .el-tabs__item:active) {
|
||||
border: none;
|
||||
height: 40px;
|
||||
}
|
||||
|
||||
:deep(.el-tabs--border-card > .el-tabs__header .el-tabs__item.is-active) {
|
||||
border: none;
|
||||
border-top: 2px solid var(--prev-color-primary);
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
color: #303133;
|
||||
line-height: 16px;
|
||||
}
|
||||
|
||||
:deep(.el-tabs--border-card > .el-tabs__header .el-tabs__item) {
|
||||
border: none;
|
||||
}
|
||||
|
||||
:deep(.el-tabs--border-card > .el-tabs__header .el-tabs__item) {
|
||||
margin-top: 0;
|
||||
transition: none;
|
||||
height: 40px !important;
|
||||
line-height: 40px !important;
|
||||
width: 92px !important;
|
||||
font-size: 13px;
|
||||
font-weight: 400;
|
||||
color: #303133;
|
||||
line-height: 16px;
|
||||
}
|
||||
|
||||
:deep(.el-tabs--border-card) {
|
||||
border: none;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.section {
|
||||
padding: 20px 0;
|
||||
border-bottom: 1px dashed #eee;
|
||||
}
|
||||
.section:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
.section-title {
|
||||
padding-left: 10px;
|
||||
border-left: 3px solid var(--prev-color-primary, #1890ff);
|
||||
font-size: 15px;
|
||||
font-weight: 500;
|
||||
color: #303133;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.detail-grid {
|
||||
padding: 0;
|
||||
}
|
||||
.detail-item {
|
||||
display: flex;
|
||||
padding: 8px 0;
|
||||
font-size: 13px;
|
||||
color: #666;
|
||||
}
|
||||
.detail-item .label {
|
||||
flex-shrink: 0;
|
||||
color: #909399;
|
||||
margin-right: 4px;
|
||||
}
|
||||
.detail-item .value {
|
||||
flex: 1;
|
||||
word-break: break-all;
|
||||
}
|
||||
.price-label {
|
||||
color: #ed4014 !important;
|
||||
}
|
||||
.price-value {
|
||||
color: #ed4014;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.goods-table {
|
||||
border: 1px solid #ebeef5;
|
||||
border-radius: 4px;
|
||||
}
|
||||
.goods-cell {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
.goods-img {
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
border-radius: 4px;
|
||||
margin-right: 12px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.goods-meta {
|
||||
min-width: 0;
|
||||
}
|
||||
.goods-name {
|
||||
margin: 0;
|
||||
font-size: 13px;
|
||||
color: #303133;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.goods-sku {
|
||||
margin: 2px 0 0;
|
||||
font-size: 12px;
|
||||
color: #909399;
|
||||
}
|
||||
|
||||
.card-key-wrapper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
.card-key {
|
||||
font-family: monospace;
|
||||
font-size: 12px;
|
||||
color: #303133;
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.form-img {
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
object-fit: cover;
|
||||
margin-right: 8px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.tl-section {
|
||||
padding: 16px 0;
|
||||
}
|
||||
:deep(.el-timeline-item__content .tl-title) {
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
color: #303133;
|
||||
}
|
||||
:deep(.el-timeline-item__content .tl-desc) {
|
||||
margin-left: 8px;
|
||||
font-size: 12px;
|
||||
color: #909399;
|
||||
}
|
||||
|
||||
.empty-tip {
|
||||
padding: 40px;
|
||||
}
|
||||
.empty-tips {
|
||||
padding: 20px 0;
|
||||
color: #909399;
|
||||
font-size: 13px;
|
||||
}
|
||||
</style>
|
||||
@ -1,194 +0,0 @@
|
||||
<template>
|
||||
<div class="cardkey-order-list">
|
||||
<el-card :bordered="false" shadow="never" :body-style="{ padding: 0 }">
|
||||
<div class="padding-add">
|
||||
<el-form :inline="true" @submit.prevent="onSearch">
|
||||
<el-form-item label="订单号">
|
||||
<el-input
|
||||
v-model="search.keyword"
|
||||
placeholder="请输入订单号/收货人/电话"
|
||||
clearable
|
||||
@keyup.enter="onSearch"
|
||||
style="width: 220px"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="订单状态">
|
||||
<el-select v-model="search.status_code" placeholder="全部" clearable style="width: 120px">
|
||||
<el-option label="待支付" value="pending_payment" />
|
||||
<el-option label="待发货" value="pending_delivery" />
|
||||
<el-option label="已发货" value="delivered" />
|
||||
<el-option label="已完成" value="completed" />
|
||||
<el-option label="已取消" value="canceled" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="onSearch">查询</el-button>
|
||||
<el-button @click="onReset">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
</el-card>
|
||||
|
||||
<el-card :bordered="false" shadow="never" class="ivu-mt mt16" :body-style="{ padding: '20px 20px 20px' }">
|
||||
<el-table :data="list" v-loading="loading" stripe empty-text="暂无订单数据" row-key="id">
|
||||
<el-table-column label="订单号" min-width="180" prop="order_no" show-overflow-tooltip />
|
||||
<el-table-column label="商品" min-width="220">
|
||||
<template #default="{ row }">
|
||||
<div class="goods-cell">
|
||||
<el-image v-if="row.image" :src="row.image" class="goods-img" />
|
||||
<span class="goods-name">{{ row.title || '-' }}</span>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="商品总价" width="100">
|
||||
<template #default="{ row }">{{ row.total_price || '0.00' }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="实付金额" width="100">
|
||||
<template #default="{ row }">
|
||||
<span class="pay-price">{{ row.pay_price || '0.00' }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="订单状态" width="110">
|
||||
<template #default="{ row }">
|
||||
<el-tag :type="getStatusType(row.status_code)">{{ getStatusText(row.status_code) }}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="支付状态" width="100">
|
||||
<template #default="{ row }">
|
||||
<el-tag :type="row.pay_status == 1 ? 'success' : 'info'">{{
|
||||
row.pay_status == 1 ? '已支付' : '未支付'
|
||||
}}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="下单时间" width="160">
|
||||
<template #default="{ row }">{{ formatDate(row.add_time) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="100" fixed="right">
|
||||
<template #default="{ row }">
|
||||
<a v-db-click @click="goDetail(row.order_no)">详情</a>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<div class="acea-row row-right page">
|
||||
<pagination
|
||||
v-if="total"
|
||||
:total="total"
|
||||
v-model:page="search.page"
|
||||
v-model:limit="search.limit"
|
||||
@pagination="loadList"
|
||||
/>
|
||||
</div>
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { onMounted, ref } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { ElMessage } from 'element-plus';
|
||||
import { cardkeyOrderList } from '../cardkeyProduct';
|
||||
import setting from '@/setting';
|
||||
|
||||
defineOptions({ name: 'cardkeyOrderList' });
|
||||
|
||||
const router = useRouter();
|
||||
const routePre = setting.routePre;
|
||||
|
||||
const loading = ref(false);
|
||||
const list = ref([]);
|
||||
const total = ref(0);
|
||||
const search = ref({ page: 1, limit: 15, keyword: '', status_code: '' });
|
||||
|
||||
async function loadList() {
|
||||
loading.value = true;
|
||||
try {
|
||||
const params = { page: search.value.page, limit: search.value.limit };
|
||||
if (search.value.keyword) params.keyword = search.value.keyword;
|
||||
if (search.value.status_code) params.status_code = search.value.status_code;
|
||||
const res = await cardkeyOrderList(params);
|
||||
const data = res.data || {};
|
||||
list.value = data.list || data.data || [];
|
||||
total.value = data.count || data.total || 0;
|
||||
} catch (e) {
|
||||
ElMessage.error(e.message || '获取订单列表失败');
|
||||
}
|
||||
loading.value = false;
|
||||
}
|
||||
function onSearch() {
|
||||
search.value.page = 1;
|
||||
loadList();
|
||||
}
|
||||
function onReset() {
|
||||
search.value = { page: 1, limit: 15, keyword: '', status_code: '' };
|
||||
loadList();
|
||||
}
|
||||
function goDetail(orderNo) {
|
||||
router.push({ path: routePre + '/product/cardkey/order/detail/' + orderNo });
|
||||
}
|
||||
function getStatusText(status) {
|
||||
const map = {
|
||||
pending_payment: '待支付',
|
||||
pending_delivery: '待发货',
|
||||
delivered: '已发货',
|
||||
completed: '已完成',
|
||||
canceled: '已取消',
|
||||
refunding: '退款中',
|
||||
refunded: '已退款',
|
||||
};
|
||||
return map[status] || status || '-';
|
||||
}
|
||||
function getStatusType(status) {
|
||||
const map = {
|
||||
pending_payment: 'warning',
|
||||
pending_delivery: 'primary',
|
||||
delivered: 'primary',
|
||||
completed: 'success',
|
||||
canceled: 'info',
|
||||
refunding: 'warning',
|
||||
refunded: 'danger',
|
||||
};
|
||||
return map[status] || '';
|
||||
}
|
||||
function formatDate(ts) {
|
||||
if (!ts) return '--';
|
||||
const d = new Date(ts * 1000);
|
||||
const y = d.getFullYear();
|
||||
const M = ('0' + (d.getMonth() + 1)).slice(-2);
|
||||
const day = ('0' + d.getDate()).slice(-2);
|
||||
const h = ('0' + d.getHours()).slice(-2);
|
||||
const m = ('0' + d.getMinutes()).slice(-2);
|
||||
return y + '-' + M + '-' + day + ' ' + h + ':' + m;
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
loadList();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.mt16 {
|
||||
margin-top: 16px;
|
||||
}
|
||||
.goods-cell {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
.goods-img {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border-radius: 4px;
|
||||
margin-right: 8px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.goods-name {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
font-size: 13px;
|
||||
}
|
||||
.pay-price {
|
||||
color: #f56022;
|
||||
font-weight: bold;
|
||||
}
|
||||
</style>
|
||||
@ -1,123 +0,0 @@
|
||||
/**
|
||||
* 卡密商品路由(UMD 扩展模式)
|
||||
* 页面通过 PageContainer 运行时加载 UMD 扩展包(/admin/static/extensions/cardkey/),
|
||||
* 主构建不再打包页面源码;扩展未安装(UMD 缺失)时页面显示"扩展未安装"。
|
||||
* 路由参数(:id? / :orderNo)由子页面从 $route.params 自行读取。
|
||||
*/
|
||||
import setting from '@/setting';
|
||||
const routePre = setting.routePre;
|
||||
const pre = 'product_';
|
||||
|
||||
const pageContainer = () => import('@/pages/system/plugin/PageContainer');
|
||||
|
||||
export default [
|
||||
{
|
||||
path: routePre + '/product/cardkey/list',
|
||||
meta: {
|
||||
auth: ['admin-cardkey-product-list'],
|
||||
title: '卡密商品',
|
||||
keepAlive: true,
|
||||
},
|
||||
component: () => import('@/layout'),
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
name: `${pre}cardkeyProductList`,
|
||||
component: pageContainer,
|
||||
props: { typeKey: 'cardkey', section: 'cardkey', action: 'list' },
|
||||
meta: {
|
||||
auth: ['admin-cardkey-product-list'],
|
||||
title: '卡密商品',
|
||||
keepAlive: true,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: routePre + '/product/cardkey/add',
|
||||
name: `${pre}cardkeyProductAdd`,
|
||||
meta: {
|
||||
auth: ['admin-cardkey-product-add'],
|
||||
title: '添加商品',
|
||||
},
|
||||
component: () => import('@/layout'),
|
||||
children: [
|
||||
{
|
||||
path: ':id?',
|
||||
name: `${pre}cardkeyProductAddId`,
|
||||
component: pageContainer,
|
||||
props: { typeKey: 'cardkey', section: 'cardkey', action: 'add' },
|
||||
meta: {
|
||||
auth: ['admin-cardkey-product-add'],
|
||||
title: '添加商品',
|
||||
activeMenu: routePre + '/product/cardkey/list',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: routePre + '/product/cardkey/stock/list',
|
||||
meta: {
|
||||
auth: ['admin-cardkey-stock-list'],
|
||||
title: '卡密库存',
|
||||
keepAlive: true,
|
||||
},
|
||||
component: () => import('@/layout'),
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
name: `${pre}cardkeyStockList`,
|
||||
component: pageContainer,
|
||||
props: { typeKey: 'cardkey', section: 'cardkey', action: 'stock' },
|
||||
meta: {
|
||||
auth: ['admin-cardkey-stock-list'],
|
||||
title: '卡密库存',
|
||||
keepAlive: true,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: routePre + '/product/cardkey/order/list',
|
||||
meta: {
|
||||
auth: ['admin-cardkey-order-list'],
|
||||
title: '订单管理',
|
||||
keepAlive: true,
|
||||
},
|
||||
component: () => import('@/layout'),
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
name: `${pre}cardkeyOrderList`,
|
||||
component: pageContainer,
|
||||
props: { typeKey: 'cardkey', section: 'cardkey', action: 'order' },
|
||||
meta: {
|
||||
auth: ['admin-cardkey-order-list'],
|
||||
title: '订单管理',
|
||||
keepAlive: true,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: routePre + '/product/cardkey/order/detail/:orderNo',
|
||||
meta: {
|
||||
auth: ['admin-cardkey-order-list'],
|
||||
title: '订单详情',
|
||||
},
|
||||
component: () => import('@/layout'),
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
name: `${pre}cardkeyOrderDetail`,
|
||||
component: pageContainer,
|
||||
props: { typeKey: 'cardkey', section: 'cardkey', action: 'order_detail' },
|
||||
meta: {
|
||||
auth: ['admin-cardkey-order-list'],
|
||||
title: '订单详情',
|
||||
activeMenu: routePre + '/product/cardkey/order/list',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
@ -1,248 +0,0 @@
|
||||
<template>
|
||||
<div class="cardkey-stock">
|
||||
<el-card :bordered="false" shadow="never" :body-style="{ padding: 0 }">
|
||||
<div class="padding-add">
|
||||
<el-form :inline="true" @submit.prevent="onSearch">
|
||||
<el-form-item label="商品名称">
|
||||
<el-input
|
||||
v-model="search.store_name"
|
||||
placeholder="请输入商品名称/关键字/ID"
|
||||
clearable
|
||||
@keyup.enter="onSearch"
|
||||
style="width: 220px"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="onSearch">查询</el-button>
|
||||
<el-button @click="onReset">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
</el-card>
|
||||
|
||||
<el-card :bordered="false" shadow="never" class="ivu-mt mt16" :body-style="{ padding: '20px 20px 20px' }">
|
||||
<el-table :data="list" v-loading="loading" stripe empty-text="暂无商品数据" row-key="id">
|
||||
<el-table-column label="商品ID" width="80" prop="id" />
|
||||
<el-table-column label="商品图" width="90">
|
||||
<template #default="{ row }">
|
||||
<div class="tabBox_img" v-viewer>
|
||||
<img v-lazy="row.image" />
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="商品名称" min-width="220">
|
||||
<template #default="{ row }">
|
||||
<span>{{ row.store_name }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="卡密类型" width="110">
|
||||
<template #default="{ row }">
|
||||
<span>{{ row.card_type === 'single' ? '单卡密' : '组合卡密' }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="卡密库存" width="110">
|
||||
<template #default="{ row }">
|
||||
<el-tag :type="(row.card_count || 0) > 0 ? 'success' : 'danger'"> {{ row.card_count || 0 }} 张 </el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="商品售价" width="100">
|
||||
<template #default="{ row }">{{ row.price }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="160" fixed="right">
|
||||
<template #default="{ row }">
|
||||
<a v-db-click @click="openCard(row)">卡密管理</a>
|
||||
<a v-db-click @click="openImport(row)">导入卡密</a>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<div class="acea-row row-right page">
|
||||
<pagination
|
||||
v-if="total"
|
||||
:total="total"
|
||||
v-model:page="search.page"
|
||||
v-model:limit="search.limit"
|
||||
@pagination="loadList"
|
||||
/>
|
||||
</div>
|
||||
</el-card>
|
||||
|
||||
<!-- 卡密列表弹窗 -->
|
||||
<el-dialog v-model="cardDialog" title="卡密库存明细" width="720px" :close-on-click-modal="false">
|
||||
<el-table :data="cardList" v-loading="cardLoading" stripe empty-text="暂无卡密,请先导入">
|
||||
<el-table-column label="ID" width="70" prop="id" />
|
||||
<el-table-column label="卡号" min-width="160">
|
||||
<template #default="{ row }">{{ row.card_content || '--' }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="卡密" min-width="160">
|
||||
<template #default="{ row }">{{ row.card_password || '--' }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="状态" width="100">
|
||||
<template #default="{ row }">
|
||||
<el-tag :type="getCardStatusType(row.status)">{{ getCardStatusText(row.status) }}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="关联订单" width="180">
|
||||
<template #default="{ row }">{{ row.order_no || '--' }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="发放时间" width="160">
|
||||
<template #default="{ row }">{{ row.sent_time ? formatDate(row.sent_time) : '--' }}</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 导入卡密弹窗 -->
|
||||
<el-dialog
|
||||
v-model="importDialog"
|
||||
:title="'导入卡密 - ' + (currentProduct ? currentProduct.store_name : '')"
|
||||
width="640px"
|
||||
:close-on-click-modal="false"
|
||||
>
|
||||
<el-alert
|
||||
type="info"
|
||||
show-icon
|
||||
:closable="false"
|
||||
title="每行一张卡密,格式:卡号,卡密(英文逗号分隔)"
|
||||
style="margin-bottom: 16px"
|
||||
/>
|
||||
<el-input
|
||||
type="textarea"
|
||||
v-model="importText"
|
||||
:rows="10"
|
||||
placeholder="例如: CARD001,ABC123456 CARD002,DEF789012"
|
||||
/>
|
||||
<template #footer
|
||||
><span class="dialog-footer">
|
||||
<el-button @click="importDialog = false">取 消</el-button>
|
||||
<el-button type="primary" :loading="importLoading" @click="submitImport">确 定</el-button>
|
||||
</span></template
|
||||
>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { onMounted, ref } from 'vue';
|
||||
import { ElMessage } from 'element-plus';
|
||||
import { cardkeyProductList, cardkeyProductCardList, cardkeyProductImportCard } from '../cardkeyProduct';
|
||||
|
||||
defineOptions({ name: 'cardkeyStockList' });
|
||||
|
||||
const loading = ref(false);
|
||||
const list = ref([]);
|
||||
const total = ref(0);
|
||||
const search = ref({ page: 1, limit: 15, store_name: '' });
|
||||
const cardDialog = ref(false);
|
||||
const cardLoading = ref(false);
|
||||
const cardList = ref([]);
|
||||
const currentProduct = ref(null);
|
||||
const importDialog = ref(false);
|
||||
const importLoading = ref(false);
|
||||
const importText = ref('');
|
||||
|
||||
async function loadList() {
|
||||
loading.value = true;
|
||||
try {
|
||||
const params = { page: search.value.page, limit: search.value.limit };
|
||||
if (search.value.store_name) params.store_name = search.value.store_name;
|
||||
const res = await cardkeyProductList(params);
|
||||
const data = res.data || {};
|
||||
list.value = data.list || [];
|
||||
total.value = data.count || 0;
|
||||
} catch (e) {
|
||||
ElMessage.error(e.message || '获取商品列表失败');
|
||||
}
|
||||
loading.value = false;
|
||||
}
|
||||
function onSearch() {
|
||||
search.value.page = 1;
|
||||
loadList();
|
||||
}
|
||||
function onReset() {
|
||||
search.value = { page: 1, limit: 15, store_name: '' };
|
||||
loadList();
|
||||
}
|
||||
function openCard(row) {
|
||||
currentProduct.value = row;
|
||||
cardDialog.value = true;
|
||||
cardLoading.value = true;
|
||||
cardkeyProductCardList(row.id)
|
||||
.then((res) => {
|
||||
cardList.value = res.data || [];
|
||||
})
|
||||
.catch((e) => {
|
||||
ElMessage.error(e.message || '获取卡密列表失败');
|
||||
})
|
||||
.finally(() => {
|
||||
cardLoading.value = false;
|
||||
});
|
||||
}
|
||||
function openImport(row) {
|
||||
currentProduct.value = row;
|
||||
importText.value = '';
|
||||
importDialog.value = true;
|
||||
}
|
||||
async function submitImport() {
|
||||
const lines = importText.value
|
||||
.split('\n')
|
||||
.map((line) => line.trim())
|
||||
.filter((line) => line !== '');
|
||||
if (!lines.length) {
|
||||
ElMessage.warning('请先输入卡密内容');
|
||||
return;
|
||||
}
|
||||
const cards = lines.map((line) => {
|
||||
// 支持 "卡号,卡密" 或仅 "卡密" 两种格式
|
||||
const parts = line.split(/[,,\s]+/).filter((p) => p !== '');
|
||||
return { card_content: parts[0] || '', card_password: parts[1] || parts[0] || '' };
|
||||
});
|
||||
importLoading.value = true;
|
||||
try {
|
||||
const res = await cardkeyProductImportCard(currentProduct.value.id, cards);
|
||||
ElMessage.success(res.msg || `导入成功,共导入${cards.length}条卡密`);
|
||||
importDialog.value = false;
|
||||
loadList();
|
||||
} catch (e) {
|
||||
ElMessage.error(e.message || '导入失败');
|
||||
}
|
||||
importLoading.value = false;
|
||||
}
|
||||
function getCardStatusText(status) {
|
||||
const map = { unused: '可用', reserved: '待支付预留', sent: '已发放', used: '已使用', recycled: '已回收' };
|
||||
return map[status] || status || '-';
|
||||
}
|
||||
function getCardStatusType(status) {
|
||||
const map = { unused: 'info', reserved: 'warning', sent: 'success', used: 'info', recycled: 'danger' };
|
||||
return map[status] || '';
|
||||
}
|
||||
function formatDate(ts) {
|
||||
if (!ts) return '--';
|
||||
const d = new Date(ts * 1000);
|
||||
const y = d.getFullYear();
|
||||
const M = ('0' + (d.getMonth() + 1)).slice(-2);
|
||||
const day = ('0' + d.getDate()).slice(-2);
|
||||
const h = ('0' + d.getHours()).slice(-2);
|
||||
const m = ('0' + d.getMinutes()).slice(-2);
|
||||
return y + '-' + M + '-' + day + ' ' + h + ':' + m;
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
loadList();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.mt16 {
|
||||
margin-top: 16px;
|
||||
}
|
||||
.tabBox_img {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
}
|
||||
.tabBox_img img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
@ -1,108 +0,0 @@
|
||||
/**
|
||||
* 渠道码模块 API
|
||||
*/
|
||||
import request from '@/libs/request';
|
||||
|
||||
/**
|
||||
* @description 渠道码分类列表
|
||||
*/
|
||||
export function wechatQrcodeTree() {
|
||||
return request({
|
||||
url: `marketing/channel_code/cate/list`,
|
||||
method: 'get',
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 获取渠道码创建、编辑分类表单
|
||||
*/
|
||||
export function wechatQrcodeCreate(id) {
|
||||
return request({
|
||||
url: `marketing/channel_code/cate/create/${id}`,
|
||||
method: 'get',
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 获取渠道码列表
|
||||
*/
|
||||
export function wechatQrcodeList(params) {
|
||||
return request({
|
||||
url: `marketing/channel_code/list`,
|
||||
method: 'GET',
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 渠道码修改状态
|
||||
*/
|
||||
export function wechatQrcodeStatusApi(data) {
|
||||
return request({
|
||||
url: `marketing/channel_code/set_status/${data.id}/${data.status}`,
|
||||
method: 'PUT',
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 获取渠道码用户列表
|
||||
*/
|
||||
export function getUserList(params) {
|
||||
return request({
|
||||
url: `marketing/channel_code/user_list/${params.id}`,
|
||||
method: 'get',
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 获取渠道码详情
|
||||
*/
|
||||
export function wechatQrcodeDetail(id) {
|
||||
return request({
|
||||
url: `marketing/channel_code/info/${id}`,
|
||||
method: 'get',
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 渠道码保存
|
||||
*/
|
||||
export function wechatQrcodeSaveApi(id, data) {
|
||||
return request({
|
||||
url: `marketing/channel_code/save/${id}`,
|
||||
method: 'POST',
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 渠道码统计
|
||||
*/
|
||||
export function wechatQrcodeStatistic(id, params) {
|
||||
return request({
|
||||
url: `marketing/channel_code/statistic/${id}`,
|
||||
method: 'GET',
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 删除渠道码分类
|
||||
*/
|
||||
export function wechatQrcodeCateDelApi(id) {
|
||||
return request({
|
||||
url: `marketing/channel_code/cate/del/${id}`,
|
||||
method: 'DELETE',
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 删除渠道码
|
||||
*/
|
||||
export function wechatQrcodeDelApi(id) {
|
||||
return request({
|
||||
url: `marketing/channel_code/del/${id}`,
|
||||
method: 'DELETE',
|
||||
});
|
||||
}
|
||||
@ -1,10 +0,0 @@
|
||||
{
|
||||
"key": "channel_code",
|
||||
"title": "渠道码",
|
||||
"version": "1.0.0",
|
||||
"pages": [
|
||||
{ "path": "channelCodeIndex", "title": "渠道码管理" },
|
||||
{ "path": "createCode", "title": "创建渠道码" },
|
||||
{ "path": "codeStatistic", "title": "渠道码统计" }
|
||||
]
|
||||
}
|
||||
@ -1,609 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-row class="ivu-mt box-wrapper">
|
||||
<el-col :span="4" class="left-wrapper">
|
||||
<div class="tree_tit" v-db-click @click="addSort">
|
||||
<i class="el-icon-circle-plus"></i>
|
||||
添加分组
|
||||
</div>
|
||||
<div class="tree">
|
||||
<el-tree
|
||||
:data="labelSort"
|
||||
node-key="id"
|
||||
default-expand-all
|
||||
highlight-current
|
||||
:expand-on-click-node="false"
|
||||
@node-click="bindMenuItem"
|
||||
:current-node-key="treeId"
|
||||
>
|
||||
<template #default="{ data }"
|
||||
><span class="custom-tree-node">
|
||||
<div class="file-name">
|
||||
<img v-if="!data.pid" class="icon" src="../../../../assets/images/file.jpg" />
|
||||
<el-tooltip class="item" effect="dark" :content="data.cate_name" placement="top">
|
||||
<div class="text line1">
|
||||
{{ data.cate_name }}
|
||||
</div>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
<span v-if="data.id">
|
||||
<el-dropdown @command="(command) => clickMenu(data, command)">
|
||||
<i class="el-icon-more el-icon--right"></i>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item command="1">编辑分组</el-dropdown-item>
|
||||
<el-dropdown-item v-if="data.id" command="2">删除分组</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
</span>
|
||||
</span></template
|
||||
>
|
||||
</el-tree>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="20">
|
||||
<el-card :bordered="false" shadow="never" class="left-radius-none">
|
||||
<el-row class="action-row mb14">
|
||||
<el-col :span="18">
|
||||
<el-button v-auth="['marketing-channel_code-create']" type="primary" v-db-click @click="add"
|
||||
>新建渠道码</el-button
|
||||
>
|
||||
<!-- <el-button v-auth="['marketing-channel_code-create']" type="success" v-db-click @click="addSort">添加分组</el-button> -->
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<div class="flex">
|
||||
<el-input class="mr10" v-model="tableFrom.name" search placeholder="请输入渠道码名称"> </el-input>
|
||||
<el-button type="primary" v-db-click @click="userSearchs">搜索</el-button>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-table
|
||||
:data="tableList"
|
||||
v-loading="loading"
|
||||
highlight-current-row
|
||||
no-userFrom-text="暂无数据"
|
||||
no-filtered-userFrom-text="暂无筛选结果"
|
||||
>
|
||||
<el-table-column label="渠道码" width="80">
|
||||
<template #default="scope">
|
||||
<div class="tabBox_img" v-viewer>
|
||||
<img v-lazy="scope.row.image" />
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="渠道码名称" min-width="80">
|
||||
<template #default="scope">
|
||||
<span>{{ scope.row.name }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="总关注数" min-width="80">
|
||||
<template #default="scope">
|
||||
<span>{{ scope.row.follow }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="昨日新增关注" min-width="80">
|
||||
<template #default="scope">
|
||||
<span>{{ scope.row.y_follow }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="用户标签" min-width="80">
|
||||
<template #default="scope">
|
||||
<el-tag class="label-name" v-for="(item, index) in scope.row.label_name" :key="index">{{
|
||||
item
|
||||
}}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="时间" min-width="80">
|
||||
<template #default="scope">
|
||||
<span v-if="scope.row.stop === 0"> 永久 </span>
|
||||
<span v-if="scope.row.stop === 1">
|
||||
<div>{{ scope.row.add_time }}</div>
|
||||
<div>-</div>
|
||||
<div>{{ scope.row.end_time }}</div>
|
||||
</span>
|
||||
<span v-if="scope.row.stop === -1">已过期</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="关联推广员" min-width="80">
|
||||
<template #default="scope">
|
||||
<div class="tabBox_img" v-viewer>
|
||||
<img v-lazy="scope.row.avatar" />
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="状态" min-width="80">
|
||||
<template #default="scope">
|
||||
<el-switch
|
||||
class="defineSwitch"
|
||||
:active-value="1"
|
||||
:inactive-value="0"
|
||||
v-model="scope.row.status"
|
||||
:value="scope.row.status"
|
||||
:disabled="scope.row.lottery_status == 2 ? true : false"
|
||||
@change="onchangeIsShow(scope.row)"
|
||||
size="large"
|
||||
active-text="开启"
|
||||
inactive-text="关闭"
|
||||
>
|
||||
</el-switch>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" fixed="right" width="170">
|
||||
<template #default="scope">
|
||||
<a v-db-click @click="edit(scope.row)">编辑</a>
|
||||
<el-divider direction="vertical"></el-divider>
|
||||
<a v-db-click @click="del(scope.row, '删除二维码', scope.$index)">删除</a>
|
||||
<el-divider direction="vertical"></el-divider>
|
||||
<el-dropdown @command="changeMenu(scope.row, $event)" :transfer="true">
|
||||
<span class="el-dropdown-link">更多<i class="el-icon-arrow-down el-icon--right"></i> </span>
|
||||
<template #dropdown
|
||||
><el-dropdown-menu>
|
||||
<el-dropdown-item command="1">下载</el-dropdown-item>
|
||||
<el-dropdown-item command="2">统计</el-dropdown-item>
|
||||
<el-dropdown-item command="3">用户列表</el-dropdown-item>
|
||||
</el-dropdown-menu></template
|
||||
>
|
||||
</el-dropdown>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<div class="acea-row row-right page">
|
||||
<pagination
|
||||
v-if="total"
|
||||
:total="total"
|
||||
v-model:page="tableFrom.page"
|
||||
v-model:limit="tableFrom.limit"
|
||||
@pagination="getList"
|
||||
/>
|
||||
</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-dialog v-model="modals" title="渠道码用户列表" :close-on-click-modal="false" width="900px">
|
||||
<el-table :data="tabList" empty-text="暂无数据" highlight-current-row max-height="400">
|
||||
<el-table-column label="UID" min-width="120">
|
||||
<template #default="scope">
|
||||
<span>{{ scope.row.uid }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="用户头像" min-width="120">
|
||||
<template #default="scope">
|
||||
<div class="tabBox_img" v-viewer>
|
||||
<img v-lazy="scope.row.avatar" />
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="用户昵称" min-width="120">
|
||||
<template #default="scope">
|
||||
<span>{{ scope.row.nickname }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<div class="acea-row row-right page">
|
||||
<pagination
|
||||
v-if="total2"
|
||||
:total="total2"
|
||||
v-model:page="userData.page"
|
||||
v-model:limit="userData.limit"
|
||||
@pagination="getUserList"
|
||||
/>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed, onActivated, onMounted, ref } from 'vue';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { ElMessage } from 'element-plus';
|
||||
import {
|
||||
wechatQrcodeList,
|
||||
wechatQrcodeCreate,
|
||||
wechatQrcodeTree,
|
||||
wechatQrcodeStatusApi,
|
||||
getUserList as getUserListApi,
|
||||
wechatQrcodeCateDelApi,
|
||||
wechatQrcodeDelApi,
|
||||
} from './../api';
|
||||
import { scrollTop } from '@/libs/util';
|
||||
import modalForm from '@/utils/modalForm';
|
||||
import { modalSure } from '@/utils/public';
|
||||
import setting from '@/setting';
|
||||
import { useMediaStore } from '@/store/module/media';
|
||||
|
||||
defineOptions({ name: 'marketing_channel_code' });
|
||||
|
||||
const router = useRouter();
|
||||
const routePre = setting.routePre;
|
||||
const { isMobile } = storeToRefs(useMediaStore());
|
||||
|
||||
const labelWidth = computed(() => (isMobile.value ? undefined : '80px'));
|
||||
const labelPosition = computed(() => (isMobile.value ? 'top' : 'right'));
|
||||
|
||||
const treeId = ref('');
|
||||
const isChat = true;
|
||||
const formValidate3 = ref({
|
||||
page: 1,
|
||||
limit: 15,
|
||||
});
|
||||
const total3 = ref(0);
|
||||
const loading3 = ref(false);
|
||||
const modals3 = ref(false);
|
||||
const tabList = ref([]);
|
||||
const formValidate5 = ref({
|
||||
page: 1,
|
||||
limit: 15,
|
||||
uid: 0,
|
||||
to_uid: 0,
|
||||
id: 0,
|
||||
});
|
||||
const tableList5 = ref([]);
|
||||
const FromData = ref(null);
|
||||
const formValidate = ref({
|
||||
page: 1,
|
||||
limit: 15,
|
||||
data: '',
|
||||
type: '',
|
||||
nickname: '',
|
||||
});
|
||||
const tableList2 = ref([]);
|
||||
const modals = ref(false);
|
||||
const total = ref(0);
|
||||
const tableFrom = ref({
|
||||
page: 1,
|
||||
limit: 15,
|
||||
cate_id: 0,
|
||||
name: '',
|
||||
});
|
||||
const userData = ref({
|
||||
id: 0,
|
||||
page: 1,
|
||||
limit: 15,
|
||||
});
|
||||
const timeVal = ref([]);
|
||||
const loading = ref(false);
|
||||
const tableList = ref([]);
|
||||
const loading2 = ref(false);
|
||||
const total2 = ref(0);
|
||||
const addFrom = ref({
|
||||
uids: [],
|
||||
});
|
||||
const selections = ref([]);
|
||||
const rows = ref({});
|
||||
const rowRecord = ref({});
|
||||
const theme3 = 'light';
|
||||
const labelSort = ref([]);
|
||||
const sortName = ref('');
|
||||
const current = ref(0);
|
||||
const uid = ref(0);
|
||||
const orderId = ref(0);
|
||||
|
||||
// 原 filters:转为普通 function
|
||||
function typeFilter(status) {
|
||||
const statusMap = {
|
||||
wechat: '微信用户',
|
||||
routine: '小程序用户',
|
||||
};
|
||||
return statusMap[status];
|
||||
}
|
||||
|
||||
onActivated(() => {
|
||||
getUserLabelAll();
|
||||
});
|
||||
|
||||
onMounted(() => {
|
||||
getUserLabelAll();
|
||||
});
|
||||
|
||||
function changeMenu(row, name) {
|
||||
orderId.value = row.id;
|
||||
switch (name) {
|
||||
case '1':
|
||||
downLoadCode(row.image);
|
||||
break;
|
||||
case '2':
|
||||
// vue-router 4 中 path 内拼接的 query 会被丢弃,必须用 query 对象传递参数
|
||||
router.push({
|
||||
path: routePre + '/marketing/channel_code/code_statistic',
|
||||
query: { id: row.id },
|
||||
});
|
||||
break;
|
||||
case '3':
|
||||
modals.value = true;
|
||||
userData.value.id = row.id;
|
||||
getUserList();
|
||||
break;
|
||||
default:
|
||||
}
|
||||
}
|
||||
function downLoadCode(url) {
|
||||
if (!url) return ElMessage.warning('暂无二维码');
|
||||
var image = new Image();
|
||||
image.src = url;
|
||||
// 解决跨域 Canvas 污染问题
|
||||
image.setAttribute('crossOrigin', 'anonymous');
|
||||
image.onload = function () {
|
||||
var canvas = document.createElement('canvas');
|
||||
canvas.width = image.width;
|
||||
canvas.height = image.height;
|
||||
var context = canvas.getContext('2d');
|
||||
context.drawImage(image, 0, 0, image.width, image.height);
|
||||
|
||||
var url = canvas.toDataURL(); //得到图片的base64编码数据
|
||||
var a = document.createElement('a'); // 生成一个a元素
|
||||
var event = new MouseEvent('click'); // 创建一个单击事件
|
||||
a.download = name || 'photo'; // 设置图片名称
|
||||
a.href = url; // 将生成的URL设置为a.href属性
|
||||
a.dispatchEvent(event); // 触发a的单击事件
|
||||
};
|
||||
}
|
||||
// 获取渠道码用户列表
|
||||
function getUserList() {
|
||||
getUserListApi(userData.value)
|
||||
.then(async (res) => {
|
||||
let data = res.data;
|
||||
let arr = [];
|
||||
data.list.map((i) => {
|
||||
arr.push(i.user);
|
||||
});
|
||||
tabList.value = arr;
|
||||
total2.value = data.count;
|
||||
loading2.value = false;
|
||||
})
|
||||
.catch((res) => {
|
||||
loading.value = false;
|
||||
tabList.value = [];
|
||||
ElMessage.error(res.msg);
|
||||
});
|
||||
}
|
||||
|
||||
// 获取分组
|
||||
function getUserLabelAll(key) {
|
||||
wechatQrcodeTree().then((res) => {
|
||||
let data = res.data.data;
|
||||
let obj = {
|
||||
cate_name: '全部',
|
||||
id: '',
|
||||
};
|
||||
data.unshift(obj);
|
||||
data.forEach((el) => {
|
||||
el.status = false;
|
||||
});
|
||||
if (!key) {
|
||||
sortName.value = data[0].id;
|
||||
tableFrom.value.cate_id = data[0].id;
|
||||
getList();
|
||||
}
|
||||
labelSort.value = data;
|
||||
});
|
||||
}
|
||||
// 添加分类
|
||||
function addSort() {
|
||||
modalForm(wechatQrcodeCreate(0)).then(() => getUserLabelAll());
|
||||
}
|
||||
//编辑标签
|
||||
function labelEdit(item) {
|
||||
modalForm(wechatQrcodeCreate(item.id)).then(() => getUserLabelAll(1));
|
||||
}
|
||||
function deleteSort(row, tit) {
|
||||
let num = labelSort.value.findIndex((e) => {
|
||||
return e.id == row.id;
|
||||
});
|
||||
let delfromData = {
|
||||
title: tit,
|
||||
num: num,
|
||||
url: `marketing/channel_code/cate/del/${row.id}`,
|
||||
method: 'DELETE',
|
||||
ids: '',
|
||||
};
|
||||
modalSure(delfromData)
|
||||
.then((res) => {
|
||||
ElMessage.success(res.msg);
|
||||
labelSort.value.splice(num, 1);
|
||||
labelSort.value = [];
|
||||
getUserLabelAll();
|
||||
})
|
||||
.catch((res) => {
|
||||
ElMessage.error(res.msg);
|
||||
});
|
||||
}
|
||||
// 显示标签小菜单
|
||||
function showMenu(item) {
|
||||
labelSort.value.forEach((el) => {
|
||||
if (el.id == item.id) {
|
||||
el.status = item.status ? false : true;
|
||||
} else {
|
||||
el.status = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
function bindMenuItem(name, index) {
|
||||
tableFrom.value.page = 1;
|
||||
current.value = index;
|
||||
labelSort.value.forEach((el) => {
|
||||
el.status = false;
|
||||
});
|
||||
tableFrom.value.cate_id = name.id;
|
||||
getList();
|
||||
}
|
||||
function cancel() {
|
||||
formValidate.value = {
|
||||
page: 1,
|
||||
limit: 15,
|
||||
data: '',
|
||||
type: '',
|
||||
nickname: '',
|
||||
};
|
||||
}
|
||||
// 编辑
|
||||
function edit(row) {
|
||||
// vue-router 4 中 path 内拼接的 query 会被丢弃,必须用 query 对象传递参数
|
||||
router.push({
|
||||
path: routePre + '/marketing/channel_code/create',
|
||||
query: { id: row.id },
|
||||
});
|
||||
}
|
||||
// 添加
|
||||
function add() {
|
||||
router.push({
|
||||
path: routePre + '/marketing/channel_code/create',
|
||||
});
|
||||
}
|
||||
//
|
||||
function getListService() {
|
||||
loading2.value = true;
|
||||
kefucreateApi(formValidate.value)
|
||||
.then(async (res) => {
|
||||
let data = res.data;
|
||||
tableList2.value = data.list;
|
||||
total2.value = data.count;
|
||||
tableList2.value.map((item) => {
|
||||
item._isChecked = false;
|
||||
});
|
||||
loading2.value = false;
|
||||
})
|
||||
.catch((res) => {
|
||||
loading2.value = false;
|
||||
ElMessage.error(res.msg);
|
||||
});
|
||||
}
|
||||
// 搜索
|
||||
function userSearchs() {
|
||||
formValidate.value.page = 1;
|
||||
getList();
|
||||
}
|
||||
// 删除
|
||||
function del(row, tit, num) {
|
||||
let delfromData = {
|
||||
title: tit,
|
||||
num: num,
|
||||
url: `/marketing/channel_code/del/${row.id}`,
|
||||
method: 'DELETE',
|
||||
ids: '',
|
||||
};
|
||||
modalSure(delfromData)
|
||||
.then((res) => {
|
||||
ElMessage.success(res.msg);
|
||||
tableList.value.splice(num, 1);
|
||||
})
|
||||
.catch((res) => {
|
||||
ElMessage.error(res.msg);
|
||||
});
|
||||
}
|
||||
// 列表
|
||||
function getList() {
|
||||
loading.value = true;
|
||||
wechatQrcodeList(tableFrom.value)
|
||||
.then(async (res) => {
|
||||
let data = res.data;
|
||||
tableList.value = data.list;
|
||||
total.value = res.data.count;
|
||||
loading.value = false;
|
||||
})
|
||||
.catch((res) => {
|
||||
loading.value = false;
|
||||
ElMessage.error(res.msg);
|
||||
});
|
||||
}
|
||||
// 修改是否显示
|
||||
function onchangeIsShow(row) {
|
||||
let data = {
|
||||
id: row.id,
|
||||
status: row.status,
|
||||
};
|
||||
wechatQrcodeStatusApi(data)
|
||||
.then(async (res) => {
|
||||
ElMessage.success(res.msg);
|
||||
})
|
||||
.catch((res) => {
|
||||
ElMessage.error(res.msg);
|
||||
});
|
||||
}
|
||||
// 点击菜单
|
||||
function clickMenu(data, name) {
|
||||
if (name == 1) {
|
||||
labelEdit(data);
|
||||
} else if (name == 2) {
|
||||
deleteSort(data, '删除分类');
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.showOn {
|
||||
color: #2d8cf0;
|
||||
background: #f0faff;
|
||||
z-index: 2;
|
||||
}
|
||||
.tabBox_img {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
|
||||
img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
.modelBox {
|
||||
:deep(.ivu-table-header) {
|
||||
width: 100% !important;
|
||||
}
|
||||
}
|
||||
.label-name {
|
||||
margin: 2px 2px;
|
||||
}
|
||||
.trees-coadd {
|
||||
width: 100%;
|
||||
height: 385px;
|
||||
.scollhide {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow-x: hidden;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
}
|
||||
.scollhide::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
:deep(.ivu-menu-vertical .ivu-menu-item-group-title) {
|
||||
display: none;
|
||||
}
|
||||
:deep(.ivu-menu-vertical.ivu-menu-light:after) {
|
||||
display: none;
|
||||
}
|
||||
.left-wrapper {
|
||||
height: 904px;
|
||||
background: #fff;
|
||||
border-right: 1px solid #f2f2f2;
|
||||
}
|
||||
.menu-item {
|
||||
z-index: 50;
|
||||
position: relative;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
word-break: break-all;
|
||||
.icon-box {
|
||||
z-index: 3;
|
||||
position: absolute;
|
||||
right: 20px;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
display: none;
|
||||
}
|
||||
&:hover .icon-box {
|
||||
display: block;
|
||||
}
|
||||
.right-menu {
|
||||
z-index: 10;
|
||||
position: absolute;
|
||||
right: -106px;
|
||||
top: -11px;
|
||||
width: auto;
|
||||
min-width: 121px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@ -1,275 +0,0 @@
|
||||
<template>
|
||||
<div v-loading="spinShow">
|
||||
<!-- <div class="i-layout-page-header header-title">
|
||||
<div class="fl_header">
|
||||
<span>
|
||||
<el-button icon="ios-arrow-back" type="text" v-db-click @click="$router.go(-1)">返回</el-button>
|
||||
</span>
|
||||
<el-divider direction="vertical"></el-divider>
|
||||
<span class="ivu-page-header-title">{{ $route.meta.title }}</span>
|
||||
</div>
|
||||
</div> -->
|
||||
<pages-header
|
||||
:title="$route.meta.title"
|
||||
:backUrl="routePre + '/marketing/channel_code/channelCodeIndex'"
|
||||
></pages-header>
|
||||
<cards-data class="mt16" :cardLists="cardLists" v-if="cardLists.length >= 0"></cards-data>
|
||||
<el-card :bordered="false" shadow="never" class="ivu-mt">
|
||||
<div class="table-head">
|
||||
<h3>关注趋势</h3>
|
||||
<date-range-picker
|
||||
:editable="false"
|
||||
clearable
|
||||
@change="onchangeTime"
|
||||
v-model="timeVal"
|
||||
format="YYYY/MM/DD"
|
||||
value-format="YYYY/MM/DD"
|
||||
range-separator="-"
|
||||
class="mr20"
|
||||
></date-range-picker>
|
||||
</div>
|
||||
<echarts-new :option-data="optionData" :styles="style" height="100%" width="100%" v-if="optionData"></echarts-new>
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue';
|
||||
import { useRoute } from 'vue-router';
|
||||
import cardsData from '@/components/cards/cards';
|
||||
import echartsNew from '@/components/echartsNew/index';
|
||||
import { getBasic, getChannel, getType } from '@/api/statistic';
|
||||
import { wechatQrcodeStatistic as wechatQrcodeStatisticApi } from './../api';
|
||||
import { formatDate } from '@/utils/validate';
|
||||
import echartsFrom from '@/components/echarts/index';
|
||||
import setting from '@/setting';
|
||||
|
||||
defineOptions({ name: 'index' });
|
||||
|
||||
const route = useRoute();
|
||||
const routePre = setting.routePre;
|
||||
|
||||
const timeVal = ref([]);
|
||||
const style = { height: '400px' };
|
||||
const infoList = ref({});
|
||||
const infoList2 = ref({});
|
||||
const echartLeft = ref(true);
|
||||
const echartRight = ref(false);
|
||||
const loading = ref(false);
|
||||
const loading2 = ref(false);
|
||||
const fromList = ref({
|
||||
title: '选择时间',
|
||||
custom: true,
|
||||
fromTxt: [
|
||||
{ text: '全部', val: '' },
|
||||
{ text: '今天', val: 'today' },
|
||||
{ text: '本周', val: 'week' },
|
||||
{ text: '本月', val: 'month' },
|
||||
{ text: '本季度', val: 'quarter' },
|
||||
{ text: '本年', val: 'year' },
|
||||
],
|
||||
});
|
||||
const formValidate = ref({
|
||||
time: '',
|
||||
});
|
||||
const cardLists = ref([
|
||||
{
|
||||
col: 6,
|
||||
count: 0,
|
||||
name: '昨日新增关注',
|
||||
className: 'md-rose',
|
||||
},
|
||||
{
|
||||
col: 6,
|
||||
count: 0,
|
||||
name: '昨日参与',
|
||||
className: 'ios-speedometer-outline',
|
||||
},
|
||||
{
|
||||
col: 6,
|
||||
count: 0,
|
||||
name: '总关注',
|
||||
className: 'ios-speedometer-outline',
|
||||
},
|
||||
{
|
||||
col: 6,
|
||||
count: 0,
|
||||
name: '参与总人数',
|
||||
className: 'md-rose',
|
||||
},
|
||||
]);
|
||||
const optionData = ref({});
|
||||
const spinShow = ref(false);
|
||||
const id = route.query.id;
|
||||
|
||||
const end = new Date();
|
||||
const start = new Date();
|
||||
start.setTime(start.setTime(new Date(new Date().getFullYear(), new Date().getMonth(), new Date().getDate() - 29)));
|
||||
timeVal.value = [start, end];
|
||||
formValidate.value.time = formatDate(start, 'yyyy/MM/dd') + '-' + formatDate(end, 'yyyy/MM/dd');
|
||||
// getBasic();
|
||||
// getTrend();
|
||||
// getChannel();
|
||||
// getType();
|
||||
getQrcodeStatistic();
|
||||
|
||||
function getQrcodeStatistic() {
|
||||
wechatQrcodeStatisticApi(id, formValidate.value).then((res) => {
|
||||
let arr = ['y_follow', 'y_scan', 'all_follow', 'all_scan'];
|
||||
cardLists.value.map((i, index) => {
|
||||
i.count = res.data[arr[index]];
|
||||
});
|
||||
getTrend(res.data.trend.series, res.data.trend.xAxis);
|
||||
});
|
||||
}
|
||||
function timeG(dd) {
|
||||
var d = new Date(dd);
|
||||
var datetime =
|
||||
d.getFullYear() +
|
||||
'-' +
|
||||
(d.getMonth() + 1) +
|
||||
'-' +
|
||||
d.getDate() +
|
||||
' ' +
|
||||
d.getHours() +
|
||||
':' +
|
||||
d.getMinutes() +
|
||||
':' +
|
||||
d.getSeconds();
|
||||
return datetime;
|
||||
}
|
||||
|
||||
function selectChange(e) {}
|
||||
// 具体日期
|
||||
function onchangeTime(e) {
|
||||
timeVal.value = e;
|
||||
formValidate.value.time = timeVal.value ? timeVal.value.join('-') : '';
|
||||
getQrcodeStatistic();
|
||||
}
|
||||
// 统计图
|
||||
function getTrend(seriesData, xAxisData) {
|
||||
spinShow.value = true;
|
||||
let legend = seriesData.map((item) => {
|
||||
return item.name;
|
||||
});
|
||||
let xAxis = xAxisData;
|
||||
let col = ['#5B8FF9', '#5AD8A6', '#FFAB2B', '#5D7092'];
|
||||
let series = [];
|
||||
seriesData.map((item, index) => {
|
||||
series.push({
|
||||
name: item.name,
|
||||
type: 'line',
|
||||
data: item.data,
|
||||
itemStyle: {
|
||||
normal: {
|
||||
color: col[index],
|
||||
},
|
||||
},
|
||||
smooth: 0,
|
||||
});
|
||||
});
|
||||
optionData.value = {
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
axisPointer: {
|
||||
type: 'cross',
|
||||
label: {
|
||||
backgroundColor: '#6a7985',
|
||||
},
|
||||
},
|
||||
},
|
||||
legend: {
|
||||
x: 'center',
|
||||
data: legend,
|
||||
},
|
||||
grid: {
|
||||
left: '3%',
|
||||
right: '4%',
|
||||
bottom: '3%',
|
||||
containLabel: true,
|
||||
},
|
||||
toolbox: {
|
||||
feature: {
|
||||
saveAsImage: {},
|
||||
},
|
||||
},
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
boundaryGap: true,
|
||||
// axisTick:{
|
||||
// show:false
|
||||
// },
|
||||
// axisLine:{
|
||||
// show:false
|
||||
// },
|
||||
// splitLine: {
|
||||
// show: false
|
||||
// },
|
||||
axisLabel: {
|
||||
interval: 0,
|
||||
rotate: 40,
|
||||
textStyle: {
|
||||
color: '#000000',
|
||||
},
|
||||
},
|
||||
data: xAxis,
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value',
|
||||
axisLine: {
|
||||
show: false,
|
||||
},
|
||||
axisTick: {
|
||||
show: false,
|
||||
},
|
||||
axisLabel: {
|
||||
textStyle: {
|
||||
color: '#7F8B9C',
|
||||
},
|
||||
},
|
||||
splitLine: {
|
||||
show: true,
|
||||
lineStyle: {
|
||||
color: '#F5F7F9',
|
||||
},
|
||||
},
|
||||
},
|
||||
series: series,
|
||||
};
|
||||
spinShow.value = false;
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.cl {
|
||||
margin-right: 20px;
|
||||
}
|
||||
.code-row-bg {
|
||||
display: flex;
|
||||
flex-wrap: nowrap;
|
||||
}
|
||||
.code-row-bg .ivu-mt {
|
||||
width: 100%;
|
||||
margin: 0 5px;
|
||||
}
|
||||
.ech-box {
|
||||
margin-top: 10px;
|
||||
}
|
||||
.change-style {
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 15px;
|
||||
padding: 0px 10px;
|
||||
cursor: pointer;
|
||||
}
|
||||
.table-head {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
.return {
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
.i-layout-page-header {
|
||||
padding-left: 13px;
|
||||
}
|
||||
</style>
|
||||
@ -1,566 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
<pages-header
|
||||
:title="$route.meta.title"
|
||||
:backUrl="routePre + '/marketing/channel_code/channelCodeIndex'"
|
||||
></pages-header>
|
||||
<el-card :bordered="false" shadow="never" class="mt16">
|
||||
<el-form :model="formData" label-width="100px" :rules="ruleValidate">
|
||||
<el-form-item label="渠道码名称:">
|
||||
<el-input
|
||||
clearable
|
||||
v-model="formData.name"
|
||||
placeholder="请输入渠道码名称"
|
||||
class="content_width"
|
||||
maxlength="20"
|
||||
show-word-limit
|
||||
></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="渠道码分组:">
|
||||
<el-select clearable v-model="formData.cate_id" class="content_width">
|
||||
<el-option
|
||||
:value="item.id"
|
||||
v-for="(item, index) in labelSort"
|
||||
:key="index"
|
||||
:label="item.cate_name"
|
||||
></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="用户标签:">
|
||||
<div style="display: flex">
|
||||
<div class="labelInput acea-row row-between-wrapper" v-db-click @click="openLabel">
|
||||
<div style="width: 90%">
|
||||
<div v-if="dataLabel.length">
|
||||
<el-tag closable v-for="(item, index) in dataLabel" @close="closeLabel(item)" :key="index">{{
|
||||
item.label_name
|
||||
}}</el-tag>
|
||||
</div>
|
||||
<span class="span" v-else>选择用户关联标签</span>
|
||||
</div>
|
||||
<div class="ivu-icon ivu-icon-ios-arrow-down"></div>
|
||||
</div>
|
||||
<span class="addfont" v-db-click @click="addLabel">新增标签</span>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="关联推广员:">
|
||||
<div class="picBox" v-db-click @click="customer">
|
||||
<div class="pictrue" v-if="formData.avatar">
|
||||
<img v-lazy="formData.avatar" />
|
||||
</div>
|
||||
<div class="upLoad acea-row row-center-wrapper" v-else>
|
||||
<i class="el-icon-user" style="font-size: 24px"></i>
|
||||
</div>
|
||||
</div>
|
||||
<div class="trip">扫码注册的新用户,将自动成为此推广员的下级,与分销推广功能一致</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="有效期:">
|
||||
<el-radio-group v-model="isReceiveTime">
|
||||
<el-radio :label="0" :value="0">永久</el-radio>
|
||||
<el-radio :label="1" :value="1">有效期</el-radio>
|
||||
</el-radio-group>
|
||||
<div v-show="isReceiveTime">
|
||||
<el-input-number
|
||||
:controls="false"
|
||||
:max="10000"
|
||||
:precision="0"
|
||||
v-model="formData.time"
|
||||
placeholder="请输入天数"
|
||||
class="input-number-unit-class"
|
||||
class-unit="天"
|
||||
></el-input-number>
|
||||
</div>
|
||||
<div class="trip">临时码过期后不能再扫码,永久二维码最大创建数量为10万个</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="回复内容:">
|
||||
<el-radio-group v-model="formData.type">
|
||||
<el-radio label="text" value="text">文字内容</el-radio>
|
||||
<el-radio label="voice" value="voice">声音消息</el-radio>
|
||||
<el-radio label="image" value="image">图片消息</el-radio>
|
||||
<el-radio label="news" value="news">图文消息</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="消息内容:" prop="content" v-if="formData.type === 'text' || formData.type === 'url'">
|
||||
<el-input
|
||||
type="textarea"
|
||||
rows="2"
|
||||
clearable
|
||||
v-model="formData.content.content"
|
||||
:placeholder="formData.type === 'text' ? '请填写消息内容' : '请填写网址链接'"
|
||||
class="content_width"
|
||||
></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="选取图文:" v-if="formData.type === 'news'">
|
||||
<el-button v-db-click @click="modals = true">选择图文消息</el-button>
|
||||
<div class="news-box" v-if="formData.content.list.title">
|
||||
<img class="news_pic" :src="formData.content.list.image_input[0]" />
|
||||
<span>{{ formData.content.list.title }}</span>
|
||||
<i class="el-icon-error del_icon" v-db-click @click="delContent"></i>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
:label="formData.type === 'image' ? '图片地址:' : '语音地址:'"
|
||||
prop="src"
|
||||
v-if="formData.type === 'image' || formData.type === 'voice'"
|
||||
>
|
||||
<div class="acea-row row-middle">
|
||||
<el-input
|
||||
readonly="readonly"
|
||||
placeholder="请填入链接地址"
|
||||
class="content_width mr15"
|
||||
v-model="formData.content.src"
|
||||
/>
|
||||
<el-upload
|
||||
:show-file-list="false"
|
||||
:action="fileUrl"
|
||||
:on-success="handleSuccess"
|
||||
:format="formData.type === 'image' ? formatImg : formatVoice"
|
||||
:max-size="2048"
|
||||
:headers="header"
|
||||
:on-format-error="handleFormatError"
|
||||
:on-exceeded-size="handleMaxSize"
|
||||
class="mr20"
|
||||
style="margin-top: 1px"
|
||||
accept="image/*,.mp3"
|
||||
:before-upload="beforeUpload"
|
||||
>
|
||||
<el-button type="primary">上传</el-button>
|
||||
</el-upload>
|
||||
</div>
|
||||
<span v-show="formData.type === 'image'">文件最大2Mb,支持bmp/png/jpeg/jpg/gif格式</span>
|
||||
<span v-show="formData.type === 'voice'">文件最大2Mb,支持mp3格式,播放长度不超过60s</span>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button class="submit" type="primary" v-db-click @click="save" :loading="loading" :disabled="disabled"
|
||||
>立即提交</el-button
|
||||
>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
<el-dialog v-model="customerShow" title="请选择商城用户" :show-close="true" width="1000px">
|
||||
<customerInfo v-if="customerShow" @imageObject="imageObject"></customerInfo>
|
||||
</el-dialog>
|
||||
<!--图文消息 -->
|
||||
<el-dialog v-model="modals" title="发送消息" width="1200px" class="modelBox">
|
||||
<news-category
|
||||
v-if="modals"
|
||||
@getCentList="getCentList"
|
||||
:scrollerHeight="scrollerHeight"
|
||||
:contentTop="contentTop"
|
||||
:contentWidth="contentWidth"
|
||||
:maxCols="maxCols"
|
||||
></news-category>
|
||||
</el-dialog>
|
||||
<el-dialog
|
||||
v-model="labelShow"
|
||||
scrollable
|
||||
title="请选择用户标签"
|
||||
:closable="false"
|
||||
width="540px"
|
||||
:footer-hide="true"
|
||||
:mask-closable="false"
|
||||
>
|
||||
<userLabel ref="userLabelRef" @activeData="activeData" @close="labelClose"></userLabel>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
import { ElMessage } from 'element-plus';
|
||||
import userLabel from '@/components/labelList';
|
||||
|
||||
import goodsList from '@/components/goodsList/index';
|
||||
import newsCategory from '@/components/newsCategory/index';
|
||||
import { labelListApi } from '@/api/product';
|
||||
import { userLabelAddApi } from '@/api/user';
|
||||
import { wechatQrcodeSaveApi, wechatQrcodeTree, wechatQrcodeDetail } from './../api';
|
||||
import Setting from '@/setting';
|
||||
import { getCookies } from '@/libs/util';
|
||||
import customerInfo from '@/components/customerInfo';
|
||||
import { isPicUpload, isVoiceUpload } from '@/utils';
|
||||
import modalForm from '@/utils/modalForm';
|
||||
|
||||
defineOptions({ name: 'createCode' });
|
||||
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
const routePre = Setting.routePre;
|
||||
|
||||
const userLabelRef = ref(null);
|
||||
const customerShow = ref(false);
|
||||
const labelShow = ref(false);
|
||||
const disabled = ref(false);
|
||||
const maxCols = 4;
|
||||
const labelSelect = ref([]);
|
||||
|
||||
const scrollerHeight = '600';
|
||||
const contentTop = '10';
|
||||
const contentWidth = '98%';
|
||||
const formatImg = ['jpg', 'jpeg', 'png', 'bmp', 'gif'];
|
||||
const formatVoice = ['mp3', 'wma', 'wav', 'amr'];
|
||||
const header = ref({});
|
||||
const fileUrl = Setting.apiBaseURL + '/file/upload/1';
|
||||
|
||||
const formData = ref({
|
||||
name: '',
|
||||
type: 'text',
|
||||
time: undefined,
|
||||
label_id: [],
|
||||
image: '',
|
||||
cate_id: '',
|
||||
content: {
|
||||
content: '',
|
||||
src: '',
|
||||
list: {},
|
||||
},
|
||||
});
|
||||
const labelSort = ref([]);
|
||||
const isReceiveTime = ref(0);
|
||||
const modals = ref(false);
|
||||
const ruleValidate = {
|
||||
name: [
|
||||
{
|
||||
required: true,
|
||||
message: '请填写二维码名称',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
cate_id: [
|
||||
{
|
||||
required: true,
|
||||
message: '请选择二维码分组',
|
||||
trigger: 'change',
|
||||
},
|
||||
],
|
||||
};
|
||||
const id = ref(0);
|
||||
const dataLabel = ref([]);
|
||||
const loading = ref(false);
|
||||
|
||||
getUserLabelAll();
|
||||
getLabelList();
|
||||
getToken();
|
||||
if (route.query.id) {
|
||||
id.value = route.query.id;
|
||||
getDetail();
|
||||
}
|
||||
|
||||
function beforeUpload(file) {
|
||||
if (formData.value.type === 'image') {
|
||||
return isPicUpload(file);
|
||||
}
|
||||
if (formData.value.type === 'voice') {
|
||||
return isVoiceUpload(file);
|
||||
}
|
||||
}
|
||||
function activeData(val) {
|
||||
labelShow.value = false;
|
||||
dataLabel.value = val;
|
||||
}
|
||||
// 标签弹窗关闭
|
||||
function labelClose() {
|
||||
labelShow.value = false;
|
||||
}
|
||||
function openLabel(row) {
|
||||
labelShow.value = true;
|
||||
if (dataLabel.value.length) userLabelRef.value.userLabel(JSON.parse(JSON.stringify(dataLabel.value)));
|
||||
}
|
||||
function closeLabel(label) {
|
||||
let index = dataLabel.value.indexOf(dataLabel.value.filter((d) => d.id == label.id)[0]);
|
||||
dataLabel.value.splice(index, 1);
|
||||
}
|
||||
function getDetail() {
|
||||
wechatQrcodeDetail(id.value).then((res) => {
|
||||
formData.value = res.data;
|
||||
if (res.data.time > 0) {
|
||||
isReceiveTime.value = 1;
|
||||
}
|
||||
if (res.data.label_id.length) {
|
||||
dataLabel.value = res.data.label_id;
|
||||
}
|
||||
});
|
||||
}
|
||||
function customer() {
|
||||
customerShow.value = true;
|
||||
}
|
||||
function addLabel() {
|
||||
modalForm(userLabelAddApi(0)).then(() => getLabelList());
|
||||
}
|
||||
// 用户标签
|
||||
function getLabelList() {
|
||||
labelListApi()
|
||||
.then((res) => {
|
||||
labelSelect.value = res.data.list;
|
||||
})
|
||||
.catch((res) => {
|
||||
ElMessage.error(res.msg);
|
||||
});
|
||||
}
|
||||
function imageObject(e) {
|
||||
customerShow.value = false;
|
||||
formData.value.uid = e.uid;
|
||||
formData.value.avatar = e.image;
|
||||
}
|
||||
function getCentList(val) {
|
||||
formData.value.content.list = val.new[0];
|
||||
modals.value = false;
|
||||
}
|
||||
function delContent() {
|
||||
formData.value.content.list = {};
|
||||
}
|
||||
// 上传成功
|
||||
function handleSuccess(res, file) {
|
||||
if (res.status === 200) {
|
||||
formData.value.content.src = res.data.src;
|
||||
ElMessage.success(res.msg);
|
||||
} else {
|
||||
ElMessage.error(res.msg);
|
||||
}
|
||||
}
|
||||
function handleFormatError(file) {
|
||||
if (formData.value.type === 'image') {
|
||||
ElMessage.warning('请上传bmp/png/jpeg/jpg/gif格式的图片');
|
||||
} else {
|
||||
ElMessage.warning('请上传mp3/wma/wav/amr格式的语音');
|
||||
}
|
||||
}
|
||||
function handleMaxSize(file) {
|
||||
ElMessage.warning('请上传文件2M以内的文件');
|
||||
}
|
||||
// 上传头部token
|
||||
function getToken() {
|
||||
header.value['Authori-zation'] = 'Bearer ' + getCookies('token');
|
||||
}
|
||||
function selectMenu(name) {
|
||||
formData.value.type = name;
|
||||
}
|
||||
// 获取分类
|
||||
function getUserLabelAll() {
|
||||
wechatQrcodeTree().then((res) => {
|
||||
let data = res.data.data;
|
||||
labelSort.value = data;
|
||||
});
|
||||
}
|
||||
// 创建
|
||||
function save() {
|
||||
if (!formData.value.name) {
|
||||
return ElMessage.error('请输入二维码名称');
|
||||
}
|
||||
if (!formData.value.cate_id) {
|
||||
return ElMessage.error('请选择分组');
|
||||
}
|
||||
if (!dataLabel.value.length) {
|
||||
return ElMessage.error('请选择用户标签');
|
||||
} else {
|
||||
let ids = [];
|
||||
dataLabel.value.map((i) => {
|
||||
ids.push(i.id);
|
||||
});
|
||||
formData.value.label_id = ids;
|
||||
}
|
||||
if (!formData.value.uid) {
|
||||
return ElMessage.error('请选择推广员');
|
||||
}
|
||||
if (isReceiveTime.value) {
|
||||
if (formData.value.time < 1) {
|
||||
return ElMessage.error('使用有效期限不能小于1天');
|
||||
}
|
||||
} else {
|
||||
formData.value.time = 0;
|
||||
}
|
||||
if (formData.value.type === 'text' || formData.value.type === 'url') {
|
||||
if (!formData.value.content.content.trim()) {
|
||||
return ElMessage.error('请输入内容');
|
||||
}
|
||||
}
|
||||
if (formData.value.type === 'voice' || formData.value.type === 'image') {
|
||||
if (!formData.value.content.src.trim()) {
|
||||
return ElMessage.error('请先上传消息');
|
||||
}
|
||||
}
|
||||
if (formData.value.type === 'news') {
|
||||
if (!formData.value.content.list.title.trim()) {
|
||||
return ElMessage.error('请选择图文消息');
|
||||
}
|
||||
}
|
||||
disabled.value = false;
|
||||
loading.value = true;
|
||||
wechatQrcodeSaveApi(id.value, formData.value)
|
||||
.then((res) => {
|
||||
disabled.value = true;
|
||||
ElMessage.success(res.msg);
|
||||
setTimeout(() => {
|
||||
router.push({
|
||||
path: routePre + '/marketing/channel_code/channelCodeIndex',
|
||||
});
|
||||
}, 1000);
|
||||
})
|
||||
.catch((err) => {
|
||||
disabled.value = true;
|
||||
ElMessage.error(err.msg);
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.content_width {
|
||||
width: 460px;
|
||||
}
|
||||
.ivu-row {
|
||||
border: 1px solid #f2f2f2;
|
||||
}
|
||||
.ivu-form-item {
|
||||
padding: 10px 0;
|
||||
max-width: 1100px;
|
||||
}
|
||||
.ivu-form :deep(.ivu-form-item-label) {
|
||||
font-weight: 700;
|
||||
font-size: 14px !important;
|
||||
}
|
||||
.ivu-input-wrapper {
|
||||
width: 320px;
|
||||
}
|
||||
.ivu-radio-wrapper {
|
||||
margin-right: 30px;
|
||||
font-size: 14px !important;
|
||||
}
|
||||
.ivu-radio-wrapper :deep(.ivu-radio) {
|
||||
margin-right: 10px;
|
||||
}
|
||||
.ivu-input-number {
|
||||
width: 160px;
|
||||
}
|
||||
.ivu-date-picker {
|
||||
width: 320px;
|
||||
}
|
||||
.ivu-icon-ios-camera-outline {
|
||||
width: 58px;
|
||||
height: 58px;
|
||||
border: 1px dotted rgba(0, 0, 0, 0.1);
|
||||
border-radius: 4px;
|
||||
background-color: rgba(0, 0, 0, 0.02);
|
||||
line-height: 58px;
|
||||
cursor: pointer;
|
||||
vertical-align: middle;
|
||||
}
|
||||
.upload-list {
|
||||
width: 58px;
|
||||
height: 58px;
|
||||
border: 1px dotted rgba(0, 0, 0, 0.1);
|
||||
border-radius: 4px;
|
||||
margin-right: 15px;
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
vertical-align: middle;
|
||||
}
|
||||
:deep(.el-tag) {
|
||||
margin-right: 5px;
|
||||
}
|
||||
.upload-list img {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
.ivu-icon-ios-close-circle {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
transform: translate(50%, -50%);
|
||||
}
|
||||
.modelBox :deep(.ivu-modal-body) {
|
||||
padding: 0 16px 16px 16px !important;
|
||||
}
|
||||
.header-save {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.trip {
|
||||
font-size: 12px;
|
||||
color: #ccc;
|
||||
}
|
||||
|
||||
textarea {
|
||||
padding: 0 5px;
|
||||
border-radius: 3px;
|
||||
border-color: #c5c8ce;
|
||||
outline-color: #2d8cf0;
|
||||
font-size: 14px;
|
||||
}
|
||||
.picBox {
|
||||
display: inline-block;
|
||||
cursor: pointer;
|
||||
.upLoad {
|
||||
width: 58px;
|
||||
height: 58px;
|
||||
line-height: 58px;
|
||||
border: 1px dotted rgba(0, 0, 0, 0.1);
|
||||
border-radius: 4px;
|
||||
background: rgba(0, 0, 0, 0.02);
|
||||
}
|
||||
.pictrue {
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
border: 1px dotted rgba(0, 0, 0, 0.1);
|
||||
margin-right: 10px;
|
||||
|
||||
img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
.iconfont {
|
||||
color: #898989;
|
||||
}
|
||||
}
|
||||
.addfont {
|
||||
display: inline-block;
|
||||
font-size: 12px;
|
||||
font-weight: 400;
|
||||
color: var(--prev-color-primary);
|
||||
margin-left: 14px;
|
||||
cursor: pointer;
|
||||
margin-left: 10px;
|
||||
}
|
||||
.iconxiayi {
|
||||
font-size: 14px;
|
||||
}
|
||||
.ivu-page-header-title {
|
||||
padding-bottom: 0;
|
||||
}
|
||||
.news-box {
|
||||
width: 200px;
|
||||
background-color: #f2f2f2;
|
||||
padding: 10px;
|
||||
border-radius: 10px;
|
||||
margin-top: 20px;
|
||||
position: relative;
|
||||
.news_pic {
|
||||
width: 100%;
|
||||
height: 150px;
|
||||
}
|
||||
.del_icon {
|
||||
position: absolute;
|
||||
right: -8px;
|
||||
top: -8px;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
.labelInput {
|
||||
border: 1px solid #dcdee2;
|
||||
width: 460px;
|
||||
padding: 0 15px;
|
||||
border-radius: 5px;
|
||||
min-height: 30px;
|
||||
cursor: pointer;
|
||||
.span {
|
||||
font-size: 12px;
|
||||
color: #c5c8ce;
|
||||
}
|
||||
.ivu-icon-ios-arrow-down {
|
||||
font-size: 14px;
|
||||
color: #808695;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@ -1,77 +0,0 @@
|
||||
/**
|
||||
* 渠道码扩展路由
|
||||
* 兼容模式:既是 Vue Router 路由配置,也包含 section/action 元数据供扩展机制使用
|
||||
*/
|
||||
import setting from '@/setting';
|
||||
const routePre = setting.routePre;
|
||||
const pre = 'channel_code_';
|
||||
|
||||
export default [
|
||||
{
|
||||
path: routePre + '/marketing/channel_code/channelCodeIndex',
|
||||
section: 'channel_code',
|
||||
action: 'channelCodeIndex',
|
||||
meta: {
|
||||
auth: true,
|
||||
title: '公众号渠道码',
|
||||
keepAlive: true,
|
||||
},
|
||||
component: () => import('@/layout'),
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
name: `${pre}channelCodeIndex`,
|
||||
component: () => import('./pages/channelCodeIndex'),
|
||||
meta: {
|
||||
auth: true,
|
||||
title: '公众号渠道码',
|
||||
keepAlive: true,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: routePre + '/marketing/channel_code/create',
|
||||
section: 'channel_code',
|
||||
action: 'createCode',
|
||||
meta: {
|
||||
auth: ['marketing-channel_code-create'],
|
||||
title: '渠道码',
|
||||
},
|
||||
component: () => import('@/layout'),
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
name: `${pre}createCode`,
|
||||
component: () => import('./pages/createCode'),
|
||||
meta: {
|
||||
auth: ['marketing-channel_code-create'],
|
||||
title: '渠道码',
|
||||
activeMenu: routePre + '/marketing/channel_code/channelCodeIndex',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: routePre + '/marketing/channel_code/code_statistic',
|
||||
section: 'channel_code',
|
||||
action: 'codeStatistic',
|
||||
meta: {
|
||||
auth: ['marketing-channel_code-statistic'],
|
||||
title: '二维码统计',
|
||||
},
|
||||
component: () => import('@/layout'),
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
name: `${pre}codeStatistic`,
|
||||
component: () => import('./pages/codeStatistic'),
|
||||
meta: {
|
||||
auth: ['marketing-channel_code-statistic'],
|
||||
title: '二维码统计',
|
||||
activeMenu: routePre + '/marketing/channel_code/channelCodeIndex',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
@ -1,38 +0,0 @@
|
||||
<template>
|
||||
<div class="combination-app">
|
||||
<div class="section-content">
|
||||
<component :is="sectionComponent" :params="params" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed } from 'vue';
|
||||
import ProductList from './pages/product/index.vue';
|
||||
import PinkList from './pages/pink/index.vue';
|
||||
import CreateProduct from './pages/create/index.vue';
|
||||
import Statistics from './pages/statistics/index.vue';
|
||||
|
||||
defineOptions({ name: 'CombinationApp' });
|
||||
|
||||
const props = defineProps({
|
||||
section: { type: String, default: 'combination' },
|
||||
action: { type: String, default: 'product' },
|
||||
params: { type: Object, default: () => ({}) },
|
||||
});
|
||||
|
||||
const actionComponents = {
|
||||
product: ProductList,
|
||||
pink: PinkList,
|
||||
create: CreateProduct,
|
||||
statistics: Statistics,
|
||||
};
|
||||
|
||||
const sectionComponent = computed(() => actionComponents[props.action] || ProductList);
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.combination-app {
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
@ -1,130 +0,0 @@
|
||||
/**
|
||||
* 拼团模块 API
|
||||
*/
|
||||
import request from '@/libs/request';
|
||||
|
||||
/**
|
||||
* 拼团商品列表
|
||||
*/
|
||||
export function combinationListApi(params) {
|
||||
return request({
|
||||
url: 'marketing/combination',
|
||||
method: 'GET',
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改拼团商品状态
|
||||
*/
|
||||
export function combinationSetStatusApi(data) {
|
||||
return request({
|
||||
url: `marketing/combination/set_status/${data.id}/${data.status}`,
|
||||
method: 'PUT',
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 拼团统计(全局)
|
||||
*/
|
||||
export function statisticsApi() {
|
||||
return request({
|
||||
url: 'marketing/combination/statistics',
|
||||
method: 'GET',
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 拼团商品详情
|
||||
*/
|
||||
export function combinationInfoApi(id) {
|
||||
return request({
|
||||
url: `marketing/combination/${id}`,
|
||||
method: 'GET',
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存拼团商品(新增/编辑)
|
||||
*/
|
||||
export function combinationCreatApi(data) {
|
||||
return request({
|
||||
url: `marketing/combination/${data.id || 0}`,
|
||||
method: 'POST',
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 拼团列表(已开团的)
|
||||
*/
|
||||
export function combineListApi(params) {
|
||||
return request({
|
||||
url: 'marketing/combination/combine/list',
|
||||
method: 'GET',
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 拼团人列表
|
||||
*/
|
||||
export function orderPinkListApi(id) {
|
||||
return request({
|
||||
url: `marketing/combination/order_pink/${id}`,
|
||||
method: 'GET',
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 拼团导出
|
||||
*/
|
||||
export function storeCombinationApi(data) {
|
||||
return request({
|
||||
url: 'export/combination_list',
|
||||
method: 'GET',
|
||||
params: data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 拼团统计-头部卡片
|
||||
*/
|
||||
export function getcombinationStatistics(id) {
|
||||
return request({
|
||||
url: `marketing/combination/statistics/head/${id}`,
|
||||
method: 'GET',
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 拼团统计-参与人员
|
||||
*/
|
||||
export function getcombinationStatisticsPeople(id, params) {
|
||||
return request({
|
||||
url: `marketing/combination/statistics/list/${id}`,
|
||||
method: 'GET',
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 拼团统计-订单列表
|
||||
*/
|
||||
export function getcombinationStatisticsOrder(id, params) {
|
||||
return request({
|
||||
url: `marketing/combination/statistics/order/${id}`,
|
||||
method: 'GET',
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 拼团立即成团
|
||||
*/
|
||||
export function combineJoinApi(id) {
|
||||
return request({
|
||||
url: `marketing/combination/immediately/${id}`,
|
||||
method: 'GET',
|
||||
});
|
||||
}
|
||||
@ -1,11 +0,0 @@
|
||||
{
|
||||
"key": "combination",
|
||||
"title": "拼团活动",
|
||||
"version": "1.0.0",
|
||||
"pages": [
|
||||
{ "path": "product", "title": "拼团商品管理" },
|
||||
{ "path": "pink", "title": "拼团列表" },
|
||||
{ "path": "create/:id?/:copy?", "title": "添加/编辑拼团商品" },
|
||||
{ "path": "statistics/:id", "title": "拼团统计" }
|
||||
]
|
||||
}
|
||||
@ -1,5 +0,0 @@
|
||||
import CombinationApp from './App.vue';
|
||||
import routes from './routes.js';
|
||||
|
||||
export default CombinationApp;
|
||||
export { routes };
|
||||
@ -1,837 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
<pages-header
|
||||
ref="pageHeader"
|
||||
:title="$route.params.id && !$route.params.copy ? '编辑拼团商品' : '添加拼团商品'"
|
||||
:backUrl="$routeProStr + '/marketing/combination/product'"
|
||||
></pages-header>
|
||||
<el-card :bordered="false" shadow="never" class="mt16">
|
||||
<el-row class="mt30 acea-row row-middle row-center">
|
||||
<el-col :span="20">
|
||||
<steps :stepList="stepList" :isActive="current"></steps>
|
||||
</el-col>
|
||||
<el-col :span="23" v-loading="spinShow">
|
||||
<el-form
|
||||
class="form mt30"
|
||||
ref="formRef"
|
||||
:model="formValidate"
|
||||
:rules="ruleValidate"
|
||||
:label-width="labelWidth"
|
||||
:label-position="labelPosition"
|
||||
@submit.prevent
|
||||
>
|
||||
<el-form-item label="选择商品:" prop="image_input" v-if="current === 0">
|
||||
<div class="picBox" v-db-click @click="changeGoods">
|
||||
<div class="pictrue" v-if="formValidate.image">
|
||||
<img v-lazy="formValidate.image" />
|
||||
</div>
|
||||
<div class="upLoad acea-row row-center-wrapper" v-else>
|
||||
<i class="el-icon-goods" style="font-size: 24px"></i>
|
||||
</div>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-row v-show="current === 1">
|
||||
<el-col :span="24">
|
||||
<el-form-item label="商品主图:" prop="image">
|
||||
<div class="picBox" v-db-click @click="modalPicTap('dan', 'danFrom')">
|
||||
<div class="pictrue" v-if="formValidate.image"><img v-lazy="formValidate.image" /></div>
|
||||
<div class="upLoad acea-row row-center-wrapper" v-else>
|
||||
<i class="el-icon-picture-outline" style="font-size: 24px"></i>
|
||||
</div>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="商品轮播图:" prop="images">
|
||||
<div class="acea-row">
|
||||
<div
|
||||
class="pictrue"
|
||||
v-for="(item, index) in formValidate.images"
|
||||
:key="index"
|
||||
draggable="true"
|
||||
@dragstart="handleDragStart($event, item)"
|
||||
@dragover.prevent="handleDragOver($event, item)"
|
||||
@dragenter="handleDragEnter($event, item)"
|
||||
@dragend="handleDragEnd($event, item)"
|
||||
>
|
||||
<img v-lazy="item" />
|
||||
<i class="el-icon-circle-close btndel" v-db-click @click="handleRemove(index)"></i>
|
||||
</div>
|
||||
<div
|
||||
v-if="formValidate.images.length < 10"
|
||||
class="upLoad acea-row row-center-wrapper"
|
||||
v-db-click
|
||||
@click="modalPicTap('duo')"
|
||||
>
|
||||
<i class="el-icon-picture-outline" style="font-size: 24px"></i>
|
||||
</div>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24">
|
||||
<el-col v-bind="grid">
|
||||
<el-form-item label="拼团名称:" prop="title">
|
||||
<el-input
|
||||
clearable
|
||||
placeholder="请输入拼团名称"
|
||||
v-model="formValidate.title"
|
||||
class="content_width"
|
||||
maxlength="80"
|
||||
show-word-limit
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-col>
|
||||
<el-col :span="24">
|
||||
<el-col v-bind="grid">
|
||||
<el-form-item label="拼团简介:" prop="info">
|
||||
<el-input
|
||||
placeholder="请输入拼团简介"
|
||||
type="textarea"
|
||||
:rows="4"
|
||||
v-model="formValidate.info"
|
||||
class="content_width"
|
||||
maxlength="100"
|
||||
show-word-limit
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-col>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="拼团时间:" prop="section_time">
|
||||
<div>
|
||||
<el-date-picker
|
||||
clearable
|
||||
:editable="false"
|
||||
type="datetimerange"
|
||||
format="YYYY-MM-DD HH:mm"
|
||||
value-format="YYYY-MM-DD HH:mm"
|
||||
range-separator="-"
|
||||
start-placeholder="开始日期"
|
||||
end-placeholder="结束日期"
|
||||
@change="onchangeTime"
|
||||
class="content_width"
|
||||
v-model="formValidate.section_time"
|
||||
></el-date-picker>
|
||||
<div class="grey">设置活动开启结束时间,用户可以在设置时间内发起参与拼团</div>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24" v-if="formValidate.virtual_type == 0">
|
||||
<el-form-item label="物流方式:" prop="logistics">
|
||||
<el-checkbox-group v-model="formValidate.logistics">
|
||||
<el-checkbox label="1">快递</el-checkbox>
|
||||
<el-checkbox label="2">到店</el-checkbox>
|
||||
</el-checkbox-group>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24" v-if="formValidate.virtual_type == 0 && formValidate.logistics.includes('1')">
|
||||
<el-form-item label="运费设置:">
|
||||
<el-radio-group v-model="formValidate.freight">
|
||||
<el-radio :label="2" :value="2">固定邮费</el-radio>
|
||||
<el-radio :label="3" :value="3">运费模板</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col
|
||||
:span="24"
|
||||
v-if="
|
||||
formValidate.freight != 3 &&
|
||||
formValidate.freight != 1 &&
|
||||
formValidate.virtual_type == 0 &&
|
||||
formValidate.logistics.includes('1')
|
||||
"
|
||||
>
|
||||
<el-form-item label="">
|
||||
<div class="acea-row">
|
||||
<el-input-number
|
||||
:controls="false"
|
||||
:min="0"
|
||||
:max="9999999999"
|
||||
v-model="formValidate.postage"
|
||||
placeholder="请输入金额"
|
||||
class="input-number-unit-class"
|
||||
class-unit="元"
|
||||
/>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24" v-if="formValidate.freight == 3 && formValidate.virtual_type == 0">
|
||||
<el-form-item label="" prop="temp_id">
|
||||
<div class="acea-row">
|
||||
<el-select
|
||||
v-model="formValidate.temp_id"
|
||||
clearable
|
||||
placeholder="请选择运费模板"
|
||||
class="content_width"
|
||||
>
|
||||
<el-option
|
||||
v-for="(item, index) in templateList"
|
||||
:value="item.id"
|
||||
:key="index"
|
||||
:label="item.name"
|
||||
></el-option>
|
||||
</el-select>
|
||||
<span class="addfont" v-db-click @click="freight">新增运费模板</span>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="拼团时效:" prop="effective_time">
|
||||
<div>
|
||||
<el-input-number
|
||||
:controls="false"
|
||||
placeholder="请输入拼团时效"
|
||||
class="input-number-unit-class"
|
||||
class-unit="小时"
|
||||
v-model="formValidate.effective_time"
|
||||
/>
|
||||
<div class="grey">
|
||||
用户发起拼团后开始计时,需在设置时间内邀请到规定好友人数参团,超过时效时间则系统判定拼团失败,自动发起退款
|
||||
</div>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="拼团人数:" prop="people">
|
||||
<div>
|
||||
<el-input-number
|
||||
:controls="false"
|
||||
:min="2"
|
||||
:max="10000"
|
||||
placeholder="请输入拼团人数"
|
||||
:precision="0"
|
||||
v-model="formValidate.people"
|
||||
class="input-number-unit-class"
|
||||
class-unit="人"
|
||||
/>
|
||||
<div class="grey">单次拼团需要参与的用户数</div>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="虚拟成团补齐人数:" prop="virtualPeople">
|
||||
<div>
|
||||
<el-input-number
|
||||
:controls="false"
|
||||
placeholder="设置虚拟成团的补齐人数"
|
||||
:precision="0"
|
||||
:max="10000"
|
||||
:min="0"
|
||||
v-model="formValidate.virtualPeople"
|
||||
class="input-number-unit-class"
|
||||
class-unit="人"
|
||||
/>
|
||||
<div class="grey">
|
||||
如:5人团设置补齐2人,当团队成员大于等于3人时,拼团结束时自动补齐剩余最多2个位置,不开启虚拟成团请设置为0
|
||||
</div>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="单位:" prop="unit_name">
|
||||
<el-input clearable placeholder="请输入单位" v-model="formValidate.unit_name" class="content_width" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="总购买数量限制:" prop="num">
|
||||
<div>
|
||||
<el-input-number
|
||||
:controls="false"
|
||||
:min="1"
|
||||
placeholder="请输入总数量限制"
|
||||
:precision="0"
|
||||
:max="10000"
|
||||
v-model="formValidate.num"
|
||||
class="input-number-unit-class"
|
||||
:class-unit="formValidate.unit_name || '件'"
|
||||
/>
|
||||
<div class="grey">该商品活动期间内,用户可购买的最大数量</div>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="单次购买数量限制:" prop="once_num">
|
||||
<div>
|
||||
<el-input-number
|
||||
:controls="false"
|
||||
:min="1"
|
||||
placeholder="请输入单次购买数量限制"
|
||||
:precision="0"
|
||||
:max="10000"
|
||||
v-model="formValidate.once_num"
|
||||
class="input-number-unit-class"
|
||||
:class-unit="formValidate.unit_name || '件'"
|
||||
/>
|
||||
<div class="grey">用户参与拼团时,一次购买最大数量限制</div>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="团长返佣比例:" prop="head_commission">
|
||||
<div>
|
||||
<el-input-number
|
||||
:controls="false"
|
||||
:min="0"
|
||||
:max="100"
|
||||
placeholder="团长返佣比例"
|
||||
:precision="0"
|
||||
v-model="formValidate.head_commission"
|
||||
class="input-number-unit-class"
|
||||
class-unit="%"
|
||||
/>
|
||||
<div class="grey">
|
||||
拼团成功后,如果团长是分销员,则订单确认收货时给团长返佣金,比例是实际支付金额的0-100%
|
||||
</div>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="拼团是否参与分销:" props="is_commission">
|
||||
<div>
|
||||
<el-switch
|
||||
class="defineSwitch"
|
||||
:active-value="1"
|
||||
:inactive-value="0"
|
||||
v-model="formValidate.is_commission"
|
||||
size="large"
|
||||
active-text="开启"
|
||||
inactive-text="关闭"
|
||||
>
|
||||
</el-switch>
|
||||
<div class="grey">拼团商品是否参与商城分销返佣</div>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="排序:">
|
||||
<el-input-number
|
||||
:controls="false"
|
||||
placeholder="请输入排序"
|
||||
:precision="0"
|
||||
:max="10000"
|
||||
:min="0"
|
||||
v-model="formValidate.sort"
|
||||
class="content_width"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="热门推荐:" props="is_hot">
|
||||
<el-switch
|
||||
class="defineSwitch"
|
||||
:active-value="1"
|
||||
:inactive-value="0"
|
||||
v-model="formValidate.is_host"
|
||||
size="large"
|
||||
active-text="开启"
|
||||
inactive-text="关闭"
|
||||
></el-switch>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="活动状态:" props="is_show">
|
||||
<el-switch
|
||||
class="defineSwitch"
|
||||
:active-value="1"
|
||||
:inactive-value="0"
|
||||
v-model="formValidate.is_show"
|
||||
size="large"
|
||||
active-text="开启"
|
||||
inactive-text="关闭"
|
||||
></el-switch>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="规格选择:">
|
||||
<el-table
|
||||
ref="multipleTableRef"
|
||||
:data="specsData"
|
||||
:row-key="getRowKeys"
|
||||
border
|
||||
@selection-change="changeCheckbox"
|
||||
>
|
||||
<el-table-column type="selection" :reserve-selection="true" width="55"></el-table-column>
|
||||
<el-table-column
|
||||
:label="item.title"
|
||||
:min-width="item.minWidth"
|
||||
v-for="(item, index) in columns"
|
||||
:key="index"
|
||||
>
|
||||
<template #default="scope">
|
||||
<template v-if="item.key"
|
||||
><span>{{ scope.row[item.key] }}</span></template
|
||||
>
|
||||
<template v-else-if="item.slot === 'pic'">
|
||||
<div
|
||||
class="acea-row row-middle row-center-wrapper"
|
||||
v-db-click
|
||||
@click="modalPicTap('dan', 'danTable', scope.$index)"
|
||||
>
|
||||
<div class="pictrue pictrueTab" v-if="scope.row.pic"><img v-lazy="scope.row.pic" /></div>
|
||||
<div class="upLoad pictrueTab acea-row row-center-wrapper" v-else>
|
||||
<i class="el-icon-picture-outline" style="font-size: 24px"></i>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else-if="item.slot === 'price'">
|
||||
<el-input-number
|
||||
:controls="false"
|
||||
v-model="scope.row.price"
|
||||
:min="0"
|
||||
:precision="2"
|
||||
class="priceBox"
|
||||
></el-input-number>
|
||||
</template>
|
||||
<template v-if="item.slot === 'quota'">
|
||||
<el-input-number
|
||||
:controls="false"
|
||||
v-model="scope.row.quota"
|
||||
:min="1"
|
||||
class="priceBox"
|
||||
></el-input-number>
|
||||
</template>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row v-show="current === 2">
|
||||
<el-col :span="24">
|
||||
<el-form-item label="内容:">
|
||||
<WangEditor
|
||||
style="width: 90%"
|
||||
:content="formValidate.description"
|
||||
:ai-default-prompt="aiDefaultPrompt"
|
||||
@editorContent="getEditorContent"
|
||||
></WangEditor>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-form-item>
|
||||
<el-button
|
||||
class="submission"
|
||||
v-db-click
|
||||
@click="step"
|
||||
:disabled="($route.params.id && current === 1) || current === 0"
|
||||
>上一步</el-button
|
||||
>
|
||||
<el-button
|
||||
:disabled="submitOpen && current === 2"
|
||||
type="primary"
|
||||
class="submission"
|
||||
v-db-click
|
||||
@click="next"
|
||||
>{{ current === 2 ? '提交' : '下一步' }}</el-button
|
||||
>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-card>
|
||||
<el-dialog v-model="modals" title="商品列表" class="paymentFooter" width="1000px">
|
||||
<goods-list ref="goodslistRef" @getProductId="getProductId"></goods-list>
|
||||
</el-dialog>
|
||||
<el-dialog v-model="modalPic" width="950px" title="上传商品图" :close-on-click-modal="false">
|
||||
<uploadPictures
|
||||
:isChoice="isChoice"
|
||||
@getPic="getPic"
|
||||
@getPicD="getPicD"
|
||||
:gridBtn="gridBtn"
|
||||
:gridPic="gridPic"
|
||||
v-if="modalPic"
|
||||
></uploadPictures>
|
||||
</el-dialog>
|
||||
<freight-template ref="templateRef" @addSuccess="productGetTemplate"></freight-template>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed, nextTick, onMounted, ref } from 'vue';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
import { ElMessage } from 'element-plus';
|
||||
import goodsList from '@/components/goodsList/index';
|
||||
import WangEditor from '@/components/wangEditor/index.vue';
|
||||
import uploadPictures from '@/components/uploadPictures';
|
||||
import { combinationInfoApi, combinationCreatApi } from '../../api';
|
||||
import { productAttrsApi } from '@/api/marketing';
|
||||
import { productGetTemplateApi } from '@/api/product';
|
||||
import freightTemplate from '@/components/freightTemplate/index';
|
||||
import steps from '@/components/steps/index';
|
||||
import setting from '@/setting';
|
||||
import { useMediaStore } from '@/store/module/media';
|
||||
|
||||
defineOptions({ name: 'combinationProductCreate' });
|
||||
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
const mediaStore = useMediaStore();
|
||||
|
||||
const routePre = setting.routePre;
|
||||
|
||||
const isMobile = computed(() => mediaStore.isMobile);
|
||||
const labelWidth = computed(() => (isMobile.value ? undefined : '155px'));
|
||||
const labelPosition = computed(() => (isMobile.value ? 'top' : 'right'));
|
||||
|
||||
const formRef = ref(null);
|
||||
const goodslistRef = ref(null);
|
||||
const multipleTableRef = ref(null);
|
||||
const templateRef = ref(null);
|
||||
|
||||
const submitOpen = ref(false);
|
||||
const spinShow = ref(false);
|
||||
const isChoice = ref('');
|
||||
const current = ref(0);
|
||||
const modalPic = ref(false);
|
||||
const grid = { xl: 12, lg: 20, md: 24, sm: 24, xs: 24 };
|
||||
const grid2 = { xl: 8, lg: 8, md: 12, sm: 24, xs: 24 };
|
||||
const gridPic = { xl: 6, lg: 8, md: 12, sm: 12, xs: 12 };
|
||||
const gridBtn = { xl: 4, lg: 8, md: 8, sm: 8, xs: 8 };
|
||||
const stepList = ['选择拼团商品', '填写基础信息', '修改商品详情'];
|
||||
const modals = ref(false);
|
||||
const modal_loading = ref(false);
|
||||
const images = ref([]);
|
||||
const templateList = ref([]);
|
||||
const columns = ref([]);
|
||||
const specsData = ref([]);
|
||||
const picTit = ref('');
|
||||
const tableIndex = ref(0);
|
||||
const copy = ref(0);
|
||||
const description = ref('');
|
||||
let dragging = null;
|
||||
|
||||
const formValidate = ref({
|
||||
images: [],
|
||||
info: '',
|
||||
title: '',
|
||||
image: '',
|
||||
unit_name: '',
|
||||
price: 0,
|
||||
effective_time: 24,
|
||||
stock: 1,
|
||||
sales: 0,
|
||||
sort: 0,
|
||||
is_postage: 0,
|
||||
is_commission: 0,
|
||||
is_host: 0,
|
||||
is_show: 0,
|
||||
section_time: [],
|
||||
description: '',
|
||||
id: 0,
|
||||
product_id: 0,
|
||||
people: 2,
|
||||
once_num: 1,
|
||||
num: 1,
|
||||
temp_id: '',
|
||||
attrs: [],
|
||||
items: [],
|
||||
virtual: 100,
|
||||
virtualPeople: 0,
|
||||
head_commission: 0,
|
||||
logistics: ['1'],
|
||||
freight: 2,
|
||||
postage: 1,
|
||||
});
|
||||
// AI 写作默认提示词:优先带入当前商品标题(弹窗内未被用户修改过的提示词会跟随刷新)
|
||||
const aiDefaultPrompt = computed(() => {
|
||||
const title = (formValidate.value.title || '').trim();
|
||||
return title
|
||||
? `请围绕商品《${title}》撰写一篇产品推广文章,介绍产品亮点、使用场景与适用人群,结构清晰,800字左右。`
|
||||
: '写一篇产品推广文章,介绍产品亮点、使用场景与适用人群,结构清晰,800字左右。';
|
||||
});
|
||||
const ruleValidate = {
|
||||
image: [{ required: true, message: '请选择主图', trigger: 'change' }],
|
||||
images: [{ required: true, type: 'array', message: '请选择轮播图', trigger: 'change', min: 1 }],
|
||||
title: [{ required: true, message: '请输入拼团名称', trigger: 'blur' }],
|
||||
info: [{ required: true, message: '请输入拼团简介', trigger: 'blur' }],
|
||||
section_time: [{ required: true, type: 'array', message: '请选择活动时间', trigger: 'change' }],
|
||||
unit_name: [{ required: true, message: '请输入单位', trigger: 'blur' }],
|
||||
effective_time: [{ required: true, type: 'number', message: '请输入拼团时效(小时)', trigger: 'blur' }],
|
||||
people: [{ required: true, type: 'number', message: '请输入拼团人数', trigger: 'blur' }],
|
||||
num: [{ required: true, type: 'number', message: '请输入购买数量限制', trigger: 'blur' }],
|
||||
once_num: [{ required: true, type: 'number', message: '请输入单次购买数量限制', trigger: 'blur' }],
|
||||
virtualPeople: [{ required: true, type: 'number', message: '请输入虚拟成团补齐人数', trigger: 'blur' }],
|
||||
temp_id: [{ required: true, message: '请选择运费模板', trigger: 'change', type: 'number' }],
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
if (route.params.id) {
|
||||
copy.value = route.params.copy;
|
||||
current.value = 1;
|
||||
getInfo();
|
||||
}
|
||||
productGetTemplate();
|
||||
});
|
||||
|
||||
function getEditorContent(data) {
|
||||
description.value = data;
|
||||
}
|
||||
function freight() {
|
||||
templateRef.value.id = 0;
|
||||
templateRef.value.isTemplate = true;
|
||||
}
|
||||
function productAttrs(row) {
|
||||
productAttrsApi(row.id, 3)
|
||||
.then((res) => {
|
||||
let data = res.data.info;
|
||||
specsData.value = data.attrs;
|
||||
specsData.value.forEach(function (item, index) {
|
||||
specsData.value[index]['id'] = index;
|
||||
});
|
||||
formValidate.value.items = data.items;
|
||||
columns.value = data.header;
|
||||
})
|
||||
.catch((res) => {
|
||||
ElMessage.error(res.msg);
|
||||
});
|
||||
}
|
||||
function changeCheckbox(selection) {
|
||||
formValidate.value.attrs = selection;
|
||||
}
|
||||
function productGetTemplate() {
|
||||
productGetTemplateApi().then((res) => {
|
||||
templateList.value = res.data;
|
||||
});
|
||||
}
|
||||
function getProductId(row) {
|
||||
modal_loading.value = false;
|
||||
modals.value = false;
|
||||
setTimeout(() => {
|
||||
formValidate.value = {
|
||||
images: row.slider_image,
|
||||
info: row.store_info,
|
||||
title: row.store_name,
|
||||
image: row.image,
|
||||
unit_name: row.unit_name,
|
||||
price: 0,
|
||||
effective_time: 24,
|
||||
stock: row.stock,
|
||||
sales: row.sales,
|
||||
sort: row.sort,
|
||||
is_postage: row.is_postage,
|
||||
is_commission: 0,
|
||||
is_host: row.is_hot,
|
||||
is_show: 0,
|
||||
section_time: [],
|
||||
id: 0,
|
||||
people: 2,
|
||||
num: 1,
|
||||
once_num: 1,
|
||||
product_id: row.id,
|
||||
temp_id: row.temp_id,
|
||||
virtual: 100,
|
||||
virtualPeople: 0,
|
||||
logistics: row.logistics,
|
||||
freight: row.freight,
|
||||
postage: row.postage,
|
||||
custom_form: row.custom_form,
|
||||
virtual_type: row.virtual_type,
|
||||
head_commission: 0,
|
||||
description: row.description,
|
||||
};
|
||||
productAttrs(row);
|
||||
}, 500);
|
||||
}
|
||||
function onchangeTime(e) {
|
||||
formValidate.value.section_time = e;
|
||||
}
|
||||
function getInfo() {
|
||||
spinShow.value = true;
|
||||
combinationInfoApi(route.params.id)
|
||||
.then(async (res) => {
|
||||
let info = res.data.info;
|
||||
formValidate.value = info;
|
||||
formValidate.value.virtualPeople = parseInt(
|
||||
formValidate.value.people - formValidate.value.people * (formValidate.value.virtual / 100),
|
||||
);
|
||||
formValidate.value['items'] = info.attrs.items;
|
||||
columns.value = info.attrs.header;
|
||||
specsData.value = info.attrs.value;
|
||||
specsData.value.forEach(function (item, index) {
|
||||
specsData.value[index]['id'] = index;
|
||||
});
|
||||
let attr = [];
|
||||
for (let index in info.attrs.value) {
|
||||
if (info.attrs.value[index]._checked) attr.push(info.attrs.value[index]);
|
||||
}
|
||||
formValidate.value.attrs = attr;
|
||||
nextTick(() => {
|
||||
attr.forEach((row) => {
|
||||
multipleTableRef.value && multipleTableRef.value.toggleRowSelection(row, true);
|
||||
});
|
||||
});
|
||||
spinShow.value = false;
|
||||
})
|
||||
.catch((res) => {
|
||||
spinShow.value = false;
|
||||
ElMessage.error(res.msg);
|
||||
});
|
||||
}
|
||||
function getRowKeys(row) {
|
||||
return row.id;
|
||||
}
|
||||
function next() {
|
||||
if (current.value === 2) {
|
||||
formValidate.value.description = description.value;
|
||||
formRef.value.validate((valid) => {
|
||||
if (valid) {
|
||||
if (copy.value == 1) formValidate.value.copy = 1;
|
||||
formValidate.value.id = Number(route.params.id) || 0;
|
||||
submitOpen.value = true;
|
||||
formValidate.value.virtual = parseInt(
|
||||
((formValidate.value.people - formValidate.value.virtualPeople) / formValidate.value.people) * 100,
|
||||
);
|
||||
combinationCreatApi(formValidate.value)
|
||||
.then(async (res) => {
|
||||
submitOpen.value = false;
|
||||
ElMessage.success(res.msg);
|
||||
setTimeout(() => {
|
||||
router.push({ path: routePre + '/marketing/combination/product' });
|
||||
}, 500);
|
||||
})
|
||||
.catch((res) => {
|
||||
submitOpen.value = false;
|
||||
ElMessage.error(res.msg);
|
||||
});
|
||||
}
|
||||
});
|
||||
} else if (current.value === 1) {
|
||||
formRef.value.validate((valid) => {
|
||||
if (valid) {
|
||||
if (formValidate.value.people < 2) return ElMessage.error('拼团人数必须大于2');
|
||||
if (formValidate.value.num < 0) return ElMessage.error('购买数量限制必须大于0');
|
||||
if (formValidate.value.once_num < 0) return ElMessage.error('单次购买数量限制必须大于0');
|
||||
if (!formValidate.value.attrs) return ElMessage.error('请选择属性规格');
|
||||
for (let index in formValidate.value.attrs) {
|
||||
if (formValidate.value.attrs[index].quota <= 0) return ElMessage.error('拼团限量必须大于0');
|
||||
if (formValidate.value.attrs[index].quota > formValidate.value.attrs[index]['stock'])
|
||||
return ElMessage.error('拼团限量不能超过规格库存');
|
||||
}
|
||||
current.value += 1;
|
||||
} else {
|
||||
return ElMessage.warning('请完善您的信息');
|
||||
}
|
||||
});
|
||||
} else {
|
||||
if (formValidate.value.image) current.value += 1;
|
||||
else ElMessage.warning('请选择商品');
|
||||
}
|
||||
}
|
||||
function step() {
|
||||
current.value--;
|
||||
}
|
||||
function modalPicTap(tit, picTitVal, index) {
|
||||
modalPic.value = true;
|
||||
isChoice.value = tit === 'dan' ? '单选' : '多选';
|
||||
picTit.value = picTitVal;
|
||||
tableIndex.value = index;
|
||||
}
|
||||
function getPic(pc) {
|
||||
switch (picTit.value) {
|
||||
case 'danFrom':
|
||||
formValidate.value.image = pc.att_dir;
|
||||
break;
|
||||
default:
|
||||
if (!!formValidate.value.attrs && formValidate.value.attrs.length)
|
||||
specsData.value[tableIndex.value]['_checked'] = true;
|
||||
specsData.value[tableIndex.value].pic = pc.att_dir;
|
||||
}
|
||||
modalPic.value = false;
|
||||
}
|
||||
function getPicD(pc) {
|
||||
images.value = pc;
|
||||
images.value.map((item) => {
|
||||
formValidate.value.images.push(item.att_dir);
|
||||
formValidate.value.images = formValidate.value.images.splice(0, 10);
|
||||
});
|
||||
modalPic.value = false;
|
||||
}
|
||||
function handleRemove(i) {
|
||||
images.value.splice(i, 1);
|
||||
formValidate.value.images.splice(i, 1);
|
||||
}
|
||||
function changeGoods() {
|
||||
modals.value = true;
|
||||
nextTick(() => {
|
||||
if (!goodslistRef.value) return;
|
||||
goodslistRef.value.formValidate.is_show = -1;
|
||||
goodslistRef.value.formValidate.type = 3;
|
||||
goodslistRef.value.getList();
|
||||
goodslistRef.value.goodsCategory();
|
||||
});
|
||||
}
|
||||
function handleDragStart(e, item) {
|
||||
dragging = item;
|
||||
}
|
||||
function handleDragEnd(e, item) {
|
||||
dragging = null;
|
||||
}
|
||||
function handleDragOver(e) {
|
||||
e.dataTransfer.dropEffect = 'move';
|
||||
}
|
||||
function handleDragEnter(e, item) {
|
||||
e.dataTransfer.effectAllowed = 'move';
|
||||
if (item === dragging) return;
|
||||
const newItems = [...formValidate.value.images];
|
||||
const src = newItems.indexOf(dragging);
|
||||
const dst = newItems.indexOf(item);
|
||||
newItems.splice(dst, 0, ...newItems.splice(src, 1));
|
||||
formValidate.value.images = newItems;
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.content_width {
|
||||
width: 460px;
|
||||
}
|
||||
.grey {
|
||||
font-size: 12px;
|
||||
color: #999;
|
||||
}
|
||||
.priceBox {
|
||||
width: 100%;
|
||||
}
|
||||
.addfont {
|
||||
font-size: 12px;
|
||||
color: var(--prev-color-primary);
|
||||
margin-left: 10px;
|
||||
cursor: pointer;
|
||||
}
|
||||
.form {
|
||||
.picBox {
|
||||
display: inline-block;
|
||||
cursor: pointer;
|
||||
}
|
||||
.pictrue {
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
border: 1px dotted rgba(0, 0, 0, 0.1);
|
||||
margin-right: 15px;
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
.btndel {
|
||||
position: absolute;
|
||||
z-index: 9;
|
||||
width: 20px !important;
|
||||
height: 20px !important;
|
||||
left: 46px;
|
||||
top: -4px;
|
||||
}
|
||||
}
|
||||
.upLoad {
|
||||
width: 58px;
|
||||
height: 58px;
|
||||
line-height: 58px;
|
||||
border: 1px dotted rgba(0, 0, 0, 0.1);
|
||||
border-radius: 4px;
|
||||
background: rgba(0, 0, 0, 0.02);
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@ -1,263 +0,0 @@
|
||||
<template>
|
||||
<div class="article-manager">
|
||||
<el-card :bordered="false" shadow="never" class="ivu-mb-16" :body-style="{ padding: 0 }">
|
||||
<div class="padding-add">
|
||||
<el-form
|
||||
ref="formRef"
|
||||
:model="formValidate"
|
||||
:label-width="labelWidth"
|
||||
:label-position="labelPosition"
|
||||
@submit.prevent
|
||||
inline
|
||||
>
|
||||
<el-form-item label="时间选择:">
|
||||
<date-range-picker
|
||||
clearable
|
||||
v-model="timeVal"
|
||||
:editable="false"
|
||||
@change="onchangeTime"
|
||||
format="YYYY/MM/DD"
|
||||
value-format="YYYY/MM/DD"
|
||||
class="mr20"
|
||||
></date-range-picker>
|
||||
</el-form-item>
|
||||
<el-form-item label="拼团状态:">
|
||||
<el-select
|
||||
v-model="formValidate.status"
|
||||
placeholder="请选择"
|
||||
clearable
|
||||
@change="userSearchs"
|
||||
class="form_content_width"
|
||||
>
|
||||
<el-option :value="1" label="进行中"></el-option>
|
||||
<el-option :value="2" label="已完成"></el-option>
|
||||
<el-option :value="3" label="未完成"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
</el-card>
|
||||
<cards-data :cardLists="cardLists" v-if="cardLists.length >= 0"></cards-data>
|
||||
<el-card :bordered="false" shadow="never" class="ivu-mt">
|
||||
<el-table :data="tableList" v-loading="loading" highlight-current-row>
|
||||
<el-table-column label="头像" min-width="90">
|
||||
<template #default="scope">
|
||||
<div class="tabBox_img" v-viewer><img v-lazy="scope.row.avatar" /></div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="开团团长" min-width="150">
|
||||
<template #default="scope"
|
||||
><span>{{ scope.row.nickname + ' / ' + scope.row.uid }}</span></template
|
||||
>
|
||||
</el-table-column>
|
||||
<el-table-column label="开团时间" min-width="150">
|
||||
<template #default="scope"
|
||||
><span>{{ $filters.formatDate(scope.row.add_time) }}</span></template
|
||||
>
|
||||
</el-table-column>
|
||||
<el-table-column label="拼团商品" min-width="180">
|
||||
<template #default="scope"
|
||||
><span>{{ scope.row.title + ' / ' + scope.row.cid }}</span></template
|
||||
>
|
||||
</el-table-column>
|
||||
<el-table-column label="几人团" min-width="80">
|
||||
<template #default="scope"
|
||||
><span>{{ scope.row.people }}</span></template
|
||||
>
|
||||
</el-table-column>
|
||||
<el-table-column label="几人参加" min-width="80">
|
||||
<template #default="scope"
|
||||
><span>{{ scope.row.count_people }}</span></template
|
||||
>
|
||||
</el-table-column>
|
||||
<el-table-column label="结束时间" min-width="120">
|
||||
<template #default="scope"
|
||||
><span>{{ $filters.formatDate(scope.row.stop_time) }}</span></template
|
||||
>
|
||||
</el-table-column>
|
||||
<el-table-column label="状态" min-width="120">
|
||||
<template #default="scope">
|
||||
<el-tag type="info" v-show="scope.row.status === 1">进行中</el-tag>
|
||||
<el-tag v-show="scope.row.status === 2">已完成</el-tag>
|
||||
<el-tag type="warning" v-show="scope.row.status === 3">未完成</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" fixed="right" width="150">
|
||||
<template #default="scope">
|
||||
<a v-db-click @click="Info(scope.row)">查看详情</a>
|
||||
<el-divider v-if="scope.row.status === 1" direction="vertical"></el-divider>
|
||||
<a v-if="scope.row.status === 1" v-db-click @click="joinCombination(scope.row)">立即成团</a>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<div class="acea-row row-right page">
|
||||
<pagination
|
||||
v-if="total"
|
||||
:total="total"
|
||||
v-model:page="formValidate.page"
|
||||
v-model:limit="formValidate.limit"
|
||||
@pagination="getList"
|
||||
/>
|
||||
</div>
|
||||
</el-card>
|
||||
<!-- 详情模态框-->
|
||||
<el-dialog v-model="modals" class="tableBox" title="查看详情" :close-on-click-modal="false" width="720px">
|
||||
<el-table
|
||||
ref="selection"
|
||||
:data="tabList3"
|
||||
v-loading="loading2"
|
||||
empty-text="暂无数据"
|
||||
highlight-current-row
|
||||
max-height="600"
|
||||
>
|
||||
<el-table-column label="ID" width="80">
|
||||
<template #default="scope"
|
||||
><span>{{ scope.row.id }}</span></template
|
||||
>
|
||||
</el-table-column>
|
||||
<el-table-column label="用户名称" min-width="100">
|
||||
<template #default="scope"
|
||||
><span>{{ scope.row.nickname + ' / ' + scope.row.uid }}</span></template
|
||||
>
|
||||
</el-table-column>
|
||||
<el-table-column label="用户头像" min-width="150">
|
||||
<template #default="scope">
|
||||
<div class="tabBox_img" v-viewer><img v-lazy="scope.row.avatar" /></div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="订单编号" min-width="100">
|
||||
<template #default="scope"
|
||||
><span>{{ scope.row.order_id }}</span></template
|
||||
>
|
||||
</el-table-column>
|
||||
<el-table-column label="金额" min-width="100">
|
||||
<template #default="scope"
|
||||
><span>{{ scope.row.total_price }}</span></template
|
||||
>
|
||||
</el-table-column>
|
||||
<el-table-column label="订单状态" min-width="100">
|
||||
<template #default="scope">
|
||||
<el-tag v-show="scope.row.is_refund != 0">已退款</el-tag>
|
||||
<el-tag type="danger" v-show="scope.row.is_refund === 0">未退款</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed, onMounted, ref } from 'vue';
|
||||
import { ElMessage, ElMessageBox } from 'element-plus';
|
||||
import cardsData from '@/components/cards/cards';
|
||||
import { combineListApi, orderPinkListApi, statisticsApi, combineJoinApi } from '../../api';
|
||||
import { useMediaStore } from '@/store/module/media';
|
||||
|
||||
defineOptions({ name: 'combinationPinkList' });
|
||||
|
||||
const mediaStore = useMediaStore();
|
||||
|
||||
const isMobile = computed(() => mediaStore.isMobile);
|
||||
const labelWidth = computed(() => (isMobile.value ? undefined : '80px'));
|
||||
const labelPosition = computed(() => (isMobile.value ? 'top' : 'right'));
|
||||
|
||||
const formRef = ref(null);
|
||||
const cardLists = ref([]);
|
||||
const modals = ref(false);
|
||||
const loading = ref(false);
|
||||
const formValidate = ref({ status: '', data: '', page: 1, limit: 15 });
|
||||
const tableList = ref([]);
|
||||
const total = ref(0);
|
||||
const timeVal = ref([]);
|
||||
const loading2 = ref(false);
|
||||
const tabList3 = ref([]);
|
||||
const rows = ref({});
|
||||
|
||||
onMounted(() => {
|
||||
getList();
|
||||
getStatistics();
|
||||
});
|
||||
|
||||
function getStatistics() {
|
||||
statisticsApi()
|
||||
.then(async (res) => {
|
||||
cardLists.value = res.data.res;
|
||||
})
|
||||
.catch((res) => {
|
||||
ElMessage.error(res.msg);
|
||||
});
|
||||
}
|
||||
function Info(row) {
|
||||
modals.value = true;
|
||||
rows.value = row;
|
||||
orderPinkListApi(row.id)
|
||||
.then(async (res) => {
|
||||
tabList3.value = res.data.list;
|
||||
loading.value = false;
|
||||
})
|
||||
.catch((res) => {
|
||||
loading.value = false;
|
||||
ElMessage.error(res.msg);
|
||||
});
|
||||
}
|
||||
function joinCombination(row) {
|
||||
ElMessageBox.confirm('确认成团?', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
})
|
||||
.then(() => {
|
||||
combineJoinApi(row.id)
|
||||
.then((res) => {
|
||||
ElMessage.success(res.msg);
|
||||
getList();
|
||||
})
|
||||
.catch((res) => {
|
||||
ElMessage.error(res.msg);
|
||||
});
|
||||
})
|
||||
.catch(() => {
|
||||
ElMessage.info('已取消');
|
||||
});
|
||||
}
|
||||
function onchangeTime(e) {
|
||||
timeVal.value = e || [];
|
||||
formValidate.value.data = timeVal.value[0] === '' ? '' : timeVal.value ? timeVal.value.join('-') : '';
|
||||
formValidate.value.page = 1;
|
||||
getList();
|
||||
}
|
||||
function getList() {
|
||||
loading.value = true;
|
||||
formValidate.value.status = formValidate.value.status || '';
|
||||
combineListApi(formValidate.value)
|
||||
.then(async (res) => {
|
||||
tableList.value = res.data.list;
|
||||
total.value = res.data.count;
|
||||
loading.value = false;
|
||||
})
|
||||
.catch((res) => {
|
||||
loading.value = false;
|
||||
ElMessage.error(res.msg);
|
||||
});
|
||||
}
|
||||
function userSearchs() {
|
||||
formValidate.value.page = 1;
|
||||
getList();
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.article-manager {
|
||||
margin-top: 3px;
|
||||
}
|
||||
.tabBox_img {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@ -1,288 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-card :bordered="false" shadow="never" :body-style="{ padding: 0 }">
|
||||
<div class="padding-add">
|
||||
<el-form
|
||||
ref="formRef"
|
||||
:model="formValidate"
|
||||
:label-width="labelWidth"
|
||||
label-position="right"
|
||||
@submit.prevent
|
||||
inline
|
||||
>
|
||||
<el-form-item label="上架状态:">
|
||||
<el-select
|
||||
v-model="formValidate.is_show"
|
||||
placeholder="请选择"
|
||||
clearable
|
||||
@change="userSearchs"
|
||||
class="form_content_width"
|
||||
>
|
||||
<el-option :value="1" label="上架"></el-option>
|
||||
<el-option :value="0" label="下架"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="拼团搜索:" prop="store_name">
|
||||
<el-input
|
||||
clearable
|
||||
placeholder="请输入拼团名称/ID"
|
||||
v-model="formValidate.store_name"
|
||||
class="form_content_width"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" v-db-click @click="userSearchs">查询</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
</el-card>
|
||||
<el-card :bordered="false" shadow="never" class="ivu-mt mt16">
|
||||
<el-button
|
||||
v-auth="['marketing-store_combination-create']"
|
||||
class="action-row"
|
||||
type="primary"
|
||||
v-db-click
|
||||
@click="add"
|
||||
>
|
||||
添加拼团商品
|
||||
</el-button>
|
||||
<el-button v-auth="['export-storeCombination']" class="action-row export" v-db-click @click="exports"
|
||||
>导出</el-button
|
||||
>
|
||||
<el-table :data="tableList" v-loading="loading" highlight-current-row class="mt14">
|
||||
<el-table-column label="ID" width="80">
|
||||
<template #default="scope"
|
||||
><span>{{ scope.row.id }}</span></template
|
||||
>
|
||||
</el-table-column>
|
||||
<el-table-column label="拼团图片" min-width="90">
|
||||
<template #default="scope">
|
||||
<div class="tabBox_img" v-viewer><img v-lazy="scope.row.image" /></div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="拼团名称" min-width="130">
|
||||
<template #default="scope">
|
||||
<el-tooltip placement="top" :show-after="600">
|
||||
<template #content
|
||||
><div>{{ scope.row.title }}</div></template
|
||||
>
|
||||
<span class="line2">{{ scope.row.title }}</span>
|
||||
</el-tooltip>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="原价" min-width="100">
|
||||
<template #default="scope"
|
||||
><span>{{ scope.row.ot_price }}</span></template
|
||||
>
|
||||
</el-table-column>
|
||||
<el-table-column label="拼团价" min-width="100">
|
||||
<template #default="scope"
|
||||
><span>{{ scope.row.price }}</span></template
|
||||
>
|
||||
</el-table-column>
|
||||
<el-table-column label="拼团人数" min-width="80">
|
||||
<template #default="scope"
|
||||
><span>{{ scope.row.count_people }}</span></template
|
||||
>
|
||||
</el-table-column>
|
||||
<el-table-column label="参与人数" min-width="80">
|
||||
<template #default="scope"
|
||||
><span>{{ scope.row.count_people_all }}</span></template
|
||||
>
|
||||
</el-table-column>
|
||||
<el-table-column label="成团数量" min-width="80">
|
||||
<template #default="scope"
|
||||
><span>{{ scope.row.count_people_pink }}</span></template
|
||||
>
|
||||
</el-table-column>
|
||||
<el-table-column label="限量" min-width="80">
|
||||
<template #default="scope"
|
||||
><span>{{ scope.row.quota_show }}</span></template
|
||||
>
|
||||
</el-table-column>
|
||||
<el-table-column label="限量剩余" min-width="80">
|
||||
<template #default="scope"
|
||||
><span>{{ scope.row.quota }}</span></template
|
||||
>
|
||||
</el-table-column>
|
||||
<el-table-column label="活动状态" min-width="100">
|
||||
<template #default="scope">
|
||||
<el-tag v-show="scope.row.start_name === '进行中'">进行中</el-tag>
|
||||
<el-tag type="warning" v-show="scope.row.start_name === '未开始'">未开始</el-tag>
|
||||
<el-tag type="info" v-show="scope.row.start_name === '已结束'">已结束</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="活动时间" min-width="180">
|
||||
<template #default="scope">
|
||||
<p>开始:{{ scope.row.start_time }}</p>
|
||||
<p>结束:{{ scope.row.stop_time }}</p>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="上架状态" min-width="120">
|
||||
<template #default="scope">
|
||||
<el-switch
|
||||
class="defineSwitch"
|
||||
:active-value="1"
|
||||
:inactive-value="0"
|
||||
v-model="scope.row.is_show"
|
||||
@change="onchangeIsShow(scope.row)"
|
||||
size="large"
|
||||
active-text="上架"
|
||||
inactive-text="下架"
|
||||
>
|
||||
</el-switch>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" fixed="right" width="170">
|
||||
<template #default="scope">
|
||||
<a v-if="scope.row.stop_status === 0" v-db-click @click="edit(scope.row)">编辑</a>
|
||||
<el-divider direction="vertical" v-if="scope.row.stop_status === 0" />
|
||||
<a v-db-click @click="copy(scope.row)">复制</a>
|
||||
<el-divider direction="vertical"></el-divider>
|
||||
<a v-db-click @click="del(scope.row, '删除拼团商品', scope.$index)">删除</a>
|
||||
<el-divider direction="vertical"></el-divider>
|
||||
<a v-db-click @click="viewInfo(scope.row)">统计</a>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<div class="acea-row row-right page">
|
||||
<pagination
|
||||
v-if="total"
|
||||
:total="total"
|
||||
v-model:page="formValidate.page"
|
||||
v-model:limit="formValidate.limit"
|
||||
@pagination="getList"
|
||||
/>
|
||||
</div>
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed, onMounted, ref } from 'vue';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
import { ElMessage } from 'element-plus';
|
||||
import { combinationListApi, combinationSetStatusApi, storeCombinationApi } from '../../api';
|
||||
import exportExcel from '@/utils/newToExcel.js';
|
||||
import { modalSure } from '@/utils/public';
|
||||
import setting from '@/setting';
|
||||
import { useMediaStore } from '@/store/module/media';
|
||||
|
||||
defineOptions({ name: 'combinationProductList' });
|
||||
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
const mediaStore = useMediaStore();
|
||||
|
||||
const routePre = setting.routePre;
|
||||
|
||||
const isMobile = computed(() => mediaStore.isMobile);
|
||||
const labelWidth = computed(() => (isMobile.value ? undefined : '80px'));
|
||||
const labelPosition = computed(() => (isMobile.value ? 'top' : 'right'));
|
||||
|
||||
const formRef = ref(null);
|
||||
const loading = ref(false);
|
||||
const formValidate = ref({ is_show: '', store_name: '', page: 1, limit: 15 });
|
||||
const tableList = ref([]);
|
||||
const total = ref(0);
|
||||
|
||||
onMounted(() => {
|
||||
getList();
|
||||
});
|
||||
|
||||
async function exports() {
|
||||
let [th, filekey, data, fileName] = [[], [], [], ''];
|
||||
let excelData = JSON.parse(JSON.stringify(formValidate.value));
|
||||
excelData.page = 1;
|
||||
excelData.limit = 200;
|
||||
for (let i = 0; i < excelData.page + 1; i++) {
|
||||
let lebData = await getExcelData(excelData);
|
||||
if (!fileName) fileName = lebData.filename;
|
||||
if (!filekey.length) filekey = lebData.fileKey;
|
||||
if (!th.length) th = lebData.header;
|
||||
if (lebData.export.length) {
|
||||
data = data.concat(lebData.export);
|
||||
excelData.page++;
|
||||
} else {
|
||||
exportExcel(th, filekey, fileName, data);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
function getExcelData(excelData) {
|
||||
return new Promise((resolve) => {
|
||||
storeCombinationApi(excelData).then((res) => resolve(res.data));
|
||||
});
|
||||
}
|
||||
function add() {
|
||||
router.push({ path: routePre + '/marketing/combination/create' });
|
||||
}
|
||||
function edit(row) {
|
||||
router.push({
|
||||
path: routePre + '/marketing/combination/create/' + row.id + '/0',
|
||||
});
|
||||
}
|
||||
function copy(row) {
|
||||
router.push({
|
||||
path: routePre + '/marketing/combination/create/' + row.id + '/1',
|
||||
});
|
||||
}
|
||||
function del(row, tit, num) {
|
||||
let delfromData = { title: tit, num: num, url: `marketing/combination/${row.id}`, method: 'DELETE', ids: '' };
|
||||
modalSure(delfromData)
|
||||
.then((res) => {
|
||||
ElMessage.success(res.msg);
|
||||
tableList.value.splice(num, 1);
|
||||
})
|
||||
.catch((res) => {
|
||||
ElMessage.error(res.msg);
|
||||
});
|
||||
}
|
||||
function viewInfo(row) {
|
||||
router.push({
|
||||
path: routePre + '/marketing/combination/statistics/' + row.id,
|
||||
});
|
||||
}
|
||||
function getList() {
|
||||
loading.value = true;
|
||||
formValidate.value.product_id = route.params.product_id || '';
|
||||
combinationListApi(formValidate.value)
|
||||
.then(async (res) => {
|
||||
tableList.value = res.data.list;
|
||||
total.value = res.data.count;
|
||||
loading.value = false;
|
||||
})
|
||||
.catch((res) => {
|
||||
loading.value = false;
|
||||
ElMessage.error(res.msg);
|
||||
});
|
||||
}
|
||||
function userSearchs() {
|
||||
formValidate.value.page = 1;
|
||||
getList();
|
||||
}
|
||||
function onchangeIsShow(row) {
|
||||
let data = { id: row.id, status: row.is_show };
|
||||
combinationSetStatusApi(data)
|
||||
.then(async (res) => {
|
||||
ElMessage.success(res.msg);
|
||||
})
|
||||
.catch((res) => {
|
||||
ElMessage.error(res.msg);
|
||||
row.is_show = !row.is_show;
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.tabBox_img {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@ -1,250 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
<pages-header
|
||||
ref="pageHeader"
|
||||
:title="$route.meta.title"
|
||||
:backUrl="$routeProStr + '/marketing/combination/product'"
|
||||
></pages-header>
|
||||
<cards-data :cardLists="cardLists" v-if="cardLists.length >= 0" class="ivu-mt-16"></cards-data>
|
||||
<el-card :bordered="false" shadow="never">
|
||||
<el-form ref="paginationRef" :model="pagination" label-width="80px" label-position="right" @submit.prevent inline>
|
||||
<el-form-item v-if="type == 1" label="订单状态:">
|
||||
<el-select
|
||||
v-model="pagination.status"
|
||||
placeholder="请选择订单状态"
|
||||
clearable
|
||||
@change="searchList"
|
||||
class="form_content_width"
|
||||
>
|
||||
<el-option value="1" label="待发货"></el-option>
|
||||
<el-option value="2" label="待收货"></el-option>
|
||||
<el-option value="3" label="待评价"></el-option>
|
||||
<el-option value="4" label="交易完成"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="搜索:">
|
||||
<el-input
|
||||
v-model="pagination.real_name"
|
||||
:placeholder="type == 1 ? '请输入用户|订单号|UID' : '请输入用户姓名|UID'"
|
||||
class="form_content_width"
|
||||
clearable
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" v-db-click @click="searchList">查询</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<el-tabs v-model="type" @tab-change="onClickTab">
|
||||
<el-tab-pane v-for="(item, index) in tabs" :label="item.label" :name="item.type" :key="index" />
|
||||
</el-tabs>
|
||||
<el-table :data="tbody" ref="tableRef" v-loading="loading" highlight-current-row>
|
||||
<el-table-column
|
||||
:label="item.title"
|
||||
:min-width="item.minWidth"
|
||||
v-for="(item, index) in type == 1 ? thead2 : thead"
|
||||
:key="index"
|
||||
>
|
||||
<template #default="scope">
|
||||
<template v-if="item.key"
|
||||
><span>{{ scope.row[item.key] }}</span></template
|
||||
>
|
||||
<template v-else-if="item.slot === 'avatar'">
|
||||
<div class="tabBox_img" v-viewer><img v-lazy="scope.row.avatar" /></div>
|
||||
</template>
|
||||
<template v-else-if="item.slot === 'people'">
|
||||
<span>{{ scope.row.count_people + ' / ' + scope.row.people }}</span>
|
||||
</template>
|
||||
<template v-else-if="item.slot === 'status'">
|
||||
<el-tag type="info" v-show="scope.row.status === 1">进行中</el-tag>
|
||||
<el-tag type="danger" v-show="scope.row.status === 3">已失败</el-tag>
|
||||
<el-tag v-show="scope.row.status === 2">已成功</el-tag>
|
||||
</template>
|
||||
<template v-else-if="item.slot === 'action'">
|
||||
<a v-db-click @click="Info(scope.row)">查看详情</a>
|
||||
</template>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<div class="acea-row row-right page">
|
||||
<pagination
|
||||
v-if="total"
|
||||
:total="total"
|
||||
v-model:page="pagination.page"
|
||||
v-model:limit="pagination.limit"
|
||||
@pagination="getList"
|
||||
/>
|
||||
</div>
|
||||
</el-card>
|
||||
<el-dialog v-model="modals" class="tableBox" title="查看详情" :close-on-click-modal="false" width="750px">
|
||||
<el-table
|
||||
ref="selection"
|
||||
:data="tabList3"
|
||||
v-loading="loading2"
|
||||
empty-text="暂无数据"
|
||||
highlight-current-row
|
||||
max-height="600"
|
||||
>
|
||||
<el-table-column label="ID" width="80">
|
||||
<template #default="scope"
|
||||
><span>{{ scope.row.id }}</span></template
|
||||
>
|
||||
</el-table-column>
|
||||
<el-table-column label="用户头像" min-width="90">
|
||||
<template #default="scope">
|
||||
<div class="tabBox_img" v-viewer><img v-lazy="scope.row.avatar" /></div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="用户名称" min-width="130">
|
||||
<template #default="scope"
|
||||
><span>{{ scope.row.nickname + ' / ' + scope.row.uid }}</span></template
|
||||
>
|
||||
</el-table-column>
|
||||
<el-table-column label="订单编号" min-width="130">
|
||||
<template #default="scope"
|
||||
><span>{{ scope.row.order_id }}</span></template
|
||||
>
|
||||
</el-table-column>
|
||||
<el-table-column label="金额" min-width="130">
|
||||
<template #default="scope"
|
||||
><span>{{ scope.row.total_price }}</span></template
|
||||
>
|
||||
</el-table-column>
|
||||
<el-table-column label="订单状态" min-width="130">
|
||||
<template #default="scope">
|
||||
<el-tag v-show="scope.row.is_refund != 0">已退款</el-tag>
|
||||
<el-tag type="danger" v-show="scope.row.is_refund === 0">未退款</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { onMounted, ref } from 'vue';
|
||||
import { useRoute } from 'vue-router';
|
||||
import { ElMessage } from 'element-plus';
|
||||
import cardsData from '@/components/cards/cards';
|
||||
import {
|
||||
getcombinationStatistics,
|
||||
getcombinationStatisticsPeople,
|
||||
getcombinationStatisticsOrder,
|
||||
orderPinkListApi,
|
||||
} from '../../api';
|
||||
|
||||
defineOptions({ name: 'combinationStatistics' });
|
||||
|
||||
const route = useRoute();
|
||||
|
||||
const paginationRef = ref(null);
|
||||
const tableRef = ref(null);
|
||||
|
||||
const modals = ref(false);
|
||||
const id = ref(0);
|
||||
const tbody = ref([]);
|
||||
const total = ref(0);
|
||||
const loading = ref(false);
|
||||
const loading2 = ref(false);
|
||||
const tabList3 = ref([]);
|
||||
const rows = ref({});
|
||||
const tabs = [
|
||||
{ type: '0', label: '活动参与人' },
|
||||
{ type: '1', label: '活动订单' },
|
||||
];
|
||||
const type = ref('0');
|
||||
const thead = [
|
||||
{ title: '头像', slot: 'avatar' },
|
||||
{ title: '发起用户', key: 'nickname' },
|
||||
{ title: '开团时间', key: '_add_time' },
|
||||
{ title: '拼团人数', slot: 'people' },
|
||||
{ title: '结束时间', key: '_stop_time' },
|
||||
{ title: '拼团状态', slot: 'status' },
|
||||
{ title: '操作', slot: 'action' },
|
||||
];
|
||||
const thead2 = [
|
||||
{ title: '订单号', key: 'order_id' },
|
||||
{ title: '用户', key: 'real_name' },
|
||||
{ title: '订单状态', key: 'status' },
|
||||
{ title: '订单支付金额', key: 'pay_price' },
|
||||
{ title: '订单商品数', key: 'total_num' },
|
||||
{ title: '下单时间', key: 'add_time' },
|
||||
{ title: '支付时间', key: 'pay_time' },
|
||||
];
|
||||
const cardLists = ref([
|
||||
{ col: 4, count: 0, name: '活动参与人数(人)', className: 'iconcanyurenshu' },
|
||||
{ col: 4, count: 0, name: '推广人数(人)', className: 'icontuiguangrenshu' },
|
||||
{ col: 4, count: 0, name: '发起拼团数', className: 'iconfaqirenshu' },
|
||||
{ col: 4, count: 0, name: '成团数', className: 'iconchengtuanshu' },
|
||||
{ col: 4, count: 0, name: '支付订单额(元)', className: 'iconzhifudingdan' },
|
||||
{ col: 4, count: 0, name: '支付人数(人)', className: 'iconxiadanrenshu' },
|
||||
]);
|
||||
const pagination = ref({ page: 1, limit: 15, real_name: '', status: '' });
|
||||
|
||||
onMounted(() => {
|
||||
id.value = route.params.id;
|
||||
getStatistics();
|
||||
getList();
|
||||
});
|
||||
|
||||
function getStatistics() {
|
||||
getcombinationStatistics(id.value).then((res) => {
|
||||
let arr = ['people_count', 'spread_count', 'start_count', 'success_count', 'pay_price', 'pay_count'];
|
||||
cardLists.value.map((i, index) => {
|
||||
i.count = res.data[arr[index]];
|
||||
});
|
||||
});
|
||||
}
|
||||
function getList() {
|
||||
loading.value = true;
|
||||
if (type.value == 0) {
|
||||
getcombinationStatisticsPeople(id.value, pagination.value).then((res) => {
|
||||
loading.value = false;
|
||||
total.value = res.data.count;
|
||||
tbody.value = res.data.list;
|
||||
});
|
||||
} else {
|
||||
getcombinationStatisticsOrder(id.value, pagination.value).then((res) => {
|
||||
loading.value = false;
|
||||
total.value = res.data.count;
|
||||
tbody.value = res.data.list;
|
||||
});
|
||||
}
|
||||
}
|
||||
// el-tabs 的 v-model 在 tab-click 前已更新,直接读 type
|
||||
function onClickTab() {
|
||||
pagination.value.page = 1;
|
||||
pagination.value.real_name = '';
|
||||
pagination.value.status = '';
|
||||
getList();
|
||||
}
|
||||
function searchList() {
|
||||
pagination.value.page = 1;
|
||||
getList();
|
||||
}
|
||||
function Info(row) {
|
||||
modals.value = true;
|
||||
rows.value = row;
|
||||
orderPinkListApi(row.id)
|
||||
.then(async (res) => {
|
||||
tabList3.value = res.data.list;
|
||||
loading.value = false;
|
||||
})
|
||||
.catch((res) => {
|
||||
loading.value = false;
|
||||
ElMessage.error(res.msg);
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.tabBox_img {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@ -1,124 +0,0 @@
|
||||
/**
|
||||
* 拼团扩展路由
|
||||
*/
|
||||
import setting from '@/setting';
|
||||
const routePre = setting.routePre;
|
||||
const pre = 'combination_';
|
||||
|
||||
export default [
|
||||
{
|
||||
path: routePre + '/marketing/combination/product',
|
||||
section: 'combination',
|
||||
action: 'product',
|
||||
meta: {
|
||||
auth: ['marketing-combination-product'],
|
||||
title: '拼团商品',
|
||||
},
|
||||
component: () => import('@/layout'),
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
name: `${pre}product`,
|
||||
component: () => import('./pages/product/index.vue'),
|
||||
meta: {
|
||||
auth: ['marketing-combination-product'],
|
||||
title: '拼团商品',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: routePre + '/marketing/combination/create/:id?/:copy?',
|
||||
section: 'combination',
|
||||
action: 'create',
|
||||
meta: {
|
||||
auth: ['marketing-combination-create'],
|
||||
title: '添加/编辑拼团商品',
|
||||
},
|
||||
component: () => import('@/layout'),
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
name: `${pre}create`,
|
||||
component: () => import('./pages/create/index.vue'),
|
||||
meta: {
|
||||
auth: ['marketing-combination-create'],
|
||||
title: '添加/编辑拼团商品',
|
||||
activeMenu: routePre + '/marketing/combination/product',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: routePre + '/marketing/combination/pink',
|
||||
section: 'combination',
|
||||
action: 'pink',
|
||||
meta: {
|
||||
auth: ['marketing-combination-pink'],
|
||||
title: '拼团列表',
|
||||
},
|
||||
component: () => import('@/layout'),
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
name: `${pre}pink`,
|
||||
component: () => import('./pages/pink/index.vue'),
|
||||
meta: {
|
||||
auth: ['marketing-combination-pink'],
|
||||
title: '拼团列表',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: routePre + '/marketing/combination/statistics/:id',
|
||||
section: 'combination',
|
||||
action: 'statistics',
|
||||
meta: {
|
||||
auth: ['marketing-combination-statistics'],
|
||||
title: '拼团统计',
|
||||
},
|
||||
component: () => import('@/layout'),
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
name: `${pre}statistics`,
|
||||
component: () => import('./pages/statistics/index.vue'),
|
||||
meta: {
|
||||
auth: ['marketing-combination-statistics'],
|
||||
title: '拼团统计',
|
||||
activeMenu: routePre + '/marketing/combination/product',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
// 兼容旧路由
|
||||
{
|
||||
path: routePre + '/marketing/store_combination/index',
|
||||
section: 'combination',
|
||||
action: 'product',
|
||||
name: `${pre}legacyIndex`,
|
||||
meta: { title: '拼团商品' },
|
||||
},
|
||||
{
|
||||
path: routePre + '/marketing/store_combination/combina_list',
|
||||
section: 'combination',
|
||||
action: 'pink',
|
||||
name: `${pre}legacyPink`,
|
||||
meta: { title: '拼团列表' },
|
||||
},
|
||||
{
|
||||
path: routePre + '/marketing/store_combination/create/:id?/:copy?',
|
||||
section: 'combination',
|
||||
action: 'create',
|
||||
name: `${pre}legacyCreate`,
|
||||
meta: { title: '添加/编辑拼团商品' },
|
||||
},
|
||||
{
|
||||
path: routePre + '/marketing/store_combination/statistics/:id',
|
||||
section: 'combination',
|
||||
action: 'statistics',
|
||||
name: `${pre}legacyStatistics`,
|
||||
meta: { title: '拼团统计' },
|
||||
},
|
||||
];
|
||||
@ -1,133 +0,0 @@
|
||||
<template>
|
||||
<div class="coupon-setting">
|
||||
<el-form :model="couponForm" label-width="120px" label-position="right">
|
||||
<el-form-item label="优惠券面值:" prop="coupon_value">
|
||||
<el-input-number
|
||||
:controls="false"
|
||||
:min="0"
|
||||
v-model="couponForm.coupon_value"
|
||||
placeholder="请输入面值"
|
||||
class="input-number-unit-class"
|
||||
class-unit="元"
|
||||
></el-input-number>
|
||||
</el-form-item>
|
||||
<el-form-item label="优惠门槛:" prop="coupon_min">
|
||||
<el-input-number
|
||||
:controls="false"
|
||||
:min="0"
|
||||
v-model="couponForm.coupon_min"
|
||||
placeholder="请输入门槛金额"
|
||||
class="input-number-unit-class"
|
||||
class-unit="元"
|
||||
></el-input-number>
|
||||
</el-form-item>
|
||||
<el-form-item label="有效期:" prop="coupon_start_time">
|
||||
<el-date-picker
|
||||
v-model="couponForm.coupon_start_time"
|
||||
type="date"
|
||||
placeholder="开始日期"
|
||||
style="width: 48%"
|
||||
></el-date-picker>
|
||||
<span style="margin: 0 10px">至</span>
|
||||
<el-date-picker
|
||||
v-model="couponForm.coupon_end_time"
|
||||
type="date"
|
||||
placeholder="结束日期"
|
||||
style="width: 48%"
|
||||
></el-date-picker>
|
||||
</el-form-item>
|
||||
<el-form-item label="使用范围:" prop="coupon_scope">
|
||||
<el-radio-group v-model="couponForm.coupon_scope">
|
||||
<el-radio :label="0" :value="0">全店通用</el-radio>
|
||||
<el-radio :label="1" :value="1">指定分类</el-radio>
|
||||
<el-radio :label="2" :value="2">指定商品</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="指定分类:" prop="coupon_cate_id" v-if="couponForm.coupon_scope === 1">
|
||||
<el-cascader
|
||||
v-model="couponForm.coupon_cate_id"
|
||||
:options="treeSelect"
|
||||
:props="{ multiple: true, emitPath: false, checkStrictly: true }"
|
||||
clearable
|
||||
></el-cascader>
|
||||
</el-form-item>
|
||||
<el-form-item label="指定商品:" prop="coupon_product_id" v-if="couponForm.coupon_scope === 2">
|
||||
<el-select
|
||||
v-model="couponForm.coupon_product_id"
|
||||
multiple
|
||||
clearable
|
||||
placeholder="请选择商品"
|
||||
style="width: 100%"
|
||||
>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="每人限领:" prop="coupon_limit">
|
||||
<el-input-number
|
||||
:controls="false"
|
||||
:min="0"
|
||||
v-model="couponForm.coupon_limit"
|
||||
placeholder="0表示不限"
|
||||
></el-input-number>
|
||||
<span>张</span>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue';
|
||||
import { ElMessage } from 'element-plus';
|
||||
import { cascaderListApi } from '@/api/product';
|
||||
|
||||
defineOptions({ name: 'couponSetting' });
|
||||
|
||||
const props = defineProps({
|
||||
productId: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
});
|
||||
|
||||
const treeSelect = ref([]);
|
||||
const couponForm = ref({
|
||||
coupon_value: 0,
|
||||
coupon_min: 0,
|
||||
coupon_start_time: '',
|
||||
coupon_end_time: '',
|
||||
coupon_scope: 0,
|
||||
coupon_cate_id: [],
|
||||
coupon_product_id: [],
|
||||
coupon_limit: 0,
|
||||
});
|
||||
|
||||
loadCategory();
|
||||
if (props.productId) {
|
||||
loadData();
|
||||
}
|
||||
|
||||
async function loadCategory() {
|
||||
try {
|
||||
const res = await cascaderListApi(1);
|
||||
treeSelect.value = res.data;
|
||||
} catch (error) {
|
||||
ElMessage.error('加载分类失败');
|
||||
}
|
||||
}
|
||||
async function loadData() {
|
||||
try {
|
||||
} catch (error) {
|
||||
ElMessage.error('加载失败');
|
||||
}
|
||||
}
|
||||
function getFormData() {
|
||||
return { ...couponForm.value };
|
||||
}
|
||||
|
||||
defineExpose({ getFormData });
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.coupon-setting {
|
||||
padding: 20px;
|
||||
}
|
||||
</style>
|
||||
@ -1,132 +0,0 @@
|
||||
<template>
|
||||
<div class="product-add">
|
||||
<el-card :bordered="false" shadow="never" class="ivu-mt" :body-style="{ padding: 0 }">
|
||||
<div class="tab-container">
|
||||
<el-tabs v-model="activeName" type="card" @tab-click="handleClick">
|
||||
<el-tab-pane label="基本信息" name="basic">
|
||||
<basicInfo
|
||||
ref="basicInfoRef"
|
||||
:productId="productId"
|
||||
:productType="'coupon'"
|
||||
@saveSuccess="saveSuccess"
|
||||
></basicInfo>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="优惠券设置" name="coupon">
|
||||
<couponSetting ref="couponSettingRef" :productId="productId" @saveSuccess="saveSuccess"></couponSetting>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="价格与佣金" name="price">
|
||||
<priceCommission
|
||||
ref="priceCommissionRef"
|
||||
:productId="productId"
|
||||
@saveSuccess="saveSuccess"
|
||||
></priceCommission>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="商品详情" name="detail">
|
||||
<productDetail ref="productDetailRef" :productId="productId" @saveSuccess="saveSuccess"></productDetail>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="营销设置" name="marketing">
|
||||
<marketingSetting
|
||||
ref="marketingSettingRef"
|
||||
:productId="productId"
|
||||
@saveSuccess="saveSuccess"
|
||||
></marketingSetting>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="其他设置" name="other">
|
||||
<otherSetting ref="otherSettingRef" :productId="productId" @saveSuccess="saveSuccess"></otherSetting>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</div>
|
||||
<div class="bottom-btn-box">
|
||||
<el-button type="primary" class="save-btn" @click="saveProduct">保存商品</el-button>
|
||||
<el-button @click="goBack">返回列表</el-button>
|
||||
</div>
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
import { ElMessage } from 'element-plus';
|
||||
import basicInfo from '../../../../pages/product/productAdd/components/BasicInfo.vue';
|
||||
import priceCommission from '../../../../pages/product/productAdd/components/PriceCommission.vue';
|
||||
import productDetail from '../../../../pages/product/productAdd/components/ProductDetail.vue';
|
||||
import marketingSetting from '../../../../pages/product/productAdd/components/MarketingSetting.vue';
|
||||
import otherSetting from '../../../../pages/product/productAdd/components/OtherSetting.vue';
|
||||
import couponSetting from './components/CouponSetting.vue';
|
||||
import { couponProductSave, couponProductUpdate } from '@/pages/plugin/coupon/couponProduct';
|
||||
import setting from '@/setting';
|
||||
|
||||
defineOptions({ name: 'couponProductAdd' });
|
||||
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
const routePre = setting.routePre;
|
||||
|
||||
const basicInfoRef = ref(null);
|
||||
const couponSettingRef = ref(null);
|
||||
const priceCommissionRef = ref(null);
|
||||
const productDetailRef = ref(null);
|
||||
const marketingSettingRef = ref(null);
|
||||
const otherSettingRef = ref(null);
|
||||
|
||||
const activeName = ref('basic');
|
||||
const productId = ref(0);
|
||||
|
||||
const id = route.params.id;
|
||||
if (id) {
|
||||
productId.value = parseInt(id);
|
||||
}
|
||||
|
||||
function handleClick(tab) {}
|
||||
async function saveProduct() {
|
||||
const basicData = basicInfoRef.value.getFormData();
|
||||
const couponData = couponSettingRef.value.getFormData();
|
||||
const priceData = priceCommissionRef.value.getFormData();
|
||||
const detailData = productDetailRef.value.getFormData();
|
||||
const marketingData = marketingSettingRef.value.getFormData();
|
||||
const otherData = otherSettingRef.value.getFormData();
|
||||
|
||||
const formData = {
|
||||
...basicData,
|
||||
...couponData,
|
||||
...priceData,
|
||||
...detailData,
|
||||
...marketingData,
|
||||
...otherData,
|
||||
product_type: 'coupon',
|
||||
};
|
||||
|
||||
try {
|
||||
if (productId.value) {
|
||||
await couponProductUpdate(productId.value, formData);
|
||||
ElMessage.success('修改成功');
|
||||
} else {
|
||||
await couponProductSave(formData);
|
||||
ElMessage.success('添加成功');
|
||||
}
|
||||
goBack();
|
||||
} catch (error) {
|
||||
ElMessage.error(error.msg || '操作失败');
|
||||
}
|
||||
}
|
||||
function saveSuccess() {
|
||||
ElMessage.success('保存成功');
|
||||
}
|
||||
function goBack() {
|
||||
router.push({ path: routePre + '/product/coupon/list' });
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.product-add {
|
||||
.bottom-btn-box {
|
||||
text-align: center;
|
||||
padding: 20px 0;
|
||||
border-top: 1px solid #ebf0f5;
|
||||
.save-btn {
|
||||
width: 120px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@ -1,39 +0,0 @@
|
||||
import request from '@/libs/request';
|
||||
|
||||
export function couponProductList(params) {
|
||||
return request({
|
||||
url: 'coupon/product/list',
|
||||
method: 'get',
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
export function couponProductDetail(id) {
|
||||
return request({
|
||||
url: `coupon/product/${id}`,
|
||||
method: 'get',
|
||||
});
|
||||
}
|
||||
|
||||
export function couponProductSave(data) {
|
||||
return request({
|
||||
url: 'coupon/product',
|
||||
method: 'post',
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
export function couponProductUpdate(id, data) {
|
||||
return request({
|
||||
url: `coupon/product/${id}`,
|
||||
method: 'put',
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
export function couponProductDelete(id) {
|
||||
return request({
|
||||
url: `coupon/product/${id}`,
|
||||
method: 'delete',
|
||||
});
|
||||
}
|
||||
@ -1,750 +0,0 @@
|
||||
<template>
|
||||
<div class="article-manager">
|
||||
<el-card :bordered="false" shadow="never" :body-style="{ padding: 0 }">
|
||||
<div class="padding-add">
|
||||
<el-form :model="artFrom" label-width="80px" label-position="right" inline @submit.prevent>
|
||||
<div class="acea-row search-form">
|
||||
<div class="search-form-box">
|
||||
<el-form-item label="商品搜索:" label-for="store_name">
|
||||
<el-input
|
||||
clearable
|
||||
placeholder="请输入商品名称/关键字/ID"
|
||||
v-model="artFrom.store_name"
|
||||
class="form_content_width"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="商品分类:" label-for="pid">
|
||||
<el-cascader
|
||||
v-model="artFrom.cate_id"
|
||||
:options="treeSelect"
|
||||
:props="{ multiple: false, emitPath: false, checkStrictly: true }"
|
||||
clearable
|
||||
class="form_content_width"
|
||||
></el-cascader>
|
||||
</el-form-item>
|
||||
<template v-if="collapse">
|
||||
<el-form-item label="会员专属:">
|
||||
<el-select v-model="artFrom.vip_product" clearable placeholder="全部" class="form_content_width">
|
||||
<el-option label="全部" value="" />
|
||||
<el-option label="不限制" value="0" />
|
||||
<el-option label="仅会员可见可买" value="1" />
|
||||
<el-option label="所有人可见仅会员可买" value="2" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="添加时间:">
|
||||
<date-range-picker
|
||||
class="form_range_content_width"
|
||||
clearable
|
||||
v-model="timeVal"
|
||||
:editable="false"
|
||||
@change="onchangeTime"
|
||||
format="YYYY/MM/DD"
|
||||
value-format="YYYY/MM/DD"
|
||||
></date-range-picker>
|
||||
</el-form-item>
|
||||
<el-form-item label="价格:" label-for="store_name">
|
||||
<el-input
|
||||
clearable
|
||||
placeholder="最小值"
|
||||
v-model="artFrom.price_s[0]"
|
||||
class="form_range_content_width"
|
||||
/>
|
||||
~
|
||||
<el-input
|
||||
clearable
|
||||
placeholder="最大值"
|
||||
v-model="artFrom.price_s[1]"
|
||||
class="form_range_content_width"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="销量:" label-for="store_name">
|
||||
<el-input
|
||||
clearable
|
||||
placeholder="最小值"
|
||||
v-model="artFrom.sales_s[0]"
|
||||
class="form_range_content_width"
|
||||
/>
|
||||
~
|
||||
<el-input
|
||||
clearable
|
||||
placeholder="最大值"
|
||||
v-model="artFrom.sales_s[1]"
|
||||
class="form_range_content_width"
|
||||
/>
|
||||
</el-form-item>
|
||||
</template>
|
||||
</div>
|
||||
<div class="search-form-sub">
|
||||
<el-button type="primary" v-db-click @click="userSearchs">查询</el-button>
|
||||
<el-button class="ResetSearch" v-db-click @click="reset">重置</el-button>
|
||||
<a class="ivu-ml-8 font12 ml10" v-db-click @click="collapse = !collapse">
|
||||
<template v-if="!collapse"> 展开 <i class="el-icon-arrow-down" /> </template>
|
||||
<template v-else> 收起 <i class="el-icon-arrow-up" /> </template>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</el-form>
|
||||
</div>
|
||||
</el-card>
|
||||
<el-card :bordered="false" shadow="never" class="ivu-mt mt16" :body-style="{ padding: '0 20px 20px' }">
|
||||
<div class="Button">
|
||||
<router-link v-auth="['admin-coupon-product-save']" :to="routePre + '/product/coupon/add'"
|
||||
><el-button type="primary" class="mr14">添加优惠券商品</el-button></router-link
|
||||
>
|
||||
<el-dropdown class="bnt mr14" @command="batchSelect">
|
||||
<el-button>批量修改<i class="el-icon-arrow-down el-icon--right"></i></el-button>
|
||||
<template #dropdown
|
||||
><el-dropdown-menu>
|
||||
<el-dropdown-item :command="1">商品分类</el-dropdown-item>
|
||||
<el-dropdown-item :command="3">购买送积分</el-dropdown-item>
|
||||
<el-dropdown-item :command="4">购买送优惠券</el-dropdown-item>
|
||||
<el-dropdown-item :command="5">关联用户标签</el-dropdown-item>
|
||||
<el-dropdown-item v-if="artFrom.type === '1'" :command="7">批量下架</el-dropdown-item>
|
||||
<el-dropdown-item v-if="artFrom.type === '2'" :command="8">批量上架</el-dropdown-item>
|
||||
<el-dropdown-item :command="9">设置商品标签</el-dropdown-item>
|
||||
<el-dropdown-item v-if="artFrom.type !== '6'" :command="11">移到回收站</el-dropdown-item>
|
||||
<el-dropdown-item v-if="artFrom.type == '6'" :command="12">恢复商品</el-dropdown-item>
|
||||
</el-dropdown-menu></template
|
||||
>
|
||||
</el-dropdown>
|
||||
</div>
|
||||
<el-table
|
||||
ref="table"
|
||||
:data="tableList"
|
||||
class="mt14"
|
||||
v-loading="loading"
|
||||
highlight-current-row
|
||||
:row-key="getRowKey"
|
||||
@selection-change="handleSelectRow"
|
||||
empty-text="暂无数据"
|
||||
>
|
||||
<el-table-column type="selection" width="60" :reserve-selection="true"> </el-table-column>
|
||||
<el-table-column label="商品ID" width="80">
|
||||
<template #default="scope">
|
||||
<span>{{ scope.row.id }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="商品图" min-width="90">
|
||||
<template #default="scope">
|
||||
<div class="tabBox_img" v-viewer>
|
||||
<img v-lazy="scope.row.image" />
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="商品名称" min-width="250">
|
||||
<template #default="scope">
|
||||
<span>{{ scope.row.store_name }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="优惠券面值" min-width="120">
|
||||
<template #default="scope">
|
||||
<span>{{ scope.row.coupon_value || 0 }}元</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="优惠门槛" min-width="120">
|
||||
<template #default="scope">
|
||||
<span>{{ scope.row.coupon_min || 0 }}元</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="有效期" min-width="150">
|
||||
<template #default="scope">
|
||||
<span>{{ scope.row.coupon_start_time || '-' }} ~ {{ scope.row.coupon_end_time || '-' }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="商品售价" min-width="100">
|
||||
<template #default="scope">
|
||||
<span>{{ scope.row.price }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="销量" min-width="100">
|
||||
<template #default="scope">
|
||||
<span>{{ scope.row.sales }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="排序" min-width="100">
|
||||
<template #default="scope">
|
||||
<span>{{ scope.row.sort }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="状态" min-width="100">
|
||||
<template #default="scope">
|
||||
<el-switch
|
||||
class="defineSwitch"
|
||||
:active-value="1"
|
||||
:inactive-value="0"
|
||||
v-model="scope.row.is_show"
|
||||
:value="scope.row.is_show"
|
||||
:disabled="scope.row.stop_status ? true : false"
|
||||
@change="changeSwitch(scope.row)"
|
||||
size="large"
|
||||
active-text="上架"
|
||||
inactive-text="下架"
|
||||
>
|
||||
</el-switch>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" fixed="right" minWidth="100">
|
||||
<template #default="scope">
|
||||
<a v-db-click @click="edit(scope.row)">编辑</a>
|
||||
<el-divider direction="vertical"></el-divider>
|
||||
<el-dropdown>
|
||||
<span class="el-dropdown-link">更多<i class="el-icon-arrow-down el-icon--right"></i> </span>
|
||||
<template #dropdown
|
||||
><el-dropdown-menu>
|
||||
<el-dropdown-item>
|
||||
<router-link :to="{ path: routePre + '/product/product_reply/' + scope.row.id }"
|
||||
><a>查看评论</a></router-link
|
||||
>
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item @click="openModal(scope.row, 'vipPriceSet')">会员价管理</el-dropdown-item>
|
||||
<el-dropdown-item @click="openModal(scope.row, 'brokerageSet')">佣金管理</el-dropdown-item>
|
||||
<el-dropdown-item v-if="artFrom.type === '6'" @click="del(scope.row, '恢复商品', scope.$index)"
|
||||
>恢复商品</el-dropdown-item
|
||||
>
|
||||
<el-dropdown-item v-if="artFrom.type === '6'" @click="fullDel(scope.row, '彻底删除', scope.$index)"
|
||||
>彻底删除</el-dropdown-item
|
||||
>
|
||||
<el-dropdown-item v-else @click="del(scope.row, '移入回收站', scope.$index)"
|
||||
>移到回收站</el-dropdown-item
|
||||
>
|
||||
</el-dropdown-menu></template
|
||||
>
|
||||
</el-dropdown>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<div class="acea-row row-right page">
|
||||
<pagination
|
||||
v-if="total"
|
||||
:total="total"
|
||||
v-model:page="artFrom.page"
|
||||
v-model:limit="artFrom.limit"
|
||||
@pagination="getDataList"
|
||||
/>
|
||||
</div>
|
||||
</el-card>
|
||||
<brokerageSet ref="brokerageSetRef" :productId="productId"></brokerageSet>
|
||||
<vipPriceSet ref="vipPriceSetRef" :productId="productId"></vipPriceSet>
|
||||
<el-dialog
|
||||
v-model="batchModal"
|
||||
class="batch-box"
|
||||
title="批量设置"
|
||||
:show-close="true"
|
||||
:close-on-click-modal="false"
|
||||
width="540px"
|
||||
>
|
||||
<el-form
|
||||
class="batchFormData"
|
||||
:rules="ruleBatch"
|
||||
:model="batchFormData"
|
||||
label-width="90px"
|
||||
label-position="right"
|
||||
@submit.prevent
|
||||
>
|
||||
<el-row :gutter="24">
|
||||
<el-col :span="24" v-if="batchType == 1">
|
||||
<el-form-item label="商品分类:" prop="cate_id">
|
||||
<el-cascader
|
||||
v-model="batchFormData.cate_id"
|
||||
:options="treeSelect"
|
||||
:props="{ multiple: true, emitPath: false, checkStrictly: true }"
|
||||
clearable
|
||||
style="width: 400px"
|
||||
></el-cascader>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24" v-if="[3, 4, 5].includes(batchType)">
|
||||
<el-form-item label="赠送积分:" prop="give_integral" v-if="batchType == 3">
|
||||
<el-input-number
|
||||
:controls="false"
|
||||
v-model="batchFormData.give_integral"
|
||||
:min="0"
|
||||
:max="9999999999"
|
||||
placeholder="请输入积分"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="赠送优惠券:" v-if="batchType == 4">
|
||||
<div v-if="couponName.length" class="mb20">
|
||||
<el-tag closable v-for="(item, index) in couponName" :key="index" @close="handleClose(item)">{{
|
||||
item.title
|
||||
}}</el-tag>
|
||||
</div>
|
||||
<el-button type="primary" v-db-click @click="addCoupon">添加优惠券</el-button>
|
||||
</el-form-item>
|
||||
<el-form-item label="关联标签:" prop="label_id" v-if="batchType == 5">
|
||||
<div class="acea-row label_width">
|
||||
<div class="labelInput acea-row row-between-wrapper" v-db-click @click="openLabel">
|
||||
<div style="width: auto">
|
||||
<div v-if="dataLabel.length">
|
||||
<el-tag
|
||||
class="m-r-2"
|
||||
closable
|
||||
v-for="(item, index) in dataLabel"
|
||||
@close="closeLabel(item)"
|
||||
:key="index"
|
||||
>{{ item.label_name }}</el-tag
|
||||
>
|
||||
</div>
|
||||
<span class="span" v-else>选择用户关联标签</span>
|
||||
</div>
|
||||
<div class="iconfont iconxiayi"></div>
|
||||
</div>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
<template #footer
|
||||
><span class="dialog-footer">
|
||||
<el-button v-db-click @click="clearBatchData">取 消</el-button>
|
||||
<el-button type="primary" v-db-click @click="batchSub">确 定</el-button>
|
||||
</span></template
|
||||
>
|
||||
</el-dialog>
|
||||
<el-dialog
|
||||
v-model="labelShow"
|
||||
title="请选择用户标签"
|
||||
width="540px"
|
||||
:show-close="true"
|
||||
:close-on-click-modal="false"
|
||||
>
|
||||
<userLabel @activeData="activeData" @close="labelClose"></userLabel>
|
||||
</el-dialog>
|
||||
<el-dialog v-model="tagShow" title="请选择商品标签" :show-close="true" width="540px" :close-on-click-modal="false">
|
||||
<goodsLabel :defaultLabelList="goodsLabelList" @activeLabel="activeGoodsLabel" @close="labelClose"></goodsLabel>
|
||||
</el-dialog>
|
||||
<coupon-list ref="couponTemplates" @nameId="nameId" :couponids="batchFormData.coupon_ids"></coupon-list>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { nextTick, onActivated, ref } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { ElMessage } from 'element-plus';
|
||||
import { couponProductList } from '@/pages/plugin/coupon/couponProduct';
|
||||
import {
|
||||
PostgoodsIsShow,
|
||||
cascaderListApi,
|
||||
productShowApi,
|
||||
productUnshowApi,
|
||||
batchSetting,
|
||||
productLabelUseListApi,
|
||||
} from '@/api/product';
|
||||
import userLabel from '@/components/labelList';
|
||||
import goodsLabel from '@/components/goodsLabel';
|
||||
import couponList from '@/components/couponList';
|
||||
import brokerageSet from '../../../pages/product/components/brokerageSet.vue';
|
||||
import vipPriceSet from '../../../pages/product/components/vipPriceSet.vue';
|
||||
import { modalSure } from '@/utils/public';
|
||||
import setting from '@/setting';
|
||||
|
||||
defineOptions({ name: 'couponProduct' });
|
||||
|
||||
const router = useRouter();
|
||||
const routePre = setting.routePre;
|
||||
|
||||
const table = ref(null);
|
||||
const brokerageSetRef = ref(null);
|
||||
const vipPriceSetRef = ref(null);
|
||||
const couponTemplates = ref(null);
|
||||
|
||||
const batchModal = ref(false);
|
||||
const labelShow = ref(false);
|
||||
const tagShow = ref(false);
|
||||
const batchType = ref(1);
|
||||
const batchFormData = ref({
|
||||
cate_id: [],
|
||||
give_integral: 0,
|
||||
label_id: [],
|
||||
coupon_ids: [],
|
||||
});
|
||||
const ruleBatch = ref({});
|
||||
const couponName = ref([]);
|
||||
const dataLabel = ref([]);
|
||||
const artFrom = ref({
|
||||
page: 1,
|
||||
limit: 15,
|
||||
store_name: '',
|
||||
cate_id: '',
|
||||
vip_product: '',
|
||||
sales_s: ['', ''],
|
||||
price_s: ['', ''],
|
||||
time: '',
|
||||
type: '1',
|
||||
});
|
||||
const tableList = ref([]);
|
||||
const total = ref(0);
|
||||
const loading = ref(false);
|
||||
const treeSelect = ref([]);
|
||||
const ids = ref([]);
|
||||
const multipleSelection = ref([]);
|
||||
const productId = ref(0);
|
||||
const goodsLabelList = ref([]);
|
||||
const timeVal = ref([]);
|
||||
const collapse = ref(false);
|
||||
|
||||
onActivated(() => {
|
||||
goodsCategory();
|
||||
getLabelList();
|
||||
getDataList();
|
||||
});
|
||||
|
||||
function onchangeTime(e) {
|
||||
timeVal.value = e;
|
||||
artFrom.value.time = timeVal.value ? timeVal.value.join('-') : '';
|
||||
artFrom.value.page = 1;
|
||||
getDataList();
|
||||
}
|
||||
function getLabelList() {
|
||||
productLabelUseListApi()
|
||||
.then((res) => {
|
||||
res.data.map((el) => {
|
||||
if (el.list && el.list.length) {
|
||||
el.list.map((label) => {
|
||||
label.active = false;
|
||||
});
|
||||
}
|
||||
});
|
||||
goodsLabelList.value = res.data;
|
||||
})
|
||||
.catch((res) => {
|
||||
ElMessage.error(res.msg);
|
||||
});
|
||||
}
|
||||
function openModal(row, type) {
|
||||
productId.value = row.id;
|
||||
const modalRefs = { vipPriceSet: vipPriceSetRef, brokerageSet: brokerageSetRef };
|
||||
modalRefs[type].value.visible = true;
|
||||
}
|
||||
function batchSub() {
|
||||
let data = batchFormData.value;
|
||||
data.ids = ids.value;
|
||||
data.type = batchType.value;
|
||||
let activeIds = [];
|
||||
dataLabel.value.forEach((item) => {
|
||||
activeIds.push(item.id);
|
||||
});
|
||||
data.label_id = activeIds;
|
||||
batchSetting(data)
|
||||
.then((res) => {
|
||||
ElMessage.success(res.msg);
|
||||
getDataList();
|
||||
clearBatchData(false);
|
||||
ids.value = [];
|
||||
})
|
||||
.catch((err) => {
|
||||
ElMessage.error(err.msg);
|
||||
});
|
||||
}
|
||||
function clearBatchData(status) {
|
||||
if (!status) {
|
||||
batchFormData.value = {
|
||||
cate_id: [],
|
||||
give_integral: null,
|
||||
label_id: [],
|
||||
coupon_ids: [],
|
||||
label_list: [],
|
||||
};
|
||||
dataLabel.value = [];
|
||||
}
|
||||
batchModal.value = false;
|
||||
table.value.clearSelection();
|
||||
}
|
||||
function batchSelect(type) {
|
||||
if (!ids.value.length) {
|
||||
ElMessage.warning('请选择要修改的商品');
|
||||
} else if (type === 7) {
|
||||
onDismount();
|
||||
} else if (type === 8) {
|
||||
onShelves();
|
||||
} else if (type === 9) {
|
||||
batchType.value = type;
|
||||
tagShow.value = true;
|
||||
} else if (type === 11) {
|
||||
batchGoodsSetting('全部移到回收站', 1);
|
||||
} else if (type === 12) {
|
||||
batchGoodsSetting('恢复选中商品', 2);
|
||||
} else {
|
||||
batchType.value = type;
|
||||
batchModal.value = true;
|
||||
}
|
||||
}
|
||||
function batchGoodsSetting(tit, type) {
|
||||
let url = type == 1 ? 'product/product/batch_delete' : 'product/product/batch_recover';
|
||||
let delfromData = {
|
||||
title: tit,
|
||||
url,
|
||||
method: 'post',
|
||||
ids: {
|
||||
ids: ids.value,
|
||||
},
|
||||
un: 1,
|
||||
};
|
||||
modalSure(delfromData)
|
||||
.then((res) => {
|
||||
ElMessage.success(res.msg);
|
||||
getDataList();
|
||||
})
|
||||
.catch((res) => {
|
||||
ElMessage.error(res.msg);
|
||||
});
|
||||
}
|
||||
function activeData(val) {
|
||||
labelShow.value = false;
|
||||
dataLabel.value = val;
|
||||
}
|
||||
function nameId(id, names) {
|
||||
batchFormData.value.coupon_ids = id;
|
||||
couponName.value = unique(names);
|
||||
}
|
||||
function handleClose(name) {
|
||||
let index = couponName.value.indexOf(name);
|
||||
couponName.value.splice(index, 1);
|
||||
batchFormData.value.coupon_ids.splice(index, 1);
|
||||
}
|
||||
function unique(arr) {
|
||||
const res = new Map();
|
||||
return arr.filter((arr) => !res.has(arr.id) && res.set(arr.id, 1));
|
||||
}
|
||||
function labelClose() {
|
||||
labelShow.value = false;
|
||||
tagShow.value = false;
|
||||
}
|
||||
function activeGoodsLabel(data) {
|
||||
tagShow.value = false;
|
||||
batchFormData.value.label_list = Array.from(new Set(data));
|
||||
batchSub();
|
||||
}
|
||||
function openLabel() {
|
||||
labelShow.value = true;
|
||||
}
|
||||
function closeLabel(label) {
|
||||
let index = dataLabel.value.indexOf(dataLabel.value.filter((d) => d.id == label.id)[0]);
|
||||
dataLabel.value.splice(index, 1);
|
||||
}
|
||||
function addCoupon() {
|
||||
couponTemplates.value.isTemplate = true;
|
||||
couponTemplates.value.tableList();
|
||||
}
|
||||
function onShelves() {
|
||||
if (ids.value.length === 0) {
|
||||
ElMessage.warning('请选择要上架的商品');
|
||||
} else {
|
||||
let data = {
|
||||
ids: ids.value,
|
||||
};
|
||||
productShowApi(data)
|
||||
.then((res) => {
|
||||
ElMessage.success(res.msg);
|
||||
getDataList();
|
||||
})
|
||||
.catch((res) => {
|
||||
ElMessage.error(res.msg);
|
||||
});
|
||||
}
|
||||
}
|
||||
function onDismount() {
|
||||
if (ids.value.length === 0) {
|
||||
ElMessage.warning('请选择要下架的商品');
|
||||
} else {
|
||||
let data = {
|
||||
ids: ids.value,
|
||||
};
|
||||
productUnshowApi(data)
|
||||
.then((res) => {
|
||||
ElMessage.success(res.msg);
|
||||
artFrom.value.page = 1;
|
||||
getDataList();
|
||||
})
|
||||
.catch((res) => {
|
||||
ElMessage.error(res.msg);
|
||||
});
|
||||
}
|
||||
}
|
||||
function getRowKey(row) {
|
||||
return row.id;
|
||||
}
|
||||
function handleSelectRow(selection) {
|
||||
const uniqueArr = [];
|
||||
const selIds = [];
|
||||
for (let i = 0; i < selection.length; i++) {
|
||||
const item = selection[i];
|
||||
if (!selIds.includes(item.id)) {
|
||||
uniqueArr.push(item);
|
||||
selIds.push(item.id);
|
||||
}
|
||||
}
|
||||
ids.value = selIds;
|
||||
multipleSelection.value = uniqueArr;
|
||||
}
|
||||
function goodsCategory() {
|
||||
cascaderListApi(1)
|
||||
.then((res) => {
|
||||
treeSelect.value = res.data;
|
||||
})
|
||||
.catch((res) => {
|
||||
ElMessage.error(res.msg);
|
||||
});
|
||||
}
|
||||
function getDataList() {
|
||||
loading.value = true;
|
||||
artFrom.value.cate_id = artFrom.value.cate_id || '';
|
||||
couponProductList(artFrom.value)
|
||||
.then((res) => {
|
||||
tableList.value = res.data.list || [];
|
||||
total.value = res.data.count || 0;
|
||||
nextTick(() => {
|
||||
showSelectData();
|
||||
});
|
||||
loading.value = false;
|
||||
})
|
||||
.catch((res) => {
|
||||
loading.value = false;
|
||||
ElMessage.error(res.msg || '获取列表失败');
|
||||
});
|
||||
}
|
||||
function showSelectData() {
|
||||
if (multipleSelection.value.length > 0) {
|
||||
tableList.value.forEach((row) => {
|
||||
multipleSelection.value.forEach((item) => {
|
||||
if (row.id === item.id) {
|
||||
table.value.toggleRowSelection(item, true);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
function userSearchs() {
|
||||
artFrom.value.page = 1;
|
||||
getDataList();
|
||||
}
|
||||
function changeSwitch(row) {
|
||||
PostgoodsIsShow(row.id, row.is_show)
|
||||
.then((res) => {
|
||||
ElMessage.success(res.msg);
|
||||
getDataList();
|
||||
})
|
||||
.catch((res) => {
|
||||
row.is_show = !row.is_show ? 1 : 0;
|
||||
ElMessage.error(res.msg);
|
||||
});
|
||||
}
|
||||
function edit(row) {
|
||||
router.push({ path: routePre + '/product/coupon/add/' + row.id });
|
||||
}
|
||||
function del(row, tit, num) {
|
||||
let delfromData = {
|
||||
title: tit,
|
||||
num: num,
|
||||
url: `product/product/${row.id}`,
|
||||
method: 'DELETE',
|
||||
ids: '',
|
||||
un: 1,
|
||||
};
|
||||
modalSure(delfromData)
|
||||
.then((res) => {
|
||||
ElMessage.success(res.msg);
|
||||
tableList.value.splice(num, 1);
|
||||
getDataList();
|
||||
})
|
||||
.catch((res) => {
|
||||
ElMessage.error(res.msg);
|
||||
});
|
||||
}
|
||||
function fullDel(row, tit, num) {
|
||||
let delfromData = {
|
||||
title: tit,
|
||||
num: num,
|
||||
url: `product/full_del/${row.id}`,
|
||||
method: 'DELETE',
|
||||
};
|
||||
modalSure(delfromData)
|
||||
.then((res) => {
|
||||
ElMessage.success(res.msg);
|
||||
tableList.value.splice(num, 1);
|
||||
getDataList();
|
||||
})
|
||||
.catch((res) => {
|
||||
ElMessage.error(res.msg);
|
||||
});
|
||||
}
|
||||
function reset() {
|
||||
artFrom.value = {
|
||||
page: 1,
|
||||
limit: 15,
|
||||
store_name: '',
|
||||
cate_id: '',
|
||||
vip_product: '',
|
||||
sales_s: ['', ''],
|
||||
price_s: ['', ''],
|
||||
time: '',
|
||||
type: '1',
|
||||
};
|
||||
timeVal.value = [];
|
||||
getDataList();
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.tabBox_img {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
.labelInput {
|
||||
border: 1px solid #dcdee2;
|
||||
padding: 0 15px 0 10px;
|
||||
border-radius: 5px;
|
||||
min-height: 30px;
|
||||
cursor: pointer;
|
||||
font-size: 12px;
|
||||
.span {
|
||||
color: #c5c8ce;
|
||||
}
|
||||
.iconxiayi {
|
||||
margin-left: 5px;
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
.el-dropdown-link {
|
||||
cursor: pointer;
|
||||
color: var(--prev-color-primary);
|
||||
font-size: 12px;
|
||||
}
|
||||
.el-icon-arrow-down {
|
||||
font-size: 12px;
|
||||
}
|
||||
.el-dropdown-menu__item {
|
||||
a {
|
||||
color: #606266;
|
||||
}
|
||||
}
|
||||
.label_width {
|
||||
width: 400px;
|
||||
}
|
||||
.search-form {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
.search-form-box {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
flex: 1;
|
||||
}
|
||||
.search-form-sub {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
}
|
||||
}
|
||||
.batch-box {
|
||||
:deep(.ivu-modal-body) {
|
||||
overflow: auto;
|
||||
min-height: 350px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@ -1,28 +0,0 @@
|
||||
/**
|
||||
* 优惠券商品路由
|
||||
*/
|
||||
import setting from '@/setting';
|
||||
const routePre = setting.routePre;
|
||||
const pre = 'product_';
|
||||
|
||||
export default [
|
||||
{
|
||||
path: routePre + '/product/coupon/list',
|
||||
name: `${pre}couponProductList`,
|
||||
meta: {
|
||||
auth: ['admin-coupon-product-list'],
|
||||
title: '优惠券商品',
|
||||
},
|
||||
component: () => import('@/pages/plugin/coupon/index'),
|
||||
},
|
||||
{
|
||||
path: routePre + '/product/coupon/add/:id?',
|
||||
name: `${pre}couponProductAdd`,
|
||||
meta: {
|
||||
auth: ['admin-coupon-product-add'],
|
||||
title: '优惠券商品添加',
|
||||
activeMenu: routePre + '/product/coupon/list',
|
||||
},
|
||||
component: () => import('@/pages/plugin/coupon/add'),
|
||||
},
|
||||
];
|
||||
@ -1,44 +0,0 @@
|
||||
<template>
|
||||
<div class="agent-app">
|
||||
<div class="section-content">
|
||||
<component :is="sectionComponent" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed } from 'vue';
|
||||
import AgentManage from './agentManage.vue';
|
||||
import SpreadApply from './spread/apply.vue';
|
||||
import DivisionList from './division/list/index.vue';
|
||||
import AgentIndex from './division/agent/index.vue';
|
||||
import AgentStatistics from './division/agent/statistics.vue';
|
||||
import ApplyList from './division/agent/applyList.vue';
|
||||
import Agreement from './division/agent/agreement.vue';
|
||||
|
||||
defineOptions({ name: 'AgentApp' });
|
||||
|
||||
const props = defineProps({
|
||||
section: { type: String, default: 'distribution' },
|
||||
action: { type: String, default: 'manage' },
|
||||
params: { type: Object, default: () => ({}) },
|
||||
});
|
||||
|
||||
const actionComponents = {
|
||||
manage: AgentManage,
|
||||
apply: SpreadApply,
|
||||
list: DivisionList,
|
||||
agent: AgentIndex,
|
||||
statistics: AgentStatistics,
|
||||
applyList: ApplyList,
|
||||
agreement: Agreement,
|
||||
};
|
||||
|
||||
const sectionComponent = computed(() => actionComponents[props.action] || AgentManage);
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.agent-app {
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
@ -1,557 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-card :bordered="false" shadow="never" class="ivu-mb-16" :body-style="{ padding: 0 }">
|
||||
<div class="padding-add">
|
||||
<el-form
|
||||
ref="formValidateRef"
|
||||
:model="formValidate"
|
||||
:label-width="labelWidth"
|
||||
:label-position="labelPosition"
|
||||
@submit.prevent
|
||||
inline
|
||||
>
|
||||
<el-form-item label="时间选择:">
|
||||
<date-range-picker
|
||||
clearable
|
||||
v-model="timeVal"
|
||||
:editable="false"
|
||||
@change="onchangeTime"
|
||||
format="YYYY/MM/DD"
|
||||
value-format="YYYY/MM/DD"
|
||||
class="mr20"
|
||||
></date-range-picker>
|
||||
</el-form-item>
|
||||
<el-form-item label="搜索:" label-for="status">
|
||||
<el-input
|
||||
clearable
|
||||
placeholder="请输入姓名、电话、UID"
|
||||
v-model="formValidate.nickname"
|
||||
class="form_content_width"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" v-db-click @click="userSearchs">查询</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
</el-card>
|
||||
<cards-data :cardLists="cardLists" v-if="cardLists.length >= 0"></cards-data>
|
||||
<el-card :bordered="false" shadow="never">
|
||||
<el-button v-auth="['export-userAgent']" class="export" v-db-click @click="exports">导出</el-button>
|
||||
<el-table
|
||||
ref="selection"
|
||||
:data="tableList"
|
||||
class="mt14"
|
||||
v-loading="loading"
|
||||
empty-text="暂无数据"
|
||||
highlight-current-row
|
||||
>
|
||||
<el-table-column label="ID" width="80">
|
||||
<template #default="scope">
|
||||
<span>{{ scope.row.uid }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="头像" min-width="90">
|
||||
<template #default="scope">
|
||||
<div class="tabBox_img" v-viewer>
|
||||
<img v-lazy="scope.row.headimgurl ? scope.row.headimgurl : moren" />
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="用户信息" width="150">
|
||||
<template #default="scope">
|
||||
<div class="name">
|
||||
<div class="item">昵称:{{ scope.row.nickname }}</div>
|
||||
<div class="item">姓名:{{ scope.row.real_name }}</div>
|
||||
<div class="item">电话:{{ scope.row.phone }}</div>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="分销等级" min-width="120">
|
||||
<template #default="scope">
|
||||
<div>{{ scope.row.agentLevel ? scope.row.agentLevel.name : '--' }}</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="推广用户数量" min-width="120">
|
||||
<template #default="scope">
|
||||
<span>{{ scope.row.spread_count }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="推广订单数量" min-width="120">
|
||||
<template #default="scope">
|
||||
<div>{{ scope.row.spread_order.order_count }}</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="推广订单金额" min-width="120">
|
||||
<template #default="scope">
|
||||
<div>{{ scope.row.spread_order.order_price || '0.00' }}</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="佣金总金额" min-width="120">
|
||||
<template #default="scope">
|
||||
<div>{{ scope.row.brokerage_money }}</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="已提现金额" min-width="120">
|
||||
<template #default="scope">
|
||||
<div>{{ scope.row.extract_count_price }}</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="提现次数" min-width="120">
|
||||
<template #default="scope">
|
||||
<div>{{ scope.row.extract_count_num }}</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="未提现金额" min-width="120">
|
||||
<template #default="scope">
|
||||
<div>{{ scope.row.new_money }}</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="上级推广人" min-width="120">
|
||||
<template #default="scope">
|
||||
<div>{{ scope.row.spread_name }}</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" fixed="right" width="120">
|
||||
<template #default="scope">
|
||||
<a v-db-click @click="promoters(scope.row, 'man')">推广人</a>
|
||||
<el-divider direction="vertical"></el-divider>
|
||||
<el-dropdown @command="changeMenu(scope.row, $event, scope.$index)" :transfer="true">
|
||||
<span class="el-dropdown-link">更多<i class="el-icon-arrow-down el-icon--right"></i> </span>
|
||||
<template #dropdown
|
||||
><el-dropdown-menu>
|
||||
<el-dropdown-item command="1">推广订单</el-dropdown-item>
|
||||
<el-dropdown-item command="2">推广二维码</el-dropdown-item>
|
||||
<el-dropdown-item command="3">修改上级推广人</el-dropdown-item>
|
||||
<el-dropdown-item command="4" v-if="scope.row.spread_uid">清除上级推广人</el-dropdown-item>
|
||||
<el-dropdown-item command="5">取消推广资格</el-dropdown-item>
|
||||
<el-dropdown-item command="6">修改分销等级</el-dropdown-item>
|
||||
</el-dropdown-menu></template
|
||||
>
|
||||
</el-dropdown>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<div class="acea-row row-right page">
|
||||
<pagination
|
||||
v-if="total"
|
||||
:total="total"
|
||||
v-model:page="formValidate.page"
|
||||
v-model:limit="formValidate.limit"
|
||||
@pagination="getList"
|
||||
/>
|
||||
</div>
|
||||
</el-card>
|
||||
<!-- 推广人列表-->
|
||||
<promoters-list ref="promotersLists"></promoters-list>
|
||||
<!-- 推广二维码-->
|
||||
<el-dialog v-model="modals" title="推广二维码" :close-on-click-modal="false" width="540px">
|
||||
<div class="acea-row row-around" v-loading="spinShow">
|
||||
<div class="acea-row row-column-around row-between-wrapper">
|
||||
<div class="QRpic" v-if="code_src"><img v-lazy="code_src" /></div>
|
||||
<span class="QRpic_sp1 mt10" v-db-click @click="getWeChat">公众号推广二维码</span>
|
||||
</div>
|
||||
<div class="acea-row row-column-around row-between-wrapper">
|
||||
<div class="QRpic" v-if="code_xcx"><img v-lazy="code_xcx" /></div>
|
||||
<span class="QRpic_sp2 mt10" v-db-click @click="getXcx">小程序推广二维码</span>
|
||||
</div>
|
||||
<div class="acea-row row-column-around row-between-wrapper">
|
||||
<div class="QRpic" v-if="code_h5"><img v-lazy="code_h5" /></div>
|
||||
<span class="QRpic_sp2 mt10" v-db-click @click="getH5">H5推广二维码</span>
|
||||
</div>
|
||||
</div>
|
||||
</el-dialog>
|
||||
<!--修改推广人-->
|
||||
<el-dialog v-model="promoterShow" title="修改推广人" width="540px" :show-close="true">
|
||||
<el-form ref="formInlineRef" :model="formInline" label-width="100px" @submit.prevent>
|
||||
<el-form-item label="用户头像:" prop="image">
|
||||
<div class="picBox" v-db-click @click="customer">
|
||||
<div class="pictrue" v-if="formInline.image">
|
||||
<img v-lazy="formInline.image" />
|
||||
</div>
|
||||
<div class="upLoad acea-row row-center-wrapper" v-else>
|
||||
<i class="el-icon-picture-outline" style="font-size: 24px"></i>
|
||||
</div>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer
|
||||
><span class="dialog-footer">
|
||||
<el-button v-db-click @click="cancel('formInline')">取 消</el-button>
|
||||
<el-button type="primary" v-db-click @click="putSend('formInline')">提交</el-button>
|
||||
</span></template
|
||||
>
|
||||
</el-dialog>
|
||||
<el-dialog v-model="customerShow" title="请选择商城用户" :show-close="true" width="1000px">
|
||||
<customerInfo v-if="customerShow" @imageObject="imageObject"></customerInfo>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import moren from '@/assets/images/moren.jpg';
|
||||
import { computed, ref } from 'vue';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { ElMessage } from 'element-plus';
|
||||
import cardsData from '@/components/cards/cards';
|
||||
import searchFrom from '@/components/publicSearchFrom';
|
||||
import { useMediaStore } from '@/store/module/media';
|
||||
import {
|
||||
agentListApi,
|
||||
statisticsApi,
|
||||
lookCodeApi,
|
||||
lookxcxCodeApi,
|
||||
lookh5CodeApi,
|
||||
userAgentApi,
|
||||
agentSpreadApi,
|
||||
} from './api';
|
||||
import promotersList from './handle/promotersList';
|
||||
import customerInfo from '@/components/customerInfo';
|
||||
import { membershipDataAddApi } from '@/api/membershipLevel';
|
||||
import modalForm from '@/utils/modalForm';
|
||||
import { modalSure } from '@/utils/public';
|
||||
|
||||
defineOptions({ name: 'agentManage' });
|
||||
|
||||
const { isMobile } = storeToRefs(useMediaStore());
|
||||
const labelWidth = computed(() => (isMobile.value ? undefined : '80px'));
|
||||
const labelPosition = computed(() => (isMobile.value ? 'top' : 'right'));
|
||||
|
||||
const customerShow = ref(false);
|
||||
const promoterShow = ref(false);
|
||||
const modals = ref(false);
|
||||
const spinShow = ref(false);
|
||||
const rows = ref({});
|
||||
const formValidate = ref({
|
||||
nickname: '',
|
||||
data: '',
|
||||
page: 1,
|
||||
limit: 15,
|
||||
});
|
||||
const date = ref('all');
|
||||
const total = ref(0);
|
||||
const cardLists = ref([]);
|
||||
const loading = ref(false);
|
||||
const tableList = ref([]);
|
||||
const timeVal = ref([]);
|
||||
const code_src = ref('');
|
||||
const code_xcx = ref('');
|
||||
const code_h5 = ref('');
|
||||
const formInline = ref({
|
||||
uid: 0,
|
||||
spread_uid: 0,
|
||||
image: '',
|
||||
});
|
||||
|
||||
const formValidateRef = ref(null);
|
||||
const formInlineRef = ref(null);
|
||||
const selection = ref(null);
|
||||
const promotersLists = ref(null);
|
||||
|
||||
// 提交
|
||||
function putSend(name) {
|
||||
formInlineRef.value.validate((valid) => {
|
||||
if (valid) {
|
||||
if (!formInline.value.spread_uid) {
|
||||
return ElMessage.error('请上传用户');
|
||||
}
|
||||
agentSpreadApi(formInline.value)
|
||||
.then((res) => {
|
||||
promoterShow.value = false;
|
||||
ElMessage.success(res.msg);
|
||||
getList();
|
||||
formInlineRef.value.resetFields();
|
||||
})
|
||||
.catch((res) => {
|
||||
ElMessage.error(res.msg);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
// 导出
|
||||
function exports() {
|
||||
let data = {
|
||||
data: formValidate.value.data,
|
||||
nickname: formValidate.value.nickname,
|
||||
};
|
||||
userAgentApi(data)
|
||||
.then((res) => {
|
||||
location.href = res.data[0];
|
||||
})
|
||||
.catch((res) => {
|
||||
ElMessage.error(res.msg);
|
||||
});
|
||||
}
|
||||
// 操作
|
||||
function changeMenu(row, name, index) {
|
||||
switch (name) {
|
||||
case '1':
|
||||
promoters(row, 'order'); //推广人订单
|
||||
break;
|
||||
case '2':
|
||||
spreadQR(row); //推广方式二维码
|
||||
break;
|
||||
case '3':
|
||||
editS(row); //修改上级推广人
|
||||
break;
|
||||
case '4': //清除上级推广人
|
||||
del_parent(row, '清除【 ' + row.nickname + ' 】的上级推广人', index);
|
||||
break;
|
||||
case '5': //取消推广资格
|
||||
del_agent(row, '取消【 ' + row.nickname + ' 】的推广资格', index);
|
||||
break;
|
||||
case '6': //修改推广等级
|
||||
modalForm(membershipDataAddApi({ uid: row.uid }, '/distribution/get_level_form')).then(() => getList());
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
function editS(row) {
|
||||
promoterShow.value = true;
|
||||
formInline.value.uid = row.uid;
|
||||
}
|
||||
function customer() {
|
||||
customerShow.value = true;
|
||||
}
|
||||
function imageObject(e) {
|
||||
customerShow.value = false;
|
||||
formInline.value.spread_uid = e.uid;
|
||||
formInline.value.image = e.image;
|
||||
}
|
||||
// 清除上级关系
|
||||
function del_parent(rows2, titile, num) {
|
||||
let delfromDatap = {
|
||||
title: titile,
|
||||
num: num,
|
||||
url: `distribution/stair/delete_spread/${rows2.uid}`,
|
||||
method: 'PUT',
|
||||
ids: '',
|
||||
};
|
||||
modalSure(delfromDatap)
|
||||
.then((res) => {
|
||||
ElMessage.success(res.msg);
|
||||
getList();
|
||||
})
|
||||
.catch((res) => {
|
||||
ElMessage.error(res.msg);
|
||||
});
|
||||
}
|
||||
// 取消自己推广资格
|
||||
function del_agent(row, tit, num) {
|
||||
let delfromData = {
|
||||
title: tit,
|
||||
num: num,
|
||||
url: `distribution/stair/delete_system_spread/${row.uid}`,
|
||||
method: 'PUT',
|
||||
ids: '',
|
||||
};
|
||||
modalSure(delfromData)
|
||||
.then((res) => {
|
||||
ElMessage.success(res.msg);
|
||||
getList();
|
||||
})
|
||||
.catch((res) => {
|
||||
ElMessage.error(res.msg);
|
||||
});
|
||||
}
|
||||
function edit(row) {
|
||||
promoterShow.value = true;
|
||||
formInline.value.uid = row.uid;
|
||||
}
|
||||
function cancel(name) {
|
||||
promoterShow.value = false;
|
||||
formInlineRef.value.resetFields();
|
||||
}
|
||||
// 推广人列表 订单
|
||||
function promoters(row, tit) {
|
||||
promotersLists.value.modals = true;
|
||||
promotersLists.value.getList(row, tit);
|
||||
}
|
||||
// 统计
|
||||
function getStatistics() {
|
||||
let data = {
|
||||
nickname: formValidate.value.nickname,
|
||||
data: formValidate.value.data,
|
||||
};
|
||||
statisticsApi(data)
|
||||
.then(async (res) => {
|
||||
let data = res.data;
|
||||
cardLists.value = data.res;
|
||||
})
|
||||
.catch((res) => {
|
||||
ElMessage.error(res.msg);
|
||||
});
|
||||
}
|
||||
// 具体日期
|
||||
function onchangeTime(e) {
|
||||
timeVal.value = e;
|
||||
formValidate.value.data = timeVal.value ? timeVal.value.join('-') : '';
|
||||
formValidate.value.page = 1;
|
||||
if (!e[0]) {
|
||||
formValidate.value.data = '';
|
||||
}
|
||||
getList();
|
||||
getStatistics();
|
||||
}
|
||||
// 选择时间
|
||||
function selectChange(tab) {
|
||||
formValidate.value.page = 1;
|
||||
formValidate.value.data = tab;
|
||||
timeVal.value = [];
|
||||
getList();
|
||||
getStatistics();
|
||||
}
|
||||
// 列表
|
||||
function getList() {
|
||||
loading.value = true;
|
||||
agentListApi(formValidate.value)
|
||||
.then(async (res) => {
|
||||
let data = res.data;
|
||||
tableList.value = data.list;
|
||||
total.value = res.data.count;
|
||||
loading.value = false;
|
||||
})
|
||||
.catch((res) => {
|
||||
loading.value = false;
|
||||
ElMessage.error(res.msg);
|
||||
});
|
||||
}
|
||||
// 表格搜索
|
||||
function userSearchs() {
|
||||
formValidate.value.page = 1;
|
||||
getList();
|
||||
getStatistics();
|
||||
}
|
||||
// 二维码
|
||||
function spreadQR(row) {
|
||||
modals.value = true;
|
||||
rows.value = row;
|
||||
getWeChat();
|
||||
getXcx();
|
||||
getH5();
|
||||
}
|
||||
// 公众号推广二维码
|
||||
function getWeChat() {
|
||||
spinShow.value = true;
|
||||
let data = {
|
||||
uid: rows.value.uid,
|
||||
action: 'wechant_code',
|
||||
};
|
||||
lookCodeApi(data)
|
||||
.then(async (res) => {
|
||||
let data = res.data;
|
||||
code_src.value = data.code_src;
|
||||
spinShow.value = false;
|
||||
})
|
||||
.catch((res) => {
|
||||
spinShow.value = false;
|
||||
ElMessage.error(res.msg);
|
||||
});
|
||||
}
|
||||
// 小程序推广二维码
|
||||
function getXcx() {
|
||||
spinShow.value = true;
|
||||
let data = {
|
||||
uid: rows.value.uid,
|
||||
};
|
||||
lookxcxCodeApi(data)
|
||||
.then(async (res) => {
|
||||
let data = res.data;
|
||||
code_xcx.value = data.code_src;
|
||||
spinShow.value = false;
|
||||
})
|
||||
.catch((res) => {
|
||||
spinShow.value = false;
|
||||
ElMessage.error(res.msg);
|
||||
});
|
||||
}
|
||||
function getH5() {
|
||||
spinShow.value = true;
|
||||
let data = {
|
||||
uid: rows.value.uid,
|
||||
};
|
||||
lookh5CodeApi(data)
|
||||
.then(async (res) => {
|
||||
let data = res.data;
|
||||
code_h5.value = data.code_src;
|
||||
spinShow.value = false;
|
||||
})
|
||||
.catch((res) => {
|
||||
spinShow.value = false;
|
||||
ElMessage.error(res.msg);
|
||||
});
|
||||
}
|
||||
|
||||
getList();
|
||||
getStatistics();
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.picBox {
|
||||
display: inline-block;
|
||||
cursor: pointer;
|
||||
.upLoad {
|
||||
width: 58px;
|
||||
height: 58px;
|
||||
line-height: 58px;
|
||||
border: 1px dotted rgba(0, 0, 0, 0.1);
|
||||
border-radius: 4px;
|
||||
background: rgba(0, 0, 0, 0.02);
|
||||
}
|
||||
.pictrue {
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
border: 1px dotted rgba(0, 0, 0, 0.1);
|
||||
margin-right: 10px;
|
||||
|
||||
img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
.iconfont {
|
||||
color: #898989;
|
||||
}
|
||||
}
|
||||
.QRpic {
|
||||
width: 180px;
|
||||
height: 180px;
|
||||
|
||||
img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
.QRpic_sp1 {
|
||||
font-size: 13px;
|
||||
color: #19be6b;
|
||||
cursor: pointer;
|
||||
}
|
||||
.QRpic_sp2 {
|
||||
font-size: 13px;
|
||||
color: #2d8cf0;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
img {
|
||||
height: 36px;
|
||||
display: block;
|
||||
}
|
||||
.ivu-mt .name .item {
|
||||
margin: 3px 0;
|
||||
}
|
||||
.tabform {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.Refresh {
|
||||
font-size: 12px;
|
||||
color: var(--prev-color-primary);
|
||||
cursor: pointer;
|
||||
}
|
||||
.ivu-form-item {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
/* .ivu-mt :deep(.ivu-table-header) */
|
||||
/* border-top:1px dashed #ddd!important */
|
||||
</style>
|
||||
@ -1,232 +0,0 @@
|
||||
// +----------------------------------------------------------------------
|
||||
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: CRMEB Team <admin@crmeb.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
import request from '@/libs/request';
|
||||
|
||||
/**
|
||||
* @description 分销 -- 列表
|
||||
* @param {Object} param params {Object} 传值参数
|
||||
*/
|
||||
export function agentListApi(params) {
|
||||
return request({
|
||||
url: 'distribution/index',
|
||||
method: 'get',
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 修改上级用户
|
||||
* @param {Object} param params {Object} 传值参数
|
||||
*/
|
||||
export function agentSpreadApi(data) {
|
||||
return request({
|
||||
url: 'distribution/spread',
|
||||
method: 'PUT',
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 分销 -- 表头
|
||||
* @param {Object} param params {Object} 传值参数
|
||||
*/
|
||||
export function statisticsApi(params) {
|
||||
return request({
|
||||
url: 'distribution/statistics',
|
||||
method: 'get',
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 分销 -- 推广人,订单列表
|
||||
* @param {Object} param params {Object} 传值参数
|
||||
* @param {String} param url {String} 请求地址
|
||||
*/
|
||||
export function stairListApi(url, params) {
|
||||
return request({
|
||||
url: url,
|
||||
method: 'get',
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 分销 -- 公众号推广二维码
|
||||
* @param {Object} param params {Object} 传值参数
|
||||
*/
|
||||
export function lookCodeApi(params) {
|
||||
return request({
|
||||
url: 'distribution/look_code',
|
||||
method: 'get',
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 分销 -- 小程序推广二维码
|
||||
* @param {Object} param params {Object} 传值参数
|
||||
*/
|
||||
export function lookxcxCodeApi(params) {
|
||||
return request({
|
||||
url: 'distribution/look_xcx_code',
|
||||
method: 'get',
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 分销 -- h5推广二维码
|
||||
* @param {Object} param params {Object} 传值参数
|
||||
*/
|
||||
export function lookh5CodeApi(params) {
|
||||
return request({
|
||||
url: 'distribution/look_h5_code',
|
||||
method: 'get',
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 分销 -- 用户推广列表导出
|
||||
*/
|
||||
export function userAgentApi(data) {
|
||||
return request({
|
||||
url: `export/userAgent`,
|
||||
method: 'get',
|
||||
params: data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 事业部--列表
|
||||
* @param {Object} param data {Object} 传值参数
|
||||
*/
|
||||
export function regionList(data) {
|
||||
return request({
|
||||
url: 'distribution/division/list',
|
||||
method: 'get',
|
||||
params: data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 代理商申请--列表
|
||||
* @param {Object} param data {Object} 传值参数
|
||||
*/
|
||||
export function divisionList(data) {
|
||||
return request({
|
||||
url: 'distribution/division/agent_apply/list',
|
||||
method: 'get',
|
||||
params: data,
|
||||
});
|
||||
}
|
||||
/**
|
||||
* @description 事业部统计--列表
|
||||
* @param {Object} param data {Object} 传值参数
|
||||
*/
|
||||
export function divisionStatistics(data) {
|
||||
return request({
|
||||
url: 'distribution/division/statistics',
|
||||
method: 'get',
|
||||
params: data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 代理商添加--表单
|
||||
* @param {Object} param data {Object} 传值参数
|
||||
*/
|
||||
export function agentFrom(uid) {
|
||||
return request({
|
||||
url: `distribution/division/agent/create/${uid}`,
|
||||
method: 'get',
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 代理商审核
|
||||
* @param {Object} param data {Object} 传值参数
|
||||
*/
|
||||
export function divisionFrom(id, type) {
|
||||
return request({
|
||||
url: `distribution/division/examine_apply/${id}/${type}`,
|
||||
method: 'get',
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 事业部添加--表单
|
||||
* @param {Object} param data {Object} 传值参数
|
||||
*/
|
||||
export function regionFrom(uid) {
|
||||
return request({
|
||||
url: `distribution/division/create/${uid}`,
|
||||
method: 'get',
|
||||
});
|
||||
}
|
||||
/**
|
||||
* @description 事业部列表
|
||||
* @param {Object} param data {Object} 传值参数
|
||||
*/
|
||||
export function clerkList(data) {
|
||||
return request({
|
||||
url: `distribution/division/down_list`,
|
||||
method: 'get',
|
||||
params: data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 事业部状态切换--列表
|
||||
* @param {Object} param data {Object} 传值参数
|
||||
*/
|
||||
export function isShowApi(data) {
|
||||
return request({
|
||||
url: `distribution/division/set_status/${data.status}/${data.id}`,
|
||||
method: 'put',
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 员工添加--表单
|
||||
* @param {Object} param data {Object} 传值参数
|
||||
*/
|
||||
export function staffAddFrom(uid) {
|
||||
return request({
|
||||
url: `distribution/division/staff/create/${uid}`,
|
||||
method: 'get',
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 申请列表--分销员
|
||||
* @param {Object} param data {Object} 传值参数
|
||||
*/
|
||||
export function spreadList(data) {
|
||||
return request({
|
||||
url: 'distribution/spread/apply/list',
|
||||
method: 'get',
|
||||
params: data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 审核--分销员
|
||||
* @param {Object} param data {Object} 传值参数
|
||||
*/
|
||||
export function spreadFrom(id, uid, type, data) {
|
||||
return request({
|
||||
url: `distribution/spread/apply/examine/${id}/${uid}/${type}`,
|
||||
method: 'post',
|
||||
data,
|
||||
});
|
||||
}
|
||||
@ -1,86 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="i-layout-page-header header-title">
|
||||
<span class="ivu-page-header-title">{{ $route.meta.title }}</span>
|
||||
</div>
|
||||
<el-card :bordered="false" shadow="never" class="ivu-mt">
|
||||
<el-form label-width="85px" @submit.prevent v-loading="spinShow">
|
||||
<el-form-item label="协议内容:">
|
||||
<WangEditor
|
||||
:content="agreement.content"
|
||||
:ai-default-prompt="aiDefaultPrompt"
|
||||
:ai-default-system-prompt="aiDefaultSystemPrompt"
|
||||
@editorContent="getEditorContent"
|
||||
></WangEditor>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" v-db-click @click="memberAgreementSave">保存</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue';
|
||||
import { ElMessage } from 'element-plus';
|
||||
import WangEditor from '@/components/wangEditor/index.vue';
|
||||
import { agentAgreement, agentAgreementSave } from '@/api/user';
|
||||
|
||||
const ueConfig = {
|
||||
autoHeightEnabled: false,
|
||||
initialFrameHeight: 500,
|
||||
initialFrameWidth: '100%',
|
||||
UEDITOR_HOME_URL: '/UEditor/',
|
||||
serverUrl: '',
|
||||
};
|
||||
const agreement = ref({
|
||||
content: '',
|
||||
id: 0,
|
||||
});
|
||||
const spinShow = ref(false);
|
||||
|
||||
// AI 写作默认提示词随协议数据下发(user_prompt 为 AI 弹窗输入框默认提示词,
|
||||
// system_prompt 为系统提示词,生成时按行拆分为 prompts 逐条下发)
|
||||
const aiDefaultPrompt = ref('');
|
||||
const aiDefaultSystemPrompt = ref('');
|
||||
|
||||
function getEditorContent(data) {
|
||||
agreement.value.content = data;
|
||||
}
|
||||
function memberAgreement() {
|
||||
spinShow.value = true;
|
||||
agentAgreement()
|
||||
.then((res) => {
|
||||
spinShow.value = false;
|
||||
const { title, content, status, id, system_prompt, user_prompt } = res.data;
|
||||
agreement.value.content = content;
|
||||
agreement.value.id = id || 0;
|
||||
aiDefaultPrompt.value = user_prompt || '';
|
||||
aiDefaultSystemPrompt.value = system_prompt || '';
|
||||
})
|
||||
.catch((err) => {
|
||||
ElMessage.error(err.msg);
|
||||
spinShow.value = false;
|
||||
});
|
||||
}
|
||||
// 保存
|
||||
function memberAgreementSave() {
|
||||
agentAgreementSave(agreement.value)
|
||||
.then((res) => {
|
||||
ElMessage.success('保存成功');
|
||||
memberAgreement();
|
||||
})
|
||||
.catch((err) => {
|
||||
ElMessage.error(err.msg);
|
||||
});
|
||||
}
|
||||
|
||||
memberAgreement();
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
:deep(.ivu-form-item-content) {
|
||||
line-height: unset !important;
|
||||
}
|
||||
</style>
|
||||
@ -1,351 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-card :bordered="false" shadow="never" :body-style="{ padding: 0 }">
|
||||
<div class="padding-add">
|
||||
<el-form
|
||||
ref="formValidateRef"
|
||||
:model="formValidate"
|
||||
:label-width="labelWidth"
|
||||
:label-position="labelPosition"
|
||||
@submit.prevent
|
||||
inline
|
||||
>
|
||||
<el-form-item label="搜索:">
|
||||
<el-input
|
||||
clearable
|
||||
placeholder="请输入姓名、UID"
|
||||
v-model="formValidate.keyword"
|
||||
class="form_content_width"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" v-db-click @click="userSearchs">查询</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
</el-card>
|
||||
<el-card :bordered="false" shadow="never" class="ivu-mt mt16" :body-style="{ padding: '0 20px 20px' }">
|
||||
<el-row class="ivu-mt box-wrapper">
|
||||
<el-col :xs="24" :sm="24" ref="rightBox">
|
||||
<el-tabs v-model="formValidate.status" @tab-change="userSearchs">
|
||||
<el-tab-pane name="all" label="全部"></el-tab-pane>
|
||||
<el-tab-pane
|
||||
v-for="(item, index) in statusList"
|
||||
:key="index"
|
||||
:label="item.status_name"
|
||||
:name="item.id"
|
||||
></el-tab-pane>
|
||||
</el-tabs>
|
||||
<el-table
|
||||
:data="userLists"
|
||||
ref="table"
|
||||
v-loading="loading"
|
||||
highlight-current-row
|
||||
no-formValidate-text="暂无数据"
|
||||
no-filtered-formValidate-text="暂无筛选结果"
|
||||
>
|
||||
<el-table-column label="用户UID" width="100">
|
||||
<template #default="scope">
|
||||
<span>{{ scope.row.uid }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="代理商名称" min-width="150">
|
||||
<template #default="scope">
|
||||
<span>{{ scope.row.agent_name }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="代理商电话" min-width="150">
|
||||
<template #default="scope">
|
||||
<span>{{ scope.row.phone }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="事业部名称" min-width="150">
|
||||
<template #default="scope">
|
||||
<span>{{ scope.row.division_name }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="申请图片" min-width="150">
|
||||
<template #default="scope">
|
||||
<div class="pictrue-box" v-if="scope.row.images.length">
|
||||
<div v-viewer v-for="(item, index) in scope.row.images || []" :key="index">
|
||||
<img class="pictrue mr10" v-lazy="item" :src="item" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="申请时间" min-width="150">
|
||||
<template #default="scope">
|
||||
<span>{{ scope.row.add_time }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="申请状态" min-width="150">
|
||||
<template #default="scope">
|
||||
<el-tag>{{ scope.row.status == 0 ? '申请中' : scope.row.status == 1 ? '已同意' : '已拒绝' }}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="邀请码" min-width="150">
|
||||
<template #default="scope">
|
||||
<el-tag>{{ scope.row.division_invite }}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" fixed="right" width="170">
|
||||
<template #default="scope">
|
||||
<a v-if="scope.row.status == 0" v-db-click @click="groupAdd(scope.row.id, 1)">同意</a>
|
||||
<el-divider v-if="scope.row.status == 0" direction="vertical" />
|
||||
<a v-if="scope.row.status == 0" v-db-click @click="groupAdd(scope.row.id, 0)">拒绝</a>
|
||||
<el-divider direction="vertical" v-if="scope.row.status == 0" />
|
||||
<a v-db-click @click="del(scope.row, '删除申请', scope.$index)">删除</a>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<div class="acea-row row-right page">
|
||||
<pagination
|
||||
v-if="total"
|
||||
:total="total"
|
||||
v-model:page="formValidate.page"
|
||||
v-model:limit="formValidate.limit"
|
||||
@pagination="getList"
|
||||
/>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed, onMounted, ref } from 'vue';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { ElMessage } from 'element-plus';
|
||||
import { useMediaStore } from '@/store/module/media';
|
||||
import { divisionList, divisionFrom, isShowApi, clerkList } from '../../api';
|
||||
import modalForm from '@/utils/modalForm';
|
||||
import { modalSure } from '@/utils/public';
|
||||
|
||||
defineOptions({ name: 'agent_extra' });
|
||||
|
||||
const { isMobile } = storeToRefs(useMediaStore());
|
||||
const labelWidth = computed(() => (isMobile.value ? undefined : '50px'));
|
||||
const labelPosition = computed(() => (isMobile.value ? 'top' : 'right'));
|
||||
|
||||
const grid = {
|
||||
xl: 7,
|
||||
lg: 7,
|
||||
md: 12,
|
||||
sm: 24,
|
||||
xs: 24,
|
||||
};
|
||||
const total = ref(0);
|
||||
const total2 = ref(0);
|
||||
const userLists = ref([]);
|
||||
const formInline = ref({
|
||||
uid: 0,
|
||||
proportion: 0,
|
||||
image: '',
|
||||
});
|
||||
const statusList = ref([
|
||||
{
|
||||
status_name: '申请中',
|
||||
id: '0',
|
||||
},
|
||||
{
|
||||
status_name: '已同意',
|
||||
id: '1',
|
||||
},
|
||||
{
|
||||
status_name: '已拒绝',
|
||||
id: '2',
|
||||
},
|
||||
]);
|
||||
const FromData = ref(null);
|
||||
const loading = ref(false);
|
||||
const current = ref(0);
|
||||
const formValidate = ref({
|
||||
page: 1,
|
||||
limit: 15,
|
||||
keyword: '',
|
||||
status: 'all',
|
||||
});
|
||||
const staffModal = ref(false);
|
||||
const clerkReqData = ref({
|
||||
uid: 0,
|
||||
page: 1,
|
||||
limit: 15,
|
||||
});
|
||||
const clerkLists = ref([]);
|
||||
|
||||
const formValidateRef = ref(null);
|
||||
const table = ref(null);
|
||||
const rightBox = ref(null);
|
||||
|
||||
function userSearchs() {
|
||||
formValidate.value.page = 1;
|
||||
getList();
|
||||
}
|
||||
function jump(uid) {
|
||||
clerkReqData.value.uid = uid;
|
||||
getClerkList();
|
||||
}
|
||||
function getClerkList() {
|
||||
clerkReqData.value.division_type = 3;
|
||||
clerkList(clerkReqData.value).then((res) => {
|
||||
clerkLists.value = res.data.list;
|
||||
total2.value = res.data.count;
|
||||
staffModal.value = true;
|
||||
});
|
||||
}
|
||||
// 列表
|
||||
function getList() {
|
||||
loading.value = true;
|
||||
divisionList(formValidate.value)
|
||||
.then(async (res) => {
|
||||
let data = res.data;
|
||||
userLists.value = data.list;
|
||||
total.value = data.count;
|
||||
loading.value = false;
|
||||
})
|
||||
.catch((res) => {
|
||||
loading.value = false;
|
||||
ElMessage.error(res.msg);
|
||||
});
|
||||
}
|
||||
function pageChange(index) {
|
||||
formValidate.value.page = index;
|
||||
getList();
|
||||
}
|
||||
function clerkPageChange() {
|
||||
clerkReqData.value.page = index;
|
||||
getClerkList();
|
||||
}
|
||||
// 添加表单
|
||||
function groupAdd(id, type) {
|
||||
modalForm(divisionFrom(id, type))
|
||||
.then((res) => {
|
||||
getList();
|
||||
})
|
||||
.catch((err) => {});
|
||||
}
|
||||
// 修改是否显示
|
||||
function onchangeIsShow(row) {
|
||||
let data = {
|
||||
id: row.uid,
|
||||
status: row.division_status,
|
||||
};
|
||||
isShowApi(data)
|
||||
.then(async (res) => {
|
||||
ElMessage.success(res.msg);
|
||||
})
|
||||
.catch((res) => {
|
||||
ElMessage.error(res.msg);
|
||||
});
|
||||
}
|
||||
// 编辑
|
||||
function edit(row) {}
|
||||
// 删除
|
||||
function del(row, tit, num) {
|
||||
let delfromData = {
|
||||
title: tit,
|
||||
method: 'DELETE',
|
||||
uid: row.id,
|
||||
url: `distribution/division/del_apply/${row.id}`,
|
||||
};
|
||||
modalSure(delfromData)
|
||||
.then((res) => {
|
||||
ElMessage.success(res.msg);
|
||||
userLists.value.splice(num, 1);
|
||||
})
|
||||
.catch((res) => {
|
||||
ElMessage.error(res.msg);
|
||||
});
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
getList();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.ivu-form-item {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.picBox {
|
||||
display: inline-block;
|
||||
cursor: pointer;
|
||||
.upLoad {
|
||||
width: 58px;
|
||||
height: 58px;
|
||||
line-height: 58px;
|
||||
border: 1px dotted rgba(0, 0, 0, 0.1);
|
||||
border-radius: 4px;
|
||||
background: rgba(0, 0, 0, 0.02);
|
||||
}
|
||||
.pictrue {
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
border: 1px dotted rgba(0, 0, 0, 0.1);
|
||||
margin-right: 10px;
|
||||
|
||||
img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
:deep(.ivu-menu-vertical .ivu-menu-item-group-title) {
|
||||
display: none;
|
||||
}
|
||||
:deep(.ivu-menu-vertical.ivu-menu-light:after) {
|
||||
display: none;
|
||||
}
|
||||
.left-wrapper {
|
||||
height: 904px;
|
||||
background: #fff;
|
||||
border-right: 1px solid #f2f2f2;
|
||||
}
|
||||
.menu-item {
|
||||
z-index: 50;
|
||||
position: relative;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
word-break: break-all;
|
||||
}
|
||||
:deep(.el-tabs__item) {
|
||||
height: 54px;
|
||||
line-height: 54px;
|
||||
}
|
||||
.icon-box {
|
||||
z-index: 3;
|
||||
position: absolute;
|
||||
right: 20px;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
display: none;
|
||||
}
|
||||
|
||||
.right-menu {
|
||||
z-index: 10;
|
||||
position: absolute;
|
||||
right: -106px;
|
||||
top: -11px;
|
||||
width: auto;
|
||||
min-width: 121px;
|
||||
}
|
||||
.tabBox_img {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
.pictrue-box {
|
||||
display: flex;
|
||||
align-item: center;
|
||||
}
|
||||
.pictrue {
|
||||
width: 25px;
|
||||
height: 25px;
|
||||
}
|
||||
</style>
|
||||
@ -1,389 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-card :bordered="false" shadow="never" :body-style="{ padding: 0 }">
|
||||
<div class="padding-add">
|
||||
<el-form
|
||||
ref="formValidateRef"
|
||||
:model="formValidate"
|
||||
:label-width="labelWidth"
|
||||
:label-position="labelPosition"
|
||||
@submit.prevent
|
||||
inline
|
||||
>
|
||||
<el-form-item label="搜索:">
|
||||
<el-input
|
||||
clearable
|
||||
placeholder="请输入姓名、UID"
|
||||
v-model="formValidate.keyword"
|
||||
class="form_content_width"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" v-db-click @click="userSearchs">查询</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
</el-card>
|
||||
<el-card :bordered="false" shadow="never" class="ivu-mt mt16">
|
||||
<el-row class="ivu-mt box-wrapper">
|
||||
<el-col :xs="24" :sm="24" ref="rightBox">
|
||||
<el-row>
|
||||
<el-col v-bind="grid">
|
||||
<el-button type="primary" v-db-click @click="groupAdd('0')" class="mr20">添加代理商</el-button>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-table
|
||||
:data="userLists"
|
||||
ref="table"
|
||||
class="mt14"
|
||||
v-loading="loading"
|
||||
highlight-current-row
|
||||
no-formValidate-text="暂无数据"
|
||||
no-filtered-formValidate-text="暂无筛选结果"
|
||||
>
|
||||
<el-table-column label="用户UID" width="100">
|
||||
<template #default="scope">
|
||||
<span>{{ scope.row.uid }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="头像" min-width="90">
|
||||
<template #default="scope">
|
||||
<div class="tabBox_img" v-viewer>
|
||||
<img v-lazy="scope.row.avatar" />
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="名称" min-width="130">
|
||||
<template #default="scope">
|
||||
<div class="acea-row">
|
||||
<div v-text="scope.row.division_name" class="ml10"></div>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="分销比例" min-width="130">
|
||||
<template #default="scope">
|
||||
<span> {{ scope.row.division_percent }}%</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="员工数量" min-width="130">
|
||||
<template #default="scope">
|
||||
<span>{{ scope.row.agent_count }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="截止时间" min-width="130">
|
||||
<template #default="scope">
|
||||
<span>{{ scope.row.division_end_time }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="状态" min-width="130">
|
||||
<template #default="scope">
|
||||
<el-switch
|
||||
:active-value="1"
|
||||
:inactive-value="0"
|
||||
v-model="scope.row.division_status"
|
||||
:value="scope.row.division_status"
|
||||
@change="onchangeIsShow(scope.row)"
|
||||
size="large"
|
||||
>
|
||||
</el-switch>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" fixed="right" width="220">
|
||||
<template #default="scope">
|
||||
<a v-db-click @click="staffAdd(scope.row.uid)">添加员工</a>
|
||||
<el-divider direction="vertical"></el-divider>
|
||||
<a v-db-click @click="jump(scope.row.uid)">查看员工</a>
|
||||
<el-divider direction="vertical"></el-divider>
|
||||
<a v-db-click @click="groupAdd(scope.row.uid)">编辑</a>
|
||||
<el-divider direction="vertical"></el-divider>
|
||||
<a v-db-click @click="del(scope.row, '删除代理商', scope.$index, 2)">删除</a>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<div class="acea-row row-right page">
|
||||
<pagination
|
||||
v-if="total"
|
||||
:total="total"
|
||||
v-model:page="formValidate.page"
|
||||
v-model:limit="formValidate.limit"
|
||||
@pagination="getList"
|
||||
/>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-card>
|
||||
<el-dialog v-model="staffModal" title="员工列表" class="order_box" width="1000px">
|
||||
<el-table
|
||||
:data="clerkLists"
|
||||
ref="table"
|
||||
class="mt20"
|
||||
v-loading="loading"
|
||||
highlight-current-row
|
||||
no-formValidate-text="暂无数据"
|
||||
no-filtered-formValidate-text="暂无筛选结果"
|
||||
>
|
||||
<el-table-column label="用户UID" width="120">
|
||||
<template #default="scope">
|
||||
<span>{{ scope.row.uid }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="头像" min-width="120">
|
||||
<template #default="scope">
|
||||
<div class="tabBox_img" v-viewer>
|
||||
<img v-lazy="scope.row.avatar" />
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="姓名" min-width="130">
|
||||
<template #default="scope">
|
||||
<div class="acea-row">
|
||||
<i class="el-icon-male mr10" v-show="scope.row.sex === '男'" style="color: #2db7f5; font-size: 15px"></i>
|
||||
<i
|
||||
class="el-icon-female mr10"
|
||||
v-show="scope.row.sex === '女'"
|
||||
style="color: #ed4014; font-size: 15px"
|
||||
></i>
|
||||
<div v-text="scope.row.nickname" class=""></div>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="分销比例" min-width="130">
|
||||
<template #default="scope">
|
||||
<span> {{ scope.row.division_percent }}%</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="120">
|
||||
<template #default="scope">
|
||||
<a v-db-click @click="del(scope.row, '删除员工', scope.$index, 3)">删除</a>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<div class="acea-row row-right page">
|
||||
<pagination
|
||||
v-if="total2"
|
||||
:total="total2"
|
||||
v-model:page="clerkReqData.page"
|
||||
v-model:limit="clerkReqData.limit"
|
||||
@pagination="getClerkList"
|
||||
/>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed, onMounted, ref } from 'vue';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { ElMessage } from 'element-plus';
|
||||
import { useMediaStore } from '@/store/module/media';
|
||||
import { regionList, agentFrom, isShowApi, clerkList, staffAddFrom } from '../../api';
|
||||
import modalForm from '@/utils/modalForm';
|
||||
import { modalSure } from '@/utils/public';
|
||||
|
||||
defineOptions({ name: 'agent_extra' });
|
||||
|
||||
const { isMobile } = storeToRefs(useMediaStore());
|
||||
const labelWidth = computed(() => (isMobile.value ? undefined : '50px'));
|
||||
const labelPosition = computed(() => (isMobile.value ? 'top' : 'right'));
|
||||
|
||||
const grid = {
|
||||
xl: 7,
|
||||
lg: 7,
|
||||
md: 12,
|
||||
sm: 24,
|
||||
xs: 24,
|
||||
};
|
||||
const total = ref(0);
|
||||
const total2 = ref(0);
|
||||
const userLists = ref([]);
|
||||
const formInline = ref({
|
||||
uid: 0,
|
||||
proportion: 0,
|
||||
image: '',
|
||||
});
|
||||
const FromData = ref(null);
|
||||
const loading = ref(false);
|
||||
const current = ref(0);
|
||||
const formValidate = ref({
|
||||
page: 1,
|
||||
limit: 15,
|
||||
keyword: '',
|
||||
});
|
||||
const staffModal = ref(false);
|
||||
const clerkReqData = ref({
|
||||
uid: 0,
|
||||
page: 1,
|
||||
limit: 15,
|
||||
});
|
||||
const clerkLists = ref([]);
|
||||
|
||||
const formValidateRef = ref(null);
|
||||
const table = ref(null);
|
||||
const rightBox = ref(null);
|
||||
|
||||
function userSearchs() {
|
||||
formValidate.value.page = 1;
|
||||
getList();
|
||||
}
|
||||
function jump(uid) {
|
||||
clerkReqData.value.uid = uid;
|
||||
getClerkList();
|
||||
}
|
||||
function getClerkList() {
|
||||
clerkReqData.value.division_type = 3;
|
||||
clerkList(clerkReqData.value).then((res) => {
|
||||
clerkLists.value = res.data.list;
|
||||
total2.value = res.data.count;
|
||||
staffModal.value = true;
|
||||
});
|
||||
}
|
||||
// 列表
|
||||
function getList() {
|
||||
loading.value = true;
|
||||
formValidate.value.division_type = 2;
|
||||
regionList(formValidate.value)
|
||||
.then(async (res) => {
|
||||
let data = res.data;
|
||||
userLists.value = data.list;
|
||||
total.value = data.count;
|
||||
loading.value = false;
|
||||
})
|
||||
.catch((res) => {
|
||||
loading.value = false;
|
||||
ElMessage.error(res.msg);
|
||||
});
|
||||
}
|
||||
// 添加表单
|
||||
function groupAdd(id) {
|
||||
modalForm(agentFrom(id))
|
||||
.then((res) => {
|
||||
getList();
|
||||
})
|
||||
.catch((err) => {});
|
||||
}
|
||||
//添加员工表单
|
||||
function staffAdd(id) {
|
||||
modalForm(staffAddFrom(id))
|
||||
.then((res) => {
|
||||
getList();
|
||||
})
|
||||
.catch((err) => {});
|
||||
}
|
||||
// 修改是否显示
|
||||
function onchangeIsShow(row) {
|
||||
let data = {
|
||||
id: row.uid,
|
||||
status: row.division_status,
|
||||
};
|
||||
isShowApi(data)
|
||||
.then(async (res) => {
|
||||
ElMessage.success(res.msg);
|
||||
})
|
||||
.catch((res) => {
|
||||
ElMessage.error(res.msg);
|
||||
});
|
||||
}
|
||||
// 编辑
|
||||
function edit(row) {}
|
||||
// 删除
|
||||
function del(row, tit, num, type) {
|
||||
let delfromData = {
|
||||
title: tit,
|
||||
method: 'DELETE',
|
||||
uid: row.uid,
|
||||
url: `distribution/division/del/${type}/${row.uid}`,
|
||||
};
|
||||
modalSure(delfromData)
|
||||
.then((res) => {
|
||||
ElMessage.success(res.msg);
|
||||
if (type == 2) {
|
||||
userLists.value.splice(num, 1);
|
||||
} else {
|
||||
clerkLists.value.splice(num, 1);
|
||||
}
|
||||
})
|
||||
.catch((res) => {
|
||||
ElMessage.error(res.msg);
|
||||
});
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
getList();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.ivu-form-item {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.picBox {
|
||||
display: inline-block;
|
||||
cursor: pointer;
|
||||
.upLoad {
|
||||
width: 58px;
|
||||
height: 58px;
|
||||
line-height: 58px;
|
||||
border: 1px dotted rgba(0, 0, 0, 0.1);
|
||||
border-radius: 4px;
|
||||
background: rgba(0, 0, 0, 0.02);
|
||||
}
|
||||
.pictrue {
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
border: 1px dotted rgba(0, 0, 0, 0.1);
|
||||
margin-right: 10px;
|
||||
|
||||
img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
:deep(.ivu-menu-vertical .ivu-menu-item-group-title) {
|
||||
display: none;
|
||||
}
|
||||
:deep(.ivu-menu-vertical.ivu-menu-light:after) {
|
||||
display: none;
|
||||
}
|
||||
.left-wrapper {
|
||||
height: 904px;
|
||||
background: #fff;
|
||||
border-right: 1px solid #f2f2f2;
|
||||
}
|
||||
.menu-item {
|
||||
z-index: 50;
|
||||
position: relative;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
word-break: break-all;
|
||||
&:hover .icon-box {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
.icon-box {
|
||||
z-index: 3;
|
||||
position: absolute;
|
||||
right: 20px;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
display: none;
|
||||
}
|
||||
.right-menu {
|
||||
z-index: 10;
|
||||
position: absolute;
|
||||
right: -106px;
|
||||
top: -11px;
|
||||
width: auto;
|
||||
min-width: 121px;
|
||||
}
|
||||
.tabBox_img {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@ -1,230 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-card :bordered="false" shadow="never" :body-style="{ padding: 0 }">
|
||||
<div class="padding-add">
|
||||
<el-form
|
||||
ref="formValidateRef"
|
||||
:model="formValidate"
|
||||
:label-width="labelWidth"
|
||||
:label-position="labelPosition"
|
||||
@submit.prevent
|
||||
inline
|
||||
>
|
||||
<el-form-item label="时间范围:">
|
||||
<date-range-picker
|
||||
clearable
|
||||
v-model="timeVal"
|
||||
@change="onchangeTime"
|
||||
format="YYYY/MM/DD"
|
||||
value-format="YYYY/MM/DD"
|
||||
class="mr20"
|
||||
></date-range-picker>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" v-db-click @click="userSearchs">查询</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
</el-card>
|
||||
<el-card :bordered="false" shadow="never" class="ivu-mt mt16" :body-style="{ padding: '0 20px 20px' }">
|
||||
<el-row class="ivu-mt box-wrapper">
|
||||
<el-col :xs="24" :sm="24" ref="rightBox">
|
||||
<el-tabs v-model="formValidate.type" @tab-change="userSearchs">
|
||||
<el-tab-pane
|
||||
v-for="(item, index) in statusList"
|
||||
:key="index"
|
||||
:label="item.status_name"
|
||||
:name="item.id"
|
||||
></el-tab-pane>
|
||||
</el-tabs>
|
||||
<el-table
|
||||
:data="userLists"
|
||||
ref="table"
|
||||
v-loading="loading"
|
||||
highlight-current-row
|
||||
no-formValidate-text="暂无数据"
|
||||
no-filtered-formValidate-text="暂无筛选结果"
|
||||
@sort-change="handleSortChange"
|
||||
>
|
||||
<el-table-column label="用户UID" width="150">
|
||||
<template #default="scope">
|
||||
<span>{{ scope.row.uid }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="头像" min-width="120">
|
||||
<template #default="scope">
|
||||
<div class="tabBox_img" v-viewer>
|
||||
<img v-lazy="scope.row.avatar" />
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="名称" min-width="130">
|
||||
<template #default="scope">
|
||||
<div class="acea-row">
|
||||
<div v-text="scope.row.name"></div>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
label="订单数"
|
||||
min-width="150"
|
||||
sortable="custom"
|
||||
:sort-orders="['ascending', 'descending']"
|
||||
prop="order_sum"
|
||||
>
|
||||
<template #default="scope">
|
||||
<span>{{ scope.row.order_sum }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
label="订单金额"
|
||||
min-width="150"
|
||||
sortable="custom"
|
||||
:sort-orders="['ascending', 'descending']"
|
||||
prop="order_sum_price"
|
||||
>
|
||||
<template #default="scope">
|
||||
<span>{{ scope.row.order_sum_price }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<div class="acea-row row-right page">
|
||||
<pagination
|
||||
v-if="total"
|
||||
:total="total"
|
||||
v-model:page="formValidate.page"
|
||||
v-model:limit="formValidate.limit"
|
||||
@pagination="getList"
|
||||
/>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed, onMounted, ref } from 'vue';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { ElMessage } from 'element-plus';
|
||||
import { useMediaStore } from '@/store/module/media';
|
||||
import { divisionStatistics } from '../../api';
|
||||
|
||||
defineOptions({ name: 'agent_extra' });
|
||||
|
||||
const { isMobile } = storeToRefs(useMediaStore());
|
||||
const labelWidth = computed(() => (isMobile.value ? undefined : '70px'));
|
||||
const labelPosition = computed(() => (isMobile.value ? 'top' : 'right'));
|
||||
|
||||
const grid = {
|
||||
xl: 7,
|
||||
lg: 7,
|
||||
md: 12,
|
||||
sm: 24,
|
||||
xs: 24,
|
||||
};
|
||||
const total = ref(0);
|
||||
const total2 = ref(0);
|
||||
const statusList = ref([
|
||||
{
|
||||
status_name: '事业部',
|
||||
id: '1',
|
||||
},
|
||||
{
|
||||
status_name: '代理商',
|
||||
id: '2',
|
||||
},
|
||||
{
|
||||
status_name: '员工',
|
||||
id: '3',
|
||||
},
|
||||
]);
|
||||
const userLists = ref([]);
|
||||
const formInline = ref({
|
||||
uid: 0,
|
||||
proportion: 0,
|
||||
image: '',
|
||||
});
|
||||
const timeVal = ref([]);
|
||||
|
||||
const FromData = ref(null);
|
||||
const loading = ref(false);
|
||||
const current = ref(0);
|
||||
const formValidate = ref({
|
||||
page: 1,
|
||||
limit: 15,
|
||||
time: '',
|
||||
type: '1',
|
||||
sort: '',
|
||||
order: '',
|
||||
});
|
||||
const staffModal = ref(false);
|
||||
const clerkReqData = ref({
|
||||
uid: 0,
|
||||
page: 1,
|
||||
limit: 15,
|
||||
});
|
||||
const clerkLists = ref([]);
|
||||
|
||||
const formValidateRef = ref(null);
|
||||
const table = ref(null);
|
||||
const rightBox = ref(null);
|
||||
|
||||
// 具体日期
|
||||
function onchangeTime(e) {
|
||||
timeVal.value = e || [];
|
||||
getList();
|
||||
}
|
||||
function userSearchs() {
|
||||
formValidate.value.page = 1;
|
||||
getList();
|
||||
}
|
||||
// 列表
|
||||
function getList() {
|
||||
loading.value = true;
|
||||
formValidate.value.time = timeVal.value[0] ? (timeVal.value ? timeVal.value.join('-') : '') : '';
|
||||
divisionStatistics(formValidate.value)
|
||||
.then(async (res) => {
|
||||
let data = res.data;
|
||||
userLists.value = data.list;
|
||||
total.value = data.count;
|
||||
loading.value = false;
|
||||
})
|
||||
.catch((res) => {
|
||||
loading.value = false;
|
||||
ElMessage.error(res.msg);
|
||||
});
|
||||
}
|
||||
function pageChange(index) {
|
||||
formValidate.value.page = index;
|
||||
getList();
|
||||
}
|
||||
// 添加排序方法
|
||||
function handleSortChange({ prop, order }) {
|
||||
formValidate.value.sort = prop;
|
||||
formValidate.value.order = order === 'ascending' ? 'asc' : 'desc';
|
||||
getList();
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
getList();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
:deep(.el-tabs__item) {
|
||||
height: 54px;
|
||||
line-height: 54px;
|
||||
}
|
||||
|
||||
.tabBox_img {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@ -1,382 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-card :bordered="false" shadow="never" :body-style="{ padding: 0 }">
|
||||
<div class="padding-add">
|
||||
<el-form
|
||||
ref="formValidateRef"
|
||||
:model="formValidate"
|
||||
:label-width="labelWidth"
|
||||
:label-position="labelPosition"
|
||||
@submit.prevent
|
||||
inline
|
||||
>
|
||||
<el-form-item label="搜索:">
|
||||
<el-input
|
||||
clearable
|
||||
placeholder="请输入姓名、UID"
|
||||
v-model="formValidate.keyword"
|
||||
class="form_content_width"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" v-db-click @click="userSearchs">查询</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
</el-card>
|
||||
<el-card :bordered="false" shadow="never" class="ivu-mt mt16">
|
||||
<el-row class="action-row mb14">
|
||||
<el-col :xs="24" :sm="24" ref="rightBox">
|
||||
<el-button type="primary" v-db-click @click="groupAdd('0')">添加事业部</el-button>
|
||||
<el-tooltip placement="right-start">
|
||||
<i class="el-icon-question ml10"></i>
|
||||
<template #content
|
||||
><div>
|
||||
<div>
|
||||
事业部层级说明:事业部-代理商-员工。事业部相当于总代理或者区域代理,设置成为事业部之后,关联的用户会清除上级推广人
|
||||
</div>
|
||||
<div>
|
||||
添加时候的管理员身份需要在,设置-管理权限-角色管理中设置对应的角色,事业部可以使用添加时设置的管理员账号密码登录后台
|
||||
</div>
|
||||
</div></template
|
||||
>
|
||||
</el-tooltip>
|
||||
<el-table
|
||||
:data="userLists"
|
||||
ref="table"
|
||||
class="mt14"
|
||||
v-loading="loading"
|
||||
highlight-current-row
|
||||
no-formValidate-text="暂无数据"
|
||||
no-filtered-formValidate-text="暂无筛选结果"
|
||||
>
|
||||
<el-table-column label="用户UID" width="100">
|
||||
<template #default="scope">
|
||||
<span>{{ scope.row.uid }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="头像" min-width="90">
|
||||
<template #default="scope">
|
||||
<div class="tabBox_img" v-viewer>
|
||||
<img v-lazy="scope.row.avatar" />
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="名称" min-width="130">
|
||||
<template #default="scope">
|
||||
<div class="acea-row">
|
||||
<div v-text="scope.row.division_name"></div>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="邀请码" min-width="130">
|
||||
<template #default="scope">
|
||||
<span>{{ scope.row.division_invite }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="分销比例" min-width="130">
|
||||
<template #default="scope">
|
||||
<span> {{ scope.row.division_percent }}%</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="代理商数量" min-width="130">
|
||||
<template #default="scope">
|
||||
<span>{{ scope.row.agent_count }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="截止时间" min-width="130">
|
||||
<template #default="scope">
|
||||
<span>{{ scope.row.division_end_time }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="状态" min-width="130">
|
||||
<template #default="scope">
|
||||
<el-switch
|
||||
:active-value="1"
|
||||
:inactive-value="0"
|
||||
v-model="scope.row.division_status"
|
||||
:value="scope.row.division_status"
|
||||
@change="onchangeIsShow(scope.row)"
|
||||
size="large"
|
||||
>
|
||||
</el-switch>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" fixed="right" width="170">
|
||||
<template #default="scope">
|
||||
<a v-db-click @click="jump(scope.row.uid)">查看代理商</a>
|
||||
<el-divider direction="vertical"></el-divider>
|
||||
<a v-db-click @click="groupAdd(scope.row.uid)">编辑</a>
|
||||
<el-divider direction="vertical"></el-divider>
|
||||
<a v-db-click @click="del(scope.row, '删除事业部', scope.$index)">删除</a>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<div class="acea-row row-right page">
|
||||
<pagination
|
||||
v-if="total"
|
||||
:total="total"
|
||||
v-model:page="formValidate.page"
|
||||
v-model:limit="formValidate.limit"
|
||||
@pagination="getList"
|
||||
/>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-card>
|
||||
<el-dialog v-model="staffModal" title="代理商列表" class="order_box" width="1000px">
|
||||
<el-table
|
||||
:data="clerkLists"
|
||||
ref="table"
|
||||
class="mt20"
|
||||
v-loading="loading"
|
||||
highlight-current-row
|
||||
no-formValidate-text="暂无数据"
|
||||
no-filtered-formValidate-text="暂无筛选结果"
|
||||
>
|
||||
<el-table-column label="用户UID" width="80">
|
||||
<template #default="scope">
|
||||
<span>{{ scope.row.uid }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="头像" min-width="90">
|
||||
<template #default="scope">
|
||||
<div class="tabBox_img" v-viewer>
|
||||
<img v-lazy="scope.row.avatar" />
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="名称" min-width="130">
|
||||
<template #default="scope">
|
||||
<div class="acea-row">
|
||||
<div v-text="scope.row.division_name" class="ml10"></div>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="分销比例" min-width="130">
|
||||
<template #default="scope">
|
||||
<span> {{ scope.row.division_percent }}%</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="到期时间" min-width="130">
|
||||
<template #default="scope">
|
||||
<span> {{ $filters.formatDate(scope.row.division_end_time) }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="员工数量" min-width="130">
|
||||
<template #default="scope">
|
||||
<span> {{ scope.row.agent_count }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<div class="acea-row row-right page">
|
||||
<pagination
|
||||
v-if="total2"
|
||||
:total="total2"
|
||||
v-model:page="clerkReqData.page"
|
||||
v-model:limit="clerkReqData.limit"
|
||||
@pagination="getClerkList"
|
||||
/>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed, onMounted, ref } from 'vue';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { ElMessage } from 'element-plus';
|
||||
import { useMediaStore } from '@/store/module/media';
|
||||
import { regionList, regionFrom, isShowApi, clerkList } from '../../api';
|
||||
import modalForm from '@/utils/modalForm';
|
||||
import { modalSure } from '@/utils/public';
|
||||
|
||||
defineOptions({ name: 'agent_extra' });
|
||||
|
||||
const { isMobile } = storeToRefs(useMediaStore());
|
||||
const labelWidth = computed(() => (isMobile.value ? undefined : '50px'));
|
||||
const labelPosition = computed(() => (isMobile.value ? 'top' : 'right'));
|
||||
|
||||
const grid = {
|
||||
xl: 7,
|
||||
lg: 7,
|
||||
md: 12,
|
||||
sm: 24,
|
||||
xs: 24,
|
||||
};
|
||||
const total = ref(0);
|
||||
const total2 = ref(0);
|
||||
const userLists = ref([]);
|
||||
const formInline = ref({
|
||||
uid: 0,
|
||||
proportion: 0,
|
||||
image: '',
|
||||
});
|
||||
const FromData = ref(null);
|
||||
const loading = ref(false);
|
||||
const current = ref(0);
|
||||
const formValidate = ref({
|
||||
page: 1,
|
||||
limit: 15,
|
||||
keyword: '',
|
||||
});
|
||||
const staffModal = ref(false);
|
||||
const clerkReqData = ref({
|
||||
uid: 0,
|
||||
page: 1,
|
||||
limit: 15,
|
||||
});
|
||||
const clerkLists = ref([]);
|
||||
|
||||
const formValidateRef = ref(null);
|
||||
const table = ref(null);
|
||||
const rightBox = ref(null);
|
||||
|
||||
// 搜索
|
||||
function userSearchs() {
|
||||
formValidate.value.page = 1;
|
||||
getList();
|
||||
}
|
||||
function jump(uid) {
|
||||
clerkReqData.value.uid = uid;
|
||||
getClerkList();
|
||||
}
|
||||
function getClerkList() {
|
||||
clerkReqData.value.division_type = 2;
|
||||
clerkList(clerkReqData.value).then((res) => {
|
||||
clerkLists.value = res.data.list;
|
||||
total2.value = res.data.count;
|
||||
staffModal.value = true;
|
||||
});
|
||||
}
|
||||
// 列表
|
||||
function getList() {
|
||||
loading.value = true;
|
||||
formValidate.value.division_type = 1;
|
||||
regionList(formValidate.value)
|
||||
.then(async (res) => {
|
||||
let data = res.data;
|
||||
userLists.value = data.list;
|
||||
total.value = data.count;
|
||||
loading.value = false;
|
||||
})
|
||||
.catch((res) => {
|
||||
loading.value = false;
|
||||
ElMessage.error(res.msg);
|
||||
});
|
||||
}
|
||||
// 添加表单
|
||||
function groupAdd(id) {
|
||||
modalForm(regionFrom(id))
|
||||
.then((res) => {
|
||||
getList();
|
||||
})
|
||||
.catch((err) => {});
|
||||
}
|
||||
// 修改是否显示
|
||||
function onchangeIsShow(row) {
|
||||
let data = {
|
||||
id: row.uid,
|
||||
status: row.division_status,
|
||||
};
|
||||
isShowApi(data)
|
||||
.then(async (res) => {
|
||||
ElMessage.success(res.msg);
|
||||
})
|
||||
.catch((res) => {
|
||||
ElMessage.error(res.msg);
|
||||
});
|
||||
}
|
||||
// 编辑
|
||||
function edit(row) {}
|
||||
// 删除
|
||||
function del(row, tit, num) {
|
||||
let delfromData = {
|
||||
title: tit,
|
||||
method: 'DELETE',
|
||||
uid: row.uid,
|
||||
url: `distribution/division/del/1/${row.uid}`,
|
||||
};
|
||||
modalSure(delfromData)
|
||||
.then((res) => {
|
||||
ElMessage.success(res.msg);
|
||||
userLists.value.splice(num, 1);
|
||||
})
|
||||
.catch((res) => {
|
||||
ElMessage.error(res.msg);
|
||||
});
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
getList();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.ivu-form-item {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.picBox {
|
||||
display: inline-block;
|
||||
cursor: pointer;
|
||||
.upLoad {
|
||||
width: 58px;
|
||||
height: 58px;
|
||||
line-height: 58px;
|
||||
border: 1px dotted rgba(0, 0, 0, 0.1);
|
||||
border-radius: 4px;
|
||||
background: rgba(0, 0, 0, 0.02);
|
||||
}
|
||||
.pictrue {
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
border: 1px dotted rgba(0, 0, 0, 0.1);
|
||||
margin-right: 10px;
|
||||
|
||||
img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
:deep(.ivu-menu-vertical .ivu-menu-item-group-title) {
|
||||
display: none;
|
||||
}
|
||||
:deep(.ivu-menu-vertical.ivu-menu-light:after) {
|
||||
display: none;
|
||||
}
|
||||
.left-wrapper {
|
||||
height: 904px;
|
||||
background: #fff;
|
||||
border-right: 1px solid #f2f2f2;
|
||||
}
|
||||
.menu-item {
|
||||
z-index: 50;
|
||||
position: relative;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
word-break: break-all;
|
||||
&:hover .icon-box {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
.right-menu {
|
||||
z-index: 10;
|
||||
position: absolute;
|
||||
right: -106px;
|
||||
top: -11px;
|
||||
width: auto;
|
||||
min-width: 121px;
|
||||
}
|
||||
.tabBox_img {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@ -1,14 +0,0 @@
|
||||
{
|
||||
"key": "distribution",
|
||||
"title": "分销管理",
|
||||
"version": "1.0.0",
|
||||
"pages": [
|
||||
{ "path": "agent_manage/index", "title": "分销员管理" },
|
||||
{ "path": "spread/apply", "title": "分销员申请" },
|
||||
{ "path": "division/list/index", "title": "事业部列表" },
|
||||
{ "path": "division/agent/index", "title": "代理商列表" },
|
||||
{ "path": "division/agent/statistics", "title": "事业部统计" },
|
||||
{ "path": "division/agent/applyList", "title": "代理商申请" },
|
||||
{ "path": "division/agent/agreement", "title": "代理商规则" }
|
||||
]
|
||||
}
|
||||
@ -1,281 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-dialog
|
||||
v-model="modals"
|
||||
:title="listTitle === 'man' ? '统计推广人列表' : '推广订单'"
|
||||
:close-on-click-modal="false"
|
||||
width="1000px"
|
||||
@closed="onCancel"
|
||||
>
|
||||
<div class="table_box">
|
||||
<el-form
|
||||
ref="formValidateRef"
|
||||
:model="formValidate"
|
||||
:label-width="labelWidth"
|
||||
:label-position="labelPosition"
|
||||
@submit.prevent
|
||||
inline
|
||||
>
|
||||
<el-form-item label="时间选择:">
|
||||
<date-range-picker
|
||||
clearable
|
||||
:editable="false"
|
||||
@change="onchangeTime"
|
||||
v-model="timeVal"
|
||||
value-format="YYYY/MM/DD"
|
||||
></date-range-picker>
|
||||
</el-form-item>
|
||||
<el-form-item label="用户类型:">
|
||||
<el-select v-model="formValidate.type" clearable class="form_content_width">
|
||||
<el-option
|
||||
v-for="(item, i) in listTitle === 'man' ? fromList.fromTxt2 : fromList.fromTxt3"
|
||||
:key="i"
|
||||
:value="item.val"
|
||||
:label="item.text"
|
||||
></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="搜索:" v-if="listTitle === 'man'">
|
||||
<el-input
|
||||
clearable
|
||||
placeholder="请输入请姓名、电话、UID"
|
||||
v-model="formValidate.nickname"
|
||||
class="form_content_width"
|
||||
></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="订单号:" v-if="listTitle === 'order'">
|
||||
<el-input
|
||||
clearable
|
||||
placeholder="请输入请订单号"
|
||||
v-model="formValidate.order_id"
|
||||
class="form_content_width"
|
||||
></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" v-db-click @click="userSearchs">查询</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
<el-table
|
||||
ref="selection"
|
||||
:data="tabList"
|
||||
v-loading="loading"
|
||||
empty-text="暂无数据"
|
||||
highlight-current-row
|
||||
max-height="400"
|
||||
>
|
||||
<template v-if="listTitle === 'man'">
|
||||
<el-table-column label="UID" width="80">
|
||||
<template #default="scope">
|
||||
<span>{{ scope.row.uid }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="头像" min-width="90">
|
||||
<template #default="scope">
|
||||
<div class="tabBox_img" v-viewer>
|
||||
<img v-lazy="scope.row.avatar ? scope.row.avatar : moren" />
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="用户信息" min-width="130">
|
||||
<template #default="scope">
|
||||
<span>{{ scope.row.nickname }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="是否推广员" min-width="130">
|
||||
<template #default="scope">
|
||||
<span>{{ scope.row.promoter_name }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="推广人数" min-width="130">
|
||||
<template #default="scope">
|
||||
<span>{{ scope.row.spread_count }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="订单数" min-width="130">
|
||||
<template #default="scope">
|
||||
<span>{{ scope.row.order_count }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="绑定时间" min-width="130">
|
||||
<template #default="scope">
|
||||
<span>{{ $filters.formatDate(scope.row.spread_time) }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</template>
|
||||
<template v-else>
|
||||
<el-table-column label="订单ID" min-width="130">
|
||||
<template #default="scope">
|
||||
<span>{{ scope.row.order_id }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="用户信息" min-width="130">
|
||||
<template #default="scope">
|
||||
<span>{{ scope.row.user_info }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="时间" min-width="130">
|
||||
<template #default="scope">
|
||||
<span>{{ scope.row._add_time }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="返佣金额" min-width="130">
|
||||
<template #default="scope">
|
||||
<span>{{ scope.row.brokerage_price || 0 }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="事业部返佣金额" min-width="130" v-if="rowsList.division_type == 1">
|
||||
<template #default="scope">
|
||||
<span>{{ scope.row.division_brokerage || 0 }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="代理商返佣金额" min-width="130" v-if="rowsList.division_type == 2">
|
||||
<template #default="scope">
|
||||
<span>{{ scope.row.agent_brokerage || 0 }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="员工返佣金额" min-width="130" v-if="rowsList.division_type == 3">
|
||||
<template #default="scope">
|
||||
<span>{{ scope.row.staff_brokerage || 0 }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</template>
|
||||
</el-table>
|
||||
<div class="acea-row row-right page">
|
||||
<pagination
|
||||
v-if="total"
|
||||
:total="total"
|
||||
v-model:page="formValidate.page"
|
||||
v-model:limit="formValidate.limit"
|
||||
@pagination="pageChange"
|
||||
/>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import moren from '@/assets/images/moren.jpg';
|
||||
import { computed, ref } from 'vue';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { ElMessage } from 'element-plus';
|
||||
import { useMediaStore } from '@/store/module/media';
|
||||
import { stairListApi } from '../api';
|
||||
|
||||
defineOptions({ name: 'promotersList' });
|
||||
|
||||
const { isMobile } = storeToRefs(useMediaStore());
|
||||
const labelWidth = computed(() => (isMobile.value ? undefined : '80px'));
|
||||
const labelPosition = computed(() => (isMobile.value ? 'top' : 'right'));
|
||||
|
||||
const modals = ref(false);
|
||||
const fromList = ref({
|
||||
title: '选择时间',
|
||||
custom: true,
|
||||
fromTxt: [
|
||||
{ text: '全部', val: '' },
|
||||
{ text: '今天', val: 'today' },
|
||||
{ text: '昨天', val: 'yesterday' },
|
||||
{ text: '最近7天', val: 'lately7' },
|
||||
{ text: '最近30天', val: 'lately30' },
|
||||
{ text: '本月', val: 'month' },
|
||||
{ text: '本年', val: 'year' },
|
||||
],
|
||||
fromTxt2: [
|
||||
{ text: '全部', val: '' },
|
||||
{ text: '一级推广人', val: 1 },
|
||||
{ text: '二级推广人', val: 2 },
|
||||
],
|
||||
fromTxt3: [
|
||||
{ text: '全部', val: '' },
|
||||
{ text: '一级推广人订单', val: 1 },
|
||||
{ text: '二级推广人订单', val: 2 },
|
||||
{ text: '事业部推广订单', val: 3 },
|
||||
{ text: '代理商推广订单', val: 4 },
|
||||
],
|
||||
});
|
||||
const formValidate = ref({
|
||||
limit: 15,
|
||||
page: 1,
|
||||
nickname: '',
|
||||
data: '',
|
||||
type: '',
|
||||
order_id: '',
|
||||
uid: 0,
|
||||
});
|
||||
const loading = ref(false);
|
||||
const tabList = ref([]);
|
||||
const total = ref(0);
|
||||
const timeVal = ref([]);
|
||||
const columns4 = ref([]);
|
||||
const listTitle = ref('');
|
||||
const rowsList = ref({
|
||||
division_type: 0,
|
||||
});
|
||||
|
||||
const formValidateRef = ref(null);
|
||||
const selection = ref(null);
|
||||
|
||||
function onCancel() {
|
||||
formValidate.value = {
|
||||
limit: 15,
|
||||
page: 1,
|
||||
nickname: '',
|
||||
data: '',
|
||||
type: '',
|
||||
order_id: '',
|
||||
uid: 0,
|
||||
};
|
||||
timeVal.value = [];
|
||||
}
|
||||
// 具体日期
|
||||
function onchangeTime(e) {
|
||||
timeVal.value = e;
|
||||
formValidate.value.data = timeVal.value ? timeVal.value.join('-') : '';
|
||||
getList(rowsList.value, listTitle.value);
|
||||
}
|
||||
// 选择时间
|
||||
function selectChange(tab) {
|
||||
formValidate.value.data = tab;
|
||||
timeVal.value = [];
|
||||
getList(rowsList.value, listTitle.value);
|
||||
}
|
||||
// 列表
|
||||
function getList(row, tit) {
|
||||
listTitle.value = tit;
|
||||
rowsList.value = row;
|
||||
loading.value = true;
|
||||
let url = '';
|
||||
if (listTitle.value === 'man') {
|
||||
url = 'distribution/stair';
|
||||
} else {
|
||||
url = 'distribution/stair/order';
|
||||
}
|
||||
formValidate.value.uid = row.uid;
|
||||
stairListApi(url, formValidate.value)
|
||||
.then(async (res) => {
|
||||
let data = res.data;
|
||||
tabList.value = data.list;
|
||||
total.value = data.count;
|
||||
loading.value = false;
|
||||
})
|
||||
.catch((res) => {
|
||||
loading.value = false;
|
||||
tabList.value = [];
|
||||
ElMessage.error(res.msg);
|
||||
});
|
||||
}
|
||||
function pageChange() {
|
||||
getList(rowsList.value, listTitle.value);
|
||||
}
|
||||
// 搜索
|
||||
function userSearchs() {
|
||||
formValidate.value.page = 1;
|
||||
getList(rowsList.value, listTitle.value);
|
||||
}
|
||||
|
||||
// 页面通过 $refs.promotersLists 控制弹窗并调用 getList
|
||||
defineExpose({ modals, getList });
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
@ -1,5 +0,0 @@
|
||||
import AgentApp from './App.vue';
|
||||
import routes from './routes.js';
|
||||
|
||||
export default AgentApp;
|
||||
export { routes };
|
||||
@ -1,101 +0,0 @@
|
||||
/**
|
||||
* 分销扩展路由配置
|
||||
* 兼容模式:既是 Vue Router 路由配置(带 component 的项由 routers.js 扫描注册),
|
||||
* 也包含 section/action 元数据供扩展机制使用
|
||||
*/
|
||||
import setting from '@/setting';
|
||||
|
||||
const routePre = setting.routePre;
|
||||
const pre = 'agent_';
|
||||
|
||||
export default [
|
||||
{
|
||||
path: 'agent_manage/index',
|
||||
section: 'distribution',
|
||||
action: 'manage',
|
||||
name: `${pre}agentManage`,
|
||||
meta: {
|
||||
auth: ['agent-agent-manage'],
|
||||
title: '分销员管理',
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'spread/apply',
|
||||
section: 'distribution',
|
||||
action: 'apply',
|
||||
name: `${pre}spreadApply`,
|
||||
meta: {
|
||||
auth: ['admin-agent-spread-apply'],
|
||||
title: '分销员申请',
|
||||
},
|
||||
},
|
||||
/** 事业部 */
|
||||
{
|
||||
path: routePre + '/division',
|
||||
name: 'division',
|
||||
redirect: { name: 'division_list' },
|
||||
component: () => import('@/layout'),
|
||||
children: [
|
||||
{
|
||||
path: 'index',
|
||||
section: 'distribution',
|
||||
action: 'list',
|
||||
name: 'division_list',
|
||||
component: () => import('@/pages/system/plugin/PageContainer'),
|
||||
props: { typeKey: 'distribution', section: 'distribution', action: 'list' },
|
||||
meta: {
|
||||
auth: ['agent-division-index'],
|
||||
title: '事业部列表',
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'agent/index',
|
||||
section: 'distribution',
|
||||
action: 'agent',
|
||||
name: 'division_agent',
|
||||
component: () => import('@/pages/system/plugin/PageContainer'),
|
||||
props: { typeKey: 'distribution', section: 'distribution', action: 'agent' },
|
||||
meta: {
|
||||
auth: ['agent-division-agent-index'],
|
||||
title: '代理商列表',
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'agent/statistics',
|
||||
section: 'distribution',
|
||||
action: 'statistics',
|
||||
name: 'division_statistics',
|
||||
component: () => import('@/pages/system/plugin/PageContainer'),
|
||||
props: { typeKey: 'distribution', section: 'distribution', action: 'statistics' },
|
||||
meta: {
|
||||
auth: ['agent-division-statistics'],
|
||||
title: '事业部统计',
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'agent/applyList',
|
||||
section: 'distribution',
|
||||
action: 'applyList',
|
||||
name: 'division_applyList',
|
||||
component: () => import('@/pages/system/plugin/PageContainer'),
|
||||
props: { typeKey: 'distribution', section: 'distribution', action: 'applyList' },
|
||||
meta: {
|
||||
auth: ['agent-division-agent-applyList'],
|
||||
title: '代理商申请',
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'agent/agreement',
|
||||
section: 'distribution',
|
||||
action: 'agreement',
|
||||
name: 'division_agreement',
|
||||
component: () => import('@/pages/system/plugin/PageContainer'),
|
||||
props: { typeKey: 'distribution', section: 'distribution', action: 'agreement' },
|
||||
meta: {
|
||||
auth: ['agent-division-agent-agreement'],
|
||||
title: '代理商规则',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
@ -1,352 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-card :bordered="false" shadow="never" :body-style="{ padding: 0 }">
|
||||
<div class="padding-add">
|
||||
<el-form
|
||||
ref="formValidateRef"
|
||||
:model="formValidate"
|
||||
:label-width="labelWidth"
|
||||
:label-position="labelPosition"
|
||||
@submit.prevent
|
||||
inline
|
||||
>
|
||||
<el-form-item label="搜索:">
|
||||
<el-input
|
||||
clearable
|
||||
placeholder="请输入姓名、UID"
|
||||
v-model="formValidate.keyword"
|
||||
class="form_content_width"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" v-db-click @click="userSearchs">查询</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
</el-card>
|
||||
<el-card :bordered="false" shadow="never" class="ivu-mt mt16" :body-style="{ padding: '0 20px 20px' }">
|
||||
<el-row class="box-wrapper">
|
||||
<el-col :xs="24" :sm="24" ref="rightBox">
|
||||
<el-tabs v-model="formValidate.status" @tab-change="userSearchs">
|
||||
<el-tab-pane name="all" label="全部"></el-tab-pane>
|
||||
<el-tab-pane
|
||||
v-for="(item, index) in statusList"
|
||||
:key="index"
|
||||
:label="item.status_name"
|
||||
:name="item.id"
|
||||
></el-tab-pane>
|
||||
</el-tabs>
|
||||
<el-table
|
||||
:data="userLists"
|
||||
ref="table"
|
||||
v-loading="loading"
|
||||
highlight-current-row
|
||||
no-formValidate-text="暂无数据"
|
||||
no-filtered-formValidate-text="暂无筛选结果"
|
||||
>
|
||||
<el-table-column label="编号" width="80">
|
||||
<template #default="scope">
|
||||
<span>{{ scope.row.id }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="用户UID" width="80">
|
||||
<template #default="scope">
|
||||
<span>{{ scope.row.uid }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="用户昵称" min-width="150">
|
||||
<template #default="scope">
|
||||
<span>{{ scope.row.nickname }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="分销员电话" min-width="150">
|
||||
<template #default="scope">
|
||||
<span>{{ scope.row.phone }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="分销员姓名" min-width="150">
|
||||
<template #default="scope">
|
||||
<span>{{ scope.row.real_name }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="申请状态" min-width="150">
|
||||
<template #default="scope">
|
||||
<el-tag>{{ scope.row.status == 0 ? '申请中' : scope.row.status == 1 ? '已同意' : '已拒绝' }}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="申请时间" min-width="150">
|
||||
<template #default="scope">
|
||||
<span>{{ scope.row.add_time }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="申请理由" min-width="150">
|
||||
<template #default="scope">
|
||||
<span>{{ scope.row.content }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" fixed="right" width="170">
|
||||
<template #default="scope">
|
||||
<a v-if="scope.row.status == 0" v-db-click @click="examine(scope.row.id, scope.row.uid, 1)">同意</a>
|
||||
<el-divider v-if="scope.row.status == 0" direction="vertical" />
|
||||
<a v-if="scope.row.status == 0" v-db-click @click="examine(scope.row.id, scope.row.uid, 2)">拒绝</a>
|
||||
<el-divider direction="vertical" v-if="scope.row.status == 0" />
|
||||
<a v-db-click @click="del(scope.row, '删除申请', scope.$index)">删除</a>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<div class="acea-row row-right page">
|
||||
<pagination
|
||||
v-if="total"
|
||||
:total="total"
|
||||
v-model:page="formValidate.page"
|
||||
v-model:limit="formValidate.limit"
|
||||
@pagination="getList"
|
||||
/>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed, onMounted, ref } from 'vue';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { ElMessage, ElMessageBox } from 'element-plus';
|
||||
import { useMediaStore } from '@/store/module/media';
|
||||
import { spreadList, spreadFrom, clerkList } from '../api';
|
||||
import { modalSure } from '@/utils/public';
|
||||
|
||||
defineOptions({ name: 'agent_extra' });
|
||||
|
||||
const { isMobile } = storeToRefs(useMediaStore());
|
||||
const labelWidth = computed(() => (isMobile.value ? undefined : '50px'));
|
||||
const labelPosition = computed(() => (isMobile.value ? 'top' : 'right'));
|
||||
|
||||
const grid = {
|
||||
xl: 7,
|
||||
lg: 7,
|
||||
md: 12,
|
||||
sm: 24,
|
||||
xs: 24,
|
||||
};
|
||||
const total = ref(0);
|
||||
const total2 = ref(0);
|
||||
const userLists = ref([]);
|
||||
const formInline = ref({
|
||||
uid: 0,
|
||||
proportion: 0,
|
||||
image: '',
|
||||
});
|
||||
const statusList = ref([
|
||||
{
|
||||
status_name: '申请中',
|
||||
id: '0',
|
||||
},
|
||||
{
|
||||
status_name: '已同意',
|
||||
id: '1',
|
||||
},
|
||||
{
|
||||
status_name: '已拒绝',
|
||||
id: '2',
|
||||
},
|
||||
]);
|
||||
const FromData = ref(null);
|
||||
const loading = ref(false);
|
||||
const current = ref(0);
|
||||
const formValidate = ref({
|
||||
page: 1,
|
||||
limit: 15,
|
||||
keyword: '',
|
||||
status: 'all',
|
||||
});
|
||||
const staffModal = ref(false);
|
||||
const clerkReqData = ref({
|
||||
uid: 0,
|
||||
page: 1,
|
||||
limit: 15,
|
||||
});
|
||||
const clerkLists = ref([]);
|
||||
|
||||
const formValidateRef = ref(null);
|
||||
const table = ref(null);
|
||||
const rightBox = ref(null);
|
||||
|
||||
function userSearchs() {
|
||||
formValidate.value.page = 1;
|
||||
getList();
|
||||
}
|
||||
// 列表
|
||||
function getList() {
|
||||
loading.value = true;
|
||||
spreadList(formValidate.value)
|
||||
.then(async (res) => {
|
||||
let data = res.data;
|
||||
userLists.value = data.list;
|
||||
total.value = data.count;
|
||||
loading.value = false;
|
||||
})
|
||||
.catch((res) => {
|
||||
loading.value = false;
|
||||
ElMessage.error(res.msg);
|
||||
});
|
||||
}
|
||||
function pageChange(index) {
|
||||
formValidate.value.page = index;
|
||||
getList();
|
||||
}
|
||||
// 审核
|
||||
function examine(id, uid, type) {
|
||||
if (type == 1) {
|
||||
let data = {
|
||||
title: type == 1 ? '通过分销员申请' : '拒绝分销员申请',
|
||||
url: `distribution/spread/apply/examine/${id}/${uid}/${type}`,
|
||||
method: 'post',
|
||||
ids: '',
|
||||
};
|
||||
modalSure(data)
|
||||
.then((res) => {
|
||||
ElMessage.success(res.msg);
|
||||
getList();
|
||||
})
|
||||
.catch((res) => {
|
||||
ElMessage.error(res.msg);
|
||||
});
|
||||
} else {
|
||||
ElMessageBox.prompt('请输入拒绝理由', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
})
|
||||
.then(({ value }) => {
|
||||
let data = {
|
||||
refusal_reason: value,
|
||||
};
|
||||
spreadFrom(id, uid, type, data).then((res) => {
|
||||
ElMessage.success(res.msg);
|
||||
getList();
|
||||
});
|
||||
})
|
||||
.catch(() => {
|
||||
ElMessage({
|
||||
type: 'info',
|
||||
message: '取消输入',
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
// 编辑
|
||||
function edit(row) {}
|
||||
// 删除
|
||||
function del(row, tit, num) {
|
||||
let delfromData = {
|
||||
title: tit,
|
||||
method: 'DELETE',
|
||||
uid: row.id,
|
||||
url: `distribution/spread/apply/del/${row.id}`,
|
||||
};
|
||||
modalSure(delfromData)
|
||||
.then((res) => {
|
||||
ElMessage.success(res.msg);
|
||||
userLists.value.splice(num, 1);
|
||||
})
|
||||
.catch((res) => {
|
||||
ElMessage.error(res.msg);
|
||||
});
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
getList();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.ivu-form-item {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.picBox {
|
||||
display: inline-block;
|
||||
cursor: pointer;
|
||||
.upLoad {
|
||||
width: 58px;
|
||||
height: 58px;
|
||||
line-height: 58px;
|
||||
border: 1px dotted rgba(0, 0, 0, 0.1);
|
||||
border-radius: 4px;
|
||||
background: rgba(0, 0, 0, 0.02);
|
||||
}
|
||||
.pictrue {
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
border: 1px dotted rgba(0, 0, 0, 0.1);
|
||||
margin-right: 10px;
|
||||
|
||||
img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
:deep(.ivu-menu-vertical .ivu-menu-item-group-title) {
|
||||
display: none;
|
||||
}
|
||||
:deep(.ivu-menu-vertical.ivu-menu-light:after) {
|
||||
display: none;
|
||||
}
|
||||
.left-wrapper {
|
||||
height: 904px;
|
||||
background: #fff;
|
||||
border-right: 1px solid #f2f2f2;
|
||||
}
|
||||
.menu-item {
|
||||
z-index: 50;
|
||||
position: relative;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
word-break: break-all;
|
||||
&:hover .icon-box {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
.icon-box {
|
||||
z-index: 3;
|
||||
position: absolute;
|
||||
right: 20px;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
display: none;
|
||||
}
|
||||
|
||||
:deep(.el-tabs__item) {
|
||||
height: 54px;
|
||||
line-height: 54px;
|
||||
}
|
||||
.right-menu {
|
||||
z-index: 10;
|
||||
position: absolute;
|
||||
right: -106px;
|
||||
top: -11px;
|
||||
width: auto;
|
||||
min-width: 121px;
|
||||
}
|
||||
.tabBox_img {
|
||||
width: 36px;
|
||||
|
||||
height: 36px;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
|
||||
img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
.pictrue-box {
|
||||
display: flex;
|
||||
align-item: center;
|
||||
}
|
||||
.pictrue {
|
||||
width: 25px;
|
||||
height: 25px;
|
||||
}
|
||||
</style>
|
||||
@ -1,35 +0,0 @@
|
||||
<template>
|
||||
<div class="integral-app">
|
||||
<div class="section-content">
|
||||
<component :is="sectionComponent" :params="params" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed } from 'vue';
|
||||
import ProductList from './pages/product/index.vue';
|
||||
import ProductCreate from './pages/product/create.vue';
|
||||
import OrderList from './pages/order/index.vue';
|
||||
const actionComponents = {
|
||||
product: ProductList,
|
||||
product_create: ProductCreate,
|
||||
order: OrderList,
|
||||
};
|
||||
|
||||
defineOptions({ name: 'IntegralApp' });
|
||||
|
||||
const props = defineProps({
|
||||
section: { type: String, default: 'integral' },
|
||||
action: { type: String, default: 'product' },
|
||||
params: { type: Object, default: () => ({}) },
|
||||
});
|
||||
|
||||
const sectionComponent = computed(() => actionComponents[props.action] || ProductList);
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.integral-app {
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
@ -1,232 +0,0 @@
|
||||
/**
|
||||
* 积分商城 API
|
||||
*/
|
||||
import request from '@/libs/request';
|
||||
|
||||
/**
|
||||
* 积分商品列表
|
||||
*/
|
||||
export function integralProductListApi(params) {
|
||||
return request({
|
||||
url: 'marketing/integral_product',
|
||||
method: 'GET',
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 积分商品保存(新增/编辑)
|
||||
*/
|
||||
export function integralAddApi(data) {
|
||||
return request({
|
||||
url: `marketing/integral/${data.id}`,
|
||||
method: 'post',
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 积分商品详情
|
||||
*/
|
||||
export function integralInfoApi(id) {
|
||||
return request({
|
||||
url: `marketing/integral/${id}`,
|
||||
method: 'GET',
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 积分商品修改状态
|
||||
*/
|
||||
export function integralIsShowApi(data) {
|
||||
return request({
|
||||
url: `marketing/integral/set_show/${data.id}/${data.is_show}`,
|
||||
method: 'put',
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 积分商品删除
|
||||
*/
|
||||
export function integralDelApi(id) {
|
||||
return request({
|
||||
url: `marketing/integral/${id}`,
|
||||
method: 'DELETE',
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取商品规格
|
||||
*/
|
||||
export function productAttrsApi(id, type) {
|
||||
return request({
|
||||
url: `product/product/attrs/${id}/${type}`,
|
||||
method: 'GET',
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 积分订单列表
|
||||
*/
|
||||
export function integralOrderList(params) {
|
||||
return request({
|
||||
url: 'marketing/integral/order/list',
|
||||
method: 'get',
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 积分订单统计数据(头部tab)
|
||||
*/
|
||||
export function integralGetOrdes(data) {
|
||||
return request({
|
||||
url: 'marketing/integral/order/chart',
|
||||
method: 'get',
|
||||
params: data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 积分订单详情
|
||||
*/
|
||||
export function getIntegralOrderDataInfo(id) {
|
||||
return request({
|
||||
url: `marketing/integral/order/info/${id}`,
|
||||
method: 'get',
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 积分订单物流
|
||||
*/
|
||||
export function getExpress(id) {
|
||||
return request({
|
||||
url: `marketing/integral/order/express/${id}`,
|
||||
method: 'get',
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取快递公司
|
||||
*/
|
||||
export function getExpressData(status) {
|
||||
return request({
|
||||
url: `marketing/integral/order/express_list?status=` + status,
|
||||
method: 'get',
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 积分订单配送信息表单
|
||||
*/
|
||||
export function getIntegralOrderDistribution(id) {
|
||||
return request({
|
||||
url: `marketing/integral/order/distribution/${id}`,
|
||||
method: 'get',
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 积分订单发货
|
||||
*/
|
||||
export function integralOrderPutDelivery(data) {
|
||||
return request({
|
||||
url: `marketing/integral/order/delivery/${data.id}`,
|
||||
method: 'put',
|
||||
data: data.datas,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 积分订单修改配送信息
|
||||
*/
|
||||
export function integralOrderPutDistribution(data) {
|
||||
return request({
|
||||
url: `marketing/integral/order/distribution/${data.id}`,
|
||||
method: 'put',
|
||||
data: data.datas,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 积分订单备注
|
||||
*/
|
||||
export function integralOrderPutRemarkData(data) {
|
||||
return request({
|
||||
url: `marketing/integral/order/remark/${data.id}`,
|
||||
method: 'put',
|
||||
data: { remark: data.remark },
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 积分订单状态记录
|
||||
*/
|
||||
export function getIntegralOrderRecord(data) {
|
||||
return request({
|
||||
url: `marketing/integral/order/status/${data.id}`,
|
||||
method: 'get',
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取配送员列表
|
||||
*/
|
||||
export function orderDeliveryList() {
|
||||
return request({
|
||||
url: 'marketing/integral/order/delivery/list',
|
||||
method: 'get',
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 电子面单模板
|
||||
*/
|
||||
export function orderExpressTemp(data) {
|
||||
return request({
|
||||
url: 'marketing/integral/order/express/temp',
|
||||
method: 'get',
|
||||
params: data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 积分面单配置
|
||||
*/
|
||||
export function orderSheetInfo() {
|
||||
return request({
|
||||
url: 'marketing/integral/order/sheet_info',
|
||||
method: 'get',
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 积分订单确认收货
|
||||
*/
|
||||
export function integralOrderTake(id) {
|
||||
return request({
|
||||
url: `marketing/integral/order/take/${id}`,
|
||||
method: 'put',
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 积分订单删除
|
||||
*/
|
||||
export function integralOrderDel(id) {
|
||||
return request({
|
||||
url: `marketing/integral/order/del/${id}`,
|
||||
method: 'DELETE',
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 积分订单打印
|
||||
*/
|
||||
export function integralOrderPrint(id) {
|
||||
return request({
|
||||
url: `marketing/integral/order/print/${id}`,
|
||||
method: 'post',
|
||||
});
|
||||
}
|
||||
@ -1,9 +0,0 @@
|
||||
{
|
||||
"key": "integral",
|
||||
"title": "积分商城",
|
||||
"version": "1.0.0",
|
||||
"pages": [
|
||||
{ "path": "product", "title": "积分商品管理" },
|
||||
{ "path": "order", "title": "积分订单管理" }
|
||||
]
|
||||
}
|
||||
@ -1,5 +0,0 @@
|
||||
import IntegralApp from './App.vue';
|
||||
import routes from './routes.js';
|
||||
|
||||
export default IntegralApp;
|
||||
export { routes };
|
||||
@ -1,363 +0,0 @@
|
||||
<template>
|
||||
<div v-loading="spinShow">
|
||||
<el-card :bordered="false" shadow="never" :body-style="{ padding: 0 }">
|
||||
<div class="padding-add">
|
||||
<el-form :model="orderData" :label-width="labelWidth" label-position="right" @submit.prevent inline>
|
||||
<el-form-item label="订单搜索:">
|
||||
<el-input
|
||||
placeholder="请输入订单号/用户昵称/UID"
|
||||
v-model="orderData.real_name"
|
||||
clearable
|
||||
style="width: 350px"
|
||||
>
|
||||
<template #prepend
|
||||
><el-select placeholder="请选择" clearable v-model="orderData.field_key" style="width: 100px">
|
||||
<el-option value="all" label="全部"></el-option>
|
||||
<el-option value="order_id" label="订单号"></el-option>
|
||||
<el-option value="real_name" label="用户昵称"></el-option>
|
||||
<el-option value="uid" label="UID"></el-option> </el-select
|
||||
></template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="订单状态:">
|
||||
<el-select
|
||||
placeholder="请选择"
|
||||
clearable
|
||||
v-model="orderData.status"
|
||||
@change="getList"
|
||||
class="form_content_width"
|
||||
>
|
||||
<el-option :value="item.status" :label="item.name" v-for="(item, i) in statusList" :key="i"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="下单时间:">
|
||||
<date-range-picker
|
||||
clearable
|
||||
v-model="timeVal"
|
||||
:editable="false"
|
||||
@change="onchangeTime"
|
||||
format="YYYY/MM/DD"
|
||||
value-format="YYYY/MM/DD"
|
||||
></date-range-picker>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" v-db-click @click="getList">查询</el-button>
|
||||
<el-button v-db-click @click="reset">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
</el-card>
|
||||
<!-- tabs -->
|
||||
<el-card :bordered="false" shadow="never" class="ivu-mt mt16">
|
||||
<el-tag
|
||||
class="mr10 mb10"
|
||||
v-for="(item, i) in tablists"
|
||||
:key="i"
|
||||
:type="orderData.type === item.status ? '' : 'info'"
|
||||
@click="onClickTab(item)"
|
||||
style="cursor: pointer"
|
||||
>
|
||||
{{ item.name }} ({{ item.count }})
|
||||
</el-tag>
|
||||
</el-card>
|
||||
<!-- 订单列表 -->
|
||||
<el-card :bordered="false" shadow="never" class="ivu-mt mt16">
|
||||
<el-table :data="orderList" v-loading="loading" highlight-current-row class="mt14">
|
||||
<el-table-column label="订单号" min-width="150">
|
||||
<template #default="scope">
|
||||
<span>{{ scope.row.order_id }}</span>
|
||||
<span v-if="scope.row.is_del == 1" style="color: #ed4014; display: block">用户已删除</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="用户信息" min-width="100">
|
||||
<template #default="scope"> {{ scope.row.nickname }}/{{ scope.row.uid }} </template>
|
||||
</el-table-column>
|
||||
<el-table-column label="商品信息" min-width="300">
|
||||
<template #default="scope">
|
||||
<div class="tabBox">
|
||||
<div class="tabBox_img" v-viewer>
|
||||
<img v-lazy="scope.row.image" />
|
||||
</div>
|
||||
<span class="tabBox_tit">{{ scope.row.store_name + ' | ' }}{{ scope.row.suk || '' }}</span>
|
||||
<span class="tabBox_pice">{{ '积分' + scope.row.total_price + ' x ' + scope.row.total_num }}</span>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="兑换积分" min-width="80">
|
||||
<template #default="scope">
|
||||
<span>{{ scope.row.total_price }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="订单状态" min-width="80">
|
||||
<template #default="scope">
|
||||
<span>{{ scope.row.status_name }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="下单时间" min-width="100">
|
||||
<template #default="scope">
|
||||
<span>{{ scope.row.add_time }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" fixed="right" width="160">
|
||||
<template #default="scope">
|
||||
<a v-db-click @click="openSend(scope.row)" v-if="scope.row.status === 1">发送货</a>
|
||||
<a v-db-click @click="openDistribution(scope.row)" v-if="scope.row.status === 2">配送信息</a>
|
||||
<el-divider direction="vertical" v-if="scope.row.status === 1 || scope.row.status === 2" />
|
||||
<el-dropdown @command="changeMenu(scope.row, $event)" :transfer="true">
|
||||
<span class="el-dropdown-link">更多<i class="el-icon-arrow-down el-icon--right"></i></span>
|
||||
<template #dropdown
|
||||
><el-dropdown-menu>
|
||||
<el-dropdown-item command="detail">订单详情</el-dropdown-item>
|
||||
<el-dropdown-item command="record">订单记录</el-dropdown-item>
|
||||
<el-dropdown-item command="remark" v-show="scope.row.status !== 4">订单备注</el-dropdown-item>
|
||||
<el-dropdown-item command="take" v-show="scope.row.status === 2">已收货</el-dropdown-item>
|
||||
<el-dropdown-item command="del" v-show="scope.row.is_del === 1">删除订单</el-dropdown-item>
|
||||
</el-dropdown-menu></template
|
||||
>
|
||||
</el-dropdown>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<div class="acea-row row-right page">
|
||||
<pagination
|
||||
v-if="total"
|
||||
:total="total"
|
||||
v-model:page="page.pageNum"
|
||||
v-model:limit="page.pageSize"
|
||||
@pagination="getList"
|
||||
/>
|
||||
</div>
|
||||
</el-card>
|
||||
<!-- 弹窗组件 -->
|
||||
<order-details ref="detailsRef" :orderDatalist="orderDatalist" :orderId="orderId"></order-details>
|
||||
<order-remark ref="remarkRef" :orderId="orderId" @submitFail="submitFail"></order-remark>
|
||||
<order-record ref="recordRef" :orderId="orderId"></order-record>
|
||||
<order-send ref="sendRef" :orderId="orderId" @submitFail="submitFail"></order-send>
|
||||
<!-- 配送信息编辑表单 -->
|
||||
<edit-from ref="edits" :FromData="FromData" @submitFail="submitFail"></edit-from>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed, onActivated, onMounted, ref } from 'vue';
|
||||
import { useRoute } from 'vue-router';
|
||||
import { ElMessage } from 'element-plus';
|
||||
import { integralOrderList, integralGetOrdes, getIntegralOrderDataInfo, getIntegralOrderDistribution } from '../../api';
|
||||
import orderDetails from './orderDetails.vue';
|
||||
import orderRemark from './orderRemark.vue';
|
||||
import orderRecord from './orderRecord.vue';
|
||||
import orderSend from './orderSend.vue';
|
||||
import editFrom from '@/components/from/from';
|
||||
import { modalSure } from '@/utils/public';
|
||||
import { useMediaStore } from '@/store/module/media';
|
||||
|
||||
defineOptions({ name: 'integralOrderList' });
|
||||
|
||||
const route = useRoute();
|
||||
const mediaStore = useMediaStore();
|
||||
|
||||
const detailsRef = ref(null);
|
||||
const remarkRef = ref(null);
|
||||
const recordRef = ref(null);
|
||||
const sendRef = ref(null);
|
||||
const edits = ref(null);
|
||||
|
||||
const isMobile = computed(() => mediaStore.isMobile);
|
||||
const labelWidth = computed(() => (isMobile.value ? undefined : '80px'));
|
||||
const labelPosition = computed(() => (isMobile.value ? 'top' : 'right'));
|
||||
|
||||
const spinShow = ref(false);
|
||||
const loading = ref(false);
|
||||
const orderList = ref([]);
|
||||
const tablists = ref([]);
|
||||
const statusList = ref([
|
||||
{ status: '', name: '全部' },
|
||||
{ status: 1, name: '未发货' },
|
||||
{ status: 2, name: '待收货' },
|
||||
{ status: 3, name: '已完成' },
|
||||
]);
|
||||
const orderData = ref({
|
||||
status: '',
|
||||
data: '',
|
||||
real_name: '',
|
||||
field_key: 'all',
|
||||
product_id: '',
|
||||
type: '',
|
||||
});
|
||||
const timeVal = ref([]);
|
||||
const orderId = ref(0);
|
||||
const orderDatalist = ref(null);
|
||||
const FromData = ref(null);
|
||||
const total = ref(0);
|
||||
const page = ref({
|
||||
pageNum: 1,
|
||||
pageSize: 15,
|
||||
});
|
||||
|
||||
onMounted(() => {
|
||||
getTabs();
|
||||
getList();
|
||||
});
|
||||
|
||||
onActivated(() => {
|
||||
getList();
|
||||
});
|
||||
|
||||
function getTabs() {
|
||||
spinShow.value = true;
|
||||
integralGetOrdes({
|
||||
data: orderData.value.data,
|
||||
product_id: route.query.product_id || '',
|
||||
})
|
||||
.then((res) => {
|
||||
tablists.value = res.data;
|
||||
spinShow.value = false;
|
||||
})
|
||||
.catch((res) => {
|
||||
spinShow.value = false;
|
||||
ElMessage.error(res.msg);
|
||||
});
|
||||
}
|
||||
function onClickTab(item) {
|
||||
orderData.value.type = item.status;
|
||||
page.value.pageNum = 1;
|
||||
getList();
|
||||
}
|
||||
function getList() {
|
||||
loading.value = true;
|
||||
orderData.value.product_id = route.query.product_id || '';
|
||||
integralOrderList({
|
||||
page: page.value.pageNum,
|
||||
limit: page.value.pageSize,
|
||||
status: orderData.value.status,
|
||||
data: orderData.value.data,
|
||||
real_name: orderData.value.real_name,
|
||||
field_key: orderData.value.field_key,
|
||||
type: orderData.value.type === 0 ? '' : orderData.value.type,
|
||||
product_id: orderData.value.product_id,
|
||||
})
|
||||
.then(async (res) => {
|
||||
let data = res.data;
|
||||
orderList.value = data.data;
|
||||
total.value = data.count;
|
||||
loading.value = false;
|
||||
})
|
||||
.catch((res) => {
|
||||
loading.value = false;
|
||||
ElMessage.error(res.msg);
|
||||
});
|
||||
}
|
||||
function onchangeTime(e) {
|
||||
timeVal.value = e;
|
||||
orderData.value.data = timeVal.value ? timeVal.value.join('-') : '';
|
||||
getList();
|
||||
}
|
||||
function openSend(row) {
|
||||
orderId.value = row.id;
|
||||
sendRef.value.modals = true;
|
||||
sendRef.value.getList(1);
|
||||
sendRef.value.getDeliveryList();
|
||||
}
|
||||
function openDistribution(row) {
|
||||
getIntegralOrderDistribution(row.id)
|
||||
.then(async (res) => {
|
||||
FromData.value = res.data;
|
||||
edits.value.modals = true;
|
||||
})
|
||||
.catch((res) => {
|
||||
ElMessage.error(res.msg);
|
||||
});
|
||||
}
|
||||
function changeMenu(row, name) {
|
||||
orderId.value = row.id;
|
||||
switch (name) {
|
||||
case 'detail':
|
||||
getIntegralOrderDataInfo(row.id)
|
||||
.then(async (res) => {
|
||||
orderDatalist.value = res.data;
|
||||
detailsRef.value.modals = true;
|
||||
})
|
||||
.catch((res) => {
|
||||
ElMessage.error(res.msg);
|
||||
});
|
||||
break;
|
||||
case 'record':
|
||||
recordRef.value.modals = true;
|
||||
recordRef.value.getList(row.id);
|
||||
break;
|
||||
case 'remark':
|
||||
remarkRef.value.modals = true;
|
||||
remarkRef.value.formValidate.remark = row.remark;
|
||||
break;
|
||||
case 'take':
|
||||
modalSure({
|
||||
title: '修改确认收货',
|
||||
url: `marketing/integral/order/take/${row.id}`,
|
||||
method: 'put',
|
||||
ids: '',
|
||||
})
|
||||
.then((res) => {
|
||||
ElMessage.success(res.msg);
|
||||
getList();
|
||||
})
|
||||
.catch((res) => {
|
||||
ElMessage.error(res.msg);
|
||||
});
|
||||
break;
|
||||
case 'del':
|
||||
modalSure({
|
||||
title: '删除订单',
|
||||
url: `marketing/integral/order/del/${row.id}`,
|
||||
method: 'DELETE',
|
||||
ids: '',
|
||||
})
|
||||
.then((res) => {
|
||||
ElMessage.success(res.msg);
|
||||
getList();
|
||||
})
|
||||
.catch((res) => {
|
||||
ElMessage.error(res.msg);
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
function reset() {
|
||||
orderData.value = {
|
||||
status: '',
|
||||
data: '',
|
||||
real_name: '',
|
||||
field_key: 'all',
|
||||
product_id: route.query.product_id || '',
|
||||
type: '',
|
||||
};
|
||||
timeVal.value = [];
|
||||
page.value.pageNum = 1;
|
||||
getList();
|
||||
getTabs();
|
||||
}
|
||||
function submitFail() {
|
||||
getList();
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.tabBox {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
.tabBox_img {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
.tabBox_tit {
|
||||
width: 60%;
|
||||
font-size: 12px;
|
||||
margin: 0 2px 0 10px;
|
||||
letter-spacing: 1px;
|
||||
padding: 5px 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@ -1,51 +0,0 @@
|
||||
<template>
|
||||
<el-dialog v-model="modals" title="订单详情" width="680px" class="order_box" :show-close="true">
|
||||
<el-row v-if="orderDatalist">
|
||||
<el-col :span="24">
|
||||
<el-card :bordered="false" shadow="never" class="ivu-mt">
|
||||
<template #header
|
||||
><div><span>用户信息</span></div></template
|
||||
>
|
||||
<el-row>
|
||||
<el-col :span="12">用户昵称:{{ orderDatalist.userInfo.nickname }}</el-col>
|
||||
<el-col :span="12">用户电话:{{ orderDatalist.userInfo.phone }}</el-col>
|
||||
</el-row>
|
||||
</el-card>
|
||||
</el-col>
|
||||
<el-col :span="24">
|
||||
<el-card :bordered="false" shadow="never" class="ivu-mt">
|
||||
<template #header
|
||||
><div><span>订单信息</span></div></template
|
||||
>
|
||||
<el-row>
|
||||
<el-col :span="12">订单号:{{ orderDatalist.orderInfo.order_id }}</el-col>
|
||||
<el-col :span="12">下单时间:{{ orderDatalist.orderInfo.add_time }}</el-col>
|
||||
<el-col :span="12">商品名称:{{ orderDatalist.orderInfo.store_name }}</el-col>
|
||||
<el-col :span="12">商品规格:{{ orderDatalist.orderInfo.suk }}</el-col>
|
||||
<el-col :span="12">兑换积分:{{ orderDatalist.orderInfo.total_price }}</el-col>
|
||||
<el-col :span="12">订单状态:{{ orderDatalist.orderInfo.status_name }}</el-col>
|
||||
</el-row>
|
||||
<el-row v-if="orderDatalist.orderInfo.user_address">
|
||||
<el-col :span="24">收货地址:{{ orderDatalist.orderInfo.user_address }}</el-col>
|
||||
</el-row>
|
||||
</el-card>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<template #footer><span></span></template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue';
|
||||
|
||||
defineOptions({ name: 'integralOrderDetails' });
|
||||
|
||||
defineProps({
|
||||
orderDatalist: Object,
|
||||
orderId: Number,
|
||||
});
|
||||
|
||||
const modals = ref(false);
|
||||
|
||||
defineExpose({ modals });
|
||||
</script>
|
||||
@ -1,53 +0,0 @@
|
||||
<template>
|
||||
<el-dialog v-model="modals" title="订单记录" width="680px" class="order_box" :show-close="true">
|
||||
<el-table :data="recordList" v-loading="loading" empty-text="暂无数据">
|
||||
<el-table-column label="操作时间" min-width="160">
|
||||
<template #default="scope">
|
||||
<span>{{ scope.row.change_time }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作类型" min-width="100">
|
||||
<template #default="scope">
|
||||
<span>{{ scope.row.change_type }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作描述" min-width="200">
|
||||
<template #default="scope">
|
||||
<span>{{ scope.row.change_message }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<template #footer><span></span></template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue';
|
||||
import { ElMessage } from 'element-plus';
|
||||
import { getIntegralOrderRecord } from '../../api';
|
||||
|
||||
defineOptions({ name: 'integralOrderRecord' });
|
||||
|
||||
defineProps({
|
||||
orderId: Number,
|
||||
});
|
||||
|
||||
const modals = ref(false);
|
||||
const loading = ref(false);
|
||||
const recordList = ref([]);
|
||||
|
||||
function getList(id) {
|
||||
loading.value = true;
|
||||
getIntegralOrderRecord({ id })
|
||||
.then(async (res) => {
|
||||
recordList.value = res.data;
|
||||
loading.value = false;
|
||||
})
|
||||
.catch((res) => {
|
||||
loading.value = false;
|
||||
ElMessage.error(res.msg);
|
||||
});
|
||||
}
|
||||
|
||||
defineExpose({ modals, getList });
|
||||
</script>
|
||||
@ -1,52 +0,0 @@
|
||||
<template>
|
||||
<el-dialog v-model="modals" title="订单备注" width="500px" class="order_box" :show-close="true">
|
||||
<el-form ref="formValidate" :model="formValidate" label-width="80px">
|
||||
<el-form-item label="备注内容:">
|
||||
<el-input v-model="formValidate.remark" type="textarea" :rows="4" placeholder="请输入备注内容"></el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer
|
||||
><span class="dialog-footer">
|
||||
<el-button v-db-click @click="modals = false">取消</el-button>
|
||||
<el-button type="primary" v-db-click @click="submit">确定</el-button>
|
||||
</span></template
|
||||
>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue';
|
||||
import { ElMessage } from 'element-plus';
|
||||
import { integralOrderPutRemarkData } from '../../api';
|
||||
|
||||
defineOptions({ name: 'integralOrderRemark' });
|
||||
|
||||
const props = defineProps({
|
||||
orderId: [Number, String],
|
||||
});
|
||||
|
||||
const emit = defineEmits(['submitFail']);
|
||||
|
||||
const modals = ref(false);
|
||||
const formValidate = ref({
|
||||
remark: '',
|
||||
});
|
||||
|
||||
function submit() {
|
||||
let data = {
|
||||
id: props.orderId,
|
||||
remark: formValidate.value.remark,
|
||||
};
|
||||
integralOrderPutRemarkData(data)
|
||||
.then(async (res) => {
|
||||
ElMessage.success(res.msg);
|
||||
modals.value = false;
|
||||
emit('submitFail');
|
||||
})
|
||||
.catch((res) => {
|
||||
ElMessage.error(res.msg);
|
||||
});
|
||||
}
|
||||
|
||||
defineExpose({ modals, formValidate });
|
||||
</script>
|
||||
@ -1,268 +0,0 @@
|
||||
<template>
|
||||
<el-dialog v-model="modals" title="订单发送货" width="720px" class="order_box" :show-close="true">
|
||||
<el-form ref="formItemRef" :model="formItem" label-width="100px" @submit.prevent>
|
||||
<el-form-item label="选择类型:">
|
||||
<el-radio-group v-model="formItem.type" @input="changeRadio">
|
||||
<el-radio label="1" value="1">发货</el-radio>
|
||||
<el-radio label="2" value="2">送货</el-radio>
|
||||
<el-radio label="3" value="3">虚拟</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item v-show="formItem.type == '1' && export_open" label="发货类型:">
|
||||
<el-radio-group v-model="formItem.express_record_type" @input="changeExpress">
|
||||
<el-radio label="1" value="1">手动填写</el-radio>
|
||||
<el-radio label="2" value="2">电子面单打印</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<div v-show="formItem.type === '1'">
|
||||
<el-form-item label="快递公司:">
|
||||
<el-select
|
||||
v-model="formItem.delivery_name"
|
||||
filterable
|
||||
placeholder="请选择快递公司"
|
||||
style="width: 80%"
|
||||
@change="expressChange"
|
||||
>
|
||||
<el-option
|
||||
v-for="(item, i) in express"
|
||||
:value="item.value"
|
||||
:key="item.value"
|
||||
:label="item.value"
|
||||
></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item v-if="formItem.express_record_type === '1'" label="快递单号:">
|
||||
<el-input v-model="formItem.delivery_id" placeholder="请输入快递单号" style="width: 80%"></el-input>
|
||||
</el-form-item>
|
||||
<template v-if="formItem.express_record_type === '2'">
|
||||
<el-form-item label="电子面单:" class="express_temp_id">
|
||||
<el-select v-model="formItem.express_temp_id" placeholder="请选择电子面单" style="width: 80%">
|
||||
<el-option
|
||||
v-for="(item, i) in expressTemp"
|
||||
:value="item.temp_id"
|
||||
:key="i"
|
||||
:label="item.title"
|
||||
></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="寄件人姓名:">
|
||||
<el-input v-model="formItem.to_name" placeholder="请输入寄件人姓名" style="width: 80%"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="寄件人电话:">
|
||||
<el-input v-model="formItem.to_tel" placeholder="请输入寄件人电话" style="width: 80%"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="寄件人地址:">
|
||||
<el-input v-model="formItem.to_addr" placeholder="请输入寄件人地址" style="width: 80%"></el-input>
|
||||
</el-form-item>
|
||||
</template>
|
||||
</div>
|
||||
<div v-show="formItem.type === '2'">
|
||||
<el-form-item label="送货人:">
|
||||
<el-select
|
||||
v-model="formItem.sh_delivery"
|
||||
placeholder="请选择送货人"
|
||||
style="width: 80%"
|
||||
@change="shDeliveryChange"
|
||||
>
|
||||
<el-option
|
||||
v-for="(item, i) in deliveryList"
|
||||
:value="item.id"
|
||||
:key="i"
|
||||
:label="`${item.wx_name} (${item.phone})`"
|
||||
></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</div>
|
||||
<div v-show="formItem.type === '3'">
|
||||
<el-form-item label="备注:">
|
||||
<el-input
|
||||
v-model="formItem.fictitious_content"
|
||||
type="textarea"
|
||||
:autosize="{ minRows: 2, maxRows: 5 }"
|
||||
placeholder="备注"
|
||||
style="width: 80%"
|
||||
></el-input>
|
||||
</el-form-item>
|
||||
</div>
|
||||
</el-form>
|
||||
<template #footer
|
||||
><span class="dialog-footer">
|
||||
<el-button v-db-click @click="cancel">取消</el-button>
|
||||
<el-button type="primary" v-db-click @click="putSend">提交</el-button>
|
||||
</span></template
|
||||
>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue';
|
||||
import { ElMessage } from 'element-plus';
|
||||
import {
|
||||
getExpressData,
|
||||
orderExpressTemp,
|
||||
orderDeliveryList,
|
||||
orderSheetInfo,
|
||||
integralOrderPutDelivery,
|
||||
} from '../../api';
|
||||
|
||||
defineOptions({ name: 'integralOrderSend' });
|
||||
|
||||
const props = defineProps({
|
||||
orderId: Number,
|
||||
});
|
||||
|
||||
const emit = defineEmits(['submitFail']);
|
||||
|
||||
const formItemRef = ref(null);
|
||||
const formItem = ref({
|
||||
type: '1',
|
||||
express_record_type: '1',
|
||||
delivery_name: '',
|
||||
delivery_id: '',
|
||||
express_temp_id: '',
|
||||
to_name: '',
|
||||
to_tel: '',
|
||||
to_addr: '',
|
||||
sh_delivery: '',
|
||||
sh_delivery_name: '',
|
||||
sh_delivery_id: '',
|
||||
sh_delivery_uid: '',
|
||||
fictitious_content: '',
|
||||
});
|
||||
const modals = ref(false);
|
||||
const express = ref([]);
|
||||
const expressTemp = ref([]);
|
||||
const deliveryList = ref([]);
|
||||
const export_open = ref(false);
|
||||
|
||||
function changeRadio(o) {
|
||||
formItemRef.value.resetFields();
|
||||
formItem.value.type = o;
|
||||
if (o === '1') {
|
||||
getList(1);
|
||||
}
|
||||
}
|
||||
function changeExpress(j) {
|
||||
if (j === '2') {
|
||||
formItem.value.delivery_name = '';
|
||||
formItem.value.express_temp_id = '';
|
||||
expressTemp.value = [];
|
||||
getList(2);
|
||||
} else {
|
||||
getList(1);
|
||||
}
|
||||
}
|
||||
function reset() {
|
||||
formItem.value = {
|
||||
type: '1',
|
||||
express_record_type: '1',
|
||||
delivery_name: '',
|
||||
delivery_id: '',
|
||||
express_temp_id: '',
|
||||
to_name: '',
|
||||
to_tel: '',
|
||||
to_addr: '',
|
||||
sh_delivery: '',
|
||||
sh_delivery_name: '',
|
||||
sh_delivery_id: '',
|
||||
sh_delivery_uid: '',
|
||||
fictitious_content: '',
|
||||
};
|
||||
}
|
||||
function getList(type) {
|
||||
let status = type === 2 ? 1 : '';
|
||||
getExpressData(status)
|
||||
.then(async (res) => {
|
||||
express.value = res.data;
|
||||
getSheetInfo();
|
||||
})
|
||||
.catch((res) => {
|
||||
ElMessage.error(res.msg);
|
||||
});
|
||||
}
|
||||
function putSend() {
|
||||
let data = { id: props.orderId, datas: formItem.value };
|
||||
if (formItem.value.type === '1' && formItem.value.express_record_type === '1') {
|
||||
if (!formItem.value.delivery_name) return ElMessage.error('快递公司不能为空');
|
||||
if (!formItem.value.delivery_id) return ElMessage.error('快递单号不能为空');
|
||||
}
|
||||
if (formItem.value.type === '2' && !formItem.value.sh_delivery) {
|
||||
return ElMessage.error('送货人不能为空');
|
||||
}
|
||||
integralOrderPutDelivery(data)
|
||||
.then(async (res) => {
|
||||
emit('submitFail');
|
||||
modals.value = false;
|
||||
ElMessage.success(res.msg);
|
||||
reset();
|
||||
})
|
||||
.catch((res) => {
|
||||
ElMessage.error(res.msg);
|
||||
});
|
||||
}
|
||||
function cancel() {
|
||||
modals.value = false;
|
||||
reset();
|
||||
}
|
||||
function expressChange(value) {
|
||||
let expressItem = express.value.find((item) => item.value === value);
|
||||
if (!expressItem) return;
|
||||
formItem.value.delivery_code = expressItem.code;
|
||||
if (formItem.value.express_record_type === '2') {
|
||||
expressTemp.value = [];
|
||||
formItem.value.express_temp_id = '';
|
||||
orderExpressTemp({ com: formItem.value.delivery_code })
|
||||
.then((res) => {
|
||||
expressTemp.value = res.data;
|
||||
if (!res.data.length) {
|
||||
ElMessage.error('请配置所选快递公司的电子面单');
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
ElMessage.error(err.msg);
|
||||
});
|
||||
}
|
||||
}
|
||||
function getDeliveryList() {
|
||||
orderDeliveryList()
|
||||
.then((res) => {
|
||||
deliveryList.value = res.data.list;
|
||||
})
|
||||
.catch((err) => {
|
||||
ElMessage.error(err.msg);
|
||||
});
|
||||
}
|
||||
function getSheetInfo() {
|
||||
orderSheetInfo()
|
||||
.then((res) => {
|
||||
const data = res.data;
|
||||
for (const key in data) {
|
||||
if (data.hasOwnProperty(key)) {
|
||||
formItem.value[key] = data[key];
|
||||
}
|
||||
}
|
||||
export_open.value = data.export_open === undefined ? true : data.export_open;
|
||||
if (!export_open.value) formItem.value.express_record_type = '1';
|
||||
formItem.value.to_addr = data.to_add;
|
||||
})
|
||||
.catch((err) => {
|
||||
ElMessage.error(err.msg);
|
||||
});
|
||||
}
|
||||
function shDeliveryChange(value) {
|
||||
let deliveryItem = deliveryList.value.find((item) => item.id === value);
|
||||
if (deliveryItem) {
|
||||
formItem.value.sh_delivery_name = deliveryItem.wx_name;
|
||||
formItem.value.sh_delivery_id = deliveryItem.phone;
|
||||
formItem.value.sh_delivery_uid = deliveryItem.uid;
|
||||
}
|
||||
}
|
||||
|
||||
defineExpose({ modals, getList, getDeliveryList });
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.express_temp_id {
|
||||
position: relative;
|
||||
}
|
||||
</style>
|
||||
@ -1,616 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
<pages-header
|
||||
:title="$route.params.id ? '编辑积分商品' : '添加积分商品'"
|
||||
:backUrl="$routeProStr + '/marketing/integral/product'"
|
||||
></pages-header>
|
||||
<el-card :bordered="false" shadow="never" class="mt16">
|
||||
<el-row class="mt30 acea-row row-middle row-center" v-loading="spinShow">
|
||||
<el-col :span="20">
|
||||
<steps :stepList="stepList" :isActive="current"></steps>
|
||||
</el-col>
|
||||
<el-col :span="23">
|
||||
<el-form
|
||||
class="form mt30"
|
||||
ref="formValidateRef"
|
||||
:model="formValidate"
|
||||
:rules="ruleValidate"
|
||||
:label-width="labelWidth"
|
||||
:label-position="labelPosition"
|
||||
@submit.prevent
|
||||
>
|
||||
<!-- 第一步:选择商品 -->
|
||||
<el-form-item label="选择商品:" prop="image_input" v-if="current === 0">
|
||||
<div class="picBox" v-db-click @click="changeGoods">
|
||||
<div class="pictrue" v-if="formValidate.image">
|
||||
<img v-lazy="formValidate.image" />
|
||||
</div>
|
||||
<div class="upLoad acea-row row-center-wrapper" v-else>
|
||||
<i class="el-icon-goods" style="font-size: 24px"></i>
|
||||
</div>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<!-- 第二步:基础信息 -->
|
||||
<el-col v-show="current === 1">
|
||||
<el-col :span="24">
|
||||
<el-form-item prop="image">
|
||||
<template #label
|
||||
><div class="custom-label">
|
||||
<div>
|
||||
<div>商品主图</div>
|
||||
<div>(750*750)</div>
|
||||
</div>
|
||||
<div>:</div>
|
||||
</div></template
|
||||
>
|
||||
<div class="picBox" v-db-click @click="modalPicTap('dan', 'danFrom')">
|
||||
<div class="pictrue" v-if="formValidate.image">
|
||||
<img v-lazy="formValidate.image" />
|
||||
</div>
|
||||
<div class="upLoad acea-row row-center-wrapper" v-else>
|
||||
<i class="el-icon-picture-outline" style="font-size: 24px"></i>
|
||||
</div>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24">
|
||||
<el-form-item prop="images">
|
||||
<template #label
|
||||
><div class="custom-label">
|
||||
<div>
|
||||
<div>商品轮播图</div>
|
||||
<div>(750*750)</div>
|
||||
</div>
|
||||
<div>:</div>
|
||||
</div></template
|
||||
>
|
||||
<div class="acea-row">
|
||||
<div
|
||||
class="pictrue"
|
||||
v-for="(item, index) in formValidate.images"
|
||||
:key="index"
|
||||
draggable="true"
|
||||
@dragstart="handleDragStart($event, item)"
|
||||
@dragover.prevent="handleDragOver($event, item)"
|
||||
@dragenter="handleDragEnter($event, item)"
|
||||
@dragend="handleDragEnd($event, item)"
|
||||
>
|
||||
<img v-lazy="item" />
|
||||
<i class="el-icon-circle-close btndel" v-db-click @click="handleRemove(index)"></i>
|
||||
</div>
|
||||
<div
|
||||
v-if="formValidate.images.length < 10"
|
||||
class="upLoad acea-row row-center-wrapper"
|
||||
v-db-click
|
||||
@click="modalPicTap('duo')"
|
||||
>
|
||||
<i class="el-icon-picture-outline" style="font-size: 24px"></i>
|
||||
</div>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24">
|
||||
<el-col v-bind="grid">
|
||||
<el-form-item label="商品标题:" prop="title" label-for="title">
|
||||
<el-input
|
||||
placeholder="请输入商品标题"
|
||||
v-model="formValidate.title"
|
||||
class="content_width"
|
||||
maxlength="80"
|
||||
show-word-limit
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-col>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="用户兑换数量限制:" prop="num">
|
||||
<div class="acea-row row-middle">
|
||||
<el-input-number
|
||||
:controls="false"
|
||||
:min="1"
|
||||
:max="9999999999"
|
||||
placeholder="请输入数量限制"
|
||||
element-id="num"
|
||||
:precision="0"
|
||||
v-model="formValidate.num"
|
||||
class="content_width"
|
||||
/>
|
||||
<div class="ml10 grey">每个用户可购买该商品总数限制</div>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="单位:" prop="unit_name" label-for="unit_name">
|
||||
<el-input
|
||||
placeholder="请输入单位"
|
||||
element-id="unit_name"
|
||||
v-model="formValidate.unit_name"
|
||||
class="content_width"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="排序:">
|
||||
<el-input-number
|
||||
:controls="false"
|
||||
placeholder="请输入排序"
|
||||
element-id="sort"
|
||||
:precision="0"
|
||||
v-model="formValidate.sort"
|
||||
class="content_width"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="上架状态:" props="is_show" label-for="status">
|
||||
<el-radio-group element-id="is_show" v-model="formValidate.is_show">
|
||||
<el-radio :label="1" :value="1" class="radio">开启</el-radio>
|
||||
<el-radio :label="0" :value="0">关闭</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col v-bind="grid2">
|
||||
<el-form-item label="热门推荐:" props="is_host" label-for="is_host">
|
||||
<el-radio-group element-id="is_host" v-model="formValidate.is_host">
|
||||
<el-radio :label="1" :value="1" class="radio">开启</el-radio>
|
||||
<el-radio :label="0" :value="0">关闭</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="规格选择:">
|
||||
<el-table
|
||||
ref="multipleTable"
|
||||
:data="specsData"
|
||||
border
|
||||
:row-key="getRowKeys"
|
||||
class="mt14"
|
||||
highlight-current-row
|
||||
@selection-change="changeCheckbox"
|
||||
>
|
||||
<el-table-column type="selection" :reserve-selection="true" width="55"> </el-table-column>
|
||||
<el-table-column
|
||||
:label="item.title"
|
||||
:min-width="item.minWidth"
|
||||
v-for="(item, index) in columns"
|
||||
:key="index"
|
||||
>
|
||||
<template #default="scope">
|
||||
<template v-if="item.key">
|
||||
<div>
|
||||
<span>{{ scope.row[item.key] }}</span>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else-if="item.slot === 'pic'">
|
||||
<div
|
||||
class="acea-row row-middle row-center-wrapper"
|
||||
v-db-click
|
||||
@click="modalPicTap('dan', 'danTable', scope.$index)"
|
||||
>
|
||||
<div class="pictrue pictrueTab" v-if="scope.row.pic">
|
||||
<img v-lazy="scope.row.pic" />
|
||||
</div>
|
||||
<div class="upLoad pictrueTab acea-row row-center-wrapper" v-else>
|
||||
<i class="el-icon-picture-outline" style="font-size: 24px"></i>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else-if="item.slot === 'price'">
|
||||
<el-input-number
|
||||
:controls="false"
|
||||
v-model="scope.row.price"
|
||||
:min="0"
|
||||
:precision="0"
|
||||
class="priceBox"
|
||||
:active-change="false"
|
||||
></el-input-number>
|
||||
</template>
|
||||
<template v-else-if="item.slot === 'quota'">
|
||||
<el-input-number
|
||||
:controls="false"
|
||||
v-model="scope.row.quota"
|
||||
:min="1"
|
||||
class="priceBox"
|
||||
></el-input-number>
|
||||
</template>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-col>
|
||||
<!-- 第三步:商品详情 -->
|
||||
<el-row v-show="current === 2">
|
||||
<el-col :span="24">
|
||||
<el-form-item label="内容:">
|
||||
<WangEditor
|
||||
style="width: 90%"
|
||||
:content="formValidate.description"
|
||||
:ai-default-prompt="aiDefaultPrompt"
|
||||
@editorContent="getEditorContent"
|
||||
>
|
||||
</WangEditor>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-col :span="24">
|
||||
<el-form-item>
|
||||
<el-button
|
||||
class="submission"
|
||||
v-db-click
|
||||
@click="step"
|
||||
:disabled="($route.params.id && current === 1) || current === 0"
|
||||
>上一步</el-button
|
||||
>
|
||||
<el-button
|
||||
:disabled="submitOpen && current === 2"
|
||||
type="primary"
|
||||
class="submission"
|
||||
v-db-click
|
||||
@click="next('formValidate')"
|
||||
>{{ current === 2 ? '提交' : '下一步' }}</el-button
|
||||
>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-form>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-card>
|
||||
<!-- 选择商品 -->
|
||||
<el-dialog v-model="modals" title="商品列表" class="paymentFooter" width="1000px">
|
||||
<goods-list ref="goodslist" @getProductId="getProductId"></goods-list>
|
||||
</el-dialog>
|
||||
<!-- 上传图片 -->
|
||||
<el-dialog v-model="modalPic" width="950px" title="上传商品图" :close-on-click-modal="false">
|
||||
<uploadPictures
|
||||
:isChoice="isChoice"
|
||||
@getPic="getPic"
|
||||
@getPicD="getPicD"
|
||||
:gridBtn="gridBtn"
|
||||
:gridPic="gridPic"
|
||||
v-if="modalPic"
|
||||
></uploadPictures>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed, nextTick, onMounted, ref } from 'vue';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
import { ElMessage } from 'element-plus';
|
||||
import goodsList from '@/components/goodsList/index';
|
||||
import WangEditor from '@/components/wangEditor/index.vue';
|
||||
import uploadPictures from '@/components/uploadPictures';
|
||||
import steps from '@/components/steps/index';
|
||||
import { integralAddApi, productAttrsApi, integralInfoApi } from '../../api';
|
||||
import setting from '@/setting';
|
||||
import { useMediaStore } from '@/store/module/media';
|
||||
|
||||
defineOptions({ name: 'integralProductCreate' });
|
||||
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
const routePre = setting.routePre;
|
||||
const mediaStore = useMediaStore();
|
||||
|
||||
const formValidateRef = ref(null);
|
||||
const multipleTable = ref(null);
|
||||
const goodslist = ref(null);
|
||||
|
||||
const isMobile = computed(() => mediaStore.isMobile);
|
||||
const labelWidth = computed(() => (isMobile.value ? undefined : '135px'));
|
||||
const labelPosition = computed(() => (isMobile.value ? 'top' : 'right'));
|
||||
|
||||
const submitOpen = ref(false);
|
||||
const spinShow = ref(false);
|
||||
const isChoice = ref('');
|
||||
const current = ref(0);
|
||||
const modalPic = ref(false);
|
||||
const grid = { xl: 12, lg: 20, md: 24, sm: 24, xs: 24 };
|
||||
const grid2 = { xl: 8, lg: 12, md: 12, sm: 24, xs: 24 };
|
||||
const gridPic = { xl: 6, lg: 8, md: 12, sm: 12, xs: 12 };
|
||||
const gridBtn = { xl: 4, lg: 8, md: 8, sm: 8, xs: 8 };
|
||||
const stepList = ref(['选择积分商品', '填写基础信息', '修改商品详情']);
|
||||
const modals = ref(false);
|
||||
const modal_loading = ref(false);
|
||||
const formValidate = ref({
|
||||
images: [],
|
||||
title: '',
|
||||
image: '',
|
||||
unit_name: '',
|
||||
price: 0,
|
||||
sales: 0,
|
||||
stock: 0,
|
||||
sort: 0,
|
||||
num: 1,
|
||||
once_num: 1,
|
||||
is_host: 0,
|
||||
is_show: 1,
|
||||
description: '',
|
||||
id: 0,
|
||||
product_id: 0,
|
||||
attrs: [],
|
||||
items: [],
|
||||
});
|
||||
// AI 写作默认提示词:优先带入当前商品标题(弹窗内未被用户修改过的提示词会跟随刷新)
|
||||
const aiDefaultPrompt = computed(() => {
|
||||
const title = (formValidate.value.title || '').trim();
|
||||
return title
|
||||
? `请围绕商品《${title}》撰写一篇产品推广文章,介绍产品亮点、使用场景与适用人群,结构清晰,800字左右。`
|
||||
: '写一篇产品推广文章,介绍产品亮点、使用场景与适用人群,结构清晰,800字左右。';
|
||||
});
|
||||
const description = ref('');
|
||||
const columns = ref([]);
|
||||
const specsData = ref([]);
|
||||
const picTit = ref('');
|
||||
const tableIndex = ref(0);
|
||||
const copy = ref(0);
|
||||
const ruleValidate = ref({
|
||||
image: [{ required: true, message: '请选择主图', trigger: 'change' }],
|
||||
images: [
|
||||
{ required: true, type: 'array', message: '请选择轮播图', trigger: 'change' },
|
||||
{ type: 'array', min: 1, message: '至少选择一张轮播图', trigger: 'change' },
|
||||
],
|
||||
title: [{ required: true, message: '请输入商品标题', trigger: 'blur' }],
|
||||
unit_name: [{ required: true, message: '请输入单位', trigger: 'blur' }],
|
||||
num: [{ required: true, type: 'number', message: '请输入兑换数量限制', trigger: 'blur' }],
|
||||
});
|
||||
// 非响应式内部状态(原代码未在 data 中声明)
|
||||
let dragging = null;
|
||||
|
||||
onMounted(() => {
|
||||
if (route.params.id) {
|
||||
copy.value = route.params.copy || 0;
|
||||
current.value = 1;
|
||||
getInfo();
|
||||
}
|
||||
});
|
||||
|
||||
function getEditorContent(data) {
|
||||
description.value = data;
|
||||
}
|
||||
function productAttrs(rows) {
|
||||
productAttrsApi(rows.id, 4)
|
||||
.then((res) => {
|
||||
let data = res.data.info;
|
||||
specsData.value = data.attrs;
|
||||
specsData.value.forEach(function (item, index) {
|
||||
specsData.value[index]['id'] = index;
|
||||
});
|
||||
formValidate.value.items = data.items;
|
||||
columns.value = data.header;
|
||||
})
|
||||
.catch((res) => {
|
||||
ElMessage.error(res.msg);
|
||||
});
|
||||
}
|
||||
function changeCheckbox(selection) {
|
||||
formValidate.value.attrs = selection;
|
||||
}
|
||||
function getProductId(row) {
|
||||
modal_loading.value = false;
|
||||
modals.value = false;
|
||||
setTimeout(() => {
|
||||
formValidate.value = {
|
||||
images: row.slider_image || [],
|
||||
title: row.store_name,
|
||||
image: row.image,
|
||||
unit_name: row.unit_name,
|
||||
price: 0,
|
||||
sales: row.sales,
|
||||
stock: row.stock,
|
||||
sort: row.sort,
|
||||
num: 1,
|
||||
once_num: 1,
|
||||
is_host: 0,
|
||||
is_show: 1,
|
||||
description: row.description || '',
|
||||
id: 0,
|
||||
product_id: row.id,
|
||||
attrs: [],
|
||||
items: [],
|
||||
};
|
||||
productAttrs(row);
|
||||
}, 500);
|
||||
}
|
||||
function getInfo() {
|
||||
spinShow.value = true;
|
||||
integralInfoApi(route.params.id)
|
||||
.then(async (res) => {
|
||||
let info = res.data.info;
|
||||
formValidate.value = info;
|
||||
formValidate.value['items'] = info.attrs.items;
|
||||
columns.value = info.attrs.header;
|
||||
specsData.value = info.attrs.value;
|
||||
specsData.value.forEach(function (item, index) {
|
||||
specsData.value[index]['id'] = index;
|
||||
});
|
||||
let attr = [];
|
||||
for (let index in info.attrs.value) {
|
||||
if (info.attrs.value[index]._checked) {
|
||||
attr.push(info.attrs.value[index]);
|
||||
}
|
||||
}
|
||||
formValidate.value.attrs = attr;
|
||||
attr.forEach((row) => {
|
||||
multipleTable.value.toggleRowSelection(row, true);
|
||||
});
|
||||
spinShow.value = false;
|
||||
})
|
||||
.catch((res) => {
|
||||
spinShow.value = false;
|
||||
ElMessage.error(res.msg);
|
||||
});
|
||||
}
|
||||
function getRowKeys(row) {
|
||||
return row.id;
|
||||
}
|
||||
function next(name) {
|
||||
if (current.value === 2) {
|
||||
formValidate.value.description = description.value;
|
||||
formValidateRef.value.validate((valid) => {
|
||||
if (valid) {
|
||||
if (copy.value == 1) formValidate.value.copy = 1;
|
||||
formValidate.value.id = Number(route.params.id) || 0;
|
||||
submitOpen.value = true;
|
||||
integralAddApi(formValidate.value)
|
||||
.then(async (res) => {
|
||||
submitOpen.value = false;
|
||||
ElMessage.success(res.msg);
|
||||
setTimeout(() => {
|
||||
router.push({ path: routePre + '/marketing/integral/product' });
|
||||
}, 500);
|
||||
})
|
||||
.catch((res) => {
|
||||
submitOpen.value = false;
|
||||
ElMessage.error(res.msg);
|
||||
});
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
} else if (current.value === 1) {
|
||||
formValidateRef.value.validate((valid) => {
|
||||
if (valid) {
|
||||
if (!formValidate.value.attrs || !formValidate.value.attrs.length) {
|
||||
return ElMessage.error('请选择属性规格');
|
||||
}
|
||||
for (let index in formValidate.value.attrs) {
|
||||
if (formValidate.value.attrs[index].quota <= 0) {
|
||||
return ElMessage.error('兑换次数必须大于0');
|
||||
}
|
||||
}
|
||||
current.value += 1;
|
||||
} else {
|
||||
return ElMessage.warning('请完善您的信息');
|
||||
}
|
||||
});
|
||||
} else {
|
||||
if (formValidate.value.image) {
|
||||
current.value += 1;
|
||||
} else {
|
||||
ElMessage.warning('请选择商品');
|
||||
}
|
||||
}
|
||||
}
|
||||
function step() {
|
||||
current.value--;
|
||||
}
|
||||
function modalPicTap(tit, picTitVal, index) {
|
||||
modalPic.value = true;
|
||||
isChoice.value = tit === 'dan' ? '单选' : '多选';
|
||||
picTit.value = picTitVal;
|
||||
tableIndex.value = index;
|
||||
}
|
||||
function getPic(pc) {
|
||||
switch (picTit.value) {
|
||||
case 'danFrom':
|
||||
formValidate.value.image = pc.att_dir;
|
||||
break;
|
||||
default:
|
||||
if (formValidate.value.attrs && formValidate.value.attrs.length) {
|
||||
specsData.value[tableIndex.value]['_checked'] = true;
|
||||
}
|
||||
specsData.value[tableIndex.value].pic = pc.att_dir;
|
||||
}
|
||||
modalPic.value = false;
|
||||
}
|
||||
function getPicD(pc) {
|
||||
pc.map((item) => {
|
||||
formValidate.value.images.push(item.att_dir);
|
||||
formValidate.value.images = formValidate.value.images.splice(0, 10);
|
||||
});
|
||||
modalPic.value = false;
|
||||
}
|
||||
function handleRemove(i) {
|
||||
formValidate.value.images.splice(i, 1);
|
||||
}
|
||||
function changeGoods() {
|
||||
modals.value = true;
|
||||
nextTick(() => {
|
||||
goodslist.value.formValidate.is_show = -1;
|
||||
goodslist.value.formValidate.type = 7;
|
||||
goodslist.value.getList();
|
||||
goodslist.value.goodsCategory();
|
||||
});
|
||||
}
|
||||
function handleDragStart(e, item) {
|
||||
dragging = item;
|
||||
}
|
||||
function handleDragEnd(e, item) {
|
||||
dragging = null;
|
||||
}
|
||||
function handleDragOver(e) {
|
||||
e.dataTransfer.dropEffect = 'move';
|
||||
}
|
||||
function handleDragEnter(e, item) {
|
||||
e.dataTransfer.effectAllowed = 'move';
|
||||
if (item === dragging) return;
|
||||
const newItems = [...formValidate.value.images];
|
||||
const src = newItems.indexOf(dragging);
|
||||
const dst = newItems.indexOf(item);
|
||||
newItems.splice(dst, 0, ...newItems.splice(src, 1));
|
||||
formValidate.value.images = newItems;
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.content_width {
|
||||
width: 460px;
|
||||
}
|
||||
.custom-label {
|
||||
display: inline-flex;
|
||||
line-height: 1.5;
|
||||
}
|
||||
.grey {
|
||||
color: #999;
|
||||
}
|
||||
.tabBox_img {
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
.tabBox_img img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
.priceBox {
|
||||
width: 100%;
|
||||
}
|
||||
.form {
|
||||
.picBox {
|
||||
display: inline-block;
|
||||
cursor: pointer;
|
||||
}
|
||||
.pictrue {
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
border: 1px dotted rgba(0, 0, 0, 0.1);
|
||||
margin-right: 15px;
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
.btndel {
|
||||
position: absolute;
|
||||
z-index: 9;
|
||||
width: 20px !important;
|
||||
height: 20px !important;
|
||||
left: 46px;
|
||||
top: -4px;
|
||||
}
|
||||
}
|
||||
.upLoad {
|
||||
width: 58px;
|
||||
height: 58px;
|
||||
line-height: 58px;
|
||||
border: 1px dotted rgba(0, 0, 0, 0.1);
|
||||
border-radius: 4px;
|
||||
background: rgba(0, 0, 0, 0.02);
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@ -1,274 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-card :bordered="false" shadow="never" :body-style="{ padding: 0 }">
|
||||
<div class="padding-add">
|
||||
<el-form :model="tableFrom" :label-width="labelWidth" label-position="right" @submit.prevent inline>
|
||||
<el-form-item label="创建时间:">
|
||||
<date-range-picker
|
||||
clearable
|
||||
v-model="timeVal"
|
||||
:editable="false"
|
||||
@change="onchangeTime"
|
||||
format="YYYY/MM/DD"
|
||||
value-format="YYYY/MM/DD"
|
||||
></date-range-picker>
|
||||
</el-form-item>
|
||||
<el-form-item label="上架状态:">
|
||||
<el-select
|
||||
placeholder="请选择"
|
||||
clearable
|
||||
v-model="tableFrom.is_show"
|
||||
@change="userSearchs"
|
||||
class="form_content_width"
|
||||
>
|
||||
<el-option value="1" label="上架"></el-option>
|
||||
<el-option value="0" label="下架"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="商品搜索:" label-for="store_name">
|
||||
<el-input
|
||||
placeholder="请输入商品名称,ID"
|
||||
v-model="tableFrom.store_name"
|
||||
clearable
|
||||
class="form_content_width"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" v-db-click @click="userSearchs">查询</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
</el-card>
|
||||
<el-card :bordered="false" shadow="never" class="ivu-mt mt16">
|
||||
<el-button
|
||||
v-auth="['marketing-store_integral-create']"
|
||||
type="primary"
|
||||
icon="md-add"
|
||||
v-db-click
|
||||
@click="add"
|
||||
class="action-row mr10"
|
||||
>添加积分商品</el-button
|
||||
>
|
||||
<el-table :data="tableList" v-loading="loading" highlight-current-row class="mt14">
|
||||
<el-table-column label="ID" min-width="50">
|
||||
<template #default="scope">
|
||||
<span>{{ scope.row.id }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="商品图片" min-width="90">
|
||||
<template #default="scope">
|
||||
<div class="tabBox_img" v-viewer>
|
||||
<img v-lazy="scope.row.image" />
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="活动标题" min-width="130">
|
||||
<template #default="scope">
|
||||
<el-tooltip placement="top" :open-delay="600">
|
||||
<template #content
|
||||
><div>{{ scope.row.title }}</div></template
|
||||
>
|
||||
<span class="line2">{{ scope.row.title }}</span>
|
||||
</el-tooltip>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="兑换积分" min-width="60">
|
||||
<template #default="scope">
|
||||
<span>{{ scope.row.price }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="限量" min-width="60">
|
||||
<template #default="scope">
|
||||
<span>{{ scope.row.quota_show }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="限量剩余" min-width="60">
|
||||
<template #default="scope">
|
||||
<span>{{ scope.row.quota }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="创建时间" min-width="100">
|
||||
<template #default="scope">
|
||||
<span>{{ scope.row.add_time }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="排序" min-width="60">
|
||||
<template #default="scope">
|
||||
<span>{{ scope.row.sort }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="状态" min-width="80">
|
||||
<template #default="scope">
|
||||
<el-switch
|
||||
class="defineSwitch"
|
||||
:active-value="1"
|
||||
:inactive-value="0"
|
||||
v-model="scope.row.is_show"
|
||||
:value="scope.row.is_show"
|
||||
@change="onchangeIsShow(scope.row)"
|
||||
size="large"
|
||||
active-text="上架"
|
||||
inactive-text="下架"
|
||||
>
|
||||
</el-switch>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" fixed="right" width="200">
|
||||
<template #default="scope">
|
||||
<a v-db-click @click="orderList(scope.row)">兑换记录</a>
|
||||
<el-divider direction="vertical"></el-divider>
|
||||
<a v-db-click @click="edit(scope.row)">编辑</a>
|
||||
<el-divider direction="vertical"></el-divider>
|
||||
<a v-db-click @click="copy(scope.row)">复制</a>
|
||||
<el-divider direction="vertical"></el-divider>
|
||||
<a v-db-click @click="del(scope.row, '删除积分商品', scope.$index)">删除</a>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<div class="acea-row row-right page">
|
||||
<pagination
|
||||
v-if="total"
|
||||
:total="total"
|
||||
v-model:page="tableFrom.page"
|
||||
v-model:limit="tableFrom.limit"
|
||||
@pagination="getList"
|
||||
/>
|
||||
</div>
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed, onActivated, onMounted, ref } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { ElMessage } from 'element-plus';
|
||||
import { integralProductListApi, integralIsShowApi } from '../../api';
|
||||
import { formatDate } from '@/utils/validate';
|
||||
import { modalSure } from '@/utils/public';
|
||||
import setting from '@/setting';
|
||||
import { useMediaStore } from '@/store/module/media';
|
||||
|
||||
defineOptions({ name: 'integralProductList' });
|
||||
|
||||
const router = useRouter();
|
||||
const routePre = setting.routePre;
|
||||
const mediaStore = useMediaStore();
|
||||
|
||||
const isMobile = computed(() => mediaStore.isMobile);
|
||||
const labelWidth = computed(() => (isMobile.value ? undefined : '80px'));
|
||||
const labelPosition = computed(() => (isMobile.value ? 'top' : 'right'));
|
||||
|
||||
const loading = ref(false);
|
||||
const tableList = ref([]);
|
||||
const timeVal = ref([]);
|
||||
const tableFrom = ref({
|
||||
integral_time: '',
|
||||
is_show: '',
|
||||
store_name: '',
|
||||
page: 1,
|
||||
limit: 15,
|
||||
});
|
||||
const total = ref(0);
|
||||
|
||||
// 原 filters.formatDate
|
||||
function filterFormatDate(time) {
|
||||
if (time !== 0) {
|
||||
let date = new Date(time * 1000);
|
||||
return formatDate(date, 'yyyy-MM-dd');
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
getList();
|
||||
});
|
||||
|
||||
onActivated(() => {
|
||||
getList();
|
||||
});
|
||||
|
||||
function add() {
|
||||
router.push({ path: routePre + '/marketing/integral/product/create' });
|
||||
}
|
||||
function orderList(row) {
|
||||
router.push({
|
||||
path: routePre + '/marketing/integral/order',
|
||||
query: { product_id: row.id },
|
||||
});
|
||||
}
|
||||
function edit(row) {
|
||||
router.push({
|
||||
path: routePre + '/marketing/integral/product/create/' + row.id + '/0',
|
||||
});
|
||||
}
|
||||
function copy(row) {
|
||||
router.push({
|
||||
path: routePre + '/marketing/integral/product/create/' + row.id + '/1',
|
||||
});
|
||||
}
|
||||
function del(row, tit, num) {
|
||||
let delfromData = {
|
||||
title: tit,
|
||||
num: num,
|
||||
url: `marketing/integral/${row.id}`,
|
||||
method: 'DELETE',
|
||||
ids: '',
|
||||
};
|
||||
modalSure(delfromData)
|
||||
.then((res) => {
|
||||
ElMessage.success(res.msg);
|
||||
tableFrom.value.page = 1;
|
||||
getList();
|
||||
})
|
||||
.catch((res) => {
|
||||
ElMessage.error(res.msg);
|
||||
});
|
||||
}
|
||||
function getList() {
|
||||
loading.value = true;
|
||||
tableFrom.value.is_show = tableFrom.value.is_show || '';
|
||||
integralProductListApi(tableFrom.value)
|
||||
.then(async (res) => {
|
||||
let data = res.data;
|
||||
tableList.value = data.list;
|
||||
total.value = res.data.count;
|
||||
loading.value = false;
|
||||
})
|
||||
.catch((res) => {
|
||||
loading.value = false;
|
||||
ElMessage.error(res.msg);
|
||||
});
|
||||
}
|
||||
function userSearchs() {
|
||||
tableFrom.value.page = 1;
|
||||
getList();
|
||||
}
|
||||
function onchangeTime(e) {
|
||||
timeVal.value = e;
|
||||
tableFrom.value.integral_time = timeVal.value ? timeVal.value.join('-') : '';
|
||||
getList();
|
||||
}
|
||||
function onchangeIsShow(row) {
|
||||
let data = { id: row.id, is_show: row.is_show };
|
||||
integralIsShowApi(data)
|
||||
.then(async (res) => {
|
||||
ElMessage.success(res.msg);
|
||||
})
|
||||
.catch((res) => {
|
||||
ElMessage.error(res.msg);
|
||||
row.is_show = !row.is_show;
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.tabBox_img {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@ -1,85 +0,0 @@
|
||||
/**
|
||||
* 积分商城扩展路由
|
||||
*
|
||||
* 说明:
|
||||
* - 仅保留插件特有的路由:积分商品、积分订单
|
||||
* - 积分记录、积分统计、积分配置为系统内置路由,已迁移至 router/modules/marketing.js
|
||||
* - 旧路由(store_integral/*、user_point/*)已移除
|
||||
*/
|
||||
import setting from '@/setting';
|
||||
const routePre = setting.routePre;
|
||||
const pre = 'integral_';
|
||||
|
||||
export default [
|
||||
{
|
||||
path: routePre + '/marketing/integral/product',
|
||||
section: 'integral',
|
||||
action: 'product',
|
||||
meta: {
|
||||
auth: ['marketing-integral-product'],
|
||||
title: '积分商品',
|
||||
keepAlive: true,
|
||||
},
|
||||
component: () => import('@/layout'),
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
name: `${pre}product`,
|
||||
name: 'integralProductList',
|
||||
component: () => import('./pages/product/index.vue'),
|
||||
meta: {
|
||||
auth: ['marketing-integral-product'],
|
||||
title: '积分商品',
|
||||
keepAlive: true,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: routePre + '/marketing/integral/product/create/:id?/:copy?',
|
||||
section: 'integral',
|
||||
action: 'product_create',
|
||||
meta: {
|
||||
auth: ['marketing-integral-save'],
|
||||
title: '添加/编辑积分商品',
|
||||
},
|
||||
component: () => import('@/layout'),
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
name: `${pre}productCreate`,
|
||||
component: () => import('./pages/product/create.vue'),
|
||||
meta: {
|
||||
auth: ['marketing-integral-save'],
|
||||
title: '添加/编辑积分商品',
|
||||
activeMenu: routePre + '/marketing/integral/product',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: routePre + '/marketing/integral/order',
|
||||
section: 'integral',
|
||||
action: 'order',
|
||||
meta: {
|
||||
auth: ['marketing-integral-order'],
|
||||
title: '积分订单',
|
||||
keepAlive: true,
|
||||
},
|
||||
component: () => import('@/layout'),
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
name: `${pre}order`,
|
||||
name: 'integralOrderList',
|
||||
component: () => import('./pages/order/index.vue'),
|
||||
meta: {
|
||||
auth: ['marketing-integral-order'],
|
||||
title: '积分订单',
|
||||
keepAlive: true,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
// 积分记录、积分统计、积分配置为系统内置路由,已移至 router/modules/marketing.js
|
||||
];
|
||||
@ -1,380 +0,0 @@
|
||||
// +----------------------------------------------------------------------
|
||||
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: CRMEB Team <admin@crmeb.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
import request from '@/libs/request';
|
||||
|
||||
/*
|
||||
* 登录
|
||||
* */
|
||||
export function AccountLogin(data) {
|
||||
return request({
|
||||
url: '/kefu/login',
|
||||
method: 'post',
|
||||
data,
|
||||
kefu: true,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取左侧客服会话列表(会话列表/会话结束,用户与游客混排)
|
||||
* @param {Object} params nickname-搜索关键字 is_end-0=会话列表 1=会话结束
|
||||
* @constructor
|
||||
*/
|
||||
export function record(params) {
|
||||
return request({
|
||||
url: '/kefu/user/record',
|
||||
method: 'get',
|
||||
params,
|
||||
kefu: true,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 结束会话:移入「会话结束」列表,不再计入未读
|
||||
* @param {Number} toUid 会话对方uid(用户或游客)
|
||||
* @constructor
|
||||
*/
|
||||
export function endChatApi(toUid) {
|
||||
return request({
|
||||
url: `/kefu/user/end_chat/${toUid}`,
|
||||
method: 'put',
|
||||
kefu: true,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 会话列表(用户+游客)未读消息总数
|
||||
* @constructor
|
||||
*/
|
||||
export function unreadNumApi() {
|
||||
return request({
|
||||
url: '/kefu/user/unread_num',
|
||||
method: 'get',
|
||||
kefu: true,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取左侧用户详情
|
||||
* @constructor
|
||||
*/
|
||||
export function userInfo(id) {
|
||||
return request({
|
||||
url: '/kefu/user/info/' + id,
|
||||
method: 'get',
|
||||
kefu: true,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 客服话术
|
||||
* @constructor
|
||||
*/
|
||||
export function speeChcraft(params) {
|
||||
return request({
|
||||
url: '/kefu/service/speechcraft',
|
||||
method: 'get',
|
||||
params,
|
||||
kefu: true,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 客服转接列表
|
||||
* @constructor
|
||||
*/
|
||||
export function transferList(params) {
|
||||
return request({
|
||||
url: '/kefu/service/transfer_list',
|
||||
method: 'get',
|
||||
params,
|
||||
kefu: true,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 客服转接列表
|
||||
* @constructor
|
||||
*/
|
||||
export function serviceTransfer(params) {
|
||||
return request({
|
||||
url: '/kefu/service/transfer',
|
||||
method: 'post',
|
||||
params,
|
||||
kefu: true,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 客服用户标签
|
||||
* @constructor
|
||||
*/
|
||||
export function userLabel(id) {
|
||||
return request({
|
||||
url: `/kefu/user/label/${id}`,
|
||||
method: 'get',
|
||||
kefu: true,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 客服用户标签更新
|
||||
* @constructor
|
||||
*/
|
||||
export function userLabelPut(id, data) {
|
||||
return request({
|
||||
url: `/kefu/user/label/${id}`,
|
||||
method: 'put',
|
||||
data,
|
||||
kefu: true,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 客服用户聊天列表
|
||||
* @constructor
|
||||
*/
|
||||
export function serviceList(params) {
|
||||
return request({
|
||||
url: `/kefu/service/list`,
|
||||
method: 'get',
|
||||
params,
|
||||
kefu: true,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 退出登录
|
||||
* @constructor
|
||||
*/
|
||||
export function AccountLogoutKefu() {
|
||||
return request({
|
||||
url: `/kefu/user/logout`,
|
||||
method: 'post',
|
||||
kefu: true,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取扫码登录凭证
|
||||
* @constructor
|
||||
*/
|
||||
export function getSanCodeKey() {
|
||||
return request({
|
||||
url: `/kefu/key`,
|
||||
method: 'get',
|
||||
kefu: true,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取轮播图和logo
|
||||
*/
|
||||
export function loginInfoApi() {
|
||||
return request({
|
||||
url: '/kefu/config',
|
||||
method: 'get',
|
||||
kefu: true,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取话术分类
|
||||
*/
|
||||
export function serviceCate(params) {
|
||||
return request({
|
||||
url: '/kefu/service/cate',
|
||||
method: 'get',
|
||||
params,
|
||||
kefu: true,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改话术
|
||||
*/
|
||||
export function serviceCateUpdate(id, params) {
|
||||
return request({
|
||||
url: '/kefu/service/speechcraft/' + id,
|
||||
method: 'PUT',
|
||||
params,
|
||||
kefu: true,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加话术
|
||||
*/
|
||||
export function addSpeeChcraft(data) {
|
||||
return request({
|
||||
url: '/kefu/service/speechcraft',
|
||||
method: 'post',
|
||||
data,
|
||||
kefu: true,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加分类
|
||||
*/
|
||||
export function addServiceCate(data) {
|
||||
return request({
|
||||
url: '/kefu/service/cate',
|
||||
method: 'post',
|
||||
data,
|
||||
kefu: true,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改分类
|
||||
*/
|
||||
export function editServiceCate(id, params) {
|
||||
return request({
|
||||
url: '/kefu/service/cate/' + id,
|
||||
method: 'PUT',
|
||||
params,
|
||||
kefu: true,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 扫码登录情况
|
||||
*/
|
||||
export function scanStatus(key, params) {
|
||||
return request({
|
||||
url: '/kefu/scan/' + key,
|
||||
method: 'get',
|
||||
params,
|
||||
kefu: true,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 客服用户分组
|
||||
* @constructor
|
||||
*/
|
||||
export function userGroupApi() {
|
||||
return request({
|
||||
url: `/kefu/user/group`,
|
||||
method: 'get',
|
||||
kefu: true,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 客服设置用户分组
|
||||
* @constructor
|
||||
*/
|
||||
export function putGroupApi(uid, id) {
|
||||
return request({
|
||||
url: `/kefu/user/group/${uid}/${id}`,
|
||||
method: 'put',
|
||||
kefu: true,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 客服配置
|
||||
* @constructor
|
||||
*/
|
||||
export function kefuConfig() {
|
||||
return request({
|
||||
url: `/kefu/config`,
|
||||
method: 'get',
|
||||
kefu: true,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 客户端 随机客服
|
||||
* @constructor
|
||||
*/
|
||||
export function serviceListApi(params) {
|
||||
return request({
|
||||
url: `kefu/tourist/user`,
|
||||
method: 'get',
|
||||
params,
|
||||
kefu: true,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 客户端 广告位
|
||||
* @constructor
|
||||
*/
|
||||
export function getAdvApi() {
|
||||
return request({
|
||||
url: `kefu/tourist/adv`,
|
||||
method: 'get',
|
||||
kefu: true,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 客户端 聊天记录
|
||||
* @constructor
|
||||
*/
|
||||
export function chatListApi(params) {
|
||||
return request({
|
||||
url: `kefu/tourist/chat`,
|
||||
method: 'get',
|
||||
params,
|
||||
kefu: true,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 客户端 客服反馈
|
||||
* @constructor
|
||||
*/
|
||||
export function feedbackDataApi() {
|
||||
return request({
|
||||
url: `kefu/tourist/feedback`,
|
||||
method: 'get',
|
||||
kefu: true,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 客户端 反馈提示语
|
||||
* @constructor
|
||||
*/
|
||||
export function feedbackFromApi(data) {
|
||||
return request({
|
||||
url: `kefu/tourist/feedback`,
|
||||
method: 'post',
|
||||
data,
|
||||
kefu: true,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 客服链接获取
|
||||
* @constructor
|
||||
*/
|
||||
export function getWorkermanUrl() {
|
||||
return request({
|
||||
url: `get_workerman_url`,
|
||||
method: 'get',
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 复制粘贴上传图片
|
||||
*/
|
||||
export function uploadImg(data) {
|
||||
return request({
|
||||
url: `kefu/upload`,
|
||||
method: 'post',
|
||||
data,
|
||||
kefu: true,
|
||||
});
|
||||
}
|
||||
@ -1,23 +0,0 @@
|
||||
// +----------------------------------------------------------------------
|
||||
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: CRMEB Team <admin@crmeb.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
import request from '@/libs/request';
|
||||
|
||||
/**
|
||||
* 客服详细信息
|
||||
* @constructor
|
||||
*/
|
||||
export function serviceInfo() {
|
||||
return request({
|
||||
url: 'kefu/service/info',
|
||||
method: 'get',
|
||||
kefu: true,
|
||||
});
|
||||
}
|
||||
@ -1,204 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="feedback" :class="change === true ? 'on' : ''">
|
||||
<div class="feedback-header acea-row">
|
||||
<span class="sp1">商城客服已离线</span>
|
||||
<div>
|
||||
<i class="el-icon-close" style="font-size: 18px" v-db-click @click="close"></i>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="!isShow">
|
||||
<div class="feedback-conent mb20">
|
||||
<div class="ft" v-text="notice"></div>
|
||||
</div>
|
||||
<div>
|
||||
<el-form :model="formItem" ref="formItemRef" class="pl15" :rules="ruleValidate">
|
||||
<el-form-item prop="rela_name">
|
||||
<el-input v-model="formItem.rela_name" placeholder="请输入您的姓名"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item prop="phone">
|
||||
<el-input v-model="formItem.phone" placeholder="请输入您的联系电话"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item prop="content">
|
||||
<el-input v-model="formItem.content" class="mb10" type="textarea" placeholder="请输入留言内容"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" v-db-click @click="handleSubmit()" style="width: 100%">提交留言</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sure" v-if="isShow">
|
||||
<div class="sure-yuan"></div>
|
||||
<div class="sp1 mb10">提交成功</div>
|
||||
<div class="sp2 mb30">您的信息提交成功,我们会尽快与您取得联系!</div>
|
||||
<el-button type="primary" v-db-click @click="close">好的</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="maskModel" @touchmove.prevent v-show="change === true"></div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted } from 'vue';
|
||||
import { ElMessage } from 'element-plus';
|
||||
import { feedbackDataApi, feedbackFromApi } from '@/pages/plugin/kefu/api';
|
||||
|
||||
defineOptions({ name: 'feedback' });
|
||||
|
||||
const props = defineProps({
|
||||
change: Boolean,
|
||||
});
|
||||
|
||||
const emit = defineEmits(['closeChange']);
|
||||
|
||||
const formItemRef = ref(null);
|
||||
const isShow = ref(false);
|
||||
const formItem = ref({
|
||||
rela_name: '',
|
||||
content: '',
|
||||
phone: '',
|
||||
});
|
||||
const notice = ref('');
|
||||
const ruleValidate = {
|
||||
rela_name: [{ required: true, message: '请输入您的姓名', trigger: 'blur' }],
|
||||
content: [{ required: true, message: '请输入留言内容', trigger: 'blur' }],
|
||||
phone: [
|
||||
{ required: true, message: '请填写手机号码', trigger: 'change' },
|
||||
{ pattern: /^1[3456789]\d{9}$/, message: '手机号码格式不正确', trigger: 'blur' },
|
||||
],
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
getNotice();
|
||||
});
|
||||
|
||||
function handleSubmit() {
|
||||
formItemRef.value.validate((valid) => {
|
||||
if (valid) {
|
||||
feedbackFromApi(formItem.value)
|
||||
.then((res) => {
|
||||
isShow.value = true;
|
||||
})
|
||||
.catch((err) => {
|
||||
ElMessage.error(err.msg);
|
||||
});
|
||||
} else {
|
||||
}
|
||||
});
|
||||
}
|
||||
function close() {
|
||||
emit('closeChange', false);
|
||||
}
|
||||
// 广告
|
||||
function getNotice() {
|
||||
feedbackDataApi()
|
||||
.then((res) => {
|
||||
notice.value = res.data.feedback;
|
||||
})
|
||||
.catch((err) => {
|
||||
ElMessage.error(err.msg);
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.maskModel {
|
||||
z-index: 7777 !important;
|
||||
}
|
||||
.on {
|
||||
opacity: 1 !important;
|
||||
transform: scale(1) !important;
|
||||
-webkit-transform: scale(1) !important;
|
||||
-o-transform: scale(1) !important;
|
||||
-moz-transform: scale(1) !important;
|
||||
-ms-transform: scale(1) !important;
|
||||
}
|
||||
.pl15 {
|
||||
padding: 0 15px;
|
||||
}
|
||||
.sure {
|
||||
width: 100%;
|
||||
height: 480px;
|
||||
text-align: center;
|
||||
&-yuan {
|
||||
width: 70px;
|
||||
height: 70px;
|
||||
border-radius: 50%;
|
||||
overflow: hidden;
|
||||
background: #55d443;
|
||||
margin: 54px auto;
|
||||
line-height: 70px;
|
||||
}
|
||||
.sp1 {
|
||||
color: #333333;
|
||||
font-size: 16px;
|
||||
}
|
||||
.sp2 {
|
||||
color: #999999;
|
||||
font-size: 13px;
|
||||
}
|
||||
}
|
||||
.feedback {
|
||||
position: fixed;
|
||||
width: 320px;
|
||||
height: 530px;
|
||||
border-radius: 2px;
|
||||
background-color: #fff;
|
||||
z-index: 9999;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
margin-left: -150px;
|
||||
margin-top: -237px;
|
||||
transition: all 0.3s ease-in-out 0s;
|
||||
-webkit-transition: all 0.3s ease-in-out 0s;
|
||||
-o-transition: all 0.3s ease-in-out 0s;
|
||||
-moz-transition: all 0.3s ease-in-out 0s;
|
||||
-webkit-transform: scale(0);
|
||||
-o-transform: scale(0);
|
||||
-moz-transform: scale(0);
|
||||
-ms-transform: scale(0);
|
||||
transform: scale(0);
|
||||
opacity: 0;
|
||||
&-header {
|
||||
width: 100%;
|
||||
height: 50px;
|
||||
line-height: 50px;
|
||||
padding: 0 15px;
|
||||
background: linear-gradient(270deg, #1890ff 0%, #3875ea 100%);
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
.sp1 {
|
||||
color: #fff;
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
&-conent {
|
||||
padding: 15px;
|
||||
.ft {
|
||||
color: #333333;
|
||||
font-size: 13px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 767px) {
|
||||
.feedback {
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100dvh;
|
||||
margin: 0;
|
||||
border-radius: 0;
|
||||
background: var(--prev-bg-white);
|
||||
|
||||
&-header {
|
||||
background: var(--prev-color-primary);
|
||||
}
|
||||
|
||||
&-conent .ft {
|
||||
color: var(--prev-color-text-regular);
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,18 +0,0 @@
|
||||
<template>
|
||||
<div class="Loads acea-row row-center-wrapper" v-if="loading && !loaded" style="margin-top: 0.2rem; font-size: 12px">
|
||||
<template v-if="loading">
|
||||
<div class="iconfontYI icon-jiazai loading acea-row row-center-wrapper"></div>
|
||||
正在加载中
|
||||
</template>
|
||||
<template v-else> 上拉加载更多 </template>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
defineOptions({ name: 'Loading' });
|
||||
|
||||
defineProps({
|
||||
loaded: Boolean,
|
||||
loading: Boolean,
|
||||
});
|
||||
</script>
|
||||
@ -1,51 +0,0 @@
|
||||
<template>
|
||||
<div class="empty-wrapper">
|
||||
<!-- 用户列表 -->
|
||||
<template v-if="status == 1">
|
||||
<img src="@/assets/images/no_chat.png" alt="" />
|
||||
</template>
|
||||
<template v-if="status == 2">
|
||||
<img src="@/assets/images/no_user.png" alt="" />
|
||||
</template>
|
||||
<template v-if="status == 3">
|
||||
<img src="@/assets/images/no_all.png" alt="" />
|
||||
</template>
|
||||
<template v-if="status == 4">
|
||||
<img src="@/assets/images/no_zf.png" alt="" />
|
||||
</template>
|
||||
<template v-if="status == 5">
|
||||
<img src="@/assets/images/no_fh.png" alt="" />
|
||||
</template>
|
||||
<template v-if="status == 6">
|
||||
<img src="@/assets/images/no_tk.png" alt="" />
|
||||
</template>
|
||||
<p>{{ msg }}</p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
defineOptions({ name: 'empty' });
|
||||
|
||||
defineProps({
|
||||
status: {
|
||||
type: [String, Number],
|
||||
default: 1,
|
||||
},
|
||||
msg: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.empty-wrapper {
|
||||
margin-top: 60px;
|
||||
text-align: center;
|
||||
font-size: 12px;
|
||||
color: #666;
|
||||
img {
|
||||
width: 36%;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@ -1,869 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
<!-- 常用语 -->
|
||||
<div class="words-mask" v-if="isWords">
|
||||
<div class="content">
|
||||
<div class="title-box">
|
||||
<div class="tab-box">
|
||||
<div
|
||||
class="tan-item"
|
||||
:class="{ on: item.key == wordsTabCur }"
|
||||
v-for="(item, index) in wordsTab"
|
||||
:key="index"
|
||||
v-db-click
|
||||
@click.stop="bindTab(item)"
|
||||
>
|
||||
{{ item.title }}
|
||||
</div>
|
||||
<div class="right-icon">
|
||||
<span class="iconfont iconbianji2" v-db-click @click.stop="isWordShow = true"></span>
|
||||
<span class="iconfont iconcha" v-db-click @click.stop="closeBox"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="input-box">
|
||||
<el-input v-model="wordsData.searchTxt" placeholder="搜索快捷回复" :search="true" @on-search="bindSearch" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="scroll-box">
|
||||
<div class="scroll-left">
|
||||
<div class="left-item add_cate" v-db-click @click.stop="openCate(0)" v-if="wordsTabCur">
|
||||
<span class="iconfont iconjiahao"></span> 分组
|
||||
</div>
|
||||
<div
|
||||
class="left-item"
|
||||
:class="{ active: wordsData.cateId == item.id }"
|
||||
v-for="item in wordsData.cate"
|
||||
:key="item.id"
|
||||
v-db-click
|
||||
@click.stop="changeCate(item)"
|
||||
>
|
||||
{{ item.name }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="right-box">
|
||||
<!-- vue-scroll 为 Vue2 专用库且未再全局注册,改用原生滚动容器(触底加载下一页) -->
|
||||
<div class="right-scroll" @scroll="handleWordsScroll">
|
||||
<div class="msg-item add-mg" v-show="wordsTabCur" v-db-click @click.stop="addMsg">
|
||||
<span class="iconfont icontianjia11"></span>添加话术
|
||||
</div>
|
||||
<div
|
||||
class="msg-item"
|
||||
v-for="(item, index) in wordsList"
|
||||
:key="index"
|
||||
v-db-click
|
||||
@click.stop="selectWords(item)"
|
||||
>
|
||||
<span class="title">{{ item.title }}</span
|
||||
>{{ item.message }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 添加分组 -->
|
||||
<el-dialog
|
||||
v-model="cateData.isCate"
|
||||
width="470px"
|
||||
:show-close="true"
|
||||
custom-class="vertical-center-modal"
|
||||
class="words-box"
|
||||
>
|
||||
<div class="mask-title">
|
||||
{{ cateData.status ? '编辑分组' : '新增分组' }}
|
||||
<span class="iconfont iconcha" v-db-click @click.stop="closeCate"></span>
|
||||
</div>
|
||||
<div class="input-box">
|
||||
<el-input class="noinput" v-model="cateData.name" placeholder="请输入分组名称" />
|
||||
</div>
|
||||
<div class="input-box">
|
||||
<el-input class="noinput" v-model="cateData.sort" placeholder="请输入分组排序" />
|
||||
</div>
|
||||
<el-button v-db-click @click.stop="cateConfirm" class="subBtn" type="primary" :disabled="cateStatus"
|
||||
>确定</el-button
|
||||
>
|
||||
</el-dialog>
|
||||
<!-- 添加话术 -->
|
||||
<el-dialog
|
||||
v-model="msgData.isCateMeg"
|
||||
width="470px"
|
||||
:show-close="true"
|
||||
custom-class="vertical-center-modal"
|
||||
class="words-box"
|
||||
>
|
||||
<div class="mask-title">
|
||||
{{ msgData.status ? '修改话术' : '添加话术' }}
|
||||
<span class="iconfont iconcha" v-db-click @click.stop="closeMsgBox"></span>
|
||||
</div>
|
||||
<div class="input-box">
|
||||
<el-input class="noinput" v-model="msgData.title" placeholder="请输入标题名称 (选填)" />
|
||||
</div>
|
||||
<div class="input-box text-area">
|
||||
<el-input class="noinput" :rows="4" type="textarea" v-model="msgData.message" placeholder="请输入您的话术" />
|
||||
</div>
|
||||
<div class="input-box">
|
||||
<el-select v-model="msgData.msgCateId">
|
||||
<el-option v-for="item in selectData" :value="item.id" :key="item.value" :label="item.name"></el-option>
|
||||
</el-select>
|
||||
</div>
|
||||
<el-button v-db-click @click.stop="msgConfirm" class="subBtn" type="primary" :disabled="msgStatus"
|
||||
>确定</el-button
|
||||
>
|
||||
</el-dialog>
|
||||
<!-- 编辑弹窗 -->
|
||||
<div class="edit-box" v-if="isWordShow">
|
||||
<div class="head">
|
||||
<div class="tit-bar">
|
||||
{{ wordsTabCur ? '个人库' : '公共库' }}<span v-db-click @click.stop="isWordShow = false">完成</span>
|
||||
</div>
|
||||
<div class="input-box noinput">
|
||||
<el-input v-model="wordsData.searchTxt" placeholder="搜索快捷回复" :search="true" @on-search="bindSearch" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="scroll-box">
|
||||
<div class="scroll-left">
|
||||
<div class="top">
|
||||
<div class="left-item add_cate" v-db-click @click.stop="openCate(0)" v-if="wordsTabCur">
|
||||
<span class="iconfont iconjiahao"></span> 分组
|
||||
</div>
|
||||
<div
|
||||
class="left-item"
|
||||
:class="{ active: wordsData.cateId == item.id }"
|
||||
v-for="item in wordsData.cate"
|
||||
:key="item.id"
|
||||
v-db-click
|
||||
@click.stop="changeCate(item)"
|
||||
>
|
||||
{{ item.name }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="bom" v-if="wordsTabCur">
|
||||
<div class="left-item edits-box" v-db-click @click.stop="editList.status = true">编辑分组</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="right-box">
|
||||
<div class="right-scroll" @scroll="handleWordsScroll">
|
||||
<div class="msg-item" v-for="(item, index) in wordsList" :key="index">
|
||||
<span class="title">{{ item.title }}</span
|
||||
>{{ item.message }}
|
||||
<div class="edit-bar" v-if="wordsTabCur">
|
||||
<span class="iconfont iconbianji1" v-db-click @click.stop="bindEdit(item)"></span>
|
||||
<span class="iconfont iconshanchu1" v-db-click @click.stop="delMsg(item, '删除话术', index)"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 编辑分组列表 -->
|
||||
<el-dialog
|
||||
v-model="editList.status"
|
||||
width="470px"
|
||||
:show-close="true"
|
||||
custom-class="vertical-center-modal"
|
||||
class="words-box cate-list"
|
||||
>
|
||||
<div class="mask-title">
|
||||
编辑分组
|
||||
<span class="iconfont iconcha" v-db-click @click.stop="editList.status = false"></span>
|
||||
</div>
|
||||
<div class="list-box">
|
||||
<div class="item" v-for="(item, index) in wordsData.cate" :key="index" :index="index">
|
||||
<span>{{ item.name }}</span>
|
||||
<div class="right-box">
|
||||
<span class="iconfont iconbianji1" v-if="index > 0" v-db-click @click.stop="openCate(1, item)"></span>
|
||||
<span
|
||||
class="iconfont iconshanchu1"
|
||||
v-if="index > 0"
|
||||
v-db-click
|
||||
@click.stop="delCate(item, '删除分组', index)"
|
||||
></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive, computed, onMounted } from 'vue';
|
||||
import { ElMessage } from 'element-plus';
|
||||
import { modalSure } from '@/utils/public';
|
||||
import {
|
||||
speeChcraft,
|
||||
serviceCate,
|
||||
addServiceCate,
|
||||
addSpeeChcraft,
|
||||
serviceCateUpdate,
|
||||
editServiceCate,
|
||||
} from '@/pages/plugin/kefu/api';
|
||||
|
||||
defineOptions({ name: 'words' });
|
||||
|
||||
const props = defineProps({
|
||||
isWords: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
});
|
||||
|
||||
const emit = defineEmits(['selectMsg', 'closeBox']);
|
||||
|
||||
const isWordShow = ref(false); // 编辑窗
|
||||
const wordsList = ref([]);
|
||||
const wordsTab = ref([
|
||||
{
|
||||
title: '个人库',
|
||||
key: 1,
|
||||
},
|
||||
{
|
||||
title: '公共库',
|
||||
key: 0,
|
||||
},
|
||||
]);
|
||||
const wordsTabCur = ref(1);
|
||||
const wordsData = reactive({
|
||||
isScroll: true,
|
||||
page: 1,
|
||||
limit: 15,
|
||||
searchTxt: '',
|
||||
cate: [], // 分类
|
||||
cateId: '', // 分类id
|
||||
});
|
||||
// 话术列表请求进行中标记:触底滚动高频触发,避免重复请求同一页
|
||||
const wordsLoading = ref(false);
|
||||
// 分组数据
|
||||
const cateData = reactive({
|
||||
status: 0, // 0 新增 1编辑
|
||||
name: '',
|
||||
sort: '',
|
||||
isCate: false, // 分组状态开关
|
||||
id: '',
|
||||
});
|
||||
// 编辑分组列表
|
||||
const editList = reactive({
|
||||
status: false,
|
||||
});
|
||||
// 话术添加数据
|
||||
const msgData = reactive({
|
||||
isCateMeg: false,
|
||||
msgCateId: '',
|
||||
message: '',
|
||||
title: '',
|
||||
status: 0, // 0 新增 1修改
|
||||
editId: '',
|
||||
});
|
||||
const selectData = ref('');
|
||||
|
||||
const cateStatus = computed(() => {
|
||||
if (cateData.name && cateData.sort) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
const msgStatus = computed(() => {
|
||||
if (msgData.message) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
onMounted(() => {
|
||||
Promise.all([getServiceCate()]);
|
||||
});
|
||||
|
||||
// 关闭添加话术弹窗
|
||||
function closeMsgBox() {
|
||||
msgData.isCateMeg = false;
|
||||
}
|
||||
// 选择话术
|
||||
function selectWords(item) {
|
||||
emit('selectMsg', item.message);
|
||||
}
|
||||
// 关闭弹窗
|
||||
function closeBox() {
|
||||
emit('closeBox');
|
||||
}
|
||||
// 搜索
|
||||
function bindSearch() {
|
||||
wordsData.page = 1;
|
||||
wordsData.isScroll = true;
|
||||
wordsLoading.value = false;
|
||||
wordsList.value = [];
|
||||
getWordsList();
|
||||
}
|
||||
// 顶部切换
|
||||
function bindTab(item) {
|
||||
wordsTabCur.value = item.key;
|
||||
wordsData.isScroll = true;
|
||||
wordsLoading.value = false;
|
||||
wordsData.page = 1;
|
||||
wordsData.cate = [];
|
||||
wordsList.value = [];
|
||||
getServiceCate();
|
||||
}
|
||||
// 选择话术分类
|
||||
function changeCate(item) {
|
||||
wordsData.isScroll = true;
|
||||
wordsLoading.value = false;
|
||||
wordsList.value = [];
|
||||
wordsData.page = 1;
|
||||
wordsData.cateId = item.id;
|
||||
msgData.msgCateId = item.id;
|
||||
getWordsList();
|
||||
}
|
||||
// 获取话术分类
|
||||
function getServiceCate() {
|
||||
serviceCate({
|
||||
type: wordsTabCur.value,
|
||||
}).then((res) => {
|
||||
let tempArr = JSON.parse(JSON.stringify(res.data.data));
|
||||
wordsData.cateId = res.data.data.length ? res.data.data[0].id : '';
|
||||
msgData.msgCateId = wordsData.cateId;
|
||||
wordsData.cate = res.data.data;
|
||||
selectData.value = tempArr;
|
||||
getWordsList();
|
||||
});
|
||||
}
|
||||
// 原生滚动触底:距底部不足 10px 时加载下一页
|
||||
function handleWordsScroll(e) {
|
||||
const el = e.target;
|
||||
if (el.scrollTop + el.clientHeight >= el.scrollHeight - 10) {
|
||||
getWordsList();
|
||||
}
|
||||
}
|
||||
// 常用语
|
||||
function getWordsList() {
|
||||
if (!wordsData.isScroll || wordsLoading.value) return;
|
||||
wordsLoading.value = true;
|
||||
speeChcraft({
|
||||
page: wordsData.page,
|
||||
limit: wordsData.limit,
|
||||
title: wordsData.searchTxt,
|
||||
cate_id: wordsData.cateId,
|
||||
type: wordsTabCur.value,
|
||||
})
|
||||
.then((res) => {
|
||||
wordsLoading.value = false;
|
||||
wordsData.isScroll = res.data.length >= wordsData.limit;
|
||||
wordsList.value = wordsList.value.concat(res.data);
|
||||
wordsData.page++;
|
||||
})
|
||||
.catch(() => {
|
||||
wordsLoading.value = false;
|
||||
});
|
||||
}
|
||||
// 打开分组弹窗
|
||||
function openCate(key, item) {
|
||||
cateData.status = key;
|
||||
cateData.isCate = true;
|
||||
if (key == 1) {
|
||||
cateData.name = item.name;
|
||||
cateData.id = item.id;
|
||||
}
|
||||
}
|
||||
// 关闭分组弹窗
|
||||
function closeCate() {
|
||||
cateData.isCate = false;
|
||||
cateData.name = '';
|
||||
cateData.sort = '';
|
||||
}
|
||||
// 分组添加
|
||||
function cateConfirm() {
|
||||
if (!cateData.status) {
|
||||
addServiceCate({
|
||||
name: cateData.name,
|
||||
sort: cateData.sort,
|
||||
})
|
||||
.then((res) => {
|
||||
cateData.isCate = false;
|
||||
cateData.name = '';
|
||||
cateData.sort = '';
|
||||
wordsData.isScroll = true;
|
||||
wordsList.value = [];
|
||||
ElMessage.success(res.msg);
|
||||
getServiceCate();
|
||||
})
|
||||
.catch((error) => {
|
||||
ElMessage.error(error.msg);
|
||||
});
|
||||
} else {
|
||||
editServiceCate(cateData.id, {
|
||||
name: cateData.name,
|
||||
sort: cateData.sort,
|
||||
}).then((res) => {
|
||||
cateData.isCate = false;
|
||||
cateData.name = '';
|
||||
cateData.sort = '';
|
||||
cateData.id = '';
|
||||
wordsData.isScroll = true;
|
||||
wordsList.value = [];
|
||||
ElMessage.success(res.msg);
|
||||
getServiceCate();
|
||||
});
|
||||
}
|
||||
}
|
||||
// 话术打开
|
||||
function addMsg() {
|
||||
msgData.isCateMeg = true;
|
||||
msgData.status = 0;
|
||||
}
|
||||
// 话术添加
|
||||
function msgConfirm() {
|
||||
if (!msgData.status) {
|
||||
addSpeeChcraft({
|
||||
title: msgData.title,
|
||||
cate_id: msgData.msgCateId,
|
||||
message: msgData.message,
|
||||
})
|
||||
.then((res) => {
|
||||
msgData.isCateMeg = false;
|
||||
msgData.title = '';
|
||||
msgData.message = '';
|
||||
msgData.msgCateId = wordsData.cateId;
|
||||
ElMessage.success(res.msg);
|
||||
wordsData.isScroll = true;
|
||||
wordsData.page = 1;
|
||||
wordsList.value = [];
|
||||
getWordsList();
|
||||
})
|
||||
.catch((error) => {
|
||||
ElMessage.error(error.msg);
|
||||
});
|
||||
} else {
|
||||
serviceCateUpdate(msgData.editId, {
|
||||
title: msgData.title,
|
||||
cate_id: msgData.msgCateId,
|
||||
message: msgData.message,
|
||||
}).then((res) => {
|
||||
msgData.isCateMeg = false;
|
||||
msgData.title = '';
|
||||
msgData.message = '';
|
||||
msgData.msgCateId = wordsData.cateId;
|
||||
ElMessage.success(res.msg);
|
||||
wordsData.isScroll = true;
|
||||
wordsData.page = 1;
|
||||
wordsList.value = [];
|
||||
getWordsList();
|
||||
});
|
||||
}
|
||||
}
|
||||
// 编辑话术
|
||||
function bindEdit(item) {
|
||||
msgData.status = 1;
|
||||
msgData.isCateMeg = true;
|
||||
msgData.message = item.message;
|
||||
msgData.title = item.title;
|
||||
msgData.editId = item.id;
|
||||
}
|
||||
// 删除话术
|
||||
function delMsg(row, tit, num) {
|
||||
let delfromData = {
|
||||
title: tit,
|
||||
num: num,
|
||||
url: `/kefu/service/speechcraft/${row.id}`,
|
||||
method: 'DELETE',
|
||||
ids: '',
|
||||
kefu: true,
|
||||
};
|
||||
modalSure(delfromData)
|
||||
.then((res) => {
|
||||
wordsList.value.splice(num, 1);
|
||||
ElMessage.success(res.msg);
|
||||
})
|
||||
.catch((res) => {
|
||||
ElMessage.error(res.msg);
|
||||
});
|
||||
}
|
||||
function delCate(row, tit, num) {
|
||||
let delfromData = {
|
||||
title: tit,
|
||||
num: num,
|
||||
url: `/kefu/service/cate/${row.id}`,
|
||||
method: 'DELETE',
|
||||
ids: '',
|
||||
kefu: true,
|
||||
};
|
||||
modalSure(delfromData)
|
||||
.then((res) => {
|
||||
wordsData.cate.splice(num, 1);
|
||||
wordsData.isScroll = true;
|
||||
wordsList.value = [];
|
||||
ElMessage.success(res.msg);
|
||||
getServiceCate();
|
||||
})
|
||||
.catch((res) => {
|
||||
ElMessage.error(res.msg);
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
// 话术列表滚动容器(替代未注册的 vue-scroll):话术弹层与编辑窗两处共用
|
||||
.right-scroll {
|
||||
height: 100%;
|
||||
overflow-y: auto;
|
||||
}
|
||||
.words-mask {
|
||||
z-index: 50;
|
||||
position: fixed;
|
||||
left: 0;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
.content {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
top: 1.14rem;
|
||||
bottom: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background: #fff;
|
||||
border-radius: 0.06rem 0.06rem 0px 0px;
|
||||
.title-box {
|
||||
padding: 0 0.3rem 0.3rem;
|
||||
position: relative;
|
||||
border-bottom: 1px solid #f5f6f9;
|
||||
.tab-box {
|
||||
position: relative;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding: 0.4rem 2.2rem 0.3rem;
|
||||
font-size: 0.32rem;
|
||||
color: #9f9f9f;
|
||||
.on {
|
||||
color: #3875ea;
|
||||
font-weight: bold;
|
||||
}
|
||||
.right-icon {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
.iconfont {
|
||||
margin-left: 0.2rem;
|
||||
font-size: 0.48rem;
|
||||
color: #c8cad0;
|
||||
}
|
||||
}
|
||||
}
|
||||
.input-box {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
width: 6.9rem;
|
||||
height: 0.64rem;
|
||||
padding-right: 0.05rem;
|
||||
margin-left: 0.18rem;
|
||||
border-radius: 0.32rem;
|
||||
overflow: hidden;
|
||||
:deep(.el-input__inner) {
|
||||
background: #f5f6f9;
|
||||
}
|
||||
:deep(.el-input__inner),
|
||||
.el-input__inner:hover,
|
||||
.el-input__inner:focus {
|
||||
border: transparent;
|
||||
box-shadow: none;
|
||||
}
|
||||
}
|
||||
.icon-cha1 {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
}
|
||||
}
|
||||
.scroll-box {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
overflow: hidden;
|
||||
.scroll-left {
|
||||
width: 1.76rem;
|
||||
height: 100%;
|
||||
overflow-y: scroll;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
background: #f5f6f9;
|
||||
.left-item {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
height: 1.09rem;
|
||||
color: #282828;
|
||||
font-size: 0.26rem;
|
||||
&.active {
|
||||
color: #3875ea;
|
||||
background: #fff;
|
||||
&:after {
|
||||
content: ' ';
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
width: 0.06rem;
|
||||
height: 0.46rem;
|
||||
background: #3875ea;
|
||||
}
|
||||
}
|
||||
&.add_cate {
|
||||
color: #9f9f9f;
|
||||
font-size: 0.26rem;
|
||||
.iconfont {
|
||||
margin-right: 0.1rem;
|
||||
font-size: 0.24rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.right-box {
|
||||
flex: 1;
|
||||
overflow: scroll;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
.msg-item {
|
||||
padding: 0.25rem 0.3rem;
|
||||
color: #888888;
|
||||
font-size: 0.28rem;
|
||||
.title {
|
||||
margin-right: 0.2rem;
|
||||
color: #282828;
|
||||
}
|
||||
&.add-mg {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
font-size: 0.28rem;
|
||||
padding: 0.15rem 0.3rem;
|
||||
.iconfont {
|
||||
font-size: 0.36rem;
|
||||
margin-right: 0.1rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.words-box {
|
||||
.mask-title {
|
||||
position: relative;
|
||||
text-align: center;
|
||||
margin-bottom: 0.5rem;
|
||||
color: #282828;
|
||||
font-size: 0.32rem;
|
||||
font-weight: bold;
|
||||
.iconfont {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
color: #c8cad0;
|
||||
font-size: 0.44rem;
|
||||
font-weight: normal;
|
||||
}
|
||||
}
|
||||
.input-box {
|
||||
height: 0.68rem;
|
||||
margin-top: 0.32rem;
|
||||
background: #f5f5f5;
|
||||
border-radius: 0.14rem;
|
||||
&.text-area {
|
||||
height: 1.92rem;
|
||||
textarea {
|
||||
display: block;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
.subBtn {
|
||||
width: 100%;
|
||||
height: 0.86rem;
|
||||
margin-top: 0.6rem;
|
||||
margin-bottom: 0.3rem;
|
||||
font-size: 0.3rem !important;
|
||||
border-radius: 0.43rem;
|
||||
&[disabled] {
|
||||
background: #c8cad0;
|
||||
color: #fff;
|
||||
font-size: 0.3rem !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
.edit-box {
|
||||
z-index: 99;
|
||||
position: fixed;
|
||||
left: 0;
|
||||
right: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background: #fff;
|
||||
.head {
|
||||
padding: 0.4rem 0.3rem 0.3rem;
|
||||
.tit-bar {
|
||||
position: relative;
|
||||
text-align: center;
|
||||
font-size: 0.32rem;
|
||||
color: #282828;
|
||||
font-weight: bold;
|
||||
span {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
color: #3875ea;
|
||||
font-size: 0.28rem;
|
||||
font-weight: normal;
|
||||
}
|
||||
}
|
||||
.input-box {
|
||||
margin-top: 0.3rem;
|
||||
background: #f5f6f9;
|
||||
border-radius: 0.39rem;
|
||||
}
|
||||
}
|
||||
.scroll-box {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
overflow: hidden;
|
||||
.scroll-left {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
position: relative;
|
||||
width: 1.76rem;
|
||||
height: 100%;
|
||||
background: #f5f6f9;
|
||||
.top {
|
||||
flex: 1;
|
||||
overflow-y: scroll;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
.left-item {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
height: 1.09rem;
|
||||
color: #282828;
|
||||
font-size: 0.26rem;
|
||||
&.active {
|
||||
color: #3875ea;
|
||||
background: #fff;
|
||||
&:after {
|
||||
content: ' ';
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
width: 0.06rem;
|
||||
height: 0.46rem;
|
||||
background: #3875ea;
|
||||
}
|
||||
}
|
||||
&.add_cate {
|
||||
color: #9f9f9f;
|
||||
font-size: 0.26rem;
|
||||
.iconfont {
|
||||
margin-right: 0.1rem;
|
||||
font-size: 0.24rem;
|
||||
}
|
||||
}
|
||||
&.edits-box {
|
||||
color: #3875ea;
|
||||
}
|
||||
}
|
||||
}
|
||||
.right-box {
|
||||
flex: 1;
|
||||
padding-left: 0.3rem;
|
||||
}
|
||||
.msg-item {
|
||||
padding: 0.25rem 0.3rem 0.25rem 0;
|
||||
color: #888888;
|
||||
font-size: 0.28rem;
|
||||
.title {
|
||||
margin-right: 0.2rem;
|
||||
color: #282828;
|
||||
}
|
||||
&.add-mg {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
font-size: 0.28rem;
|
||||
padding: 0.15rem 0.3rem;
|
||||
.iconfont {
|
||||
font-size: 0.36rem;
|
||||
margin-right: 0.1rem;
|
||||
}
|
||||
}
|
||||
.edit-bar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
margin-top: 0.25rem;
|
||||
padding-bottom: 0.1rem;
|
||||
border-bottom: 1px solid #f0f2f7;
|
||||
.iconfont {
|
||||
margin-left: 0.3rem;
|
||||
font-size: 0.32rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.cate-list {
|
||||
.list-box {
|
||||
max-height: 7.5rem;
|
||||
overflow-y: scroll;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
.item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
height: 1rem;
|
||||
border-bottom: 1px solid #f0f2f7;
|
||||
color: #282828;
|
||||
font-size: 0.28rem;
|
||||
.iconfont {
|
||||
color: #9f9f9f;
|
||||
font-size: 0.32rem;
|
||||
margin-left: 0.4rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<style>
|
||||
.kf_mobile .ivu-modal-wrap {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.vertical-center-modal {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.ivu-modal {
|
||||
top: 0;
|
||||
}
|
||||
.noinput input,
|
||||
.noinput textarea {
|
||||
border-color: transparent !important;
|
||||
background: transparent !important;
|
||||
resize: none;
|
||||
}
|
||||
.noinput input:hover,
|
||||
.noinput input:focus,
|
||||
.noinput textarea:hover,
|
||||
.noinput textarea:focus {
|
||||
border-color: transparent !important;
|
||||
box-shadow: none !important;
|
||||
}
|
||||
</style>
|
||||
@ -1,554 +0,0 @@
|
||||
<template>
|
||||
<div class="wrapper-box">
|
||||
<div class="page-account kf">
|
||||
<div class="content">
|
||||
<img :src="copyrightImg" alt="" />
|
||||
<div class="desc">
|
||||
<p class="tit">让客户服务如此简单</p>
|
||||
<p class="kefu">专业客服系统<br />助力企业打造一流的服务体验</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="container" :class="[fullWidth > 768 ? 'containerSamll' : 'containerBig']">
|
||||
<div class="index_from page-account-container">
|
||||
<div :style="{ display: !loginType ? 'block' : 'none' }">
|
||||
<div class="page-account-top">
|
||||
<div class="page-account-top-logo">客服登录</div>
|
||||
</div>
|
||||
<el-form ref="formInlineRef" :model="formInline" :rules="ruleInline" @keyup.enter="handleSubmit()">
|
||||
<el-form-item class="mb20" prop="username">
|
||||
<el-input type="text" v-model="formInline.username" placeholder="请输入用户名" size="large" />
|
||||
</el-form-item>
|
||||
<el-form-item class="mb20" prop="password">
|
||||
<el-input type="password" v-model="formInline.password" placeholder="请输入密码" size="large" />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" size="large" v-db-click @click="handleSubmit()" class="btn">登录 </el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div class="qh_box" v-if="!isMobile" v-db-click @click="bindScan">
|
||||
<span class="iconfont iconerweima2"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div :style="{ display: loginType ? 'block' : 'none' }">
|
||||
<div class="page-account-top">
|
||||
<div class="page-account-top-logo">微信扫码登录</div>
|
||||
</div>
|
||||
<div class="code-box">
|
||||
<div class="qrcode" ref="qrCodeUrl"></div>
|
||||
<div class="rxpired-box" v-show="rxpired">
|
||||
<p>已过期</p>
|
||||
<el-button type="primary" v-db-click @click="bindRefresh">点击刷新</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="qh_box" v-db-click @click="loginType = 0"><span class="iconfont iconzhanghaomima"></span></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="foot-box" v-if="copyright">{{ copyright }}</div>
|
||||
<div class="foot-box" v-else>
|
||||
Copyright © 2016~2026 <a href="https://www.crmeb.com" target="_blank">{{ version }}</a>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script setup>
|
||||
import __asset_sw_0 from '@/assets/images/sw.jpg';
|
||||
import __asset_logo_dark_1 from '@/assets/images/logo-dark.png';
|
||||
|
||||
import { ref, watch, onMounted, onBeforeUnmount } from 'vue';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
import { ElMessage } from 'element-plus';
|
||||
import { AccountLogin, getSanCodeKey, scanStatus, kefuConfig } from '@/pages/plugin/kefu/api';
|
||||
import Setting from '@/setting';
|
||||
import QRCode from '@/vendor/qrcodejs2';
|
||||
import { setCookies } from '@/libs/util';
|
||||
import { useMediaStore } from '@/store/module/media';
|
||||
import { useKefuStore } from '@/pages/plugin/kefu/store';
|
||||
|
||||
defineOptions({ name: 'kefu_index' });
|
||||
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
const mediaStore = useMediaStore();
|
||||
const kefuStore = useKefuStore();
|
||||
|
||||
const formInlineRef = ref(null);
|
||||
const qrCodeUrl = ref(null);
|
||||
|
||||
const fullWidth = ref(document.documentElement.clientWidth);
|
||||
const swiperOption = ref({
|
||||
pagination: '.swiper-pagination',
|
||||
autoplay: true,
|
||||
});
|
||||
const modals = ref(false);
|
||||
const autoLogin = ref(true);
|
||||
const imgcode = ref('');
|
||||
const formInline = ref({
|
||||
username: '',
|
||||
password: '',
|
||||
code: '',
|
||||
});
|
||||
const ruleInline = {
|
||||
username: [{ required: true, message: '请输入用户名', trigger: 'blur' }],
|
||||
password: [{ required: true, message: '请输入密码', trigger: 'blur' }],
|
||||
code: [{ required: true, message: '请输入验证码', trigger: 'blur' }],
|
||||
};
|
||||
const errorNum = ref(0);
|
||||
const jigsaw = ref(null);
|
||||
const login_logo = ref('');
|
||||
const swiperList = ref([]);
|
||||
const defaultSwiperList = ref(__asset_sw_0);
|
||||
const loginType = ref(0); // 0 账号 1 扫码
|
||||
const codeKey = ref('');
|
||||
const scanTime = ref('');
|
||||
const rxpired = ref(false); // 扫码是否过期
|
||||
const isMobile = ref(false);
|
||||
const version = ref(''); //版本号
|
||||
const isScan = ref(false);
|
||||
const timeNum = ref(0);
|
||||
const copyright = ref('');
|
||||
const copyrightImg = ref(__asset_logo_dark_1);
|
||||
|
||||
// created
|
||||
kefuConfig().then((res) => {
|
||||
version.value = res.data.version;
|
||||
copyright.value = res.data.copyright;
|
||||
if (res.data.site_name) {
|
||||
document.title = res.data.site_name;
|
||||
}
|
||||
if (res.data.copyrightImg) {
|
||||
copyrightImg.value = res.data.copyrightImg;
|
||||
}
|
||||
});
|
||||
isMobile.value = mediaStore.isMobile;
|
||||
top != window && (top.location.href = location.href);
|
||||
document.onkeydown = function (e) {
|
||||
if (route.name === 'login') {
|
||||
let key = window.event.keyCode;
|
||||
if (key === 13) {
|
||||
handleSubmit();
|
||||
}
|
||||
}
|
||||
};
|
||||
window.addEventListener('resize', handleResize);
|
||||
|
||||
// 为了避免频繁触发resize函数导致页面卡顿,使用定时器(原实现中 screenWidth 从未被读取,此处仅保留节流语义)
|
||||
let resizeTimer = false;
|
||||
watch(fullWidth, (val) => {
|
||||
if (!resizeTimer) {
|
||||
resizeTimer = true;
|
||||
setTimeout(function () {
|
||||
resizeTimer = false;
|
||||
}, 400);
|
||||
}
|
||||
});
|
||||
|
||||
watch(
|
||||
() => route.path,
|
||||
() => {
|
||||
captchas();
|
||||
},
|
||||
);
|
||||
|
||||
onMounted(function () {
|
||||
captchas();
|
||||
});
|
||||
|
||||
onBeforeUnmount(function () {
|
||||
timeNum.value = 0;
|
||||
if (qrCodeUrl.value) qrCodeUrl.value.innerHTML = '';
|
||||
window.clearInterval(scanTime.value);
|
||||
window.removeEventListener('resize', handleResize);
|
||||
});
|
||||
|
||||
// 切换扫码
|
||||
function bindScan() {
|
||||
if (!isScan.value) {
|
||||
isScan.value = true;
|
||||
getSanCodeKeyData();
|
||||
}
|
||||
loginType.value = 1;
|
||||
}
|
||||
// 生成二维码
|
||||
function creatQrCode() {
|
||||
let url = `${window.location.protocol}//${window.location.host}/pages/users/scan_login/index?key=${codeKey.value}`;
|
||||
var qrcode = new QRCode(qrCodeUrl.value, {
|
||||
text: url, // 需要转换为二维码的内容
|
||||
width: 160,
|
||||
height: 160,
|
||||
colorDark: '#000000',
|
||||
colorLight: '#ffffff',
|
||||
correctLevel: QRCode.CorrectLevel.H,
|
||||
});
|
||||
}
|
||||
// 关闭模态框
|
||||
function closeModel() {
|
||||
AccountLogin({
|
||||
account: formInline.value.username,
|
||||
password: formInline.value.password,
|
||||
imgcode: formInline.value.code,
|
||||
})
|
||||
.then(async (res) => {
|
||||
let expires = getExpiresTime(res.data.exp_time);
|
||||
// 记录用户登录信息
|
||||
setCookies('kefu_uuid', res.data.kefuInfo.uid, expires);
|
||||
setCookies('kefu_token', res.data.token, expires);
|
||||
setCookies('kefu_expires_time', res.data.exp_time, expires);
|
||||
// js-cookie 存对象会被 String() 成 "[object Object]",必须显式序列化为 JSON 字符串(对话页 JSON.parse 解析)
|
||||
setCookies('kefuInfo', JSON.stringify(res.data.kefuInfo), expires);
|
||||
|
||||
// 记录用户信息
|
||||
kefuStore.setInfo(res.data.kefuInfo);
|
||||
|
||||
if (mediaStore.isMobile) {
|
||||
//手机页面
|
||||
return router.replace({ path: route.query.redirect || Setting.routePre + '/kefu/mobile_list' });
|
||||
} else {
|
||||
// pc页面
|
||||
return router.replace({ path: route.query.redirect || Setting.routePre + '/kefu/pc_list' });
|
||||
}
|
||||
})
|
||||
.catch((res) => {
|
||||
let data = res === undefined ? {} : res;
|
||||
errorNum.value++;
|
||||
captchas();
|
||||
ElMessage.error(data.msg || '登录失败');
|
||||
if (jigsaw.value) jigsaw.value.reset();
|
||||
});
|
||||
}
|
||||
function getExpiresTime(expiresTime) {
|
||||
let nowTimeNum = Math.round(new Date() / 1000);
|
||||
let expiresTimeNum = expiresTime - nowTimeNum;
|
||||
return parseFloat(parseFloat(parseFloat(expiresTimeNum / 60) / 60) / 24);
|
||||
}
|
||||
function closefail() {
|
||||
if (jigsaw.value) jigsaw.value.reset();
|
||||
ElMessage.error('校验错误');
|
||||
}
|
||||
function handleResize(event) {
|
||||
fullWidth.value = document.documentElement.clientWidth;
|
||||
}
|
||||
function captchas() {
|
||||
imgcode.value = Setting.apiBaseURL + '/captcha_pro?' + Date.parse(new Date());
|
||||
}
|
||||
function handleSubmit() {
|
||||
formInlineRef.value.validate((valid) => {
|
||||
if (valid) {
|
||||
closeModel();
|
||||
}
|
||||
});
|
||||
}
|
||||
// 获取客服扫码key(原方法名与导入的 api 同名,改名避免遮蔽)
|
||||
function getSanCodeKeyData() {
|
||||
getSanCodeKey()
|
||||
.then((res) => {
|
||||
codeKey.value = res.data.key;
|
||||
creatQrCode();
|
||||
scanTime.value = setInterval(() => {
|
||||
timeNum.value++;
|
||||
if (timeNum.value >= 60) {
|
||||
timeNum.value = 0;
|
||||
window.clearInterval(scanTime.value);
|
||||
rxpired.value = true;
|
||||
} else {
|
||||
getScanStatus();
|
||||
}
|
||||
}, 1000);
|
||||
})
|
||||
.catch((error) => {
|
||||
timeNum.value = 0;
|
||||
window.clearInterval(scanTime.value);
|
||||
rxpired.value = true;
|
||||
ElMessage.error(error.msg);
|
||||
});
|
||||
}
|
||||
// 扫码登录情况
|
||||
function getScanStatus() {
|
||||
scanStatus(codeKey.value)
|
||||
.then(async (res) => {
|
||||
// 0 = 二维码过期需要重新获取授权凭证
|
||||
if (res.data.status == 0) {
|
||||
timeNum.value = 0;
|
||||
window.clearInterval(scanTime.value);
|
||||
rxpired.value = true;
|
||||
}
|
||||
// 1=正在扫描
|
||||
if (res.data.status == 1) {
|
||||
}
|
||||
// 3 扫描成功正在登录
|
||||
if (res.data.status == 3) {
|
||||
window.clearInterval(scanTime.value);
|
||||
let expires = getExpiresTime(res.data.exp_time);
|
||||
// 记录用户登录信息
|
||||
setCookies('kefu_uuid', res.data.kefuInfo.uid, expires);
|
||||
setCookies('kefu_token', res.data.token, expires);
|
||||
setCookies('kefu_expires_time', res.data.exp_time, expires);
|
||||
setCookies('kefuInfo', res.data.kefuInfo, expires);
|
||||
// 记录用户信息
|
||||
kefuStore.setInfo(res.data.kefuInfo);
|
||||
if (mediaStore.isMobile) {
|
||||
//手机页面
|
||||
return router.replace({ path: route.query.redirect || Setting.routePre + '/kefu/mobile_list' });
|
||||
} else {
|
||||
// pc页面
|
||||
return router.replace({ path: route.query.redirect || Setting.routePre + '/kefu/pc_list' });
|
||||
}
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
ElMessage.error(error.msg);
|
||||
timeNum.value = 0;
|
||||
window.clearInterval(scanTime.value);
|
||||
rxpired.value = true;
|
||||
});
|
||||
}
|
||||
// 刷新二维码
|
||||
function bindRefresh() {
|
||||
qrCodeUrl.value.innerHTML = '';
|
||||
rxpired.value = false;
|
||||
getSanCodeKeyData();
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.page-account {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
background-image: url('@/assets/images/kfbg_2.jpg');
|
||||
background-size: cover;
|
||||
background-position: center;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 100vh;
|
||||
overflow: auto;
|
||||
.content {
|
||||
height: 400px;
|
||||
margin-right: 100px;
|
||||
.desc {
|
||||
color: #fff;
|
||||
.tit {
|
||||
font-size: 40px;
|
||||
font-weight: 600;
|
||||
}
|
||||
.kefu {
|
||||
margin-top: 30px;
|
||||
font-weight: 500;
|
||||
font-size: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
img {
|
||||
width: 360px;
|
||||
margin-left: -100px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.code-box {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
.qrcode {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 180px;
|
||||
height: 180px;
|
||||
border: 1px solid #e5e5e6;
|
||||
}
|
||||
.rxpired-box {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
width: 160px;
|
||||
height: 160px;
|
||||
background: rgba(0, 0, 0, 0.6);
|
||||
|
||||
p {
|
||||
margin-bottom: 10px;
|
||||
font-size: 15px;
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
.page-account-top-logo {
|
||||
color: #000000;
|
||||
font-size: 21px;
|
||||
}
|
||||
.wrapper-box {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100vh;
|
||||
.foot-box {
|
||||
padding: 20px 20px;
|
||||
font-size: 14px;
|
||||
color: #666666;
|
||||
text-align: right;
|
||||
box-sizing: border-box;
|
||||
|
||||
a {
|
||||
margin-left: 0;
|
||||
color: #666666;
|
||||
}
|
||||
}
|
||||
}
|
||||
.page-account {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
}
|
||||
.page-account .code {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.page-account .code .pictrue {
|
||||
height: 40px;
|
||||
}
|
||||
.swiperPross {
|
||||
border-radius: 6px 0px 0px 6px;
|
||||
}
|
||||
.swiperPross,
|
||||
.swiperPic,
|
||||
.swiperPic img {
|
||||
width: 510px;
|
||||
height: 100%;
|
||||
}
|
||||
.swiperPic img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
.container {
|
||||
height: 400px !important;
|
||||
padding: 0 !important;
|
||||
/* overflow: hidden; */
|
||||
border-radius: 6px;
|
||||
z-index: 1;
|
||||
display: flex;
|
||||
}
|
||||
.containerSamll {
|
||||
width: 384px !important;
|
||||
|
||||
background: #fff !important;
|
||||
}
|
||||
.containerBig {
|
||||
width: 90%;
|
||||
padding-bottom: 20px;
|
||||
margin-top: 84px;
|
||||
background: #f7f7f7 !important;
|
||||
height: auto !important;
|
||||
box-shadow: 0px 3px 20px rgba(0, 20, 41, 0.06);
|
||||
}
|
||||
.index_from {
|
||||
position: relative;
|
||||
padding: 40px 40px 32px 40px;
|
||||
height: 400px;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.containerBig .index_from {
|
||||
padding: 20px;
|
||||
height: auto !important;
|
||||
}
|
||||
.index_from .qh_box {
|
||||
position: absolute;
|
||||
right: 12px;
|
||||
top: 0;
|
||||
cursor: pointer;
|
||||
.iconfont {
|
||||
color: #265bed;
|
||||
font-size: 36px;
|
||||
}
|
||||
}
|
||||
.page-account-top {
|
||||
padding: 20px 0 50px !important;
|
||||
box-sizing: border-box !important;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
.page-account-container {
|
||||
border-radius: 0px 6px 6px 0px;
|
||||
}
|
||||
.btn {
|
||||
width: 100%;
|
||||
background: #265bed;
|
||||
}
|
||||
.captchaBox {
|
||||
width: 310px;
|
||||
}
|
||||
|
||||
input {
|
||||
display: block;
|
||||
width: 290px;
|
||||
line-height: 40px;
|
||||
margin: 10px 0;
|
||||
padding: 0 10px;
|
||||
outline: none;
|
||||
border: 1px solid #c8cccf;
|
||||
border-radius: 4px;
|
||||
color: #6a6f77;
|
||||
}
|
||||
|
||||
#msg {
|
||||
width: 100%;
|
||||
line-height: 40px;
|
||||
font-size: 14px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
a:link,
|
||||
a:visited,
|
||||
a:hover,
|
||||
a:active {
|
||||
margin-left: 100px;
|
||||
color: #0366d6;
|
||||
}
|
||||
.index_from :deep(.ivu-input-large) {
|
||||
font-size: 14px !important;
|
||||
}
|
||||
</style>
|
||||
<style>
|
||||
@media screen and (min-width: 320px) and (max-width: 960px) {
|
||||
.page-account {
|
||||
background-image: url('@/assets/images/m_bg.png') !important;
|
||||
background-size: 100% auto !important;
|
||||
background-repeat: no-repeat;
|
||||
background-position: left top !important;
|
||||
display: flex;
|
||||
}
|
||||
.wrapper-box .foot-box {
|
||||
text-align: center !important;
|
||||
}
|
||||
.content {
|
||||
display: none;
|
||||
}
|
||||
.index_from {
|
||||
box-shadow: 0px 3px 20px rgba(0, 20, 41, 0.06);
|
||||
background: #fff;
|
||||
}
|
||||
.wrapper-box .foot-box {
|
||||
padding: 20px 66px !important;
|
||||
color: #adadad !important;
|
||||
font-size: 0.22rem !important;
|
||||
}
|
||||
.containerBig {
|
||||
width: 86% !important;
|
||||
border-radius: 0.2rem !important;
|
||||
overflow: hidden;
|
||||
}
|
||||
.btn {
|
||||
background: linear-gradient(90deg, #3875ea 0%, #1890fc 100%) !important;
|
||||
|
||||
border-radius: 0.41rem;
|
||||
}
|
||||
.ivu-input {
|
||||
border: 1px solid #dcdee2;
|
||||
-webkit-appearance: none; /*去除阴影边框*/
|
||||
outline: none;
|
||||
-webkit-tap-highlight-color: rgba(0, 0, 0, 0); /*点击高亮的颜色*/
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user