From e3a81bb63ffaaf499cdc55189693b104652acd00 Mon Sep 17 00:00:00 2001
From: cloudroam <cloudroam>
Date: 星期三, 14 五月 2025 10:22:44 +0800
Subject: [PATCH] 2
---
pages/mark-up/edit-partner/_partnerId/goods.vue | 29
plugins/utils.js | 104
pages/index.vue | 7
pages/home.vue | 426 +
pages/marketing/coupon/member/index.vue | 80
pages/order/list/_id.vue | 780 ++
pages/marketing/point-mall/point-distribution.vue | 250
pages/wallet/withdraw-audit.vue | 166
pages/mark-up/edit-partner/index.vue | 121
pages/marketing/point-mall/goods.vue | 254
services/auth.js | 25
pages/order/list/index.vue | 508 +
plugins/httpLang/en.js | 7
pages/marketing/coupon/receive-record.vue | 128
pages/goods/param/index.vue | 89
pages/mark-up/partner/_partnerId/category.vue | 38
pages/marketing/coupon/user/_id.vue | 71
plugins/icons.js | 500 +
pages/partner/list.vue | 434 +
services/base.js | 25
pages/goods/param/_id.vue | 59
pages/settlement/list/_id.vue | 191
pages/shop/list.vue | 154
pages/report/finance/index.vue | 400 +
plugins/element-ui.js | 18
pages/content/notice.vue | 187
pages/settlement/list/index.vue | 143
pages/bill/_type/_id.vue | 78
pages/district/tengxun/index.vue | 210
pages/goods/tag.vue | 51
pages/marketing/member-level.vue | 230
pages/content/advertisement.vue | 169
pages/mark-up/range.vue | 72
pages/sms/template/index.vue | 123
pages/wallet/supplier-finance.vue | 93
pages/marketing/coupon/member/_id.vue | 67
pages/statistics-analysis/flower-material/index.vue | 266 +
pages/report/supplier.vue | 188
pages/sms/send-batch/index.vue | 353 +
pages/goods/zone/_id.vue | 103
pages/mark-up/partner/index.vue | 58
pages/mark-up/edit-partner/_partnerId/category.vue | 28
pages/order/evaluation/index.vue | 323 +
pages/feedback.vue | 175
pages/content/filmset.vue | 187
pages/goods/list/_action/_id.vue | 198
pages/setting/freight/index.vue | 68
plugins/mixins/coupon-detail.vue | 27
pages/report/finance/_date.vue | 139
pages/supplier/sub-list.vue | 236
pages/warehouse.vue | 291 +
pages/sys/dict/index.vue | 87
pages/content/banner.vue | 204
pages/order/after-sale/index.vue | 364 +
pages/goods/category-list.vue | 331 +
pages/marketing/coupon/activity/index.vue | 392 +
pages/sys/partner-menu.vue | 97
pages/regular/config-param.vue | 143
services/index.js | 20
pages/supplier/list.vue | 393 +
pages/goods/list/index.vue | 637 ++
pages/report/partner/_date.vue | 143
pages/mark-up/partner/_partnerId/goods.vue | 38
pages/marketing/point-mall/coupon/index.vue | 252
pages/marketing/coupon/user/index.vue | 138
pages/order/after-sale/_action/_id.vue | 185
pages/regular/config-customer.vue | 109
pages/regular/sys.vue | 357 +
plugins/el-business.js | 57
pages/sys/role.vue | 80
pages/setting/service-charge.vue | 76
pages/supplier/collection-station.vue | 146
pages/sys/menu.vue | 97
pages/report/partner/index.vue | 254
pages/marketing/coupon/activity/_id.vue | 75
pages/sys/dict/_id.vue | 76
pages/sys/user.vue | 297 +
pages/sms/send-batch/_id.vue | 135
pages/bill/_type/index.vue | 174
pages/login.vue | 332 +
pages/goods/zone/index.vue | 103
pages/regular/config-param-group.vue | 64
pages/statistics-analysis/flower-sale/index.vue | 301 +
pages/setting/freight/_id.vue | 184
pages/sys/app-menu.vue | 149
pages/district/gaode/index.vue | 217
pages/marketing/member-record.vue | 83
pages/log/operation-record.vue | 77
pages/marketing/point-mall/coupon/_id.vue | 65
pages/supplier/type.vue | 56
pages/content/info.vue | 42
91 files changed, 15,957 insertions(+), 0 deletions(-)
diff --git a/pages/bill/_type/_id.vue b/pages/bill/_type/_id.vue
new file mode 100644
index 0000000..f6e9dd4
--- /dev/null
+++ b/pages/bill/_type/_id.vue
@@ -0,0 +1,78 @@
+<template>
+ <el-bus-crud v-bind="tableConfig"></el-bus-crud>
+</template>
+
+<script>
+import { dateRangeOptions } from '@/utils/options'
+import CustomDateRange from '@/components/custom-date-range.vue'
+export default {
+ data() {
+ return {
+ tableConfig: {
+ url: 'flower/api/order/list',
+ hasNew: false,
+ hasEdit: false,
+ hasDelete: false,
+ onResetView: (row) => {
+ this.$router.push(`/order/list/${row.id}`)
+ },
+ extraQuery: {
+ billId: this.$route.params.id,
+ },
+ columns: [
+ { label: '序号', type: 'index' },
+ { label: '订单号', prop: 'orderNo' },
+ { label: '收货人', prop: 'customer' },
+ { label: '花款(售价)', prop: 'totalAmount' },
+ { label: '花款(底价)', prop: 'supplierAmount' },
+ ],
+ searchFormAttrs: {
+ labelWidth: 'auto',
+ },
+ searchForm: [
+ {
+ type: 'row',
+ span: 6,
+ items: [
+ {
+ label: '下单日期:',
+ id: 'dateType',
+ component: CustomDateRange,
+ el: {
+ options: dateRangeOptions,
+ },
+ searchImmediately: true,
+ commonFormat: true,
+ commonFormatProps: [
+ 'dateType',
+ 'createStartDateStr',
+ 'createEndDateStr',
+ ],
+ span: 24,
+ },
+ { label: '订单号:', id: 'orderNo', type: 'input' },
+ { label: '商品名称:', id: 'flowerName', type: 'input' },
+ {
+ label: '收货人:',
+ id: 'customer',
+ type: 'input',
+ el: { placeholder: '收货人姓名/手机号' },
+ },
+ ],
+ },
+ ],
+ },
+ }
+ },
+ head() {
+ return {
+ title: this.isPartner ? '合伙人账单结算明细' : '普通账单结算明细',
+ }
+ },
+ computed: {
+ isPartner() {
+ return this.$route.params.type === 'partner'
+ },
+ },
+}
+</script>
diff --git a/pages/bill/_type/index.vue b/pages/bill/_type/index.vue
new file mode 100644
index 0000000..c852983
--- /dev/null
+++ b/pages/bill/_type/index.vue
@@ -0,0 +1,174 @@
+<template>
+ <div>
+ <el-row :gutter="20">
+ <el-col :span="4" class="mb-10">
+ <el-card>
+ <div class="statistic-title">售价合计</div>
+ <div class="statistic-num">{{ statistic.orderAmount }}</div>
+ </el-card>
+ </el-col>
+ <el-col :span="4" class="mb-10">
+ <el-card>
+ <div class="statistic-title">底价合计</div>
+ <div class="statistic-num">{{ statistic.supplierAmount }}</div>
+ </el-card>
+ </el-col>
+ <el-col :span="4" class="mb-10">
+ <el-card>
+ <div class="statistic-title">打包费</div>
+ <div class="statistic-num">{{ statistic.packingFee }}</div>
+ </el-card>
+ </el-col>
+ <el-col :span="4" class="mb-10">
+ <el-card>
+ <div class="statistic-title">运费</div>
+ <div class="statistic-num">{{ statistic.transportFee }}</div>
+ </el-card>
+ </el-col>
+ <el-col :span="4" class="mb-10">
+ <el-card>
+ <div class="statistic-title">区间加价</div>
+ <div class="statistic-num">{{ statistic.markupOne }}</div>
+ </el-card>
+ </el-col>
+ <el-col v-if="isPartner" :span="4" class="mb-10">
+ <el-card>
+ <div class="statistic-title">平台加价</div>
+ <div class="statistic-num">{{ statistic.markupTwo }}</div>
+ </el-card>
+ </el-col>
+ <el-col v-if="isPartner" :span="4" class="mb-10">
+ <el-card>
+ <div class="statistic-title">合伙人加价</div>
+ <div class="statistic-num">{{ statistic.markupPartner }}</div>
+ </el-card>
+ </el-col>
+ <el-col :span="4" class="mb-10">
+ <el-card>
+ <div class="statistic-title">质检退款</div>
+ <div class="statistic-num">{{ statistic.deductAmount }}</div>
+ </el-card>
+ </el-col>
+ <el-col :span="4" class="mb-10">
+ <el-card>
+ <div class="statistic-title">售后退款</div>
+ <div class="statistic-num">{{ statistic.salesAmount }}</div>
+ </el-card>
+ </el-col>
+ <el-col :span="4" class="mb-10">
+ <el-card>
+ <div class="statistic-title">优惠券金额</div>
+ <div class="statistic-num">{{ statistic.memberCouponAmount }}</div>
+ </el-card>
+ </el-col>
+ <el-col :span="4" class="mb-10">
+ <el-card>
+ <div class="statistic-title">利润合计</div>
+ <div class="statistic-num">{{ statistic.profitAmount }}</div>
+ </el-card>
+ </el-col>
+ </el-row>
+ <el-bus-crud v-bind="tableConfig" />
+ </div>
+</template>
+
+<script>
+export default {
+ data() {
+ return {
+ statistic: {},
+ tableConfig: {
+ url: `flower/api/bill/list/${this.$route.params.type}`,
+ hasNew: false,
+ hasEdit: false,
+ hasDelete: false,
+ hasView: false,
+ oprationAttrs: {
+ width: 120,
+ fixed: 'right',
+ },
+ beforeRequest: async (params) => {
+ const { code, data } = await this.$elBusHttp.request(
+ `flower/api/bill/statistics/${this.$route.params.type}`,
+ { params }
+ )
+ if (code === 0) {
+ this.statistic = data || {}
+ }
+ },
+ columns: [
+ { label: '序号', type: 'index', minWidth: 60 },
+ { label: '花款(售价)', prop: 'orderAmount', minWidth: 150 },
+ { label: '花款(底价)', prop: 'supplierAmount', minWidth: 150 },
+ { label: '发货数', prop: 'num', minWidth: 150 },
+ { label: '打包费', prop: 'packingFee', minWidth: 150 },
+ { label: '运费', prop: 'transportFee', minWidth: 150 },
+ { label: '区间加价', prop: 'markupOne', minWidth: 150 },
+ {
+ label: '平台加价',
+ prop: 'markupTwo',
+ minWidth: 150,
+ hidden: () => this.$route.params.type !== 'partner',
+ },
+ {
+ label: '合伙人加价',
+ prop: 'markupPartner',
+ minWidth: 150,
+ hidden: () => this.$route.params.type !== 'partner',
+ },
+ { label: '质检退款', prop: 'deductAmount', minWidth: 150 },
+ { label: '售后退款', prop: 'salesAmount', minWidth: 150 },
+ { label: '优惠券金额', prop: 'memberCouponAmount', minWidth: 150 },
+ { label: '利润合计', prop: 'profitAmount', minWidth: 150 },
+ {
+ label: '账单日期',
+ prop: 'billDate',
+ minWidth: 150,
+ fixed: 'right',
+ },
+ ],
+ searchForm: [
+ {
+ type: 'row',
+ items: [
+ {
+ label: '账单日期',
+ id: 'startDate',
+ component: 'el-bus-date-range',
+ commonFormat: true,
+ commonFormatProps: ['startDate', 'endDate'],
+ customClass: 'in-bus-form',
+ },
+ ],
+ },
+ ],
+ extraButtons: [
+ {
+ text: '明细',
+ atClick: (row) => {
+ const url = this.$router.resolve(
+ `/bill/${this.$route.params.type}/${row.id}`
+ ).href
+ window.open(url, '_blank')
+ },
+ },
+ ],
+ },
+ }
+ },
+ head() {
+ return {
+ title: this.isPartner ? '合伙人账单结算' : '普通用户账单结算',
+ }
+ },
+ computed: {
+ isPartner() {
+ return this.$route.params.type === 'partner'
+ },
+ },
+}
+</script>
+
+<style lang="scss" scoped>
+@import '@/assets/statistic/index.scss';
+</style>
diff --git a/pages/content/advertisement.vue b/pages/content/advertisement.vue
new file mode 100644
index 0000000..013b75f
--- /dev/null
+++ b/pages/content/advertisement.vue
@@ -0,0 +1,169 @@
+<template>
+ <el-bus-crud ref="crud" v-bind="tableConfig" />
+</template>
+
+<script>
+export default {
+ data() {
+ return {
+ tableConfig: {
+ url: 'flower/api/advertisement/page',
+ dialogNeedRequest: true,
+ persistSelection: true,
+ columns: [
+ { type: 'selection' },
+ { label: '标题', prop: 'title' },
+ {
+ label: '封面',
+ formatter: (row) => (
+ <el-bus-image src={row.cover} lazy={true} style="height:40px" />
+ ),
+ },
+ { label: '编辑日期', prop: 'updateTime' },
+ { label: '状态', prop: 'statusStr' },
+ ],
+ searchForm: [
+ {
+ type: 'row',
+ items: [{ label: '标题', id: 'title', type: 'input' }],
+ },
+ ],
+ form: [
+ {
+ label: '标题:',
+ id: 'title',
+ type: 'input',
+ rules: {
+ required: true,
+ message: '请输入标题',
+ trigger: 'blur',
+ },
+ },
+ {
+ label: '内容:',
+ id: 'content',
+ component: 'base-editor',
+ richText: true,
+ rules: { required: true, message: '请输入内容', trigger: 'blur' },
+ },
+ {
+ label: '封面:',
+ id: 'cover',
+ type: 'bus-upload',
+ el: {
+ listType: 'picture-card',
+ limitSize: 2,
+ limit: 1,
+ tipText: '大小不超过2M',
+ valueType: 'string',
+ },
+ rules: { required: true, message: '请上传封面' },
+ forceDisabled: true,
+ },
+ ],
+ extraButtons: [
+ {
+ text: (row) => (row.status === 'unpublished' ? '发布' : '下架'),
+ atClick: async (row) => {
+ const action = row.status === 'unpublished' ? '发布' : '下架'
+ try {
+ await this.$elBusUtil.confirm(`确定要${action}吗?`)
+ const { code } = await this.$elBusHttp.request(
+ 'flower/api/advertisement/page/changeStatus',
+ { params: { id: row.id } }
+ )
+ if (code === 0) {
+ this.$message.success(`${action}成功`)
+ }
+ } catch (e) {
+ return false
+ }
+ },
+ },
+ ],
+ headerButtons: [
+ {
+ text: '批量发布',
+ type: 'primary',
+ disabled: (selected) =>
+ selected.filter((item) => item.status === 'unpublished')
+ .length === 0,
+ atClick: async (selected) => {
+ const selectedNotice = selected.filter(
+ (item) => item.status === 'unpublished'
+ )
+ try {
+ await this.$elBusUtil.confirm(
+ `确定要批量发布这${selectedNotice.length}个广告吗?`
+ )
+ const { code } = await this.$elBusHttp.request(
+ 'flower/api/advertisement/page/publish/batch',
+ {
+ method: 'post',
+ data: {
+ ids: selected.map((item) => item.id),
+ },
+ }
+ )
+ if (code === 0) {
+ this.$message.success('操作成功')
+ this.$refs.crud.clearSelection()
+ }
+ } catch (e) {
+ return false
+ }
+ },
+ },
+ {
+ text: '批量删除',
+ type: 'danger',
+ disabled: (selected) => selected.length === 0,
+ atClick: async (selected) => {
+ try {
+ await this.$elBusUtil.confirm(
+ `确定要批量删除这${selected.length}个广告吗?`
+ )
+ const { code } = await this.$elBusHttp.request(
+ 'flower/api/advertisement/page/delete/batch',
+ {
+ method: 'post',
+ data: {
+ ids: selected.map((item) => item.id),
+ },
+ }
+ )
+ if (code === 0) {
+ this.$message.success('操作成功')
+ this.$refs.crud.clearSelection()
+ }
+ } catch (e) {
+ return false
+ }
+ },
+ },
+ ],
+ },
+ }
+ },
+ head() {
+ return {
+ title: '广告管理',
+ }
+ },
+}
+</script>
+
+<style lang="scss" scoped>
+::v-deep {
+ .el-upload {
+ &-list__item {
+ width: 345px;
+ height: 128px;
+ }
+ &.el-upload--picture-card {
+ width: 345px;
+ height: 128px;
+ }
+ }
+}
+</style>
diff --git a/pages/content/banner.vue b/pages/content/banner.vue
new file mode 100644
index 0000000..61798af
--- /dev/null
+++ b/pages/content/banner.vue
@@ -0,0 +1,204 @@
+<template>
+ <el-bus-crud ref="crud" v-bind="tableConfig" />
+</template>
+
+<script>
+export default {
+ data() {
+ return {
+ tableConfig: {
+ url: 'flower/api/banner/page',
+ dialogNeedRequest: true,
+ persistSelection: true,
+ columns: [
+ { type: 'selection' },
+ { label: 'banner名称', prop: 'name' },
+ { label: '图片', formatter: this.formatterImage },
+ { label: '应用模块', prop: 'moduleStr' },
+ { label: '编辑日期', prop: 'updateTime' },
+ { label: '状态', prop: 'statusStr' },
+ ],
+ searchForm: [
+ {
+ type: 'row',
+ items: [{ label: 'banner名称', id: 'name', type: 'input' }],
+ },
+ ],
+ form: [
+ {
+ label: 'banner名称:',
+ id: 'name',
+ type: 'input',
+ rules: {
+ required: true,
+ message: '请输入banner名称',
+ trigger: 'blur',
+ },
+ },
+ {
+ label: '应用模块:',
+ id: 'module',
+ type: 'bus-select-dict',
+ el: {
+ code: 'COMMON_MODULE',
+ style: 'width:100%',
+ },
+ rules: { required: true, message: '请选择应用模块' },
+ str: true,
+ },
+ {
+ label: '图片:',
+ id: 'url',
+ type: 'bus-upload',
+ el: {
+ listType: 'picture-card',
+ limitSize: 2,
+ tipText: '大小不超过2M',
+ },
+ inputFormat: (row) => {
+ if ('url' in row) {
+ if (row.url) {
+ const url = JSON.parse(row.url)
+ return url.map((item) => ({ url: item }))
+ } else {
+ return []
+ }
+ }
+ },
+ outputFormat: (val) => {
+ return val?.length
+ ? JSON.stringify(val.map((item) => item.url))
+ : null
+ },
+ forceDisabled: true,
+ rules: { required: true, message: '请上传图片' },
+ },
+ {
+ label: '内容:',
+ id: 'content',
+ component: 'base-editor',
+ richText: true,
+ rules: { required: true, message: '请输入内容', trigger: 'blur' },
+ },
+ ],
+ extraButtons: [
+ {
+ text: (row) => (row.status === 'unpublished' ? '发布' : '下架'),
+ atClick: async (row) => {
+ const action = row.status === 'unpublished' ? '发布' : '下架'
+ try {
+ await this.$elBusUtil.confirm(`确定要${action}吗?`)
+ const { code } = await this.$elBusHttp.request(
+ 'flower/api/banner/page/changeStatus',
+ { params: { id: row.id } }
+ )
+ if (code === 0) {
+ this.$message.success(`${action}成功`)
+ }
+ } catch (e) {
+ return false
+ }
+ },
+ },
+ ],
+ headerButtons: [
+ {
+ text: '批量发布',
+ type: 'primary',
+ disabled: (selected) =>
+ selected.filter((item) => item.status === 'unpublished')
+ .length === 0,
+ atClick: async (selected) => {
+ const selectedNotice = selected.filter(
+ (item) => item.status === 'unpublished'
+ )
+ try {
+ await this.$elBusUtil.confirm(
+ `确定要批量发布这${selectedNotice.length}个banner吗?`
+ )
+ const { code } = await this.$elBusHttp.request(
+ 'flower/api/banner/page/publish/batch',
+ {
+ method: 'post',
+ data: {
+ ids: selected.map((item) => item.id),
+ },
+ }
+ )
+ if (code === 0) {
+ this.$message.success('操作成功')
+ this.$refs.crud.clearSelection()
+ }
+ } catch (e) {
+ return false
+ }
+ },
+ },
+ {
+ text: '批量删除',
+ type: 'danger',
+ disabled: (selected) => selected.length === 0,
+ atClick: async (selected) => {
+ try {
+ await this.$elBusUtil.confirm(
+ `确定要批量删除这${selected.length}个banner吗?`
+ )
+ const { code } = await this.$elBusHttp.request(
+ 'flower/api/banner/page/delete/batch',
+ {
+ method: 'post',
+ data: {
+ ids: selected.map((item) => item.id),
+ },
+ }
+ )
+ if (code === 0) {
+ this.$message.success('操作成功')
+ this.$refs.crud.clearSelection()
+ }
+ } catch (e) {
+ return false
+ }
+ },
+ },
+ ],
+ },
+ }
+ },
+ head() {
+ return {
+ title: 'banner管理',
+ }
+ },
+ methods: {
+ formatterImage(row) {
+ if (row.url) {
+ try {
+ const url = JSON.parse(row.url)
+ if (Array.isArray(url) && url.length > 0) {
+ return <el-bus-image src={url[0]} style="width:150px" lazy={true} />
+ }
+ } catch (e) {
+ return null
+ }
+ }
+ return null
+ },
+ },
+}
+</script>
+
+<style lang="scss" scoped>
+::v-deep {
+ .el-upload {
+ &-list__item {
+ width: 345px;
+ height: 128px;
+ }
+ &.el-upload--picture-card {
+ width: 345px;
+ height: 128px;
+ }
+ }
+}
+</style>
diff --git a/pages/content/filmset.vue b/pages/content/filmset.vue
new file mode 100644
index 0000000..54edd61
--- /dev/null
+++ b/pages/content/filmset.vue
@@ -0,0 +1,187 @@
+<template>
+ <el-bus-crud ref="crud" v-bind="tableConfig" />
+</template>
+
+<script>
+export default {
+ data() {
+ return {
+ tableConfig: {
+ url: 'flower/api/filmset/page',
+ dialogNeedRequest: true,
+ persistSelection: true,
+ columns: [
+ { type: 'selection' },
+ { label: '标题', prop: 'title' },
+ { label: '发布日期', prop: 'publishDate' },
+ { label: '编辑日期', prop: 'updateTime' },
+ { label: '状态', prop: 'statusStr' },
+ ],
+ searchForm: [
+ {
+ type: 'row',
+ items: [
+ { label: '标题', id: 'title', type: 'input' },
+ {
+ label: '创建日期',
+ id: 'createDateBeginStr',
+ component: 'el-bus-date-range',
+ commonFormat: true,
+ commonFormatProps: ['createDateBeginStr', 'createDateEndStr'],
+ customClass: 'in-bus-form',
+ },
+ ],
+ },
+ ],
+ form: [
+ {
+ label: '标题:',
+ id: 'title',
+ type: 'input',
+ rules: {
+ required: true,
+ message: '请输入标题',
+ trigger: 'blur',
+ },
+ },
+ {
+ label: '片场内容类型:',
+ id: 'type',
+ type: 'bus-select-dict',
+ el: {
+ code: 'FILMSET_TYPE',
+ style: 'width:100%',
+ clearable: true,
+ },
+ rules: {
+ required: true,
+ message: '请选择片场内容类型',
+ },
+ },
+ {
+ label: '内容:',
+ id: 'content',
+ component: 'base-editor',
+ richText: true,
+ rules: { required: true, message: '请输入内容', trigger: 'blur' },
+ },
+ // {
+ // label: '封面:',
+ // id: 'cover',
+ // type: 'bus-upload',
+ // el: {
+ // listType: 'picture-card',
+ // limitSize: 2,
+ // limit: 1,
+ // tipText: '大小不超过2M',
+ // valueType: 'string',
+ // },
+ // forceDisabled: true,
+ // },
+ ],
+ extraButtons: [
+ {
+ text: (row) => (row.status === 'unpublished' ? '发布' : '下架'),
+ atClick: async (row) => {
+ const action = row.status === 'unpublished' ? '发布' : '下架'
+ try {
+ await this.$elBusUtil.confirm(`确定要${action}吗?`)
+ const { code } = await this.$elBusHttp.request(
+ 'flower/api/filmset/page/changeStatus',
+ { params: { id: row.id } }
+ )
+ if (code === 0) {
+ this.$message.success(`${action}成功`)
+ }
+ } catch (e) {
+ return false
+ }
+ },
+ },
+ ],
+ headerButtons: [
+ {
+ text: '批量发布',
+ type: 'primary',
+ disabled: (selected) =>
+ selected.filter((item) => item.status === 'unpublished')
+ .length === 0,
+ atClick: async (selected) => {
+ const selectedNotice = selected.filter(
+ (item) => item.status === 'unpublished'
+ )
+ try {
+ await this.$elBusUtil.confirm(
+ `确定要批量发布这${selectedNotice.length}个片场内容吗?`
+ )
+ const { code } = await this.$elBusHttp.request(
+ 'flower/api/filmset/page/publish/batch',
+ {
+ method: 'post',
+ data: {
+ ids: selected.map((item) => item.id),
+ },
+ }
+ )
+ if (code === 0) {
+ this.$message.success('操作成功')
+ this.$refs.crud.clearSelection()
+ }
+ } catch (e) {
+ return false
+ }
+ },
+ },
+ {
+ text: '批量删除',
+ type: 'danger',
+ disabled: (selected) => selected.length === 0,
+ atClick: async (selected) => {
+ try {
+ await this.$elBusUtil.confirm(
+ `确定要批量删除这${selected.length}个片场内容吗?`
+ )
+ const { code } = await this.$elBusHttp.request(
+ 'flower/api/filmset/page/delete/batch',
+ {
+ method: 'post',
+ data: {
+ ids: selected.map((item) => item.id),
+ },
+ }
+ )
+ if (code === 0) {
+ this.$message.success('操作成功')
+ this.$refs.crud.clearSelection()
+ }
+ } catch (e) {
+ return false
+ }
+ },
+ },
+ ],
+ },
+ }
+ },
+ head() {
+ return {
+ title: '片场内容管理',
+ }
+ },
+}
+</script>
+
+<style lang="scss" scoped>
+::v-deep {
+ .el-upload {
+ &-list__item {
+ width: 345px;
+ height: 128px;
+ }
+ &.el-upload--picture-card {
+ width: 345px;
+ height: 128px;
+ }
+ }
+}
+</style>
diff --git a/pages/content/info.vue b/pages/content/info.vue
new file mode 100644
index 0000000..15dd8a4
--- /dev/null
+++ b/pages/content/info.vue
@@ -0,0 +1,42 @@
+<template>
+ <el-bus-crud v-bind="tableConfig" />
+</template>
+
+<script>
+export default {
+ data() {
+ return {
+ tableConfig: {
+ url: 'flower/api/config/content/list',
+ newUrl: 'flower/api/config/content/list/save',
+ editUrl: 'flower/api/config/content/list/save',
+ hasDelete: false,
+ hasPagination: false,
+ dialogNeedRequest: true,
+ columns: [{ label: '名称', prop: 'id' }],
+ form: [
+ {
+ label: '名称:',
+ id: 'id',
+ type: 'input',
+ rules: { required: true, message: '请输入名称', trigger: 'blur' },
+ readonly: (row, item, mode) => mode !== 'new',
+ },
+ {
+ label: '内容:',
+ id: 'content',
+ component: 'base-editor',
+ richText: true,
+ rules: { required: true, message: '请输入内容', trigger: 'blur' },
+ },
+ ],
+ },
+ }
+ },
+ head() {
+ return {
+ title: '信息维护',
+ }
+ },
+}
+</script>
diff --git a/pages/content/notice.vue b/pages/content/notice.vue
new file mode 100644
index 0000000..d8e4427
--- /dev/null
+++ b/pages/content/notice.vue
@@ -0,0 +1,187 @@
+<template>
+ <el-bus-crud ref="crud" v-bind="tableConfig" />
+</template>
+
+<script>
+export default {
+ data() {
+ return {
+ tableConfig: {
+ url: 'flower/api/announcement/page',
+ dialogNeedRequest: true,
+ persistSelection: true,
+ columns: [
+ { type: 'selection' },
+ { label: '标题', prop: 'title' },
+ { label: '发布日期', prop: 'publishDate' },
+ { label: '编辑日期', prop: 'updateTime' },
+ { label: '状态', prop: 'statusStr' },
+ ],
+ searchForm: [
+ {
+ type: 'row',
+ items: [
+ { label: '标题', id: 'title', type: 'input' },
+ {
+ label: '创建日期',
+ id: 'createDateBeginStr',
+ component: 'el-bus-date-range',
+ commonFormat: true,
+ commonFormatProps: ['createDateBeginStr', 'createDateEndStr'],
+ customClass: 'in-bus-form',
+ },
+ ],
+ },
+ ],
+ form: [
+ {
+ label: '标题:',
+ id: 'title',
+ type: 'input',
+ rules: {
+ required: true,
+ message: '请输入标题',
+ trigger: 'blur',
+ },
+ },
+ {
+ label: '公告类型:',
+ id: 'type',
+ type: 'bus-select-dict',
+ el: {
+ code: 'ANNOUNCEMENT_TYPE',
+ style: 'width:100%',
+ clearable: true,
+ },
+ rules: {
+ required: true,
+ message: '请选择公告类型',
+ },
+ },
+ {
+ label: '内容:',
+ id: 'content',
+ component: 'base-editor',
+ richText: true,
+ rules: { required: true, message: '请输入内容', trigger: 'blur' },
+ },
+ {
+ label: '封面:',
+ id: 'cover',
+ type: 'bus-upload',
+ el: {
+ listType: 'picture-card',
+ limitSize: 2,
+ limit: 1,
+ tipText: '大小不超过2M',
+ valueType: 'string',
+ },
+ forceDisabled: true,
+ },
+ ],
+ extraButtons: [
+ {
+ text: (row) => (row.status === 'unpublished' ? '发布' : '下架'),
+ atClick: async (row) => {
+ const action = row.status === 'unpublished' ? '发布' : '下架'
+ try {
+ await this.$elBusUtil.confirm(`确定要${action}吗?`)
+ const { code } = await this.$elBusHttp.request(
+ 'flower/api/announcement/page/changeStatus',
+ { params: { id: row.id } }
+ )
+ if (code === 0) {
+ this.$message.success(`${action}成功`)
+ }
+ } catch (e) {
+ return false
+ }
+ },
+ },
+ ],
+ headerButtons: [
+ {
+ text: '批量发布',
+ type: 'primary',
+ disabled: (selected) =>
+ selected.filter((item) => item.status === 'unpublished')
+ .length === 0,
+ atClick: async (selected) => {
+ const selectedNotice = selected.filter(
+ (item) => item.status === 'unpublished'
+ )
+ try {
+ await this.$elBusUtil.confirm(
+ `确定要批量发布这${selectedNotice.length}个公告吗?`
+ )
+ const { code } = await this.$elBusHttp.request(
+ 'flower/api/announcement/page/publish/batch',
+ {
+ method: 'post',
+ data: {
+ ids: selected.map((item) => item.id),
+ },
+ }
+ )
+ if (code === 0) {
+ this.$message.success('操作成功')
+ this.$refs.crud.clearSelection()
+ }
+ } catch (e) {
+ return false
+ }
+ },
+ },
+ {
+ text: '批量删除',
+ type: 'danger',
+ disabled: (selected) => selected.length === 0,
+ atClick: async (selected) => {
+ try {
+ await this.$elBusUtil.confirm(
+ `确定要批量删除这${selected.length}个公告吗?`
+ )
+ const { code } = await this.$elBusHttp.request(
+ 'flower/api/announcement/page/delete/batch',
+ {
+ method: 'post',
+ data: {
+ ids: selected.map((item) => item.id),
+ },
+ }
+ )
+ if (code === 0) {
+ this.$message.success('操作成功')
+ this.$refs.crud.clearSelection()
+ }
+ } catch (e) {
+ return false
+ }
+ },
+ },
+ ],
+ },
+ }
+ },
+ head() {
+ return {
+ title: '公告管理',
+ }
+ },
+}
+</script>
+
+<style lang="scss" scoped>
+::v-deep {
+ .el-upload {
+ &-list__item {
+ width: 345px;
+ height: 128px;
+ }
+ &.el-upload--picture-card {
+ width: 345px;
+ height: 128px;
+ }
+ }
+}
+</style>
diff --git a/pages/district/gaode/index.vue b/pages/district/gaode/index.vue
new file mode 100644
index 0000000..c91519e
--- /dev/null
+++ b/pages/district/gaode/index.vue
@@ -0,0 +1,217 @@
+<template>
+ <div class="custom-crud-page">
+ <el-button type="primary" @click="openDialog">新增</el-button>
+ <el-table :data="data" style="width: 100%" row-key="id" v-loading="loading"
+ :tree-props="{ children: 'children' }">
+ <el-table-column prop="name" label="名称"></el-table-column>
+ <el-table-column prop="adcode" label="区域编码"></el-table-column>
+ <el-table-column prop="level" label="行政区划级别"></el-table-column>
+ <el-table-column prop="citycode" label="城市编码"></el-table-column>
+ <el-table-column prop="center" label="区域中心点"></el-table-column>
+ <el-table-column label="操作" width="200">
+ <template #default="scope">
+ <el-button type="text" size="small" @click="handleAddChildren(scope.row)">新增下级</el-button>
+ <el-button type="text" size="small" @click="handleEdit(scope.row)">修改</el-button>
+ <el-button type="text" size="small" @click="handleDelete(scope.row)"><span
+ style="color: red;">删除</span></el-button>
+ </template>
+ </el-table-column>
+ </el-table>
+
+ <el-dialog :visible.sync="dialogVisible" :title="form.id ? '修改' : '新增'" width="50%">
+ <el-form ref="form" :model="form" :rules="rules" label-width="150px" class="form-container">
+ <el-form-item v-if="form.parentName" label="父级节点:" prop="parentName">
+ <el-input v-model="form.parentName" readonly></el-input>
+ </el-form-item>
+ <el-form-item label="名称:" prop="name">
+ <el-input v-model="form.name" placeholder="请输入名称"></el-input>
+ </el-form-item>
+ <el-form-item label="区域编码:" prop="adcode">
+ <el-input v-model="form.adcode" placeholder="请输入区域编码"></el-input>
+ </el-form-item>
+ <el-form-item label="行政区划级别:" prop="level">
+ <el-input v-model="form.level" placeholder="行政区划级别"></el-input>
+ </el-form-item>
+ <el-form-item label="层城市编码:" prop="citycode">
+ <el-input v-model="form.citycode" placeholder="请输入城市编码"></el-input>
+ </el-form-item>
+ <el-form-item label="区域中心点:" prop="center">
+ <el-input v-model="form.center" placeholder="请输入区域中心点"></el-input>
+ </el-form-item>
+ <el-form-item>
+ <el-button type="primary" @click="handleSubmit">提交</el-button>
+ <el-button @click="handleReset">重置</el-button>
+ </el-form-item>
+ </el-form>
+ </el-dialog>
+
+ </div>
+</template>
+
+<script>
+export default {
+ data() {
+ return {
+ dialogVisible: false,
+ loading: false,
+ data: [],
+ form: {
+ parentName: '',
+ parentId: null,
+ id: '',
+ name: '',
+ adcode: '',
+ level: '',
+ citycode: '',
+ center: '',
+ },
+ rules: {
+ name: [{ required: true, message: '请输入名称', trigger: 'blur' }],
+ adcode: [{ required: true, message: '请输入区域编码', trigger: 'blur' }],
+ // citycode: [{ required: true, message: '请输入城市编码', trigger: 'blur' }],
+ // center: [{ required: true, message: '请输入区域中心点', trigger: 'blur' }],
+ // level: [{ required: true, message: '行政区划级别', trigger: 'blur' }],
+ },
+ tableData: [],
+ };
+ },
+ mounted() {
+ this.getData();
+ },
+ methods: {
+
+ openDialog() {
+ this.dialogVisible = true;
+ this.handleReset()
+ this.form = {
+ parentName: '',
+ parentId: null,
+ id: '',
+ name: '',
+ fullname: '',
+ code: '',
+ level: null,
+ }
+ },
+ async getData() {
+ this.loading = true
+ const resp = await this.$elBusHttp.request('flower/v2/district-gaode/list', {
+ params: {},
+ });
+ if (resp.code === 0) {
+ console.log(resp.data)
+ this.data = resp.data
+ }
+ this.loading = false
+ },
+
+ handleSubmit() {
+ this.$refs.form.validate(async valid => {
+ if (valid) {
+ // Handle form submission logic
+ console.log('Form data:', this.form);
+ if (this.form.id) {
+
+ const { code } = await this.$elBusHttp.request(
+ `flower/v2/district-gaode/${this.form.id}`,
+ {
+ method: 'put',
+ data: this.form,
+ }
+ )
+ if (code === 0) {
+ this.$message.success('修改成功')
+ this.dialogVisible = false
+ this.getData()
+ }
+ } else {
+ const { code } = await this.$elBusHttp.request(
+ 'flower/v2/district-gaode',
+ {
+ method: 'post',
+ data: this.form,
+ }
+ )
+ if (code === 0) {
+ this.$message.success('新增成功')
+ this.dialogVisible = false
+ this.getData()
+ }
+ }
+
+ }
+ });
+ },
+ handleReset() {
+ this.$refs.form?.resetFields();
+ },
+
+ handleAddChildren(row) {
+ this.handleReset()
+ this.form = {
+ parentName: row.name,
+ parentId: row.id,
+ id: '',
+ name: '',
+ fullname: '',
+ code: '',
+ level: null,
+ }
+ this.dialogVisible = true;
+ },
+
+ async handleEdit(row) {
+ this.form = { ...row };
+ console.log(row)
+ if (row.parentId) {
+ const resp = await this.$elBusHttp.request(`flower/v2/district-gaode/${row.parentId}`, {
+ params: {},
+ });
+ if (resp.code === 0) {
+ console.log(resp.data)
+ this.form.parentName = resp.data.name;
+ }
+ }
+ this.dialogVisible = true;
+ },
+ async handleDelete(row) {
+ try {
+ await this.$elBusUtil.confirm(`此操作将会删除所有子行政区划, 是否继续?`)
+ const { code } = await this.$elBusHttp.request(
+ `flower/v2/district-gaode/${row.id}`,
+ {
+ method: 'delete',
+ }
+ )
+ if (code === 0) {
+ this.$message.success(`删除成功`)
+ this.getData()
+ } else {
+ return false
+ }
+ } catch (error) {
+ return false
+ }
+
+
+ },
+ },
+
+ head() {
+ return {
+ title: '高德行政区划管理',
+ }
+ },
+};
+</script>
+
+<style>
+.custom-crud-page {
+ padding: 20px;
+ background-color: #FFFFFF;
+}
+
+.form-container {
+ margin-bottom: 20px;
+}
+</style>
\ No newline at end of file
diff --git a/pages/district/tengxun/index.vue b/pages/district/tengxun/index.vue
new file mode 100644
index 0000000..d382d04
--- /dev/null
+++ b/pages/district/tengxun/index.vue
@@ -0,0 +1,210 @@
+<template>
+ <div class="custom-crud-page">
+ <el-button type="primary" @click="openDialog">新增</el-button>
+ <el-table :data="data" style="width: 100%" row-key="id" v-loading="loading"
+ :tree-props="{ children: 'children' }">
+ <el-table-column prop="name" label="名称"></el-table-column>
+ <el-table-column prop="fullname" label="全称"></el-table-column>
+ <el-table-column prop="code" label="编码"></el-table-column>
+ <el-table-column prop="level" label="层级"></el-table-column>
+ <el-table-column label="操作" width="200">
+ <template #default="scope">
+ <el-button type="text" size="small" @click="handleAddChildren(scope.row)">新增下级</el-button>
+ <el-button type="text" size="small" @click="handleEdit(scope.row)">修改</el-button>
+ <el-button type="text" size="small" @click="handleDelete(scope.row)"><span
+ style="color: red;">删除</span></el-button>
+ </template>
+ </el-table-column>
+ </el-table>
+
+ <el-dialog :visible.sync="dialogVisible" :title="form.id ? '修改' : '新增'" width="50%">
+ <el-form ref="form" :model="form" :rules="rules" label-width="100px" class="form-container">
+ <el-form-item v-if="form.parentName" label="父级节点:" prop="parentName">
+ <el-input v-model="form.parentName" readonly></el-input>
+ </el-form-item>
+ <el-form-item label="名称:" prop="name">
+ <el-input v-model="form.name" placeholder="请输入名称:"></el-input>
+ </el-form-item>
+ <el-form-item label="全称:" prop="fullname">
+ <el-input v-model="form.fullname" placeholder="请输入全称:"></el-input>
+ </el-form-item>
+ <el-form-item label="编码:" prop="code">
+ <el-input v-model="form.code" placeholder="请输入编码"></el-input>
+ </el-form-item>
+ <el-form-item label="层级:" prop="level">
+ <el-input-number v-model="form.level" placeholder="请输入层级"></el-input-number>
+ </el-form-item>
+ <el-form-item>
+ <el-button type="primary" @click="handleSubmit">提交</el-button>
+ <el-button @click="handleReset">重置</el-button>
+ </el-form-item>
+ </el-form>
+ </el-dialog>
+
+ </div>
+</template>
+
+<script>
+export default {
+ data() {
+ return {
+ dialogVisible: false,
+ loading: false,
+ data: [],
+ form: {
+ parentName: '',
+ parentId: null,
+ id: '',
+ name: '',
+ fullname: '',
+ code: '',
+ level: null,
+ },
+ rules: {
+ name: [{ required: true, message: '请输入名称:', trigger: 'blur' }],
+ fullname: [{ required: true, message: '请输入全称', trigger: 'blur' }],
+ code: [{ required: true, message: '请输入编码', trigger: 'blur' }],
+ level: [{ required: true, message: '请输入层级', trigger: 'blur' }],
+ },
+ tableData: [],
+ };
+ },
+ mounted() {
+ this.getData();
+ },
+ methods: {
+
+ openDialog() {
+ this.dialogVisible = true;
+ this.handleReset()
+ this.form = {
+ parentName: '',
+ parentId: null,
+ id: '',
+ name: '',
+ fullname: '',
+ code: '',
+ level: null,
+ }
+ },
+ async getData() {
+ this.loading = true
+ const resp = await this.$elBusHttp.request('flower/v2/district-tengxun/list', {
+ params: {},
+ });
+ if (resp.code === 0) {
+ console.log(resp.data)
+ this.data = resp.data
+ }
+ this.loading = false
+ },
+
+ handleSubmit() {
+ this.$refs.form.validate(async valid => {
+ if (valid) {
+ // Handle form submission logic
+ console.log('Form data:', this.form);
+ if (this.form.id) {
+
+ const { code } = await this.$elBusHttp.request(
+ `flower/v2/district-tengxun/${this.form.id}`,
+ {
+ method: 'put',
+ data: this.form,
+ }
+ )
+ if (code === 0) {
+ this.$message.success('修改成功')
+ this.dialogVisible = false
+ this.getData()
+ }
+ } else {
+ const { code } = await this.$elBusHttp.request(
+ 'flower/v2/district-tengxun',
+ {
+ method: 'post',
+ data: this.form,
+ }
+ )
+ if (code === 0) {
+ this.$message.success('新增成功')
+ this.dialogVisible = false
+ this.getData()
+ }
+ }
+
+ }
+ });
+ },
+ handleReset() {
+ this.$refs.form?.resetFields();
+ },
+
+ handleAddChildren(row) {
+ this.handleReset()
+ this.form = {
+ parentName: row.name,
+ parentId: row.id,
+ id: '',
+ name: '',
+ fullname: '',
+ code: '',
+ level: null,
+ }
+ this.dialogVisible = true;
+ },
+
+ async handleEdit(row) {
+ this.form = { ...row };
+ console.log(row)
+ if (row.parentId) {
+ const resp = await this.$elBusHttp.request(`flower/v2/district-tengxun/${row.parentId}`, {
+ params: {},
+ });
+ if (resp.code === 0) {
+ console.log(resp.data)
+ this.form.parentName = resp.data.name;
+ }
+ }
+ this.dialogVisible = true;
+ },
+ async handleDelete(row) {
+ try {
+ await this.$elBusUtil.confirm(`此操作将会删除所有子行政区划, 是否继续?`)
+ const { code } = await this.$elBusHttp.request(
+ `flower/v2/district-tengxun/${row.id}`,
+ {
+ method: 'delete',
+ }
+ )
+ if (code === 0) {
+ this.$message.success(`删除成功`)
+ this.getData()
+ } else {
+ return false
+ }
+ } catch (error) {
+ return false
+ }
+
+
+ },
+ },
+ head() {
+ return {
+ title: '腾讯行政区划管理',
+ }
+ },
+};
+</script>
+
+<style>
+.custom-crud-page {
+ padding: 20px;
+ background-color: #FFFFFF;
+}
+
+.form-container {
+ margin-bottom: 20px;
+}
+</style>
\ No newline at end of file
diff --git a/pages/feedback.vue b/pages/feedback.vue
new file mode 100644
index 0000000..09347c6
--- /dev/null
+++ b/pages/feedback.vue
@@ -0,0 +1,175 @@
+<template>
+ <el-bus-crud ref="crud" v-bind="tableConfig" />
+</template>
+
+<script>
+import { dateRangeOptions } from '@/utils/options'
+import CustomDateRange from '@/components/custom-date-range.vue'
+export default {
+ data() {
+ return {
+ tableConfig: {
+ url: 'flower/api/feedback/page',
+ hasNew: false,
+ hasEdit: false,
+ hasDelete: false,
+ columns: [
+ { label: '反馈人', prop: 'customerName', minWidth: 120 },
+ { label: '反馈人电话', prop: 'customerTel', minWidth: 150 },
+ {
+ label: '反馈内容',
+ prop: 'feedBack',
+ minWidth: 250,
+ showOverflowTooltip: true,
+ },
+ { label: '反馈类型', prop: 'typeStr', minWidth: 120 },
+ { label: '反馈时间', prop: 'createTime', minWidth: 180 },
+ {
+ label: '回复内容',
+ prop: 'reply',
+ minWidth: 250,
+ showOverflowTooltip: true,
+ },
+ { label: '回复时间', prop: 'replyTime', minWidth: 180 },
+ ],
+ operationAttrs: {
+ width: 120,
+ fixed: 'right',
+ },
+ searchFormAttrs: {
+ labelWidth: 'auto',
+ },
+ searchForm: [
+ {
+ type: 'row',
+ items: [
+ {
+ label: '处理状态:',
+ id: 'handled',
+ type: 'bus-radio',
+ el: {
+ hasAll: true,
+ childType: 'el-radio-button',
+ fromDict: false,
+ options: [
+ { label: '已处理', value: true },
+ { label: '待处理', value: false },
+ ],
+ },
+ default: '',
+ span: 24,
+ searchImmediately: true,
+ },
+ {
+ label: '反馈日期:',
+ id: 'dateType',
+ component: CustomDateRange,
+ el: {
+ options: dateRangeOptions,
+ },
+ searchImmediately: true,
+ commonFormat: true,
+ commonFormatProps: [
+ 'dateType',
+ 'createDateBeginStr',
+ 'createDateEndStr',
+ ],
+ span: 24,
+ },
+ { label: '反馈人:', id: 'name', type: 'input' },
+ { label: '反馈人电话:', id: 'tel', type: 'input' },
+ ],
+ },
+ ],
+ form: [
+ { label: '反馈人:', id: 'customerName', type: 'input' },
+ { label: '反馈人电话:', id: 'customerTel', type: 'input' },
+ {
+ label: '反馈内容:',
+ id: 'feedBack',
+ type: 'input',
+ el: { type: 'textarea' },
+ },
+ { label: '反馈类型:', id: 'typeStr', type: 'input' },
+ {
+ label: '图片:',
+ id: 'pictures',
+ type: 'bus-upload',
+ forceDisabled: true,
+ el: {
+ listType: 'picture-card',
+ },
+ inputFormat: (row) => {
+ if ('pictures' in row) {
+ try {
+ return row.pictures
+ ? JSON.parse(row.pictures).map((i) => ({ url: i }))
+ : []
+ } catch (e) {}
+ }
+ },
+ },
+ { label: '反馈时间:', id: 'createTime', type: 'input' },
+ {
+ label: '回复内容:',
+ id: 'reply',
+ type: 'input',
+ el: { type: 'textarea' },
+ },
+ { label: '回复时间:', id: 'replyTime', type: 'input' },
+ ],
+ extraButtons: [
+ {
+ text: '回复',
+ show: (row) => !row.handled,
+ atClick: (row) => {
+ this.$refs.crud.$refs.extraDialog[0].show(row)
+ },
+ },
+ ],
+ extraDialogs: [
+ {
+ title: '回复',
+ hiddenReverseItems: [],
+ form: [
+ {
+ label: '回复内容:',
+ id: 'reply',
+ type: 'input',
+ el: {
+ rows: 6,
+ type: 'textarea',
+ },
+ rules: {
+ required: true,
+ message: '请输入回复内容',
+ trigger: 'blur',
+ },
+ },
+ ],
+ atConfirm: async (val) => {
+ const { code } = await this.$elBusHttp.request(
+ 'flower/api/feedback/page/reply',
+ {
+ method: 'post',
+ data: val,
+ }
+ )
+ if (code === 0) {
+ this.$message.success('回复成功')
+ }
+ },
+ },
+ ],
+ },
+ }
+ },
+ head() {
+ return {
+ title: '投诉反馈',
+ }
+ },
+}
+</script>
+
+<style lang="scss" scoped></style>
diff --git a/pages/goods/category-list.vue b/pages/goods/category-list.vue
new file mode 100644
index 0000000..dc51929
--- /dev/null
+++ b/pages/goods/category-list.vue
@@ -0,0 +1,331 @@
+<template>
+ <el-bus-crud ref="crud" v-bind="tableConfig" />
+</template>
+
+<script>
+import cloneDeep from 'lodash.clonedeep'
+import { getSortConfig } from '@/utils/form-item-config'
+export default {
+ data() {
+ return {
+ originalList: [],
+ expandIds: [],
+ tableConfig: {
+ url: 'flower/api/flower/category/tree',
+ hasPagination: false,
+ saveQuery: false,
+ isTree: true,
+ hasView: false,
+ canNewChild: (row) => !row.parentId,
+ dialogAttrs: {
+ width: '70%',
+ },
+ /**
+ * 优化树形数据量较大渲染卡顿的问题
+ * 使用tree的懒加载后更新数据刷新树比较麻烦,暂时不考虑这个方案
+ * 由于该分类列表最多两级
+ * 目前在渲染树时先将每个父节点下的子元素children取第一个渲染树结构,然后在展开节点时通过id找到原始的children做替换
+ * 考虑到更新数据时某些节点可能已经展开,已经展开的节点不能取第一个子元素,所以要记录展开的节点
+ * 1.在expandChange事件中更新展开的节点列表
+ * 2.当通过搜索条件搜索时,如果某些父节点不在搜索结果中,也要将它们从展开的节点中去除
+ */
+ afterRequest: (list) => {
+ this.originalList = cloneDeep(list)
+ this.expandIds = this.expandIds.filter((i) =>
+ list.find((item) => item.id === i)
+ )
+ return list.map((i) => ({
+ ...i,
+ childrenCount: Array.isArray(i.children) ? i.children.length : 0,
+ children: this.expandIds.includes(i.id)
+ ? i.children
+ : i.children.slice(0, 1),
+ }))
+ },
+ tableEventHandlers: {
+ expandChange: (row, expand) => {
+ if (expand) {
+ if (!this.expandIds.includes(row.id)) {
+ this.expandIds.push(row.id)
+ }
+ row.children =
+ this.originalList.find((i) => i.id === row.id)?.children || []
+ } else {
+ const index = this.expandIds.indexOf(row.id)
+ if (index !== -1) {
+ this.expandIds.splice(index, 1)
+ }
+ }
+ },
+ },
+ beforeOpen(row, isNew) {
+ if (isNew && row.name) {
+ row.parentName = row.name
+ }
+ if (!isNew && !row.parentId && row.parentName) {
+ row.parentName = ''
+ }
+ },
+ extraParentKeys: ['parentName', 'levelLimit'],
+ tableAttrs: {
+ rowKey: 'id',
+ },
+ columns: [
+ { label: '分类名称', prop: 'name' },
+ {
+ label: '分类图片',
+ formatter: (row) => (
+ <el-bus-image
+ style="width:50px;height:50px"
+ lazy={true}
+ src={row.imageUrl}
+ />
+ ),
+ },
+ { label: '排序', prop: 'sortBy' },
+ { label: '品种数量', formatter: (row) => row.childrenCount },
+ {
+ label: '是否显示',
+ formatter: (row) => (
+ <el-switch
+ value={row.shown}
+ onChange={this.onShownChange.bind(this, row)}
+ ></el-switch>
+ ),
+ },
+ ],
+ searchForm: [
+ {
+ type: 'row',
+ items: [{ label: '分类名称', id: 'name', type: 'input' }],
+ },
+ ],
+ form: [
+ {
+ label: '上级分类:',
+ id: 'parentName',
+ type: 'input',
+ readonly: true,
+ hidden: (row) => !row.parentName,
+ },
+ {
+ label: '分类名称:',
+ id: 'name',
+ type: 'input',
+ rules: {
+ required: true,
+ message: '请输入分类名称',
+ trigger: 'blur',
+ },
+ },
+ {
+ label: '分类图片:',
+ id: 'imageUrl',
+ type: 'bus-upload',
+ el: {
+ listType: 'picture-card',
+ limit: 1,
+ limitSize: 2,
+ tipText: '建议上传164*164的图片,大小不超过2M',
+ valueType: 'string',
+ },
+ rules: { required: true, message: '请上传分类图片' },
+ },
+ {
+ label: '等级:',
+ id: 'levelLimit',
+ type: 'bus-select-dict',
+ el: {
+ code: 'FLOWER_LEVEL',
+ multiple: true,
+ style: 'width:100%',
+ },
+ rules: { required: true, message: '请选择等级' },
+ inputFormat: (row) => {
+ if ('levelLimit' in row) {
+ return row.levelLimit ? row.levelLimit.split(',') : []
+ }
+ },
+ outputFormat: (val) => {
+ return Array.isArray(val) ? val.join(',') : null
+ },
+ hidden: (row) => row.parentName,
+ },
+ {
+ label: '分类颜色:',
+ id: 'color',
+ type: 'input',
+ hidden: (row) => !row.parentName,
+ },
+ {
+ label: '规格:',
+ id: 'unit',
+ type: 'input',
+ hidden: (row) => !row.parentName,
+ },
+ {
+ type: 'row',
+ items: [
+ {
+ label: 'A级重量:',
+ id: 'weightA',
+ type: 'input-number',
+ el: {
+ min: 0,
+ precision: 1,
+ controls: false,
+ },
+ unit: 'kg',
+ hidden: (row) =>
+ !row.parentName ||
+ !row.levelLimit ||
+ !row.levelLimit.includes('A'),
+ rules: {
+ required: true,
+ message: '请输入A级重量',
+ trigger: 'blur',
+ },
+ },
+ {
+ label: 'B级重量:',
+ id: 'weightB',
+ type: 'input-number',
+ el: {
+ min: 0,
+ precision: 1,
+ controls: false,
+ },
+ unit: 'kg',
+ hidden: (row) =>
+ !row.parentName ||
+ !row.levelLimit ||
+ !row.levelLimit.includes('B'),
+ rules: {
+ required: true,
+ message: '请输入B级重量',
+ trigger: 'blur',
+ },
+ },
+ {
+ label: 'C级重量:',
+ id: 'weightC',
+ type: 'input-number',
+ el: {
+ min: 0,
+ precision: 1,
+ controls: false,
+ },
+ unit: 'kg',
+ hidden: (row) =>
+ !row.parentName ||
+ !row.levelLimit ||
+ !row.levelLimit.includes('C'),
+ rules: {
+ required: true,
+ message: '请输入C级重量',
+ trigger: 'blur',
+ },
+ },
+ {
+ label: 'D级重量:',
+ id: 'weightD',
+ type: 'input-number',
+ el: {
+ min: 0,
+ precision: 1,
+ controls: false,
+ },
+ unit: 'kg',
+ hidden: (row) =>
+ !row.parentName ||
+ !row.levelLimit ||
+ !row.levelLimit.includes('D'),
+ rules: {
+ required: true,
+ message: '请输入D级重量',
+ trigger: 'blur',
+ },
+ },
+ {
+ label: 'E级重量:',
+ id: 'weightE',
+ type: 'input-number',
+ el: {
+ min: 0,
+ precision: 1,
+ controls: false,
+ },
+ unit: 'kg',
+ hidden: (row) =>
+ !row.parentName ||
+ !row.levelLimit ||
+ !row.levelLimit.includes('E'),
+ rules: {
+ required: true,
+ message: '请输入E级重量',
+ trigger: 'blur',
+ },
+ },
+ {
+ label: 'O级重量:',
+ id: 'weightO',
+ type: 'input-number',
+ el: {
+ min: 0,
+ precision: 1,
+ controls: false,
+ },
+ unit: 'kg',
+ hidden: (row) =>
+ !row.parentName ||
+ !row.levelLimit ||
+ !row.levelLimit.includes('O'),
+ rules: {
+ required: true,
+ message: '请输入O级重量',
+ trigger: 'blur',
+ },
+ },
+ ],
+ },
+ {
+ ...getSortConfig(),
+ },
+ ],
+ },
+ }
+ },
+ head() {
+ return {
+ title: '分类管理',
+ }
+ },
+ methods: {
+ onShownChange(row, e) {
+ const url = e
+ ? 'flower/api/flower/category/tree/shown'
+ : 'flower/api/flower/category/tree/hidden'
+ const text = e ? '显示' : '隐藏'
+ this.$elBusUtil
+ .confirm(`确定要${text}这个分类吗?`)
+ .then(async () => {
+ const { code } = await this.$elBusHttp.request(url, {
+ params: {
+ id: row.id,
+ },
+ })
+ if (code === 0) {
+ this.$message.success(`${text}成功`)
+ this.$refs.crud.getList()
+ }
+ })
+ .catch(() => {})
+ },
+ },
+}
+</script>
+
+<style lang="scss" scoped>
+.category-list {
+}
+</style>
diff --git a/pages/goods/list/_action/_id.vue b/pages/goods/list/_action/_id.vue
new file mode 100644
index 0000000..d2d522d
--- /dev/null
+++ b/pages/goods/list/_action/_id.vue
@@ -0,0 +1,198 @@
+<template>
+ <div class="base-page-wrapper">
+ <el-bus-form
+ ref="form"
+ :content="formContent"
+ :readonly="!editable"
+ label-width="auto"
+ ></el-bus-form>
+ <div class="text-center mt-20">
+ <el-button class="min-w-100" @click="goBack">返回</el-button>
+ <el-button
+ v-if="editable"
+ type="primary"
+ :loading="loading"
+ class="min-w-100"
+ @click="save"
+ >保存</el-button
+ >
+ </div>
+ </div>
+</template>
+
+<script>
+import GoodsParams from '@/components/goods/goods-params.vue'
+export default {
+ data() {
+ return {
+ loading: false,
+ formContent: [
+ {
+ type: 'row',
+ items: [
+ { label: '商品名称:', id: 'name', type: 'input', readonly: true },
+ {
+ label: '商品分类:',
+ id: 'categoryStr',
+ type: 'input',
+ readonly: true,
+ },
+ { label: '商品规格:', id: 'unit', type: 'input', readonly: true },
+ { label: '级别:', id: 'levelStr', type: 'input', readonly: true },
+ { label: '商品售价:', id: 'price', type: 'input', readonly: true },
+ {
+ label: '销量:',
+ id: 'sales',
+ type: 'input-number',
+ el: { precision: 0, min: 0, style: 'width:100%' },
+ },
+ { label: '库存:', id: 'stock', type: 'input', readonly: true },
+ { label: '商品标签:', id: 'tags', type: 'input', readonly: true },
+ {
+ label: '所属专区:',
+ id: 'zoneName',
+ type: 'input',
+ readonly: true,
+ },
+ {
+ label: '供应商名称:',
+ id: 'supplierName',
+ type: 'input',
+ readonly: true,
+ },
+ {
+ label: '供应商类型:',
+ id: 'supplierType',
+ type: 'input',
+ readonly: true,
+ },
+ {
+ label: '供应商电话:',
+ id: 'supplierTel',
+ type: 'input',
+ readonly: true,
+ },
+ {
+ label: '商品状态:',
+ id: 'status',
+ type: 'input',
+ str: true,
+ readonly: true,
+ },
+ {
+ label: '限购数量:',
+ id: 'limited',
+ type: 'input-number',
+ el: { precision: 0, min:1, max: 99999999, style: 'width:100%' },
+ },
+ {
+ label: '驳回原因:',
+ id: 'auditRemarks',
+ type: 'input',
+ el: {
+ type: 'textarea',
+ },
+ hidden: (row) => row.status !== 'REJECT',
+ readonly: true,
+ span: 24,
+ },
+ {
+ label: '列表封面图片:',
+ id: 'cover',
+ type: 'bus-upload',
+ el: {
+ listType: 'picture-card',
+ valueType: 'string',
+ },
+ forceDisabled: true,
+ span: 24,
+ readonly: true,
+ },
+ {
+ label: '轮播图:',
+ id: 'bannerList',
+ type: 'bus-upload',
+ el: {
+ listType: 'picture-card',
+ },
+ forceDisabled: true,
+ span: 24,
+ inputFormat: (row) => {
+ if ('bannerList' in row) {
+ return Array.isArray(row.bannerList)
+ ? row.bannerList.map((item) => ({ url: item }))
+ : []
+ }
+ },
+ readonly: true,
+ },
+ {
+ label: '商品参数:',
+ id: 'params',
+ component: GoodsParams,
+ span: 24,
+ forceDisabled: true,
+ el: {
+ style: 'width:50%',
+ },
+ },
+ ],
+ },
+ ],
+ }
+ },
+ head() {
+ return {
+ title: this.title,
+ }
+ },
+ computed: {
+ title() {
+ return this.$route.params.action === 'edit' ? '编辑商品' : '商品详情'
+ },
+ editable() {
+ return this.$route.params.action === 'edit'
+ },
+ },
+ mounted() {
+ this.getDetail()
+ },
+ methods: {
+ async getDetail() {
+ this.loading = true
+ const { code, data } = await this.$elBusHttp.request(
+ 'flower/api/flower/list/view',
+ { params: { id: this.$route.params.id } }
+ )
+ if (code === 0) {
+ const limited = data.limited;
+ if (limited === null) {
+ data.limited = undefined;
+ }
+ this.$refs.form.updateForm(data)
+ }
+ this.loading = false
+ },
+ goBack() {
+ this.$router.back()
+ },
+ async save() {
+ this.loading = true
+ const formValue = this.$refs.form.getFormValue()
+ const { code } = await this.$elBusHttp.request(
+ 'flower/api/flower/list/edit',
+ {
+ method: 'post',
+ data: { ...formValue, id: this.$route.params.id },
+ }
+ )
+ if (code === 0) {
+ this.$message.success('保存成功')
+ this.goBack()
+ } else {
+ this.loading = false
+ }
+ },
+ },
+}
+</script>
diff --git a/pages/goods/list/index.vue b/pages/goods/list/index.vue
new file mode 100644
index 0000000..f126596
--- /dev/null
+++ b/pages/goods/list/index.vue
@@ -0,0 +1,637 @@
+<template>
+ <el-bus-crud ref="crud" v-bind="tableConfig" ></el-bus-crud>
+</template>
+
+<script>
+import { getSortConfig,getGoodsCategoryListConfig} from '@/utils/form-item-config'
+export default {
+ data() {
+ return {
+ tableConfig: {
+ url: 'flower/api/flower/list',
+ hasNew: false,
+ persistSelection: true,
+ operationAttrs: {
+ width: '170px',
+ fixed: 'right',
+ },
+ onResetEdit: (row) => {
+ this.$router.push(`${this.$route.path}/edit/${row.id}`)
+ },
+ onResetView: (row) => {
+ this.$router.push(`${this.$route.path}/view/${row.id}`)
+ },
+ columns: [
+ { type: 'selection' },
+ { label: '商品名称', prop: 'name', minWidth: 150, fixed: 'left' },
+ {
+ label: '商品封面',
+ formatter: (row) =>
+ row.cover ? (
+ <el-bus-image
+ src={row.cover}
+ lazy={true}
+ style="width:50px;height:50px"
+ ></el-bus-image>
+ ) : null,
+ minWidth: 100,
+ },
+ { label: '级别', prop: 'levelStr', minWidth: 80 },
+ { label: '颜色', prop: 'color', minWidth: 100 },
+ { label: '供应商名称', prop: 'supplierName', minWidth: 150 },
+ { label: '供应商类型', prop: 'supplierType', minWidth: 150 },
+ { label: '商品售价', prop: 'price', minWidth: 120 },
+ { label: '虚拟销量', prop: 'sales', minWidth: 120 },
+ { label: '真实销量', prop: 'realSales', minWidth: 120 },
+ { label: '库存', prop: 'stock', minWidth: 120 },
+ { label: '限购数量', prop: 'limited', minWidth: 120 },
+ { label: '商品状态', prop: 'statusStr', minWidth: 80 },
+ { label: '商品标签', prop: 'tags', minWidth: 150 },
+ { label: '所属专区', prop: 'zoneName', minWidth: 150 },
+ {
+ label: '是否推荐',
+ formatter: (row) => (row.recommend ? '是' : '否'),
+ minWidth: 100,
+ },
+ { label: '推荐排序', prop: 'recommendRank', minWidth: 120 },
+ { label: '提交时间', prop: 'createTime', minWidth: 180 },
+ { label: '审核时间', prop: 'auditTime', minWidth: 180 },
+ {
+ label: '是否显示',
+ formatter: (row) => (
+ <el-switch
+ value={row.shown}
+ onChange={this.onShownChange.bind(this, row)}
+ ></el-switch>
+ ),
+ minWidth: 120,
+ fixed: 'right',
+ },
+ ],
+ searchFormAttrs: {
+ labelWidth: 'auto',
+ },
+ searchForm: [
+ {
+ type: 'row',
+ items: [
+ {
+ label: '商品标签:',
+ id: 'tags',
+ type: 'bus-radio',
+ el: {
+ otherInterfaceUri: 'flower/api/flower/tag/list',
+ hasAll: true,
+ props: {
+ label: 'name',
+ value: 'name',
+ dataPath: 'records',
+ },
+ extraQuery: {
+ current: 1,
+ size: 2000,
+ },
+ childType: 'el-radio-button',
+ },
+ default: '',
+ span: 24,
+ searchImmediately: true,
+ },
+ {
+ label: '商品状态:',
+ id: 'status',
+ type: 'bus-radio',
+ el: {
+ code: 'FLOWER_STATUS',
+ hasAll: true,
+ childType: 'el-radio-button',
+ },
+ default: this.$route.query.status || '',
+ span: 24,
+ searchImmediately: true,
+ },
+ {
+ label: '是否推荐:',
+ id: 'recommend',
+ type: 'bus-radio',
+ el: {
+ fromDict: false,
+ hasAll: true,
+ childType: 'el-radio-button',
+ options: [
+ { label: '是', value: true },
+ { label: '否', value: false },
+ ],
+ },
+ default: '',
+ span: 24,
+ searchImmediately: true,
+ },
+ {
+ label: '是否限购:',
+ id: 'isLimited',
+ type: 'bus-radio',
+ el: {
+ fromDict: false,
+ hasAll: true,
+ childType: 'el-radio-button',
+ options: [
+ { label: '是', value: true },
+ { label: '否', value: false },
+ ],
+ },
+ default: '',
+ span: 24,
+ searchImmediately: true,
+ },
+ {
+ label: '所属专区:',
+ id: 'zoneId',
+ type: 'bus-radio',
+ el: {
+ otherInterfaceUri: 'flower/api/flower/zone/list',
+ hasAll: true,
+ childType: 'el-radio-button',
+ props: {
+ label: 'name',
+ value: 'id',
+ },
+ },
+ default: '',
+ span: 24,
+ searchImmediately: true,
+ },
+ // {
+ // label: '商品分类:',
+ // id: 'category',
+ // component: 'cascader-filter',
+ // el: {
+ // otherInterfaceUri: 'flower/api/flower/category/tree',
+ // props: {
+ // label: 'name',
+ // value: 'id',
+ // checkStrictly: true,
+ // },
+ // emitPath: false,
+ // style: 'width:100%',
+ // clearable: true,
+ // hasAll: true,
+ // childType: 'el-radio-button',
+ // },
+ // span: 24,
+ // searchImmediately: true,
+ // },
+ {
+ label: '商品分类',
+ id: 'category',
+ type: 'bus-cascader',
+ el: {
+ otherInterfaceUri: 'flower/api/flower/category/tree',
+ props: {
+ label: 'name',
+ value: 'id',
+ emitPath: false,
+ checkStrictly: true,
+ },
+ clearable: true,
+ filterable: true,
+ style: 'width:100%',
+ },
+ },
+ // {
+ // ...getGoodsCategoryListConfig(),
+ // id: 'category',
+ // },
+ { label: '商品名称:', id: 'name', type: 'input' },
+ { label: '供应商:', id: 'supplierName', type: 'input' },
+ ],
+ },
+ ],
+ extraButtons: [
+ {
+ text: '审核',
+ show: (row) => row.status === 'PENDING',
+ atClick: (row) => {
+ this.$refs.crud.$refs.extraDialog[0].show(row)
+ return false
+ },
+ },
+ {
+ text: '设置推荐排序',
+ show: (row) => row.recommend,
+ atClick: (row) => {
+ this.$refs.crud.$refs.extraDialog[3].show(row)
+ return false
+ },
+ },
+ ],
+ headerButtons: [
+ {
+ text: '批量强制下架',
+ type: 'primary',
+ disabled: (selected) =>
+ selected.filter((item) => item.status === 'UP').length === 0,
+ atClick: async (selected) => {
+ try {
+ const selectedGoods = selected.filter(
+ (item) => item.status === 'UP'
+ )
+ await this.$elBusUtil.confirm(
+ `确定要批量强制下架这${selectedGoods.length}个商品吗?`
+ )
+ const { code } = await this.$elBusHttp.request(
+ 'flower/api/flower/list/off',
+ {
+ method: 'post',
+ data: {
+ ids: selectedGoods.map((item) => item.id),
+ },
+ }
+ )
+ if (code === 0) {
+ this.$message.success('操作成功')
+ this.$refs.crud.clearSelection()
+ } else {
+ return false
+ }
+ } catch (e) {
+ return false
+ }
+ },
+ },
+ {
+ text: '批量设置标签',
+ type: 'primary',
+ disabled: (selected) => selected.length === 0,
+ atClick: (selected) => {
+ this.$refs.crud.$refs.extraDialog[1].show({
+ ids: selected.map((item) => item.id),
+ tags: selected.length === 1 ? selected[0].tags : null,
+ })
+ return false
+ },
+ },
+ {
+ text: '批量添加专区',
+ type: 'primary',
+ disabled: (selected) => selected.length === 0,
+ atClick: (selected) => {
+ this.$refs.crud.$refs.extraDialog[2].show({
+ ids: selected.map((item) => item.id),
+ zoneId: selected.length === 1 ? selected[0].zoneId : null,
+ })
+ return false
+ },
+ },
+ {
+ text: '批量设置推荐',
+ type: 'primary',
+ disabled: (selected) =>
+ selected.filter((item) => !item.recommend).length === 0,
+ atClick: async (selected) => {
+ try {
+ const selectedGoods = selected.filter((item) => !item.recommend)
+ await this.$elBusUtil.confirm(
+ `确定要批量将这${selectedGoods.length}个商品设置为推荐吗?`
+ )
+ const { code } = await this.$elBusHttp.request(
+ 'flower/api/flower/list/recommend/set',
+ {
+ method: 'post',
+ data: {
+ ids: selectedGoods.map((item) => item.id),
+ },
+ }
+ )
+ if (code === 0) {
+ this.$message.success('操作成功')
+ this.$refs.crud.clearSelection()
+ } else {
+ return false
+ }
+ } catch (e) {
+ return false
+ }
+ },
+ },
+ {
+ text: '批量取消推荐',
+ type: 'primary',
+ disabled: (selected) =>
+ selected.filter((item) => item.recommend).length === 0,
+ atClick: async (selected) => {
+ try {
+ const selectedGoods = selected.filter((item) => item.recommend)
+ await this.$elBusUtil.confirm(
+ `确定要批量将这${selectedGoods.length}个商品取消推荐吗?`
+ )
+ const { code } = await this.$elBusHttp.request(
+ 'flower/api/flower/list/recommend/cancel',
+ {
+ method: 'post',
+ data: {
+ ids: selectedGoods.map((item) => item.id),
+ },
+ }
+ )
+ if (code === 0) {
+ this.$message.success('操作成功')
+ this.$refs.crud.clearSelection()
+ } else {
+ return false
+ }
+ } catch (e) {
+ return false
+ }
+ },
+ },
+ {
+ text: '批量审核',
+ type: 'primary',
+ disabled: (selected) =>
+ selected.filter((item) => item.status === 'PENDING').length === 0,
+ atClick: (selected) => {
+ this.$refs.crud.$refs.extraDialog[0].show({
+ ids: selected
+ .filter((item) => item.status === 'PENDING')
+ .map((item) => item.id),
+ })
+ return false
+ },
+ },
+ {
+ text: '每人限购',
+ type: 'primary',
+ disabled: (selected) => selected.length === 0,
+ atClick: (selected) => {
+ this.$refs.crud.$refs.extraDialog[4].show({
+ ids: selected.map((item) => item.id),
+ limited:
+ selected.length === 1
+ ? this.$elBusUtil.isTrueEmpty(selected[0].limited)
+ ? undefined
+ : selected[0].limited
+ : undefined,
+ })
+ return false
+ },
+ },
+ ],
+ extraDialogs: [
+ {
+ title: '审核',
+ form: [
+ {
+ id: 'ids',
+ type: 'select',
+ el: {
+ multiple: true,
+ },
+ hidden: () => true,
+ },
+ {
+ label: '审核意见:',
+ id: 'result',
+ type: 'radio-group',
+ options: [
+ { label: '审核通过', value: 'Y' },
+ { label: '审核不通过', value: 'N' },
+ ],
+ rules: { required: true, message: '请选择审核意见' },
+ on: {
+ change: (e, updateForm) => {
+ updateForm({ auditRemarks: '' })
+ },
+ },
+ },
+ {
+ label: '不通过原因:',
+ id: 'auditRemarks',
+ type: 'input',
+ el: {
+ type: 'textarea',
+ rows: 6,
+ },
+ rules: {
+ required: true,
+ message: '请输入不通过原因',
+ trigger: 'blur',
+ },
+ hidden: (row) => row.result !== 'N',
+ },
+ ],
+ atConfirm: async (val) => {
+ let url = ''
+ if (Array.isArray(val.ids) && val.ids.length > 0) {
+ url =
+ val.result === 'Y'
+ ? 'flower/api/flower/list/pass/multi'
+ : 'flower/api/flower/list/reject/multi'
+ } else {
+ url =
+ val.result === 'Y'
+ ? 'flower/api/flower/list/pass'
+ : 'flower/api/flower/list/reject'
+ }
+ const { code } = await this.$elBusHttp.request(url, {
+ method: 'post',
+ data: val,
+ })
+ if (code === 0) {
+ this.$message.success('操作成功')
+ this.$refs.crud.clearSelection()
+ }
+ },
+ },
+ {
+ title: '批量设置标签',
+ form: [
+ {
+ id: 'ids',
+ type: 'select',
+ el: {
+ multiple: true,
+ },
+ hidden: () => true,
+ },
+ {
+ label: '标签:',
+ id: 'tags',
+ type: 'bus-select',
+ el: {
+ interfaceUri: 'flower/api/flower/tag/list',
+ extraQuery: {
+ current: 1,
+ size: 2000,
+ },
+ props: {
+ label: 'name',
+ value: 'name',
+ dataPath: 'records',
+ },
+ filterable: true,
+ multiple: true,
+ style: 'width:100%',
+ },
+ outputFormat: (val) => {
+ return Array.isArray(val) ? val.join(',') : null
+ },
+ inputFormat: (row) => {
+ if ('tags' in row) {
+ return row.tags ? row.tags.split(',') : []
+ }
+ },
+ },
+ ],
+ atConfirm: async (val) => {
+ const { code } = await this.$elBusHttp.request(
+ 'flower/api/flower/list/tags',
+ {
+ method: 'post',
+ data: val,
+ }
+ )
+ if (code === 0) {
+ this.$message.success('操作成功')
+ this.$refs.crud.clearSelection()
+ }
+ },
+ },
+ {
+ title: '批量添加专区',
+ form: [
+ {
+ id: 'ids',
+ type: 'select',
+ el: {
+ multiple: true,
+ },
+ hidden: () => true,
+ },
+ {
+ label: '专区:',
+ id: 'zoneId',
+ type: 'bus-select',
+ el: {
+ interfaceUri: 'flower/api/flower/zone/list',
+ props: {
+ label: 'name',
+ value: 'id',
+ },
+ filterable: true,
+ multiple: true,
+ style: 'width:100%',
+ },
+ inputFormat: (row) => {
+ if ('zoneId' in row) {
+ return row.zoneId
+ ? row.zoneId.split(',').map((i) => parseInt(i))
+ : []
+ }
+ },
+ },
+ ],
+ atConfirm: async (val) => {
+ const { code } = await this.$elBusHttp.request(
+ 'flower/api/flower/list/zones',
+ {
+ method: 'post',
+ data: val,
+ }
+ )
+ if (code === 0) {
+ this.$message.success('操作成功')
+ this.$refs.crud.clearSelection()
+ }
+ },
+ },
+ {
+ title: '设置推荐排序',
+ form: [
+ {
+ ...getSortConfig('recommendRank'),
+ },
+ ],
+ atConfirm: async (val) => {
+ const { code } = await this.$elBusHttp.request(
+ 'flower/api/flower/list/recommend/set/rank',
+ {
+ method: 'post',
+ data: val,
+ }
+ )
+ if (code === 0) {
+ this.$message.success('设置成功')
+ }
+ },
+ },
+ {
+ title: '每人限购',
+ form: [
+ {
+ id: 'ids',
+ type: 'select',
+ el: {
+ multiple: true,
+ },
+ hidden: () => true,
+ },
+ {
+ label: '限购数量:',
+ id: 'limited',
+ type: 'input-number',
+ el: {
+ precision: 0,
+ min: 1,
+ max: 99999999,
+ style: 'width:100%',
+ },
+ },
+ ],
+ atConfirm: async (val) => {
+ const { code } = await this.$elBusHttp.request(
+ 'flower/api/flower/list/limiteds',
+ {
+ method: 'post',
+ data: val,
+ }
+ )
+ if (code === 0) {
+ this.$message.success('操作成功')
+ this.$refs.crud.clearSelection()
+ }
+ },
+ },
+ ],
+ },
+ }
+ },
+ head() {
+ return {
+ title: '商品列表',
+ }
+ },
+ methods: {
+ onShownChange(row, e) {
+ const url = e
+ ? 'flower/api/flower/list/shown'
+ : 'flower/api/flower/list/hidden'
+ const text = e ? '显示' : '隐藏'
+ this.$elBusUtil
+ .confirm(`确定要${text}这个商品吗?`)
+ .then(async () => {
+ const { code } = await this.$elBusHttp.request(url, {
+ params: {
+ id: row.id,
+ },
+ })
+ if (code === 0) {
+ this.$message.success(`${text}成功`)
+ this.$refs.crud.getList()
+ }
+ })
+ .catch(() => {})
+ },
+ },
+}
+</script>
diff --git a/pages/goods/param/_id.vue b/pages/goods/param/_id.vue
new file mode 100644
index 0000000..814b19b
--- /dev/null
+++ b/pages/goods/param/_id.vue
@@ -0,0 +1,59 @@
+<template>
+ <el-bus-crud v-bind="tableConfig" />
+</template>
+
+<script>
+import { getSortConfig } from '@/utils/form-item-config'
+export default {
+ data() {
+ return {
+ tableConfig: {
+ url: 'flower/api/flower/param/list/items',
+ extraQuery: {
+ id: this.$route.params.id,
+ },
+ extraBody: {
+ paramId: this.$route.params.id,
+ },
+ hasPagination: false,
+ columns: [
+ { label: '参数名称', prop: 'name' },
+ { label: '参数值', prop: 'content' },
+ ],
+ form: [
+ {
+ label: '参数名称:',
+ id: 'name',
+ type: 'input',
+ rules: {
+ required: true,
+ message: '请输入参数名称',
+ trigger: 'blur',
+ },
+ },
+ {
+ label: '参数值:',
+ id: 'content',
+ type: 'input',
+ rules: {
+ required: true,
+ message: '请输入参数值',
+ trigger: 'blur',
+ },
+ },
+ {
+ ...getSortConfig(),
+ },
+ ],
+ },
+ }
+ },
+ head() {
+ return {
+ title: '参数列表',
+ }
+ },
+}
+</script>
+
+<style lang="scss" scoped></style>
diff --git a/pages/goods/param/index.vue b/pages/goods/param/index.vue
new file mode 100644
index 0000000..40f14fa
--- /dev/null
+++ b/pages/goods/param/index.vue
@@ -0,0 +1,89 @@
+<template>
+ <el-bus-crud v-bind="tableConfig" />
+</template>
+
+<script>
+import { getSortConfig } from '@/utils/form-item-config'
+export default {
+ data() {
+ return {
+ tableConfig: {
+ url: 'flower/api/flower/param/list',
+ dialogNeedRequest: true,
+ extraButtons: [
+ {
+ text: '参数列表',
+ atClick: (row) => {
+ this.$router.push(`${this.$route.path}/${row.id}`)
+ },
+ },
+ ],
+ columns: [
+ { label: '参数模板名称', prop: 'name' },
+ { label: '关联分类', prop: 'categories' },
+ { label: '创建时间', prop: 'createTime' },
+ ],
+ searchForm: [
+ {
+ type: 'row',
+ items: [
+ { label: '参数模板名称', id: 'name', type: 'input' },
+ {
+ label: '商品分类',
+ id: 'categoryId',
+ type: 'bus-cascader',
+ el: {
+ otherInterfaceUri: 'flower/api/flower/category/tree',
+ props: {
+ label: 'name',
+ value: 'id',
+ emitPath: false,
+ },
+ style: 'width:100%',
+ },
+ },
+ ],
+ },
+ ],
+ form: [
+ {
+ label: '参数模板名称:',
+ id: 'name',
+ type: 'input',
+ rules: {
+ required: true,
+ message: '请输入参数模板名称',
+ trigger: 'blur',
+ },
+ },
+ {
+ label: '商品分类:',
+ id: 'categoryIds',
+ type: 'bus-cascader',
+ el: {
+ otherInterfaceUri: 'flower/api/flower/category/tree',
+ props: {
+ label: 'name',
+ value: 'id',
+ multiple: true,
+ emitPath: false,
+ },
+ style: 'width:100%',
+ },
+ str: true,
+ strKey: 'categories',
+ },
+ {
+ ...getSortConfig(),
+ },
+ ],
+ },
+ }
+ },
+ head() {
+ return {
+ title: '参数模板',
+ }
+ },
+}
+</script>
diff --git a/pages/goods/tag.vue b/pages/goods/tag.vue
new file mode 100644
index 0000000..c8d6cce
--- /dev/null
+++ b/pages/goods/tag.vue
@@ -0,0 +1,51 @@
+<template>
+ <el-bus-crud v-bind="tableConfig" />
+</template>
+
+<script>
+export default {
+ data() {
+ return {
+ tableConfig: {
+ url: 'flower/api/flower/tag/list',
+ columns: [
+ { label: '标签名称', prop: 'name' },
+ { label: '标签描述', prop: 'remarks' },
+ ],
+ searchForm: [
+ {
+ type: 'row',
+ items: [{ label: '标签名称', id: 'name', type: 'input' }],
+ },
+ ],
+ form: [
+ {
+ label: '标签名称:',
+ id: 'name',
+ type: 'input',
+ rules: {
+ required: true,
+ message: '请输入标签名称',
+ trigger: 'blur',
+ },
+ },
+ {
+ label: '标签说明:',
+ id: 'remarks',
+ type: 'input',
+ el: {
+ type: 'textarea',
+ rows: 6,
+ },
+ },
+ ],
+ },
+ }
+ },
+ head() {
+ return {
+ title: '标签列表',
+ }
+ },
+}
+</script>
diff --git a/pages/goods/zone/_id.vue b/pages/goods/zone/_id.vue
new file mode 100644
index 0000000..2899e3a
--- /dev/null
+++ b/pages/goods/zone/_id.vue
@@ -0,0 +1,103 @@
+<template>
+ <el-bus-crud ref="crud" v-bind="tableConfig" />
+</template>
+
+<script>
+import { getSortConfig } from '@/utils/form-item-config'
+export default {
+ data() {
+ return {
+ tableConfig: {
+ url: 'flower/api/flower/zone/page/flower/list',
+ hasNew: false,
+ hasEdit: false,
+ hasDelete: false,
+ hasView: false,
+ extraQuery: {
+ zoneId: this.$route.params.id,
+ },
+ columns: [
+ { label: '商品名称', prop: 'name', minWidth: 150, fixed: 'left' },
+ {
+ label: '商品封面',
+ formatter: (row) =>
+ row.cover ? (
+ <el-bus-image
+ src={row.cover}
+ lazy={true}
+ style="width:50px;height:50px"
+ ></el-bus-image>
+ ) : null,
+ minWidth: 100,
+ },
+ { label: '级别', prop: 'levelStr', minWidth: 80 },
+ { label: '颜色', prop: 'color', minWidth: 100 },
+ { label: '供应商名称', prop: 'supplierName', minWidth: 150 },
+ { label: '商品售价', prop: 'price', minWidth: 120 },
+ { label: '库存', prop: 'stock', minWidth: 120 },
+ { label: '商品状态', prop: 'statusStr', minWidth: 80 },
+ { label: '商品标签', prop: 'tags', minWidth: 150 },
+ { label: '提交时间', prop: 'createTime', minWidth: 180 },
+ { label: '排序', prop: 'zoneRank', minWidth: 120, fixed: 'right' },
+ ],
+ searchForm: [
+ {
+ type: 'row',
+ items: [
+ { label: '商品名称:', id: 'name', type: 'input' },
+ { label: '供应商:', id: 'supplierName', type: 'input' },
+ ],
+ },
+ ],
+ extraButtons: [
+ {
+ text: '设置排序',
+ atClick: (row) => {
+ this.$refs.crud.$refs.extraDialog[0].show({
+ flowerId: row.id,
+ rank: row.zoneRank,
+ })
+ return false
+ },
+ },
+ ],
+ extraDialogs: [
+ {
+ title: '设置排序',
+ form: [
+ {
+ id: 'flowerId',
+ type: 'input',
+ hidden: () => true,
+ },
+ {
+ ...getSortConfig('rank'),
+ },
+ ],
+ atConfirm: async (val) => {
+ const { code } = await this.$elBusHttp.request(
+ 'flower/api/flower/zone/page/set/rank',
+ {
+ method: 'post',
+ data: {
+ ...val,
+ id: this.$route.params.id,
+ },
+ }
+ )
+ if (code === 0) {
+ this.$message.success('设置成功')
+ }
+ },
+ },
+ ],
+ },
+ }
+ },
+ head() {
+ return {
+ title: '专区商品',
+ }
+ },
+}
+</script>
diff --git a/pages/goods/zone/index.vue b/pages/goods/zone/index.vue
new file mode 100644
index 0000000..f58e4d7
--- /dev/null
+++ b/pages/goods/zone/index.vue
@@ -0,0 +1,103 @@
+<template>
+ <el-bus-crud v-bind="tableConfig" />
+</template>
+
+<script>
+import { getSortConfig } from '@/utils/form-item-config'
+export default {
+ data() {
+ return {
+ tableConfig: {
+ url: 'flower/api/flower/zone/page',
+ columns: [
+ { label: '专区标题', prop: 'name' },
+ {
+ label: '专区图片',
+ formatter: (row) => (
+ <el-bus-image
+ src={row.bgUrl}
+ lazy={true}
+ style="height:44px"
+ ></el-bus-image>
+ ),
+ },
+ { label: '排序', prop: 'seq' },
+ { label: '状态', prop: 'statusStr' },
+ ],
+ searchForm: [
+ {
+ type: 'row',
+ items: [{ label: '专区标题', id: 'name', type: 'input' }],
+ },
+ ],
+ form: [
+ {
+ label: '专区标题:',
+ id: 'name',
+ type: 'input',
+ rules: {
+ required: true,
+ message: '请输入专区标题',
+ trigger: 'blur',
+ },
+ },
+ {
+ label: '专区图片:',
+ id: 'bgUrl',
+ type: 'bus-upload',
+ el: {
+ listType: 'picture-card',
+ limit: 1,
+ limitSize: 2,
+ tipText: '大小不超过2M',
+ valueType: 'string',
+ },
+ rules: {
+ required: true,
+ message: '请上传专区图片',
+ },
+ forceDisabled: true,
+ },
+ {
+ ...getSortConfig('seq'),
+ },
+ ],
+ extraButtons: [
+ {
+ text: (row) => (row.status === 'unpublished' ? '发布' : '下架'),
+ atClick: async (row) => {
+ const action = row.status === 'unpublished' ? '发布' : '下架'
+ try {
+ await this.$elBusUtil.confirm(`确定要${action}吗?`)
+ const { code } = await this.$elBusHttp.request(
+ 'flower/api/flower/zone/page/changeStatus',
+ { params: { id: row.id } }
+ )
+ if (code === 0) {
+ this.$message.success(`${action}成功`)
+ }
+ } catch (e) {
+ return false
+ }
+ },
+ },
+ {
+ text: '查看商品',
+ atClick: (row) => {
+ const url = this.$router.resolve(
+ `${this.$route.path}/${row.id}`
+ ).href
+ window.open(url, '_blank')
+ },
+ },
+ ],
+ },
+ }
+ },
+ head() {
+ return {
+ title: '专区列表',
+ }
+ },
+}
+</script>
diff --git a/pages/home.vue b/pages/home.vue
new file mode 100644
index 0000000..ba02cfb
--- /dev/null
+++ b/pages/home.vue
@@ -0,0 +1,426 @@
+<template>
+ <div class="home-page">
+ <div class="block-container">
+ <div class="block-container__title">待办事项</div>
+ <el-row :gutter="30">
+ <el-col v-for="item in todoList" :key="item.key" :span="6">
+ <div class="simple-item is-cursor" @click="toRoute(item.url)">
+ <img :src="item.icon" class="simple-item__img" />
+ <div>
+ <div class="simple-item__value">
+ {{ statistic[item.key] || 0 }}
+ </div>
+ <div class="simple-item__label">{{ item.label }}</div>
+ </div>
+ </div>
+ </el-col>
+ </el-row>
+ </div>
+ <div class="block-container">
+ <div class="block-container__title">销售数据</div>
+ <el-row :gutter="30">
+ <el-col
+ v-for="item in saleList"
+ :key="item.key"
+ :span="6"
+ class="bg-wrapper"
+ >
+ <div class="bg-item">
+ <div class="bg-item__label">{{ item.label }}</div>
+ <div class="bg-item__value">{{ statistic[item.key] || 0 }}</div>
+ </div>
+ </el-col>
+ </el-row>
+ </div>
+ <div class="block-container">
+ <div class="block-container__title">供应商财务</div>
+ <el-row :gutter="30">
+ <el-col v-for="item in supplierFinanceList" :key="item.key" :span="6">
+ <div class="simple-item">
+ <img :src="item.icon" class="simple-item__img" />
+ <div>
+ <div class="simple-item__value">
+ {{ statistic[item.key] || 0 }}
+ </div>
+ <div class="simple-item__label">{{ item.label }}</div>
+ </div>
+ </div>
+ </el-col>
+ </el-row>
+ </div>
+ <div class="block-container">
+ <div class="block-container__title">商品数据</div>
+ <el-row :gutter="30">
+ <el-col v-for="item in goodsList" :key="item.key" :span="6">
+ <div class="simple-item is-cursor" @click="toRoute(item.url)">
+ <img :src="item.icon" class="simple-item__img" />
+ <div>
+ <div class="simple-item__value">
+ {{ statistic[item.key] || 0 }}
+ </div>
+ <div class="simple-item__label">{{ item.label }}</div>
+ </div>
+ </div>
+ </el-col>
+ </el-row>
+ </div>
+ <div class="block-container">
+ <div class="block-container__title">店铺数据</div>
+ <el-row :gutter="30">
+ <el-col v-for="item in shopList" :key="item.key" :span="6">
+ <div class="rate-container">
+ <div class="rate-container__title">
+ {{ item.title }}:{{ getRateValue(item.key, 'count') || 0 }}
+ </div>
+ <div class="rate-container__desc">
+ <div>
+ {{ item.desc }}:{{ getRateValue(item.key, 'countToday') || 0 }}
+ </div>
+ <div :class="getRateClass(getRateValue(item.key, 'countRate'))">
+ 日环比:{{ getRateValue(item.key, 'countRate') || 0 }}%
+ <img
+ v-if="getRateValue(item.key, 'countRate') > 0"
+ src="~static/images/home/up.png"
+ class="rate-container__img"
+ />
+ <img
+ v-if="getRateValue(item.key, 'countRate') < 0"
+ src="~static/images/home/down.png"
+ class="rate-container__img"
+ />
+ </div>
+ </div>
+ </div>
+ </el-col>
+ </el-row>
+ </div>
+ </div>
+</template>
+
+<script>
+export default {
+ data() {
+ return {
+ currentDate: this.$elBusUtil.toDate(),
+ statistic: {},
+ orderStatistic: {},
+ supplierStatistic: {},
+ userStatistic: {},
+ visitStatistic: {},
+ saleStatistic: {},
+ todoList: [
+ {
+ label: '待发货',
+ key: 'orderSendCount',
+ icon: require('@/static/images/home/dfh.png'),
+ url: '/order/list?statusBackend=SEND',
+ },
+ {
+ label: '待审核商品',
+ key: 'flowerPendingCount',
+ icon: require('@/static/images/home/dshsp.png'),
+ url: '/goods/list?status=PENDING',
+ },
+ {
+ label: '待售后处理',
+ key: 'orderSalesCount',
+ icon: require('@/static/images/home/dshcl.png'),
+ url: '/order/after-sale?status=PENDING',
+ },
+ ],
+ saleList: [
+ {
+ label: '今日销售额(元)',
+ key: 'saleAmount',
+ },
+ {
+ label: '今日销售扎数(个)',
+ key: 'saleFlowerCount',
+ },
+ {
+ label: '总销售金额(元)',
+ key: 'totalSaleAmount',
+ },
+ {
+ label: '总销售扎数(个)',
+ key: 'totalSaleFlowerCount',
+ },
+ ],
+ supplierFinanceList: [
+ {
+ label: '供应商待提现(元)',
+ key: 'supplierPendingAmount',
+ icon: require('@/static/images/home/gysdtx.png'),
+ },
+ {
+ label: '供应商已提现(元)',
+ key: 'supplierCompleteAmount',
+ icon: require('@/static/images/home/gysytx.png'),
+ },
+ ],
+ goodsList: [
+ {
+ label: '商品管理',
+ key: 'flowerCount',
+ icon: require('@/static/images/home/spgl.png'),
+ url: '/goods/list',
+ },
+ {
+ label: '在售商品',
+ key: 'flowerUpCount',
+ icon: require('@/static/images/home/zssp.png'),
+ url: '/goods/list?status=UP',
+ },
+ {
+ label: '用户管理',
+ key: 'customerCount',
+ icon: require('@/static/images/home/yhgl.png'),
+ url: '/shop/list',
+ },
+ {
+ label: '订单管理',
+ key: 'orderCount',
+ icon: require('@/static/images/home/ddgl.png'),
+ url: '/order/list',
+ },
+ ],
+ shopList: [
+ {
+ title: '订单量',
+ desc: '新增订单量',
+ key: 'orderStatistic',
+ },
+ {
+ title: '供应商数量',
+ desc: '新增供应商',
+ key: 'supplierStatistic',
+ },
+ {
+ title: '全部用户量',
+ desc: '新增用户量',
+ key: 'userStatistic',
+ },
+ {
+ title: '用户访问量',
+ desc: '昨日访问量',
+ key: 'visitStatistic',
+ },
+ {
+ title: '售后订单数量',
+ desc: '新增售后量',
+ key: 'saleStatistic',
+ },
+ ],
+ }
+ },
+ head() {
+ return {
+ title: '首页',
+ }
+ },
+ mounted() {
+ this.init()
+ },
+ methods: {
+ async init() {
+ const [
+ res1,
+ res2,
+ res3,
+ orderRes,
+ supplierRes,
+ userRes,
+ visitRes,
+ saleRes,
+ ] = await Promise.all([
+ this.$elBusHttp.request('flower/api/statistics/sale/date', {
+ params: { date: this.currentDate },
+ }),
+ this.$elBusHttp.request('flower/api/statistics/flower/count'),
+ this.$elBusHttp.request('flower/api/statistics/order/amount'),
+ this.$elBusHttp.request('flower/api/statistics/order/rate', {
+ params: { date: this.currentDate },
+ }),
+ this.$elBusHttp.request('flower/api/statistics/supplier/rate', {
+ params: { date: this.currentDate },
+ }),
+ this.$elBusHttp.request('flower/api/statistics/customer/rate', {
+ params: { date: this.currentDate },
+ }),
+ this.$elBusHttp.request('flower/api/statistics/customer/visit/rate', {
+ params: { date: this.currentDate },
+ }),
+ this.$elBusHttp.request('flower/api/statistics/sales/rate', {
+ params: { date: this.currentDate },
+ }),
+ ])
+ this.statistic = { ...res1?.data, ...res2?.data, ...res3?.data }
+ this.orderStatistic = orderRes?.data || {}
+ this.supplierStatistic = supplierRes?.data || {}
+ this.userStatistic = userRes?.data || {}
+ this.visitStatistic = visitRes?.data || {}
+ this.saleStatistic = saleRes?.data || {}
+ },
+ getRateClass(rate) {
+ if (rate > 0) {
+ return 'text-success'
+ } else if (rate < 0) {
+ return 'text-danger'
+ } else {
+ return ''
+ }
+ },
+ toRoute(url) {
+ this.$router.push(url)
+ },
+ getRateValue(key1, key2) {
+ return this[key1]?.[key2]
+ },
+ },
+}
+</script>
+
+<style lang="scss" scoped>
+/* prettier-ignore */
+.home-page {
+ .block-container {
+ &:not(:last-child) {
+ margin-bottom: 36PX;
+ }
+ &__title {
+ font-size: 24PX;
+ color: $main-title-color;
+ font-weight: bold;
+ margin-bottom: 10PX;
+ }
+ .simple-item {
+ width: 100%;
+ height: 123PX;
+ background-color: #fff;
+ box-shadow: 0PX 2PX 12PX 0PX rgba(75, 76, 77, 0.1);
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ &.is-cursor {
+ cursor: pointer;
+ }
+ &__img {
+ width: 60PX;
+ height: 60PX;
+ margin-right: 22PX;
+ }
+ &__value {
+ font-size: 24PX;
+ color: $main-title-color;
+ font-weight: bold;
+ text-align: center;
+ }
+ &__label {
+ font-size: 18PX;
+ color: $sub-title-color;
+ text-align: center;
+ }
+ }
+ .bg-item {
+ width: 100%;
+ height: 123PX;
+ position: relative;
+ padding-left: 24PX;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ box-shadow: 0PX 2PX 12PX 0PX rgba(75, 76, 77, 0.1);
+ &::after {
+ content: '';
+ width: 111PX;
+ height: 94PX;
+ position: absolute;
+ right: 0;
+ bottom: 0;
+ }
+ &__value {
+ font-size: 28PX;
+ color: #fff;
+ font-weight: bold;
+ }
+ &__label {
+ font-size: 18PX;
+ color: #fff;
+ }
+ }
+ .bg-wrapper {
+ &:nth-child(1),
+ &:nth-child(2) {
+ .bg-item {
+ background: linear-gradient(136deg, #31bdff 0%, #1688fe 100%);
+ }
+ }
+ &:nth-child(3),
+ &:nth-child(4) {
+ .bg-item {
+ background: linear-gradient(135deg, #3ad1ea 0%, #01c0d6 100%);
+ }
+ }
+ &:nth-child(odd) {
+ .bg-item {
+ &::after {
+ background: url(~static/images/home/jrxse.png) no-repeat center/cover;
+ }
+ }
+ }
+ &:nth-child(even) {
+ .bg-item {
+ &::after {
+ background: url(~static/images/home/jrxszs.png) no-repeat center/cover;
+ }
+ }
+ }
+ }
+ .rate-container {
+ width: 100%;
+ height: 123PX;
+ background-color: #fff;
+ box-shadow: 0PX 2PX 12PX 0PX rgba(75, 76, 77, 0.1);
+ position: relative;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ padding: 0 24PX;
+ margin-bottom: 24PX;
+ &::after {
+ content: '今日';
+ width: 59PX;
+ height: 24PX;
+ background-color: #dcedff;
+ font-size: 14PX;
+ color: $primary-color;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ position: absolute;
+ top: 0;
+ right: 0;
+ }
+ &__title {
+ font-size: 20PX;
+ color: $main-title-color;
+ font-weight: bold;
+ margin-bottom: 10PX;
+ }
+ &__desc {
+ font-size: 16PX;
+ color: $sub-title-color;
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ }
+ &__img {
+ width: 16PX;
+ height: 16PX;
+ position: relative;
+ top: 2PX;
+ }
+ }
+ }
+}
+</style>
diff --git a/pages/index.vue b/pages/index.vue
new file mode 100644
index 0000000..3b01247
--- /dev/null
+++ b/pages/index.vue
@@ -0,0 +1,7 @@
+<template>
+ <div></div>
+</template>
+
+<script>
+export default {}
+</script>
diff --git a/pages/log/operation-record.vue b/pages/log/operation-record.vue
new file mode 100644
index 0000000..360f3bb
--- /dev/null
+++ b/pages/log/operation-record.vue
@@ -0,0 +1,77 @@
+<template>
+ <el-bus-crud ref="crud" v-bind="tableConfig" />
+</template>
+
+<script>
+export default {
+ data() {
+ return {
+ tableConfig: {
+ url: 'flower/api/operationRecord/list',
+ dialogNeedRequest: true,
+ persistSelection: true,
+ hasOperation: false,
+ hasNew: false,
+ columns: [
+ { label: '页面', prop: 'moduleName' },
+ { label: '动作', prop: 'function' },
+ { label: '操作人', prop: 'createName' },
+ { label: '操作时间', prop: 'createTime' },
+ { label: 'IP地址', prop: 'ipAddress' },
+ { label: '操作内容', prop: 'content' },
+ ],
+ searchForm: [
+ {
+ type: 'row',
+ items: [
+ {
+ label: '页面',
+ id: 'module',
+ type: 'bus-select-dict',
+ el: {
+ code: 'OPERATION_RECORD_MODULE',
+ style: 'width:100%',
+ },
+ },
+ { label: '动作', id: 'function', type: 'input' },
+ { label: '操作人', id: 'createName', type: 'input' },
+ { label: '操作内容', id: 'content', type: 'input', width: 500 },
+ {
+ label: '创建日期',
+ id: 'createDateBeginStr',
+ component: 'el-bus-date-range',
+ commonFormat: true,
+ commonFormatProps: ['createDateBeginStr', 'createDateEndStr'],
+ customClass: 'in-bus-form',
+ },
+ ],
+ },
+ ],
+ form: [],
+ extraButtons: [],
+ headerButtons: [],
+ },
+ }
+ },
+ head() {
+ return {
+ title: '操作日志',
+ }
+ },
+}
+</script>
+
+<style lang="scss" scoped>
+::v-deep {
+ .el-upload {
+ &-list__item {
+ width: 345px;
+ height: 128px;
+ }
+ &.el-upload--picture-card {
+ width: 345px;
+ height: 128px;
+ }
+ }
+}
+</style>
diff --git a/pages/login.vue b/pages/login.vue
new file mode 100644
index 0000000..10a8104
--- /dev/null
+++ b/pages/login.vue
@@ -0,0 +1,332 @@
+<template>
+
+ <div class="login-page"
+ :style="{
+ backgroundImage: 'url(' + bgUrl + ')',
+ backgroundSize: 'cover',
+ backgroundPosition: 'center',
+ height: '100vh' }
+ "
+ >
+ <div class="form-content">
+ <div class="text-22 font-bold text-mainTitle">HELLO</div>
+ <div class="text-26 font-bold text-mainTitle">
+ <!-- 欢迎来到<span class="text-primary">{{ platformName }}</span> -->
+ 欢迎来到<span class="text-primary">{{ copyright?.base_website_name }}</span>
+ </div>
+ <div class="flex items-center justify-center mt-50 mb-20">
+ <div
+ class="text-20 text-subTitle login-tab cursor-pointer mr-80"
+ :class="{ 'is-active': loginType === 'password' }"
+ @click="loginType = 'password'"
+ >
+ 密码登录
+ </div>
+ <div
+ class="text-20 text-subTitle login-tab cursor-pointer"
+ :class="{ 'is-active': loginType === 'sms' }"
+ @click="loginType = 'sms'"
+ >
+ 短信登录
+ </div>
+ </div>
+ <el-form
+ v-if="loginType === 'password'"
+ key="password"
+ ref="form"
+ size="medium"
+ :model="form"
+ :rules="rules"
+ >
+ <el-form-item prop="username">
+ <div class="input-wrapper">
+ <el-input
+ v-model="form.username"
+ placeholder="请输入用户名/手机号"
+ ></el-input>
+ </div>
+ </el-form-item>
+ <el-form-item prop="password">
+ <div class="input-wrapper">
+ <el-input
+ v-model="form.password"
+ placeholder="请输入密码"
+ type="password"
+ show-password
+ ></el-input>
+ </div>
+ </el-form-item>
+ <el-form-item prop="code">
+ <div class="input-wrapper">
+ <el-input v-model="form.code" placeholder="请输入图形验证码">
+ </el-input>
+ <img
+ v-if="captchaCodeImageSrc"
+ :src="captchaCodeImageSrc"
+ alt="图形验证码"
+ class="cursor-pointer w-auto h-45 object-contain"
+ @click="getCapacha"
+ />
+ </div>
+ </el-form-item>
+ <el-button
+ type="primary"
+ :loading="loading"
+ class="rounded-26 w-full h-50 mt-40"
+ @click="login"
+ >登录</el-button
+ >
+ </el-form>
+ <el-form
+ v-if="loginType === 'sms'"
+ key="sms"
+ ref="smsForm"
+ size="medium"
+ :model="smsForm"
+ :rules="smsRules"
+ >
+ <el-form-item prop="username">
+ <div class="input-wrapper">
+ <el-input
+ v-model="smsForm.username"
+ placeholder="请输入手机号"
+ ></el-input>
+ </div>
+ </el-form-item>
+ <el-form-item prop="smsCode">
+ <div class="input-wrapper">
+ <el-input v-model="smsForm.smsCode" placeholder="请输入短信验证码">
+ </el-input>
+ <el-bus-countdown-button
+ send-type="login"
+ :extra-body="{ userType: 'admin' }"
+ :number="smsForm.username"
+ type="text"
+ class="sms-button"
+ ></el-bus-countdown-button>
+ </div>
+ </el-form-item>
+ <el-form-item prop="code">
+ <div class="input-wrapper">
+ <el-input v-model="smsForm.code" placeholder="请输入图形验证码">
+ </el-input>
+ <img
+ v-if="smsCaptchaCodeImageSrc"
+ :src="smsCaptchaCodeImageSrc"
+ alt="图形验证码"
+ class="cursor-pointer w-auto h-45 object-contain"
+ @click="getSmsCapacha"
+ />
+ </div>
+ </el-form-item>
+ <el-button
+ type="primary"
+ :loading="loading"
+ class="rounded-26 w-full h-50 mt-40"
+ @click="smsLogin"
+ >登录</el-button
+ >
+ </el-form>
+
+ <div class="copyright">
+ <img class="copyright-logo" :src="logoUrl" /> {{ copyright?.base_website_name }} 版权所有 |
+ {{ copyright?.base_regisition_num }}
+ </div>
+ </div>
+
+ </div>
+
+</template>
+
+<script>
+export default {
+ layout: 'empty',
+ data() {
+ return {
+ platformName: this.$config.platformName,
+ loginType: 'password',
+ form: {},
+ smsForm: {},
+ loading: false,
+ captchaCodeImageSrc: null,
+ smsCaptchaCodeImageSrc: null,
+ rules: {
+ username: {
+ required: true,
+ message: '请输入用户名/手机号',
+ trigger: 'blur',
+ },
+ password: { required: true, message: '请输入密码', trigger: 'blur' },
+ code: { required: true, message: '请输入图形验证码', trigger: 'blur' },
+ },
+ smsRules: {
+ username: { required: true, message: '请输入手机号', trigger: 'blur' },
+ smsCode: {
+ required: true,
+ message: '请输入短信验证码',
+ trigger: 'blur',
+ },
+ code: { required: true, message: '请输入图形验证码', trigger: 'blur' },
+ },
+ copyright:{},
+ logoUrl:'',
+ bgUrl:'https://hmy-flower.oss-cn-shanghai.aliyuncs.com/87/878c638c06cf4c3080e6b7139f9a955cdshsp.png',
+ }
+ },
+ watch: {
+ loginType(val) {
+ if (val === 'sms' && !this.smsCaptchaCodeImageSrc) {
+ this.getSmsCapacha()
+ }
+ },
+ },
+ async mounted() {
+ await this.getCopyRight()
+ // 获取验证码图形
+ await this.getCapacha()
+ },
+ methods: {
+
+ async getCopyRight() {
+ const { code, data } = await this.$services.base.getBaseInfo()
+ if (code === 0) {
+ this.copyright = data
+ this.copyright.base_bg_url = JSON.parse(data.base_bg_url || [])
+ this.copyright.base_logo_url = JSON.parse(data.base_logo_url || [])
+ this.logoUrl = this.copyright?.base_logo_url[0]?.url
+ this.bgUrl=this.copyright?.base_bg_url[0]?.url
+ }
+ },
+ async getCapacha() {
+ const { captchaCodeId, imageSrc } =
+ await this.$services.base.createCaptcha()
+ this.form.codeId = captchaCodeId
+ this.captchaCodeImageSrc = imageSrc
+ },
+ async getSmsCapacha() {
+ const { captchaCodeId, imageSrc } =
+ await this.$services.base.createCaptcha()
+ this.smsForm.codeId = captchaCodeId
+ this.smsCaptchaCodeImageSrc = imageSrc
+ },
+ login() {
+ this.$refs.form.validate(async (res) => {
+ if (res) {
+ this.loading = true
+ const { code } = await this.$store.dispatch('auth/login', this.form)
+ if (code === 0) {
+ this.onLoginSuccess()
+ } else {
+ this.loading = false
+ this.getCapacha()
+ }
+ }
+ })
+ },
+ smsLogin() {
+ this.$refs.smsForm.validate(async (res) => {
+ if (res) {
+ this.loading = true
+ const { code } = await this.$store.dispatch(
+ 'auth/smsLogin',
+ this.smsForm
+ )
+ if (code === 0) {
+ this.onLoginSuccess()
+ } else {
+ this.loading = false
+ this.getSmsCapacha()
+ }
+ }
+ })
+ },
+ onLoginSuccess() {
+ const redirectUri = this.$elBusUtil.getQueryString('redirect_uri')
+ if (redirectUri) {
+ this.$router.replace(redirectUri).catch(() => {})
+ } else {
+ this.$router.replace('/').catch(() => {})
+ }
+ },
+ },
+}
+</script>
+
+<style lang="scss" scoped>
+.login-page {
+ width: 100%;
+ height: 100%;
+ overflow: hidden;
+ background: url('~static/images/login_bg.jpg') no-repeat center/cover;
+ display: flex;
+ align-items: center;
+ .form-content {
+ background-color: #fff;
+ width: 484px;
+ padding: 60px 48px;
+ margin-left: 20%;
+ .input-wrapper {
+ display: flex;
+ align-items: center;
+ border-bottom: 1px solid #cecece;
+ &:hover {
+ border-color: $primary-color;
+ }
+ }
+ ::v-deep {
+ .el-input {
+ flex: 1;
+ &__inner {
+ border: none;
+ border-radius: 0;
+ height: 50px;
+ line-height: 50px;
+ }
+ }
+ .el-form-item.is-error {
+ .input-wrapper {
+ border-color: $danger-color;
+ }
+ }
+ }
+ }
+ .login-tab {
+ position: relative;
+ &.is-active {
+ color: $primary-color;
+ font-weight: bold;
+ &::after {
+ content: '';
+ display: block;
+ width: 46px;
+ height: 5px;
+ border-radius: 3px;
+ background-color: $primary-color;
+ position: absolute;
+ left: 50%;
+ bottom: -6px;
+ transform: translateX(-50%);
+ }
+ }
+ }
+
+ .copyright {
+ width:100%;
+ margin: auto;
+ margin-top: 10px;
+ height: 20px;
+ display: flex;
+ justify-content: center;
+ align-content: center;
+ font-size: 12px;
+ color: gray;
+
+ .copyright-logo {
+ width: 15px;
+ height: 15px;
+ border-radius: 50px;
+ /* 设置圆角 */
+ }
+ }
+}
+</style>
diff --git a/pages/mark-up/edit-partner/_partnerId/category.vue b/pages/mark-up/edit-partner/_partnerId/category.vue
new file mode 100644
index 0000000..fe01d96
--- /dev/null
+++ b/pages/mark-up/edit-partner/_partnerId/category.vue
@@ -0,0 +1,28 @@
+<template>
+ <el-bus-crud v-bind="tableConfig" />
+</template>
+
+<script>
+import { categoryMarkUpConfig } from '@/utils/mark-up-config'
+export default {
+ data() {
+ return {
+ tableConfig: {
+ url: 'flower/api/flower/markup/spcg/list/platform',
+ newUrl: 'flower/api/flower/markup/spcg/list/save/platform',
+ editUrl: 'flower/api/flower/markup/spcg/list/save/platform',
+ hasDelete: false,
+ hasNew: false,
+ ...categoryMarkUpConfig(this.$route, this.$createElement),
+ },
+ }
+ },
+ head() {
+ return {
+ title: '合伙人加价-分类',
+ }
+ },
+}
+</script>
+
+<style lang="scss" scoped></style>
diff --git a/pages/mark-up/edit-partner/_partnerId/goods.vue b/pages/mark-up/edit-partner/_partnerId/goods.vue
new file mode 100644
index 0000000..bff97dd
--- /dev/null
+++ b/pages/mark-up/edit-partner/_partnerId/goods.vue
@@ -0,0 +1,29 @@
+<template>
+ <el-bus-crud v-bind="tableConfig" />
+</template>
+
+<script>
+import { goodsMarkUpConfig } from '@/utils/mark-up-config'
+
+export default {
+ data() {
+ return {
+ tableConfig: {
+ url: 'flower/api/flower/markup/sp/list/platform',
+ newUrl: 'flower/api/flower/markup/sp/list/save/platform',
+ editUrl: 'flower/api/flower/markup/sp/list/save/platform',
+ hasDelete: false,
+ hasNew: false,
+ ...goodsMarkUpConfig(this.$route, this.$createElement),
+ },
+ }
+ },
+ head() {
+ return {
+ title: '合伙人加价-商品',
+ }
+ },
+}
+</script>
+
+<style lang="scss" scoped></style>
diff --git a/pages/mark-up/edit-partner/index.vue b/pages/mark-up/edit-partner/index.vue
new file mode 100644
index 0000000..b792af9
--- /dev/null
+++ b/pages/mark-up/edit-partner/index.vue
@@ -0,0 +1,121 @@
+<template>
+ <el-bus-crud v-bind="tableConfig" />
+</template>
+
+<script>
+export default {
+ data() {
+ return {
+ tableConfig: {
+ url: 'flower/api/partner/page',
+ hasEdit: false,
+ hasNew: false,
+ hasDelete: false,
+ hasView: false,
+ extraQuery: {
+ status: 'P',
+ isEnabled: 1,
+ },
+ operationAttrs: {
+ width: 150,
+ fixed: 'right',
+ },
+ columns: [
+ { label: '合伙人名称', prop: 'name', minWidth: 120, fixed: 'left' },
+ {
+ label: '服务地区',
+ formatter: (row) => this.getDistrict(row),
+ minWidth: 200,
+ },
+ {
+ label: '联系方式',
+ prop: 'contactTel',
+ minWidth: 150,
+ },
+ { label: '注册时间', prop: 'createTime', minWidth: '180px' },
+ ],
+ searchForm: [
+ {
+ type: 'row',
+ items: [
+ {
+ label: '合伙人名称',
+ id: 'name',
+ type: 'input',
+ },
+ {
+ label: '手机号',
+ id: 'tel',
+ type: 'input',
+ },
+ {
+ label: '申请日期',
+ component: 'el-bus-date-range',
+ id: 'createDateBeginStr',
+ commonFormat: true,
+ commonFormatProps: ['createDateBeginStr', 'createDateEndStr'],
+ customClass: 'in-bus-form',
+ },
+ {
+ label: '服务地区',
+ id: 'province',
+ component: 'el-bus-select-area',
+ el: {
+ clearable: true,
+ },
+ commonFormat: true,
+ commonFormatProps: ['province', 'city', 'region'],
+ customClass: 'in-bus-form',
+ },
+ ],
+ },
+ ],
+ extraButtons: [
+ {
+ text: '分类加价',
+ atClick: (row) => {
+ const url = this.$router.resolve(
+ `${this.$route.path}/${row.id}/category?partnerName=${row.name}`
+ ).href
+ window.open(url, '_blank')
+ },
+ },
+ {
+ text: '商品加价',
+ atClick: (row) => {
+ const url = this.$router.resolve(
+ `${this.$route.path}/${row.id}/goods?partnerName=${row.name}`
+ ).href
+ window.open(url, '_blank')
+ },
+ },
+ ],
+ },
+ }
+ },
+ head() {
+ return {
+ title: '合伙人加价',
+ }
+ },
+ methods: {
+ getDistrict(row) {
+ if (row.province) {
+ return row.province
+ .split(',')
+ .map((item, index) =>
+ [
+ item,
+ row.city.split(',')[index],
+ row.region.split(',')[index],
+ ].join('-')
+ )
+ .join(',')
+ }
+ return ''
+ },
+ },
+}
+</script>
+
+<style lang="scss" scoped></style>
diff --git a/pages/mark-up/partner/_partnerId/category.vue b/pages/mark-up/partner/_partnerId/category.vue
new file mode 100644
index 0000000..e179a39
--- /dev/null
+++ b/pages/mark-up/partner/_partnerId/category.vue
@@ -0,0 +1,38 @@
+<template>
+ <el-bus-crud v-bind="tableConfig" />
+</template>
+
+<script>
+import { categoryMarkUpConfig } from '@/utils/mark-up-config'
+
+export default {
+ data() {
+ return {
+ tableConfig: {
+ url: 'flower/api/flower/markup/ps/spcg/list',
+ newUrl: 'flower/api/flower/markup/ps/spcg/list/save/batch',
+ editUrl: 'flower/api/flower/markup/ps/spcg/list/save',
+ onDelete: (row) => {
+ return this.$elBusHttp.request(
+ 'flower/api/flower/markup/ps/spcg/list/delete',
+ {
+ params: {
+ categoryId: row.categoryId,
+ partnerId: row.partnerId,
+ },
+ }
+ )
+ },
+ ...categoryMarkUpConfig(this.$route, this.$createElement, true),
+ },
+ }
+ },
+ head() {
+ return {
+ title: '平台加价-分类',
+ }
+ },
+}
+</script>
+
+<style lang="scss" scoped></style>
diff --git a/pages/mark-up/partner/_partnerId/goods.vue b/pages/mark-up/partner/_partnerId/goods.vue
new file mode 100644
index 0000000..8065624
--- /dev/null
+++ b/pages/mark-up/partner/_partnerId/goods.vue
@@ -0,0 +1,38 @@
+<template>
+ <el-bus-crud v-bind="tableConfig" />
+</template>
+
+<script>
+import { goodsMarkUpConfig } from '@/utils/mark-up-config'
+
+export default {
+ data() {
+ return {
+ tableConfig: {
+ url: 'flower/api/flower/markup/ps/sp/list',
+ newUrl: 'flower/api/flower/markup/ps/sp/list/save',
+ editUrl: 'flower/api/flower/markup/ps/sp/list/save',
+ onDelete: (row) => {
+ return this.$elBusHttp.request(
+ 'flower/api/flower/markup/ps/sp/list/delete',
+ {
+ params: {
+ flowerId: row.flowerId,
+ partnerId: row.partnerId,
+ },
+ }
+ )
+ },
+ ...goodsMarkUpConfig(this.$route, this.$createElement),
+ },
+ }
+ },
+ head() {
+ return {
+ title: '平台加价-商品',
+ }
+ },
+}
+</script>
+
+<style lang="scss" scoped></style>
diff --git a/pages/mark-up/partner/index.vue b/pages/mark-up/partner/index.vue
new file mode 100644
index 0000000..1cd6073
--- /dev/null
+++ b/pages/mark-up/partner/index.vue
@@ -0,0 +1,58 @@
+<template>
+ <el-bus-crud v-bind="tableConfig" />
+</template>
+
+<script>
+import { getPartnerListConfig } from '@/utils/form-item-config'
+export default {
+ data() {
+ return {
+ tableConfig: {
+ url: 'flower/api/flower/markup/ps/list',
+ hasEdit: false,
+ hasView: false,
+ columns: [
+ { label: '序号', type: 'index' },
+ { label: '合伙人名称', prop: 'name' },
+ { label: '联系人方式', prop: 'tel' },
+ ],
+ searchForm: [
+ {
+ type: 'row',
+ items: [{ label: '合伙人名称', id: 'name', type: 'input' }],
+ },
+ ],
+ form: [
+ {
+ ...getPartnerListConfig(),
+ rules: { required: true, message: '请选择合伙人' },
+ },
+ ],
+ extraButtons: [
+ {
+ text: '分类加价',
+ atClick: (row) => {
+ this.$router.push(
+ `${this.$route.path}/${row.id}/category?partnerName=${row.name}`
+ )
+ },
+ },
+ {
+ text: '商品加价',
+ atClick: (row) => {
+ this.$router.push(
+ `${this.$route.path}/${row.id}/goods?partnerName=${row.name}`
+ )
+ },
+ },
+ ],
+ },
+ }
+ },
+ head() {
+ return {
+ title: '平台加价',
+ }
+ },
+}
+</script>
diff --git a/pages/mark-up/range.vue b/pages/mark-up/range.vue
new file mode 100644
index 0000000..5fe4ec7
--- /dev/null
+++ b/pages/mark-up/range.vue
@@ -0,0 +1,72 @@
+<template>
+ <el-bus-crud v-bind="tableConfig" />
+</template>
+
+<script>
+export default {
+ data() {
+ return {
+ tableConfig: {
+ url: 'flower/api/flower/markup/pl/list',
+ hasPagination: false,
+ columns: [
+ { label: '序号', type: 'index' },
+ { label: '价格区间(元)', formatter: this.formatRange },
+ { label: '加价(元)', prop: 'fee' },
+ ],
+ beforeOpen: (row, isNew) => {
+ if (!isNew) {
+ row.lowerPriceStr = this.formatRange(row)
+ }
+ },
+ form: [
+ {
+ label: '价格区间:',
+ id: 'lowerPrice',
+ component: 'el-bus-number-range',
+ el: {
+ unit: '元',
+ },
+ commonFormat: true,
+ commonFormatProps: ['lowerPrice', 'upperPrice'],
+ commonRules: true,
+ commonRulesLevel: 1,
+ str: true,
+ },
+ {
+ label: '加价:',
+ id: 'fee',
+ type: 'input-number',
+ el: {
+ precision: 2,
+ min: 0,
+ },
+ unit: '元',
+ rules: { required: true, message: '请输入加价', trigger: 'blur' },
+ },
+ ],
+ },
+ }
+ },
+ head() {
+ return {
+ title: '区间加价',
+ }
+ },
+ methods: {
+ formatRange(row) {
+ let str = ''
+ if (!this.$elBusUtil.isTrueEmpty(row.lowerPrice)) {
+ str += `${row.lowerPrice}元<`
+ }
+ str += '底价'
+ if (!this.$elBusUtil.isTrueEmpty(row.upperPrice)) {
+ str += `≤${row.upperPrice}元`
+ }
+ return str
+ },
+ },
+}
+</script>
+
+<style lang="scss" scoped></style>
diff --git a/pages/marketing/coupon/activity/_id.vue b/pages/marketing/coupon/activity/_id.vue
new file mode 100644
index 0000000..d71d6d4
--- /dev/null
+++ b/pages/marketing/coupon/activity/_id.vue
@@ -0,0 +1,75 @@
+<template>
+ <div class="base-page-wrapper coupon-detail">
+ <el-bus-title title="优惠券信息" size="small" />
+ <el-bus-form
+ ref="form"
+ label-width="auto"
+ :content="formContent"
+ readonly
+ class="readonly-form"
+ />
+ <div class="base-page-wrapper__line"></div>
+ <el-bus-title title="领取记录" size="small" />
+ <el-bus-crud v-bind="recordTableConfig" />
+ <div class="text-center mt-20">
+ <el-button class="min-w-100" @click="goBack">返回</el-button>
+ </div>
+ </div>
+</template>
+
+<script>
+import {
+ couponForm,
+ couponRecordColumn,
+ recordTableConfig,
+ getActivityReceiveTime,
+ getActivityEffectiveTime,
+} from '@/utils/coupon-form'
+import CouponDetail from '@/plugins/mixins/coupon-detail.vue'
+export default {
+ mixins: [CouponDetail],
+ data() {
+ return {
+ detailUrl: `flower/api/v2/coupon/avtivy`,
+ formContent: [
+ {
+ type: 'row',
+ items: [
+ ...couponForm(),
+ { label: '发放数量:', id: 'couponAmount', type: 'input' },
+ { label: '每人限领:', id: 'getLimit', type: 'input' },
+ { label: '已领取:', id: 'getNum', type: 'input' },
+ { label: '剩余:', id: 'unGetNum', type: 'input' },
+ { label: '领取渠道:', id: 'getTypeName', type: 'input' },
+ {
+ label: '领取时间:',
+ id: 'getStartDate',
+ inputFormat: (row) => getActivityReceiveTime(row),
+ span: 24,
+ },
+ {
+ label: '有效期:',
+ id: 'usageStartDate',
+ inputFormat: (row) => getActivityEffectiveTime(row),
+ span: 24,
+ },
+ ],
+ },
+ ],
+ recordTableConfig: {
+ ...recordTableConfig(this.$route.params.id),
+ columns: [...couponRecordColumn('领取时间')],
+ },
+ }
+ },
+ head() {
+ return {
+ title: '活动优惠券详情',
+ }
+ },
+}
+</script>
+
+<style lang="scss" scoped>
+@import '@/assets/coupon/detail.scss';
+</style>
diff --git a/pages/marketing/coupon/activity/index.vue b/pages/marketing/coupon/activity/index.vue
new file mode 100644
index 0000000..7f65ee6
--- /dev/null
+++ b/pages/marketing/coupon/activity/index.vue
@@ -0,0 +1,392 @@
+<template>
+ <el-bus-crud v-bind="tableConfig" />
+</template>
+
+<script>
+import InputSelect from '@/components/input-select'
+import {
+ couponForm,
+ couponSearchForm,
+ getActivityEffectiveTime,
+ getActivityReceiveTime,
+ getImageUrlRules,
+ couponColumn,
+ dateTimeRules,
+} from '@/utils/coupon-form'
+export default {
+ data() {
+ return {
+ tableConfig: {
+ url: 'flower/api/v2/coupon/avtivy/page',
+ newUrl: 'flower/api/v2/coupon/avtivy',
+ viewUrl: 'flower/api/v2/coupon/avtivy',
+ viewOnPath: true,
+ editUrl: 'flower/api/v2/coupon/avtivy',
+ editMethodType: 'put',
+ editOnPath: true,
+ deleteUrl: 'flower/api/v2/coupon/avtivy',
+ deleteMethodType: 'delete',
+ deleteOnPath: true,
+ canEdit: (row) => row.status === 'inactive' || row.status === 'expired',
+ canDelete: (row) =>
+ row.status === 'inactive' || row.status === 'expired',
+ operationAttrs: {
+ width: 180,
+ fixed: 'right',
+ },
+ onResetView: (row) => {
+ this.$router.push(`${this.$route.path}/${row.id}`)
+ },
+ beforeOpen: (row, isNew) => {
+ if (!isNew) {
+ row.usageTypeStr = getActivityEffectiveTime(row)
+ row.getStartDateStr = getActivityReceiveTime(row)
+ getImageUrlRules(row, this.tableConfig.form)
+ }
+ },
+ columns: [
+ ...couponColumn(),
+ {
+ label: '优惠券图片',
+ formatter: (row) => (
+ <el-bus-image
+ style="width:50px;height:50px"
+ lazy={true}
+ src={row.imageUrl}
+ />
+ ),
+ },
+ {
+ label: '领取时间',
+ formatter: getActivityReceiveTime,
+ minWidth: 320,
+ },
+ {
+ label: '有效期',
+ formatter: getActivityEffectiveTime,
+ minWidth: 320,
+ },
+ { label: '领取渠道', prop: 'getTypeName', minWidth: 120 },
+ { label: '已领取总数', prop: 'getNum', minWidth: 150 },
+ { label: '剩余未领取总数', prop: 'unGetNum', minWidth: 150 },
+ { label: '状态', prop: 'statusName', minWidth: 120 },
+ { label: '操作人', prop: 'createByName', minWidth: 120 },
+ ],
+ // 页面上要到分,后端要传到秒
+ beforeConfirm: (data) => {
+ if (data.getStartDate) {
+ data.getStartDate = this.$elBusUtil.formatDate(
+ data.getStartDate,
+ 'YYYY-MM-DD HH:mm:ss'
+ )
+ }
+ if (data.getEndDate) {
+ data.getEndDate = this.$elBusUtil.formatDate(
+ data.getEndDate,
+ 'YYYY-MM-DD HH:mm:ss'
+ )
+ }
+ if (data.usageStartDate) {
+ data.usageStartDate = this.$elBusUtil.formatDate(
+ data.usageStartDate,
+ 'YYYY-MM-DD HH:mm:ss'
+ )
+ }
+ if (data.usageEndDate) {
+ data.usageEndDate = this.$elBusUtil.formatDate(
+ data.usageEndDate,
+ 'YYYY-MM-DD HH:mm:ss'
+ )
+ }
+ },
+ searchForm: [
+ {
+ type: 'row',
+ items: [
+ ...couponSearchForm(),
+ {
+ label: '领取渠道:',
+ id: 'getType',
+ type: 'bus-select-dict',
+ el: {
+ code: 'COUPON_GET_TYPE',
+ style: 'width:100%',
+ },
+ },
+ ],
+ },
+ ],
+ form: [
+ ...couponForm(),
+ {
+ label: '领取渠道:',
+ id: 'getType',
+ type: 'bus-select-dict',
+ el: {
+ code: 'COUPON_GET_TYPE',
+ style: 'width:100%',
+ },
+ str: true,
+ strKey: 'getTypeName',
+ rules: { required: true, message: '请选择领取渠道' },
+ on: {
+ change: (e, updateForm, obj) => {
+ if (e[0] === 'home') {
+ // 如果是首页领取的话,则图片为必传递
+ this.updateImageUrlRules(
+ this.tableConfig.form,
+ 'imageUrl',
+ true,
+ '图片为必填项目'
+ )
+ } else {
+ this.updateImageUrlRules(
+ this.tableConfig.form,
+ 'imageUrl',
+ false,
+ '请输入图片'
+ )
+ }
+ },
+ },
+ },
+ {
+ label: '优惠券图片:',
+ id: 'imageUrl',
+ type: 'bus-upload',
+ el: {
+ listType: 'picture-card',
+ limit: 1,
+ limitSize: 2,
+ tipText: '大小不超过2M',
+ valueType: 'string',
+ },
+ forceDisabled: true,
+ rules: {
+ required: true,
+ message: '请上传商品图片',
+ trigger: 'blur',
+ },
+ },
+ {
+ label: '领取时间:',
+ id: 'getStartDate',
+ component: 'el-bus-date-range',
+ el: {
+ type: 'datetime',
+ format: 'yyyy-MM-dd HH:mm',
+ valueFormat: 'yyyy-MM-dd HH:mm',
+ },
+ str: true,
+ commonRules: true,
+ commonFormat: true,
+ commonFormatProps: ['getStartDate', 'getEndDate'],
+ rules: dateTimeRules(),
+ },
+ {
+ label: '使用时间:',
+ id: 'usageType',
+ type: 'bus-select-dict',
+ el: {
+ code: 'COUPON_USAGE_TYPE',
+ style: 'width:100%',
+ },
+ str: true,
+ rules: { required: true, message: '请选择使用时间' },
+ on: {
+ change: (e, updateForm) => {
+ updateForm({
+ usageStartDate: null,
+ usageEndDate: null,
+ usageTimeNum: undefined,
+ usageTimeType: null,
+ })
+ },
+ },
+ },
+ {
+ label: '使用固定时间:',
+ id: 'usageStartDate',
+ component: 'el-bus-date-range',
+ el: {
+ type: 'datetime',
+ format: 'yyyy-MM-dd HH:mm',
+ valueFormat: 'yyyy-MM-dd HH:mm',
+ },
+ commonRules: true,
+ commonFormat: true,
+ commonFormatProps: ['usageStartDate', 'usageEndDate'],
+ hidden: (row, item, mode) =>
+ row.usageType !== 'fixed' || mode === 'view',
+ rules: (row) => {
+ return [
+ dateTimeRules(),
+ {
+ validator: (rule, value, callback) => {
+ if (
+ Array.isArray(row.getStartDate) &&
+ row.getStartDate.filter((i) => !!i).length === 2 &&
+ Array.isArray(value) &&
+ value.filter((i) => !!i).length === 2
+ ) {
+ if (value[0] < row.getStartDate[0]) {
+ callback(new Error('使用开始时间不能小于领取开始时间'))
+ } else if (value[1] < row.getStartDate[1]) {
+ callback(new Error('使用结束时间不能小于领取结束时间'))
+ } else {
+ callback()
+ }
+ } else {
+ callback()
+ }
+ },
+ },
+ ]
+ },
+ },
+ {
+ label: '领取后有效时间:',
+ id: 'usageTimeNum',
+ component: InputSelect,
+ commonRules: true,
+ commonFormat: true,
+ commonFormatProps: ['usageTimeNum', 'usageTimeType'],
+ el: {
+ inputAttrs: {
+ min: 1,
+ max: 99999999,
+ precision: 0,
+ controls: false,
+ },
+ selectAttrs: {
+ code: 'COUPON_USAGE_TIME_TYPE',
+ },
+ },
+ hidden: (row, item, mode) =>
+ row.usageType !== 'get_after_time' || mode === 'view',
+ },
+ {
+ label: '发放数量:',
+ id: 'couponAmount',
+ type: 'input-number',
+ el: {
+ precision: 0,
+ min: 1,
+ max: 99999999,
+ controls: false,
+ },
+ unit: '张',
+ rules: {
+ required: true,
+ message: '请输入发放数量',
+ trigger: 'blur',
+ },
+ },
+ {
+ label: '每人限领:',
+ id: 'getLimit',
+ type: 'input-number',
+ el: {
+ precision: 0,
+ min: 1,
+ max: 99999999,
+ controls: false,
+ },
+ unit: '张',
+ rules: (row) => [
+ {
+ required: true,
+ message: '请输入每人限领',
+ trigger: 'blur',
+ },
+ {
+ validator: (rule, value, callback) => {
+ if (value > row.couponAmount) {
+ callback(new Error('每人限领不能大于发放数量'))
+ } else {
+ callback()
+ }
+ },
+ trigger: 'blur',
+ },
+ ],
+ },
+ ],
+ extraButtons: [
+ {
+ text: '发布',
+ show: (row) => {
+ // row.status === 'inactive' || row.status === 'expired'
+ // const now = new Date(); // 获取当前时间
+ // const startDate = new Date(row.getStartDate); // 获取开始时间
+ // const endDate = new Date(row.getEndDate); // 获取结束时间
+ // // 判断当前时间是否在开始时间和结束时间之间
+ // const isInTimeRange = now >= startDate && now <= endDate;
+ const now = new Date() // 获取当前时间
+ const endDate = new Date(row.getEndDate) // 获取结束时间
+ // 判断当前时间是否已经超过领取结束时间
+ const isAfterEndDate = now <= endDate
+ if (
+ isAfterEndDate &&
+ (row.status === 'inactive' || row.status === 'expired')
+ ) {
+ return true
+ }
+ return false
+ },
+ atClick: async (row) => {
+ try {
+ await this.$elBusUtil.confirm('确定要发布吗?')
+ const { code } = await this.$elBusHttp.request(
+ `flower/api/v2/coupon/avtivy/active/${row.id}`,
+ { method: 'put' }
+ )
+ if (code === 0) {
+ this.$message.success('发布成功')
+ }
+ } catch (e) {
+ return false
+ }
+ },
+ },
+ {
+ text: '下架',
+ show: (row) => row.status === 'active',
+ atClick: async (row) => {
+ try {
+ await this.$elBusUtil.confirm('确定要下架吗?')
+ const { code } = await this.$elBusHttp.request(
+ `flower/api/v2/coupon/avtivy/expire/${row.id}`,
+ { method: 'put' }
+ )
+ if (code === 0) {
+ this.$message.success('下架成功')
+ }
+ } catch (e) {
+ return false
+ }
+ },
+ },
+ ],
+ },
+ }
+ },
+ head() {
+ return {
+ title: '活动优惠券',
+ }
+ },
+ methods: {
+ updateImageUrlRules(form, id, required, message) {
+ const curField = form.find((field) => field.id === id)
+ if (curField && curField.rules && required) {
+ curField.rules.required = true
+ curField.rules.message = message
+ } else if (curField && curField.rules) {
+ curField.rules.required = false
+ curField.rules.message = message
+ }
+ },
+ },
+}
+</script>
diff --git a/pages/marketing/coupon/member/_id.vue b/pages/marketing/coupon/member/_id.vue
new file mode 100644
index 0000000..a772353
--- /dev/null
+++ b/pages/marketing/coupon/member/_id.vue
@@ -0,0 +1,67 @@
+<template>
+ <div class="base-page-wrapper coupon-detail">
+ <el-bus-title title="优惠券信息" size="small" />
+ <el-bus-form
+ ref="form"
+ label-width="auto"
+ :content="formContent"
+ readonly
+ class="readonly-form"
+ />
+ <div class="base-page-wrapper__line"></div>
+ <el-bus-title title="发放记录" size="small" />
+ <el-bus-crud v-bind="recordTableConfig" />
+ <div class="text-center mt-20">
+ <el-button class="min-w-100" @click="goBack">返回</el-button>
+ </div>
+ </div>
+</template>
+
+<script>
+import {
+ couponForm,
+ couponRecordColumn,
+ recordTableConfig,
+} from '@/utils/coupon-form'
+import CouponDetail from '@/plugins/mixins/coupon-detail.vue'
+export default {
+ mixins: [CouponDetail],
+ data() {
+ return {
+ detailUrl: `flower/api/v2/coupon/vip`,
+ formContent: [
+ {
+ type: 'row',
+ items: [
+ ...couponForm(),
+ { label: '已发放总数:', id: 'getNum' },
+ {
+ label: '有效期:',
+ id: 'usageStartDate',
+ inputFormat: (row) => {
+ return row.usageStartDate
+ ? `${row.usageStartDate} ~ ${row.usageEndDate || ''}`
+ : ''
+ },
+ span: 24,
+ },
+ ],
+ },
+ ],
+ recordTableConfig: {
+ ...recordTableConfig(this.$route.params.id),
+ columns: [...couponRecordColumn('发放时间')],
+ },
+ }
+ },
+ head() {
+ return {
+ title: '会员优惠券详情',
+ }
+ },
+}
+</script>
+
+<style lang="scss" scoped>
+@import '@/assets/coupon/detail.scss';
+</style>
diff --git a/pages/marketing/coupon/member/index.vue b/pages/marketing/coupon/member/index.vue
new file mode 100644
index 0000000..f11da18
--- /dev/null
+++ b/pages/marketing/coupon/member/index.vue
@@ -0,0 +1,80 @@
+<template>
+ <el-bus-crud v-bind="tableConfig" />
+</template>
+
+<script>
+import { couponForm, couponSearchForm, couponColumn } from '@/utils/coupon-form'
+export default {
+ data() {
+ return {
+ tableConfig: {
+ url: 'flower/api/v2/coupon/vip/page',
+ newUrl: 'flower/api/v2/coupon/vip',
+ viewUrl: 'flower/api/v2/coupon/vip',
+ viewOnPath: true,
+ editUrl: 'flower/api/v2/coupon/vip',
+ editMethodType: 'put',
+ editOnPath: true,
+ deleteUrl: 'flower/api/v2/coupon/vip',
+ deleteMethodType: 'delete',
+ deleteOnPath: true,
+ onResetView: (row) => {
+ this.$router.push(`${this.$route.path}/${row.id}`)
+ },
+ operationAttrs: {
+ width: 140,
+ fixed: 'right',
+ },
+ columns: [
+ ...couponColumn(),
+ { label: '会员等级', prop: 'memberName' },
+ {
+ label: '有效期',
+ formatter: (row) =>
+ row.usageStartDate
+ ? `${row.usageStartDate || ''} ~ ${row.usageEndDate || ''}`
+ : '',
+ minWidth: 320,
+ },
+ { label: '已发放数量', prop: 'getNum', minWidth: 120 },
+ { label: '操作人', prop: 'createByName', minWidth: 120 },
+ ],
+ searchForm: [
+ {
+ type: 'row',
+ items: [...couponSearchForm()],
+ },
+ ],
+ form: [
+ {
+ label: '会员等级:',
+ id: 'memberId',
+ type: 'bus-select',
+ el: {
+ interfaceUri: 'flower/api/member/list',
+ props: {
+ label: 'name',
+ value: 'id',
+ dataPath: 'records',
+ },
+ extraQuery: {
+ current: 1,
+ size: 2000,
+ },
+ filterable: true,
+ style: 'width:100%',
+ },
+ rules: { required: true, message: '请选择会员等级' },
+ },
+ ...couponForm(),
+ ],
+ },
+ }
+ },
+ head() {
+ return {
+ title: '会员优惠券',
+ }
+ },
+}
+</script>
diff --git a/pages/marketing/coupon/receive-record.vue b/pages/marketing/coupon/receive-record.vue
new file mode 100644
index 0000000..9659bce
--- /dev/null
+++ b/pages/marketing/coupon/receive-record.vue
@@ -0,0 +1,128 @@
+<template>
+ <el-bus-crud v-bind="tableConfig" />
+</template>
+
+<script>
+export default {
+ data() {
+ return {
+ tableConfig: {
+ url: 'flower/v2/coupon-record/page',
+ hasNew: false,
+ hasOperation: false,
+ columns: [
+ { label: '序号', type: 'index', minWidth: 60, fixed: 'left' },
+ {
+ label: '店铺名称',
+ prop: 'customerName',
+ minWidth: 150,
+ fixed: 'left',
+ },
+ { label: '联系方式', prop: 'tel', minWidth: 120 },
+ { label: '优惠券名称', prop: 'couponName', minWidth: 150 },
+ {
+ label: '优惠券分类',
+ prop: 'categoryName',
+ minWidth: 120,
+ },
+ {
+ label: '优惠券类型',
+ prop: 'couponDiscountTypeName',
+ minWidth: 120,
+ },
+ { label: '状态', prop: 'statusName', minWidth: 120 },
+ { label: '领取时间', prop: 'createTime', minWidth: 180 },
+ {
+ label: '有效期',
+ formatter: (row) =>
+ row.effectiveStart
+ ? `${row.effectiveStart} ~ ${row.effectiveEnd || ''}`
+ : '',
+ minWidth: 320,
+ },
+ { label: '面值', prop: 'couponDiscountValue', minWidth: 120 },
+ {
+ label: '使用条件',
+ formatter: (row) => `满${row.minOrderAmount}`,
+ minWidth: 150,
+ },
+ { label: '领取渠道', prop: 'getTypeName', minWidth: 150 },
+ { label: '使用的订单号', prop: 'orderNo', minWidth: 150 },
+ ],
+ searchForm: [
+ {
+ type: 'row',
+ items: [
+ {
+ label: '优惠券分类',
+ id: 'category',
+ type: 'bus-select-dict',
+ el: {
+ code: 'COUPON_CATEGORY',
+ style: 'width:100%',
+ clearable: true,
+ },
+ },
+ {
+ label: '优惠券类型',
+ id: 'couponDiscountType',
+ type: 'bus-select-dict',
+ el: {
+ code: 'COUPON_TYPE',
+ style: 'width:100%',
+ clearable: true,
+ },
+ },
+ {
+ label: '优惠券名称',
+ id: 'name',
+ type: 'input',
+ },
+ {
+ label: '订单号',
+ id: 'orderNo',
+ type: 'input',
+ },
+ {
+ label: '用户id/店铺名称',
+ id: 'keyword',
+ type: 'input',
+ },
+ {
+ label: '联系方式',
+ id: 'tel',
+ type: 'input',
+ },
+ {
+ label: '领取渠道',
+ id: 'getType',
+ type: 'bus-select-dict',
+ el: {
+ code: 'COUPON_GET_TYPE',
+ style: 'width:100%',
+ clearable: true,
+ },
+ },
+ {
+ label: '状态',
+ id: 'status',
+ type: 'bus-select-dict',
+ el: {
+ code: 'COUPON_USED_STATUS',
+ style: 'width:100%',
+ clearable: true,
+ },
+ },
+ ],
+ },
+ ],
+ },
+ }
+ },
+ head() {
+ return {
+ title: '优惠券领取记录',
+ }
+ },
+}
+</script>
diff --git a/pages/marketing/coupon/user/_id.vue b/pages/marketing/coupon/user/_id.vue
new file mode 100644
index 0000000..09fe60f
--- /dev/null
+++ b/pages/marketing/coupon/user/_id.vue
@@ -0,0 +1,71 @@
+<template>
+ <div class="base-page-wrapper coupon-detail">
+ <el-bus-title title="优惠券信息" size="small" />
+ <el-bus-form
+ ref="form"
+ label-width="auto"
+ :content="formContent"
+ readonly
+ class="readonly-form"
+ />
+ <div class="base-page-wrapper__line"></div>
+ <el-bus-title title="发放记录" size="small" />
+ <el-bus-crud v-bind="recordTableConfig" />
+ <div class="text-center mt-20">
+ <el-button class="min-w-100" @click="goBack">返回</el-button>
+ </div>
+ </div>
+</template>
+
+<script>
+import {
+ couponForm,
+ couponRecordColumn,
+ recordTableConfig,
+} from '@/utils/coupon-form'
+import CouponDetail from '@/plugins/mixins/coupon-detail.vue'
+export default {
+ mixins: [CouponDetail],
+ data() {
+ return {
+ detailUrl: `flower/api/v2/coupon/user`,
+ formContent: [
+ {
+ type: 'row',
+ items: [
+ ...couponForm(),
+ {
+ label: '发放时间:',
+ id: 'createTime',
+ type: 'input',
+ },
+ {
+ label: '有效期:',
+ id: 'effectiveTime',
+ inputFormat: (row) => {
+ return row.usageStartDate
+ ? `${row.usageStartDate} ~ ${row.usageEndDate || ''}`
+ : `发放后${row.usageTimeNum}${row.usageTimeTypeName || ''}`
+ },
+ span: 24,
+ },
+ ],
+ },
+ ],
+ recordTableConfig: {
+ ...recordTableConfig(this.$route.params.id),
+ columns: [...couponRecordColumn('发放时间')],
+ },
+ }
+ },
+ head() {
+ return {
+ title: '用户优惠券详情',
+ }
+ },
+}
+</script>
+
+<style lang="scss" scoped>
+@import '@/assets/coupon/detail.scss';
+</style>
diff --git a/pages/marketing/coupon/user/index.vue b/pages/marketing/coupon/user/index.vue
new file mode 100644
index 0000000..1c546d1
--- /dev/null
+++ b/pages/marketing/coupon/user/index.vue
@@ -0,0 +1,138 @@
+<template>
+ <el-bus-crud v-bind="tableConfig" />
+</template>
+
+<script>
+import InputSelect from '@/components/input-select'
+import SelectShopUser from '@/components/coupon/select-shop-user'
+import { couponForm, couponSearchForm, couponColumn } from '@/utils/coupon-form'
+export default {
+ data() {
+ return {
+ tableConfig: {
+ url: 'flower/api/v2/coupon/user/page',
+ newUrl: 'flower/api/v2/coupon/user',
+ viewUrl: 'flower/api/v2/coupon/user',
+ viewOnPath: true,
+ editUrl: 'flower/api/v2/coupon/user',
+ editMethodType: 'put',
+ editOnPath: true,
+ deleteUrl: 'flower/api/v2/coupon/user',
+ deleteMethodType: 'delete',
+ deleteOnPath: true,
+ dialogNeedRequest: true,
+ canEdit: (row) => row.status === 'inactive' || row.status === 'expired',
+ canDelete: (row) =>
+ row.status === 'inactive' || row.status === 'expired',
+ onResetView: (row) => {
+ this.$router.push(`${this.$route.path}/${row.id}`)
+ },
+ operationAttrs: {
+ width: 200,
+ fixed: 'right',
+ },
+ columns: [
+ ...couponColumn(),
+ { label: '发放时间', prop: 'createTime', minWidth: 180 },
+ {
+ label: '有效期',
+ formatter: (row) =>
+ row.usageStartDate
+ ? `${row.usageStartDate} ~ ${row.usageEndDate || ''}`
+ : `发放后${row.usageTimeNum}${row.usageTimeTypeName || ''}`,
+ minWidth: 400,
+ },
+ { label: '状态', prop: 'statusName', minWidth: 120 },
+ { label: '操作人', prop: 'createByName', minWidth: 120 },
+ ],
+ searchForm: [
+ {
+ type: 'row',
+ items: [...couponSearchForm()],
+ },
+ ],
+ form: [
+ ...couponForm(),
+ {
+ label: '发放后有效期:',
+ id: 'usageTimeNum',
+ component: InputSelect,
+ commonRules: true,
+ commonFormat: true,
+ commonFormatProps: ['usageTimeNum', 'usageTimeType'],
+ el: {
+ inputAttrs: {
+ min: 1,
+ max: 99999999,
+ precision: 0,
+ controls: false,
+ },
+ selectAttrs: {
+ code: 'COUPON_USAGE_TIME_TYPE',
+ },
+ },
+ },
+ {
+ label: '领取用户:',
+ id: 'pointCostomIdList',
+ component: SelectShopUser,
+ rules: { required: true, message: '请选择领取用户' },
+ inputFormat: (row) => {
+ if ('customerList' in row) {
+ return row.customerList.filter((i) => i)
+ }
+ },
+ outputFormat: (val) => {
+ return val?.length ? val.map((i) => i.id) : []
+ },
+ forceDisabled: true,
+ },
+ ],
+ extraButtons: [
+ {
+ text: '发布',
+ show: (row) => row.status === 'inactive',
+ atClick: async (row) => {
+ try {
+ await this.$elBusUtil.confirm('确定要发布吗?')
+ const { code } = await this.$elBusHttp.request(
+ `flower/api/v2/coupon/user/active/${row.id}`,
+ { method: 'put' }
+ )
+ if (code === 0) {
+ this.$message.success('发布成功')
+ }
+ } catch (e) {
+ return false
+ }
+ },
+ },
+ {
+ text: '下架',
+ show: (row) => row.status === 'active',
+ atClick: async (row) => {
+ try {
+ await this.$elBusUtil.confirm('确定要下架吗?')
+ const { code } = await this.$elBusHttp.request(
+ `flower/api/v2/coupon/user/expire/${row.id}`,
+ { method: 'put' }
+ )
+ if (code === 0) {
+ this.$message.success('下架成功')
+ }
+ } catch (e) {
+ return false
+ }
+ },
+ },
+ ],
+ },
+ }
+ },
+ head() {
+ return {
+ title: '用户优惠券',
+ }
+ },
+}
+</script>
diff --git a/pages/marketing/member-level.vue b/pages/marketing/member-level.vue
new file mode 100644
index 0000000..e669121
--- /dev/null
+++ b/pages/marketing/member-level.vue
@@ -0,0 +1,230 @@
+<template>
+ <el-bus-crud v-bind="tableConfig" />
+</template>
+
+<script>
+import MemberRule from '@/components/coupon/member-rule.vue'
+export default {
+ data() {
+ return {
+ tableConfig: {
+ url: 'flower/api/member/list',
+ newUrl: 'flower/api/member/new',
+ editUrl: 'flower/api/member/edit',
+ deleteUrl: 'flower/api/member/delete',
+ columns: [
+ { label: '序号', type: 'index' },
+ { label: '等级名称', prop: 'name' },
+ {
+ label: '成长值',
+ formatter: (row) =>
+ `${row.startPoint ?? ''} ~ ${row.endPoint ?? ''}`,
+ },
+ { label: '等级折扣', prop: 'discountTypeStr' },
+ { label: '操作人', prop: 'createName' },
+ {
+ label: '背景图片',
+ formatter: (row) =>
+ row.background ? (
+ <el-bus-image
+ src={row.background}
+ lazy={true}
+ style="width:50px;height:50px"
+ ></el-bus-image>
+ ) : null,
+ },
+ {
+ label: '样式图片',
+ formatter: (row) =>
+ row.pictures ? (
+ <el-bus-image
+ src={row.pictures}
+ lazy={true}
+ style="width:50px;height:50px"
+ ></el-bus-image>
+ ) : null,
+ },
+ { label: '成长值获取规则', prop: 'growthValueDesc' },
+ ],
+ beforeOpen: (row, isNew) => {
+ if (!isNew) {
+ row.consumptionAmountStr = `消费${row.consumptionAmount}元等于${row.growthValue}成长值`
+ row.startPointStr = `${
+ this.$elBusUtil.isTrueEmpty(row.startPoint) ? '' : row.startPoint
+ } ~ ${
+ this.$elBusUtil.isTrueEmpty(row.endPoint) ? '' : row.endPoint
+ }`
+ }
+ },
+ searchForm: [
+ {
+ type: 'row',
+ items: [{ label: '等级名称:', id: 'name', type: 'input' }],
+ },
+ ],
+ form: [
+ {
+ label: '会员等级名称:',
+ id: 'name',
+ type: 'input',
+ rules: { required: true, message: '请输入会员等级名称' },
+ },
+ {
+ label: '成长值范围:',
+ id: 'startPoint',
+ component: 'el-bus-number-range',
+ el: {
+ unit: '',
+ separator: '<= 成长值范围 <',
+ controls: false,
+ min: 0,
+ max: 99999999,
+ },
+ commonFormat: true,
+ commonFormatProps: ['startPoint', 'endPoint'],
+ commonRules: true,
+ commonRulesLevel: 1,
+ str: true,
+ },
+ {
+ label: '折扣类型:',
+ id: 'discountType',
+ type: 'bus-select-dict',
+ el: {
+ code: 'DISCOUNT_TYPE',
+ style: 'width:100%',
+ },
+ str: true,
+ rules: { required: true, message: '请选择折扣类型' },
+ on: {
+ change: (e, updateForm) => {
+ updateForm({
+ discountRatio: undefined,
+ discountAmount: undefined,
+ })
+ },
+ },
+ },
+ {
+ label: '会员折扣:',
+ id: 'discountRatio',
+ type: 'input-number',
+ el: {
+ precision: 0,
+ min: 0,
+ max: 100,
+ controls: false,
+ },
+ unit: '%',
+ rules: {
+ required: true,
+ message: '请输入会员折扣',
+ trigger: 'blur',
+ },
+ hidden: (row) => row.discountType !== 'ratio',
+ },
+ {
+ label: '会员优惠:',
+ id: 'discountAmount',
+ type: 'input-number',
+ el: {
+ precision: 2,
+ min: 0,
+ max: 99999999,
+ controls: false,
+ },
+ unit: '元/扎',
+ rules: {
+ required: true,
+ message: '请输入会员优惠',
+ trigger: 'blur',
+ },
+ hidden: (row) => row.discountType !== 'amount',
+ },
+ {
+ label: '会员规则:',
+ id: 'consumptionAmount',
+ component: MemberRule,
+ commonRules: true,
+ commonFormat: true,
+ commonFormatProps: ['consumptionAmount', 'growthValue'],
+ str: true,
+ },
+ {
+ label: '降级规则:',
+ id: 'downgradeValue',
+ type: 'input-number',
+ el: {
+ precision: 0,
+ min: 0,
+ max: 99999999,
+ controls: false,
+ },
+ unit: '成长值',
+ rules: {
+ required: true,
+ message: '请输入降级规则',
+ trigger: 'blur',
+ },
+ },
+ {
+ label: '背景图片:',
+ id: 'background',
+ type: 'bus-upload',
+ el: {
+ listType: 'picture-card',
+ limit: 1,
+ limitSize: 2,
+ tipText: '大小不超过2M',
+ valueType: 'string',
+ },
+ forceDisabled: true,
+ rules: {
+ required: true,
+ message: '请上传背景图片',
+ trigger: 'blur',
+ },
+ },
+ {
+ label: '样式图片:',
+ id: 'pictures',
+ type: 'bus-upload',
+ el: {
+ listType: 'picture-card',
+ limit: 1,
+ limitSize: 2,
+ tipText: '大小不超过2M',
+ valueType: 'string',
+ },
+ forceDisabled: true,
+ rules: {
+ required: true,
+ message: '请上传样式图片',
+ trigger: 'blur',
+ },
+ },
+ {
+ label: '会员成长值获取规则:',
+ id: 'growthValueDesc',
+ type: 'input',
+ el: {
+ type: 'textarea',
+ rows: 6,
+ },
+ rules: {
+ required: true,
+ message: '请输入会员成长值获取规则',
+ trigger: 'blur',
+ },
+ },
+ ],
+ },
+ }
+ },
+ head() {
+ return {
+ title: '会员等级',
+ }
+ },
+}
+</script>
diff --git a/pages/marketing/member-record.vue b/pages/marketing/member-record.vue
new file mode 100644
index 0000000..7e825a0
--- /dev/null
+++ b/pages/marketing/member-record.vue
@@ -0,0 +1,83 @@
+<template>
+ <div>
+ <el-bus-crud v-bind="tableConfig"/>
+ <el-dialog title="成长值变动记录" :visible.sync="dialogVisible" width="80%">
+ <el-bus-crud
+ v-if="userId"
+ :key="dialogId"
+ :extra-query="{ userId }"
+ v-bind="recordTableConfig"
+ />
+ </el-dialog>
+ </div>
+</template>
+
+<script>
+import {v4 as uuidv4} from "uuid";
+
+export default {
+ data() {
+ return {
+ dialogVisible: false,
+ userId: null,
+ dialogId: null,
+ tableConfig: {
+ url: 'flower/api/userGrowthRecord/list',
+ hasNew: false,
+ hasEdit: false,
+ hasDelete: false,
+ hasView: false,
+ columns: [
+ {label: '序号', type: 'index'},
+ {label: '用户名称', prop: 'nickName'},
+ {label: '联系方式', prop: 'tel'},
+ {label: '当前成长值', prop: 'sumGrowthValue'},
+ {label: '当前会员等级', prop: 'levelName'},
+ ],
+ searchForm: [
+ {
+ type: 'row',
+ items: [
+ {label: '用户名称:', id: 'nickName', type: 'input'},
+ {label: '联系方式:', id: 'tel', type: 'input'},
+ {label: '会员等级:', id: 'levelName', type: 'input'}
+ ],
+ },
+ ],
+ extraButtons: [
+ {
+ text: '成长值变动记录',
+ atClick: (row) => {
+ this.dialogId = uuidv4()
+ this.userId = row.userId
+ this.dialogVisible = true
+ },
+ },
+ ],
+ },
+ recordTableConfig: {
+ url: 'flower/api/getmemberGrowthRecord/list',
+ saveQuery: false,
+ hasNew: false,
+ hasOperation: false,
+ columns: [
+ { label: '序号', type: 'index' },
+ { label: '成长值类型', prop: 'typeStr' },
+ { label: '成长值来源', prop: 'sourceStr' },
+ { label: '成长值', prop: 'growth' },
+ { label: '记录日期', prop: 'recordDate' },
+ { label: '备注', prop: 'remarks' },
+ ],
+ searchFormAttrs: {
+ labelWidth: 'auto',
+ },
+ },
+ }
+ },
+ head() {
+ return {
+ title: '会员成长值记录',
+ }
+ },
+}
+</script>
diff --git a/pages/marketing/point-mall/coupon/_id.vue b/pages/marketing/point-mall/coupon/_id.vue
new file mode 100644
index 0000000..9b63a71
--- /dev/null
+++ b/pages/marketing/point-mall/coupon/_id.vue
@@ -0,0 +1,65 @@
+<template>
+ <div class="base-page-wrapper coupon-detail">
+ <el-bus-title title="优惠券信息" size="small" />
+ <el-bus-form
+ ref="form"
+ label-width="auto"
+ :content="formContent"
+ readonly
+ class="readonly-form"
+ />
+ <div class="base-page-wrapper__line"></div>
+ <el-bus-title title="兑换记录" size="small" />
+ <el-bus-crud v-bind="recordTableConfig" />
+ <div class="text-center mt-20">
+ <el-button class="min-w-100" @click="goBack">返回</el-button>
+ </div>
+ </div>
+</template>
+
+<script>
+import {
+ couponForm,
+ couponRecordColumn,
+ recordTableConfig,
+} from '@/utils/coupon-form'
+import CouponDetail from '@/plugins/mixins/coupon-detail.vue'
+export default {
+ mixins: [CouponDetail],
+ data() {
+ return {
+ detailUrl: `flower/api/v2/coupon/point`,
+ formContent: [
+ {
+ type: 'row',
+ items: [
+ ...couponForm(),
+ {
+ label: '领取后有效时间:',
+ id: 'usageTimeNum',
+ inputFormat: (row) => {
+ return `${row.usageTimeNum}${row.usageTimeTypeName}`
+ },
+ },
+ { label: '库存:', id: 'couponAmount' },
+ { label: '积分数量:', id: 'point' },
+ ],
+ },
+ ],
+ recordTableConfig: {
+ ...recordTableConfig(this.$route.params.id),
+ columns: [...couponRecordColumn('兑换时间')],
+ },
+ }
+ },
+ head() {
+ return {
+ title: '积分优惠券详情',
+ }
+ },
+}
+</script>
+
+<style lang="scss" scoped>
+@import '@/assets/coupon/detail.scss';
+</style>
diff --git a/pages/marketing/point-mall/coupon/index.vue b/pages/marketing/point-mall/coupon/index.vue
new file mode 100644
index 0000000..28008a5
--- /dev/null
+++ b/pages/marketing/point-mall/coupon/index.vue
@@ -0,0 +1,252 @@
+<template>
+ <el-bus-crud ref="crud" v-bind="tableConfig" />
+</template>
+
+<script>
+import { couponForm, couponSearchForm, couponColumn } from '@/utils/coupon-form'
+import InputSelect from '@/components/input-select'
+export default {
+ data() {
+ return {
+ tableConfig: {
+ url: 'flower/api/v2/coupon/point/page',
+ newUrl: 'flower/api/v2/coupon/point',
+ viewUrl: 'flower/api/v2/coupon/point',
+ viewOnPath: true,
+ editUrl: 'flower/api/v2/coupon/point',
+ editMethodType: 'put',
+ editOnPath: true,
+ deleteUrl: 'flower/api/v2/coupon/point',
+ deleteMethodType: 'delete',
+ deleteOnPath: true,
+ canEdit: (row) => row.status === 'inactive' || row.status === 'expired',
+ canDelete: (row) =>
+ row.status === 'inactive' || row.status === 'expired',
+ onResetView: (row) => {
+ this.$router.push(`${this.$route.path}/${row.id}`)
+ },
+ persistSelection: true,
+ operationAttrs: {
+ width: 160,
+ fixed: 'right',
+ },
+ columns: [
+ {
+ label: '',
+ type: 'selection',
+ minWidth: 60,
+ },
+ ...couponColumn(),
+ { label: '状态', prop: 'statusName', minWidth: 120 },
+ { label: '库存', prop: 'couponAmount', minWidth: 120 },
+ { label: '所需积分', prop: 'point', minWidth: 120 },
+ ],
+ searchForm: [
+ {
+ type: 'row',
+ items: [...couponSearchForm()],
+ },
+ ],
+ form: [
+ ...couponForm(),
+ {
+ label: '领取后有效时间:',
+ id: 'usageTimeNum',
+ component: InputSelect,
+ commonRules: true,
+ commonFormat: true,
+ commonFormatProps: ['usageTimeNum', 'usageTimeType'],
+ el: {
+ inputAttrs: {
+ min: 1,
+ max: 99999999,
+ precision: 0,
+ controls: false,
+ },
+ selectAttrs: {
+ code: 'COUPON_USAGE_TIME_TYPE',
+ },
+ },
+ },
+ {
+ label: '库存:',
+ id: 'couponAmount',
+ type: 'input-number',
+ el: {
+ precision: 0,
+ min: 0,
+ max: 99999999,
+ controls: false,
+ },
+ rules: [
+ { required: true, message: '请输入库存', trigger: 'blur' },
+ {
+ type: 'number',
+ min: 1,
+ message: '库存必须大于0',
+ trigger: 'blur',
+ },
+ ],
+ },
+ {
+ label: '积分数量:',
+ id: 'point',
+ type: 'input-number',
+ el: {
+ precision: 0,
+ min: 1,
+ max: 99999999,
+ controls: false,
+ },
+ rules: {
+ required: true,
+ message: '请输入积分数量',
+ trigger: 'blur',
+ },
+ },
+ ],
+ extraButtons: [
+ {
+ text: '上架',
+ show: (row) =>
+ (row.status === 'inactive' || row.status === 'expired') &&
+ row.couponAmount > 0,
+ atClick: async (row) => {
+ try {
+ await this.$elBusUtil.confirm('确定要上架吗?')
+ const { code } = await this.$elBusHttp.request(
+ `flower/api/v2/coupon/point/active/${row.id}`,
+ { method: 'put' }
+ )
+ if (code === 0) {
+ this.$message.success('上架成功')
+ }
+ } catch (e) {
+ return false
+ }
+ },
+ },
+ {
+ text: '下架',
+ show: (row) => row.status === 'active',
+ atClick: async (row) => {
+ try {
+ await this.$elBusUtil.confirm('确定要下架吗?')
+ const { code } = await this.$elBusHttp.request(
+ `flower/api/v2/coupon/point/expire/${row.id}`,
+ { method: 'put' }
+ )
+ if (code === 0) {
+ this.$message.success('下架成功')
+ }
+ } catch (e) {
+ return false
+ }
+ },
+ },
+ ],
+ headerButtons: [
+ {
+ text: '批量上架',
+ type: 'primary',
+ disabled: (selected) =>
+ selected.filter(
+ (i) => i.status === 'inactive' || i.status === 'expired'
+ ).length === 0,
+ atClick: async (selected) => {
+ try {
+ const items = selected.filter(
+ (i) => i.status === 'inactive' || i.status === 'expired'
+ )
+ await this.$elBusUtil.confirm(
+ `确定要上架这${items.length}个商品吗?`
+ )
+ const { code } = await this.$elBusHttp.request(
+ 'flower/api/v2/coupon/point/batch/active',
+ {
+ data: { idList: items.map((i) => i.id) },
+ method: 'post',
+ }
+ )
+ if (code === 0) {
+ this.$message.success('上架成功')
+ this.$refs.crud.clearSelection()
+ }
+ } catch (e) {
+ return false
+ }
+ },
+ },
+ {
+ text: '批量下架',
+ type: 'primary',
+ disabled: (selected) =>
+ selected.filter((i) => i.status === 'active').length === 0,
+ atClick: async (selected) => {
+ try {
+ const items = selected.filter((i) => i.status === 'active')
+ await this.$elBusUtil.confirm(
+ `确定要下架这${items.length}个商品吗?`
+ )
+ const { code } = await this.$elBusHttp.request(
+ 'flower/api/v2/coupon/point/batch/expire',
+ {
+ data: { idList: items.map((i) => i.id) },
+ method: 'post',
+ }
+ )
+ if (code === 0) {
+ this.$message.success('下架成功')
+ this.$refs.crud.clearSelection()
+ }
+ } catch (e) {
+ return false
+ }
+ },
+ },
+ {
+ text: '批量删除',
+ type: 'danger',
+ disabled: (selected) =>
+ selected.filter(
+ (i) => i.status === 'inactive' || i.status === 'expired'
+ ).length === 0,
+ atClick: async (selected) => {
+ try {
+ const items = selected.filter(
+ (i) => i.status === 'inactive' || i.status === 'expired'
+ )
+ await this.$elBusUtil.confirm(
+ `确定要删除这${items.length}个商品吗?`
+ )
+ const { code } = await this.$elBusHttp.request(
+ 'flower/api/v2/coupon/point/batch/del',
+ {
+ data: { idList: items.map((i) => i.id) },
+ method: 'post',
+ }
+ )
+ if (code === 0) {
+ this.$message.success('删除成功')
+ }
+ } catch (e) {
+ return false
+ }
+ },
+ },
+ ],
+ },
+ }
+ },
+ head() {
+ return {
+ title: '积分优惠券',
+ }
+ },
+}
+</script>
+
+<style lang="scss" scoped>
+.index {
+}
+</style>
diff --git a/pages/marketing/point-mall/goods.vue b/pages/marketing/point-mall/goods.vue
new file mode 100644
index 0000000..3fc5758
--- /dev/null
+++ b/pages/marketing/point-mall/goods.vue
@@ -0,0 +1,254 @@
+<template>
+ <el-bus-crud ref="crud" v-bind="tableConfig" />
+</template>
+
+<script>
+export default {
+ data() {
+ return {
+ tableConfig: {
+ url: 'flower/api/point/goods/list',
+ canEdit: (row) => row.status === 'I',
+ canDelete: (row) => row.status === 'I',
+ columns: [
+ { label: '', type: 'selection' },
+ { label: '序号', type: 'index' },
+ {
+ label: '商品图片',
+ formatter: (row) =>
+ row.cover ? (
+ <el-bus-image
+ src={row.cover}
+ lazy={true}
+ style="width:50px;height:50px"
+ ></el-bus-image>
+ ) : null,
+ },
+ { label: '商品名称', prop: 'name' },
+ { label: '状态', prop: 'statusStr' },
+ { label: '库存', prop: 'stock' },
+ { label: '所需积分', prop: 'point' },
+ ],
+ searchForm: [
+ {
+ type: 'row',
+ items: [
+ {
+ label: '商品名称',
+ id: 'name',
+ type: 'input',
+ },
+ {
+ label: '状态',
+ id: 'status',
+ type: 'bus-select-dict',
+ el: {
+ code: 'POINT_GOODS_STATUS',
+ style: 'width:100%',
+ clearable: true,
+ },
+ },
+ ],
+ },
+ ],
+ form: [
+ {
+ label: '商品名称:',
+ id: 'name',
+ type: 'input',
+ rules: {
+ required: true,
+ message: '请输入商品名称',
+ trigger: 'blur',
+ },
+ },
+ {
+ label: '商品规格信息:',
+ id: 'description',
+ type: 'input',
+ el: {
+ type: 'textarea',
+ rows: 4,
+ },
+ rules: {
+ required: true,
+ message: '请输入商品规格信息',
+ trigger: 'blur',
+ },
+ },
+ {
+ label: '库存:',
+ id: 'stock',
+ type: 'input-number',
+ el: {
+ precision: 0,
+ min: 0,
+ max: 99999999,
+ controls: false,
+ },
+ rules: [
+ { required: true, message: '请输入库存', trigger: 'blur' },
+ {
+ type: 'number',
+ min: 1,
+ message: '库存必须大于0',
+ trigger: 'blur',
+ },
+ ],
+ },
+ {
+ label: '商品图片:',
+ id: 'cover',
+ type: 'bus-upload',
+ el: {
+ listType: 'picture-card',
+ limit: 1,
+ limitSize: 2,
+ tipText: '大小不超过2M',
+ valueType: 'string',
+ },
+ forceDisabled: true,
+ rules: {
+ required: true,
+ message: '请上传商品图片',
+ trigger: 'blur',
+ },
+ },
+ {
+ label: '积分数量:',
+ id: 'point',
+ type: 'input-number',
+ el: {
+ precision: 0,
+ min: 1,
+ max: 99999999,
+ controls: false,
+ },
+ rules: {
+ required: true,
+ message: '请输入积分数量',
+ trigger: 'blur',
+ },
+ },
+ ],
+ extraButtons: [
+ {
+ text: '上架',
+ show: (row) => row.status === 'I' && row.stock > 0,
+ atClick: async (row) => {
+ try {
+ await this.$elBusUtil.confirm('确定要上架吗?')
+ const { code } = await this.$elBusHttp.request(
+ 'flower/api/point/goods/list/on',
+ { params: { id: row.id } }
+ )
+ if (code === 0) {
+ this.$message.success('上架成功')
+ }
+ } catch (e) {
+ return false
+ }
+ },
+ },
+ {
+ text: '下架',
+ show: (row) => row.status === 'A',
+ atClick: async (row) => {
+ try {
+ await this.$elBusUtil.confirm('确定要下架吗?')
+ const { code } = await this.$elBusHttp.request(
+ 'flower/api/point/goods/list/off',
+ { params: { id: row.id } }
+ )
+ if (code === 0) {
+ this.$message.success('下架成功')
+ }
+ } catch (e) {
+ return false
+ }
+ },
+ },
+ ],
+ headerButtons: [
+ {
+ text: '批量上架',
+ type: 'primary',
+ disabled: (selected) =>
+ selected.filter((i) => i.status === 'I').length === 0,
+ atClick: async (selected) => {
+ try {
+ const items = selected.filter((i) => i.status === 'I')
+ await this.$elBusUtil.confirm(
+ `确定要上架这${items.length}个商品吗?`
+ )
+ const { code } = await this.$elBusHttp.request(
+ 'flower/api/point/goods/list/on',
+ { params: { id: items.map((i) => i.id).join(',') } }
+ )
+ if (code === 0) {
+ this.$message.success('上架成功')
+ this.$refs.crud.clearSelection()
+ }
+ } catch (e) {
+ return false
+ }
+ },
+ },
+ {
+ text: '批量下架',
+ type: 'primary',
+ disabled: (selected) =>
+ selected.filter((i) => i.status === 'A').length === 0,
+ atClick: async (selected) => {
+ try {
+ const items = selected.filter((i) => i.status === 'A')
+ await this.$elBusUtil.confirm(
+ `确定要下架这${items.length}个商品吗?`
+ )
+ const { code } = await this.$elBusHttp.request(
+ 'flower/api/point/goods/list/off',
+ { params: { id: items.map((i) => i.id).join(',') } }
+ )
+ if (code === 0) {
+ this.$message.success('下架成功')
+ this.$refs.crud.clearSelection()
+ }
+ } catch (e) {
+ return false
+ }
+ },
+ },
+ {
+ text: '批量删除',
+ type: 'danger',
+ disabled: (selected) =>
+ selected.filter((i) => i.status === 'I').length === 0,
+ atClick: async (selected) => {
+ try {
+ const items = selected.filter((i) => i.status === 'I')
+ await this.$elBusUtil.confirm(
+ `确定要删除这${items.length}个商品吗?`
+ )
+ const { code } = await this.$elBusHttp.request(
+ 'flower/api/point/goods/list/delete',
+ { params: { id: items.map((i) => i.id).join(',') } }
+ )
+ if (code === 0) {
+ this.$message.success('删除成功')
+ }
+ } catch (e) {
+ return false
+ }
+ },
+ },
+ ],
+ },
+ }
+ },
+ head() {
+ return {
+ title: '积分商品',
+ }
+ },
+}
+</script>
diff --git a/pages/marketing/point-mall/point-distribution.vue b/pages/marketing/point-mall/point-distribution.vue
new file mode 100644
index 0000000..52ea16f
--- /dev/null
+++ b/pages/marketing/point-mall/point-distribution.vue
@@ -0,0 +1,250 @@
+<template>
+ <div>
+ <el-bus-crud ref="crud" v-bind="tableConfig" />
+ <el-dialog title="积分变动记录" :visible.sync="dialogVisible" width="80%">
+ <el-bus-crud
+ v-if="customerId"
+ :key="dialogId"
+ :extra-query="{ customerId }"
+ v-bind="recordTableConfig"
+ />
+ </el-dialog>
+ </div>
+</template>
+
+<script>
+import { v4 as uuidv4 } from 'uuid'
+export default {
+ data() {
+ return {
+ dialogVisible: false,
+ customerId: null,
+ dialogId: null,
+ tableConfig: {
+ url: 'flower/api/customer/point/page',
+ hasNew: false,
+ hasEdit: false,
+ hasDelete: false,
+ hasView: false,
+ columns: [
+ { label: '序号', type: 'index' },
+ { label: '用户信息', prop: 'customerName' },
+ { label: '联系方式', prop: 'customerTel' },
+ { label: '总积分', prop: 'totalPoint' },
+ { label: '已使用积分', prop: 'usedPoint' },
+ { label: '过期积分', prop: 'expiredPoint' },
+ { label: '扣减积分', formatter: (row) => row.deductionPoint ?? 0 },
+ {
+ label: '剩余积分',
+ formatter: (row) =>
+ parseInt(row.totalPoint) -
+ parseInt(row.deductionPoint ?? 0) -
+ parseInt(row.usedPoint) -
+ parseInt(row.expiredPoint),
+ },
+ ],
+ searchForm: [
+ {
+ type: 'row',
+ items: [
+ { label: '用户名称', id: 'customerName', type: 'input' },
+ { label: '联系方式', id: 'customerTel', type: 'input' },
+ ],
+ },
+ ],
+ extraDialogs: [
+ {
+ title: '积分赠送',
+ form: [
+ {
+ id: 'customerId',
+ type: 'input',
+ hidden: () => true,
+ },
+ {
+ label: '积分赠送:',
+ id: 'point',
+ type: 'input-number',
+ el: {
+ precision: 0,
+ min: 1,
+ max: 99999999,
+ controls: false,
+ },
+ rules: {
+ required: true,
+ message: '请输入积分赠送',
+ trigger: 'blur',
+ },
+ },
+ {
+ label: '原因:',
+ id: 'remarks',
+ type: 'input',
+ el: {
+ type: 'textarea',
+ rows: 6,
+ },
+ rules: {
+ required: true,
+ message: '请输入原因',
+ trigger: 'blur',
+ },
+ },
+ ],
+ atConfirm: async (val) => {
+ const { code } = await this.$elBusHttp.request(
+ 'flower/api/customer/point/giveaway',
+ {
+ method: 'post',
+ data: val,
+ }
+ )
+ if (code === 0) {
+ this.$message.success('赠送成功')
+ }
+ },
+ },
+ {
+ title: '积分扣减',
+ form: [
+ {
+ id: 'customerId',
+ type: 'input',
+ hidden: () => true,
+ },
+ {
+ label: '积分扣减:',
+ id: 'point',
+ type: 'input-number',
+ el: {
+ precision: 0,
+ min: 1,
+ max: 99999999,
+ controls: false,
+ },
+ rules: {
+ required: true,
+ message: '请输入积分扣减',
+ trigger: 'blur',
+ },
+ },
+ {
+ label: '原因:',
+ id: 'remarks',
+ type: 'input',
+ el: {
+ type: 'textarea',
+ rows: 6,
+ },
+ rules: {
+ required: true,
+ message: '请输入原因',
+ trigger: 'blur',
+ },
+ },
+ ],
+ atConfirm: async (val) => {
+ const { code } = await this.$elBusHttp.request(
+ 'flower/api/customer/point/deduction',
+ {
+ method: 'post',
+ data: val,
+ }
+ )
+ if (code === 0) {
+ this.$message.success('扣减成功')
+ }
+ },
+ },
+ ],
+ extraButtons: [
+ {
+ text: '积分变动记录',
+ atClick: (row) => {
+ this.dialogId = uuidv4()
+ this.customerId = row.customerId
+ this.dialogVisible = true
+ },
+ },
+ {
+ text: '积分赠送',
+ atClick: (row) => {
+ this.$refs.crud.$refs.extraDialog[0].show(row)
+ return false
+ },
+ },
+ {
+ text: '积分扣减',
+ atClick: (row) => {
+ this.$refs.crud.$refs.extraDialog[1].show(row)
+ return false
+ },
+ },
+ ],
+ },
+ recordTableConfig: {
+ url: 'flower/api/customer/point/page/list',
+ saveQuery: false,
+ hasNew: false,
+ hasOperation: false,
+ columns: [
+ { label: '序号', type: 'index' },
+ { label: '变动类型', prop: 'changeTypeStr' },
+ { label: '变动积分', prop: 'point' },
+ { label: '变动原因', prop: 'typeStr' },
+ { label: '变动时间', prop: 'createTime' },
+ { label: '备注', prop: 'remarks' },
+ ],
+ searchFormAttrs: {
+ labelWidth: 'auto',
+ },
+ searchForm: [
+ {
+ type: 'row',
+ items: [
+ {
+ label: '变动原因:',
+ id: 'type',
+ type: 'bus-radio',
+ el: {
+ code: 'point_type',
+ childType: 'el-radio-button',
+ hasAll: true,
+ },
+ default: '',
+ searchImmediately: true,
+ span: 24,
+ },
+ {
+ label: '变动时间:',
+ id: 'createTimeStartStr',
+ component: 'el-bus-date-range',
+ el: {
+ type: 'datetime',
+ format: 'yyyy-MM-dd HH:mm:ss',
+ valueFormat: 'yyyy-MM-dd HH:mm:ss',
+ },
+ commonFormat: true,
+ commonFormatProps: ['createTimeStartStr', 'createTimeEndStr'],
+ searchImmediately: true,
+ span: 24,
+ },
+ {
+ label: '备注:',
+ id: 'remarks',
+ type: 'input',
+ },
+ ],
+ },
+ ],
+ },
+ }
+ },
+ head() {
+ return {
+ title: '积分发放',
+ }
+ },
+}
+</script>
diff --git a/pages/order/after-sale/_action/_id.vue b/pages/order/after-sale/_action/_id.vue
new file mode 100644
index 0000000..231afdc
--- /dev/null
+++ b/pages/order/after-sale/_action/_id.vue
@@ -0,0 +1,185 @@
+<template>
+ <div v-loading="wholeLoading" class="base-page-wrapper sale-detail">
+ <el-bus-form
+ ref="form"
+ label-width="auto"
+ :content="formContent"
+ readonly
+ class="readonly-form"
+ >
+ <template #id:baseInfo>
+ <el-bus-title title="基本信息" size="small"></el-bus-title>
+ </template>
+ <template #id:refundInfo>
+ <div class="base-page-wrapper__line"></div>
+ <el-bus-title title="退款信息" size="small"></el-bus-title>
+ </template>
+ <template #id:goodsInfo>
+ <div class="base-page-wrapper__line"></div>
+ <el-bus-title title="商品信息" size="small"></el-bus-title>
+ </template>
+ </el-bus-form>
+ <div class="text-center mt-20">
+ <el-button class="min-w-100" @click="goBack">返回</el-button>
+ </div>
+ </div>
+</template>
+
+<script>
+import VideoList from '@/components/order/video-list'
+export default {
+ data() {
+ return {
+ detail: {},
+ wholeLoading: false,
+ loading: false,
+ formContent: [
+ {
+ type: 'row',
+ id: 'baseInfo',
+ items: [
+ { label: '订单号:', id: 'orderNo', type: 'input' },
+ { label: '下单时间:', id: 'orderTime', type: 'input' },
+ { label: '申请时间:', id: 'createTime', type: 'input' },
+ { label: '审核时间:', id: 'auditTime', type: 'input' },
+ { label: '收货人:', id: 'customer', type: 'input' },
+ { label: '收货人电话:', id: 'customerTel', type: 'input' },
+ { label: '收货地址:', id: 'customerWholeAddress', type: 'input' },
+ ],
+ },
+ {
+ type: 'row',
+ id: 'refundInfo',
+ items: [
+ { id: 'status', type: 'input', hidden: () => true },
+ {
+ label: '订单状态:',
+ id: 'statusStr',
+ component: 'simple-text',
+ el: (row) => ({
+ type: row.status === 'PENDING' ? 'primary' : '',
+ }),
+ forceDisabled: true,
+ },
+ { label: '售后单号:', id: 'salesNo', type: 'input' },
+ { label: '退款金额(元):', id: 'totalFee', type: 'input' },
+ { label: '供应商扣款(元):', id: 'feeSupplier', type: 'input' },
+ { label: '平台扣款(元):', id: 'feePlatform', type: 'input' },
+ { label: '合伙人扣款(元):', id: 'feePartner', type: 'input' },
+ { label: '打包扣款(元):', id: 'feePlatformPack', type: 'input' },
+ { label: '质检扣款(元):', id: 'feePlatformCheck', type: 'input' },
+ {
+ label: '物流扣款(元):',
+ id: 'feePlatformTransport',
+ type: 'input',
+ },
+ { label: '实际总扣款(元):', id: 'totalFee', type: 'input' },
+ {
+ label: '申请理由:',
+ id: 'reason',
+ type: 'input',
+ el: { type: 'textarea' },
+ span: 24,
+ },
+ {
+ label: '平台回复:',
+ id: 'remarks',
+ type: 'input',
+ el: { type: 'textarea' },
+ span: 24,
+ },
+ {
+ label: '退款图片:',
+ id: 'pictureList',
+ type: 'bus-upload',
+ el: {
+ listType: 'picture-card',
+ size: 'small',
+ },
+ forceDisabled: true,
+ span: 24,
+ inputFormat: (row) => {
+ if ('pictureList' in row) {
+ return row?.pictureList?.length
+ ? row.pictureList.map((i) => ({ url: i }))
+ : []
+ }
+ },
+ },
+ {
+ label: '退款视频:',
+ id: 'videoList',
+ component: VideoList,
+ forceDisabled: true,
+ span: 24,
+ },
+ ],
+ },
+ {
+ type: 'row',
+ id: 'goodsInfo',
+ items: [
+ { label: '商品名称:', id: 'flowerName' },
+ { label: '商品分类:', id: 'flowerCategory' },
+ { label: '级别:', id: 'flowerLevelStr' },
+ { label: '颜色:', id: 'flowerColor' },
+ { label: '规格:', id: 'flowerUnit' },
+ { label: '原价(元):', id: 'price' },
+ { label: '券后单价(元):', id: 'realPrice' },
+ { label: '券后总金额(元):', id: 'realTotal' },
+ { label: '供应商价格(元):', id: 'supplierPrice' },
+ { label: '合伙人加价(元):', id: 'markupPartner' },
+ { label: '申请数量:', id: 'num' },
+ { label: '实际退款(元):', id: 'totalFee' },
+ ],
+ },
+ ],
+ }
+ },
+ head() {
+ return {
+ title: '售后详情',
+ }
+ },
+ computed: {
+ editable() {
+ return (
+ this.$route.params.action === 'handle' &&
+ this.detail?.status === 'PENDING'
+ )
+ },
+ },
+ mounted() {
+ this.getDetail()
+ },
+ methods: {
+ goBack() {
+ this.$router.back()
+ },
+ async getDetail() {
+ this.wholeLoading = true
+ const { code, data } = await this.$elBusHttp.request(
+ 'flower/api/sales/list/view',
+ { params: { id: this.$route.params.id } }
+ )
+ if (code === 0 && data) {
+ data.customerWholeAddress = `${data.customerProvince || ''}${
+ data.customerCity || ''
+ }${data.customerRegion || ''}${data.customerAddress || ''}`
+ this.detail = data || {}
+ this.$refs.form.updateForm(data)
+ }
+ this.wholeLoading = false
+ },
+ },
+}
+</script>
+
+<style lang="scss" scoped>
+.sale-detail {
+ border-radius: 0;
+ .el-bus-title {
+ margin-bottom: 10px;
+ }
+}
+</style>
diff --git a/pages/order/after-sale/index.vue b/pages/order/after-sale/index.vue
new file mode 100644
index 0000000..b1b99cf
--- /dev/null
+++ b/pages/order/after-sale/index.vue
@@ -0,0 +1,364 @@
+<template>
+ <el-bus-crud ref="crud" v-bind="tableConfig">
+ <template #table="{ list }">
+ <template v-if="list && list.length > 0">
+ <after-sale-table :list="list" @detail="onDetail" @handle="onHandle" />
+ </template>
+ <el-bus-empty v-else />
+ </template>
+ </el-bus-crud>
+</template>
+
+<script>
+import AfterSaleTable from '@/components/order/after-sale-table'
+const feeKeys = [
+ 'feeSupplier',
+ 'feePlatform',
+ 'feePartner',
+ 'feePlatformPack',
+ 'feePlatformCheck',
+ 'feePlatformTransport',
+ 'feePackingTransport',
+]
+export default {
+ components: {
+ AfterSaleTable,
+ },
+ data() {
+ return {
+ tableConfig: {
+ url: 'flower/api/sales/list',
+ hasNew: false,
+ hasEdit: false,
+ hasDelete: false,
+ hasExport: true,
+ exportUrl: 'flower/api/sales/list/export',
+ exportText: '售后导出',
+ searchFormAttrs: {
+ labelWidth: 'auto',
+ },
+ beforeRequest: (params) => {
+ const searchForm = this.$refs.crud?.$refs?.searchForm
+ if (searchForm) {
+ const statusComp = searchForm.getComponentById('status')
+ if (statusComp) {
+ // 组件内部不会修改这个prop直接修改可忽略警告
+ statusComp.extraQuery = { ...params, status: '' }
+ statusComp.getOtherOptions()
+ }
+ }
+ },
+ searchForm: [
+ {
+ type: 'row',
+ id: 'row',
+ items: [
+ {
+ label: '售后状态:',
+ id: 'status',
+ type: 'bus-radio',
+ el: {
+ hasAll: true,
+ otherInterfaceUri: 'flower/api/sales/status/count',
+ childType: 'el-radio-button',
+ filterOptions: (list) => {
+ return list.map((item) => {
+ return {
+ ...item,
+ label: `${item.label}(${item.orderCount})`,
+ }
+ })
+ },
+ // code: 'ORDER_SALES_STATUS',
+ },
+ default: this.$route.query.status || '',
+ span: 24,
+ searchImmediately: true,
+ on: {
+ optionsChange: (e, updateForm, { currentComp }) => {
+ if (Array.isArray(e[0]) && e[0].length > 0) {
+ const totalCount = e[0].reduce((total, current) => {
+ return (total += current.orderCount)
+ }, 0)
+ // 组件内部不会修改这个prop直接修改可忽略警告
+ currentComp.props = {
+ allLabel: `不限(${totalCount})`,
+ }
+ }
+ },
+ },
+ },
+ { label: '商品名称:', id: 'flowerName', type: 'input' },
+ { label: '订单号:', id: 'orderNo', type: 'input' },
+ { label: '售后单号:', id: 'salesNo', type: 'input' },
+ { label: '收货人姓名:', id: 'customer', type: 'input' },
+ { label: '收货人电话:', id: 'customerTel', type: 'input' },
+ { label: '供应商:', id: 'supplierName', type: 'input' },
+ {
+ label: '下单时间:',
+ id: 'orderStartDateStr',
+ component: 'el-bus-date-range',
+ commonFormat: true,
+ commonFormatProps: ['orderStartDateStr', 'orderEndDateStr'],
+ customClass: 'in-bus-form',
+ },
+ {
+ label: '售后时间:',
+ id: 'salesStartDateStr',
+ component: 'el-bus-date-range',
+ commonFormat: true,
+ commonFormatProps: ['salesStartDateStr', 'salesEndDateStr'],
+ customClass: 'in-bus-form',
+ },
+ {
+ label: '售后类别',
+ id: 'salesType',
+ type: 'bus-select-dict',
+ el: {
+ code: 'after_sale_type',
+ clearable: true,
+ style: 'width:100%',
+ },
+ },
+ ],
+ },
+ ],
+ form: [
+ {
+ type: 'row',
+ items: [
+ { label: '商品名称:', id: 'flowerName', type: 'input' },
+ { label: '合伙人加价(元):', id: 'markupPartner', type: 'input' },
+ { label: '原价(元):', id: 'price', type: 'input' },
+ { label: '券后单价(元):', id: 'realPrice', type: 'input' },
+ { label: '券后总金额(元):', id: 'realTotal', type: 'input' },
+ { label: '供应商价格(元):', id: 'supplierPrice', type: 'input' },
+ { label: '商品数量:', id: 'flowerNum', type: 'input' },
+ { label: '申请售后数量:', id: 'num', type: 'input' },
+ ],
+ },
+ {
+ type: 'row',
+ items: [
+ {
+ label: '质检总扣款(元):',
+ id: 'checkTotalAmount',
+ type: 'input',
+ span: 24,
+ customClass: 'to-red to-bold',
+ },
+ {
+ label: '降级数量:',
+ id: 'reduceNum',
+ type: 'input',
+ },
+ {
+ label: '降级总金额(元):',
+ id: 'reduceAmount',
+ type: 'input',
+ },
+ {
+ label: '缺货数量:',
+ id: 'lackNum',
+ type: 'input',
+ span: 24,
+ },
+ {
+ label: '已退总金额(元):',
+ id: 'refundTotalAmount',
+ type: 'input',
+ span: 24,
+ customClass: 'to-red to-bold',
+ },
+ ],
+ },
+ ],
+ extraDialogs: [
+ {
+ title: '售后处理',
+ readonly: true,
+ confirmText: '通过',
+ cancelText: '不通过',
+ confirmButtonAttrs: {
+ type: 'success',
+ },
+ cancelButtonAttrs: {
+ type: 'danger',
+ },
+ dialogAttrs: {
+ width: '70%',
+ },
+ form: [
+ {
+ type: 'row',
+ items: [
+ {
+ label: '供应商(元):',
+ id: 'feeSupplier',
+ type: 'input-number',
+ el: { min: 0, precision: 2, controls: false },
+ },
+ {
+ label: '平台(元):',
+ id: 'feePlatform',
+ type: 'input-number',
+ el: { min: 0, precision: 2, controls: false },
+ },
+ {
+ label: '合伙人(元):',
+ id: 'feePartner',
+ type: 'input-number',
+ el: { min: 0, precision: 2, controls: false },
+ },
+ {
+ label: '打包(元):',
+ id: 'feePlatformPack',
+ type: 'input-number',
+ el: { min: 0, precision: 2, controls: false },
+ },
+ {
+ label: '质检(元):',
+ id: 'feePlatformCheck',
+ type: 'input-number',
+ el: { min: 0, precision: 2, controls: false },
+ },
+ {
+ label: '物流(元):',
+ id: 'feePlatformTransport',
+ type: 'input-number',
+ el: { min: 0, precision: 2, controls: false },
+ },
+ {
+ label: '打包运费(元)(散户):',
+ id: 'feePackingTransport',
+ type: 'input-number',
+ el: { min: 0, precision: 2, controls: false },
+ },
+ {
+ label: '实际总扣款(元):',
+ id: 'tempTotal',
+ component: 'simple-text',
+ readonly: true,
+ forceDisabled: true,
+ el: (row) => ({
+ text: feeKeys
+ .reduce((total, current) => {
+ total += row[current] ?? 0
+ return total
+ }, 0)
+ .toFixed(2),
+ }),
+ span: 24,
+ customClass: 'to-bold-label',
+ },
+ {
+ label: '申请理由:',
+ id: 'reason',
+ type: 'input',
+ el: {
+ type: 'textarea',
+ },
+ readonly: true,
+ span: 24,
+ },
+ {
+ label: '平台回复:',
+ id: 'remarks',
+ type: 'input',
+ el: {
+ type: 'textarea',
+ rows: 6,
+ },
+ rules: {
+ required: true,
+ message: '请输入平台回复',
+ trigger: 'blur',
+ },
+ span: 24,
+ },
+ ],
+ },
+ ],
+ atConfirm: async (val) => {
+ const { code } = await this.$elBusHttp.request(
+ 'flower/api/sales/audit/agree',
+ { method: 'post', data: val }
+ )
+ if (code === 0) {
+ this.$message.success('操作成功')
+ } else {
+ return false
+ }
+ },
+ atCancel: async (val) => {
+ const { code } = await this.$elBusHttp.request(
+ 'flower/api/sales/audit/reject',
+ {
+ method: 'post',
+ data: {
+ id: val.id,
+ remarks: val.remarks,
+ },
+ }
+ )
+ if (code === 0) {
+ this.$message.success('操作成功')
+ } else {
+ return false
+ }
+ },
+ },
+ ],
+ },
+ }
+ },
+ head() {
+ return {
+ title: '售后理赔',
+ }
+ },
+ methods: {
+ onDetail(item) {
+ this.$router.push(`${this.$route.path}/view/${item.id}`)
+ },
+ async onHandle(item) {
+ const { code, data } = await this.$elBusHttp.request(
+ 'flower/api/sales/list/view',
+ { params: { id: item.id } }
+ )
+ if (code === 0) {
+ feeKeys.forEach((key) => {
+ data[key] = data[key] ?? undefined
+ })
+ this.$refs.crud.$refs.extraDialog[0].show(data)
+ }
+ },
+ },
+}
+</script>
+
+<style lang="scss" scoped>
+::v-deep {
+ .el-form-item {
+ &.to-bold {
+ .el-form-item__label,
+ .simple-text,
+ .el-bus-form-item__normal {
+ font-weight: bold;
+ }
+ }
+ &.to-red {
+ .el-form-item__label,
+ .simple-text,
+ .el-bus-form-item__normal {
+ color: $danger-color;
+ }
+ }
+ &.to-bold-label {
+ .el-form-item__label {
+ font-weight: bold;
+ }
+ }
+ }
+}
+</style>
diff --git a/pages/order/evaluation/index.vue b/pages/order/evaluation/index.vue
new file mode 100644
index 0000000..a67c40b
--- /dev/null
+++ b/pages/order/evaluation/index.vue
@@ -0,0 +1,323 @@
+<template>
+ <el-bus-crud ref="crud" v-bind="tableConfig">
+ <template #table="{ list }">
+ <template v-if="list && list.length > 0">
+ <evaluation-table
+ :list="list"
+ @detail="onDetail"
+ @handle="onHandle"
+ @delete="onDelete"
+ @show="onShow"
+ @hide="onHide"
+ />
+ </template>
+ <el-bus-empty v-else />
+ </template>
+ </el-bus-crud>
+</template>
+
+<script>
+import EvaluationTable from '@/components/order/evaluation-table'
+export default {
+ components: {
+ EvaluationTable,
+ },
+ data() {
+ return {
+ tableConfig: {
+ evaluationId: null,
+ url: 'flower/api/v2/flower-comment/page',
+ hasNew: false,
+ hasEdit: false,
+ hasDelete: true,
+ operationAttrs: {
+ width: 150,
+ fixed: 'right',
+ },
+
+ searchForm: [
+ {
+ type: 'row',
+ items: [
+ { label: '订单编号', id: 'orderNo', type: 'input' },
+ { label: '商品名称', id: 'flowerName', type: 'input' },
+ {
+ label: '评价星级',
+ id: 'commentGrade',
+ type: 'bus-select-dict',
+ el: {
+ code: 'comment_grade',
+ clearable: true,
+ style: 'width:100%',
+ },
+ },
+ {
+ label: '评价时间',
+ component: 'el-bus-date-range',
+ id: 'commentStartDate',
+ commonFormat: true,
+ commonFormatProps: ['commentStartDate', 'commentEndDate'],
+ customClass: 'in-bus-form',
+ },
+ ],
+ },
+ ],
+ form: [
+ // { label: '评价内容1', id: 'comment', type: 'input' },
+ ],
+ extraDialogs: [
+ {
+ title: '评价详情',
+ readonly: true,
+ showButton: false,
+ dialogAttrs: {
+ width: '70%',
+ closeOnClickModal: true,
+ customClass: 'evaluation-drawer-wrapper',
+ },
+ form: [
+ {
+ label: '订单编号:',
+ id: 'orderNo',
+ type: 'input',
+ readonly: true,
+ },
+ {
+ label: '商品名称:',
+ id: 'flowerName',
+ type: 'input',
+ readonly: true,
+ },
+ {
+ label: '商品封面图:',
+ id: 'flowerCover',
+ type: 'bus-upload',
+ readonly: true,
+ el: {
+ listType: 'picture-card',
+ limitSize: 2,
+ valueType: 'string',
+ },
+ forceDisabled: true,
+ },
+ {
+ label: '商品等级:',
+ id: 'flowerLevel',
+ type: 'input',
+ readonly: true,
+ },
+ {
+ label: '商品规格:',
+ id: 'flowerUnit',
+ type: 'input',
+ readonly: true,
+ },
+ {
+ label: '供应商信息:',
+ id: 'supplierName',
+ type: 'input',
+ readonly: true,
+ },
+ {
+ label: '用户信息:',
+ id: 'customerName',
+ type: 'input',
+ readonly: true,
+ },
+ {
+ label: '评价星级:',
+ id: 'commentGrade',
+ component: 'simple-text',
+ readonly: true,
+ el: {
+ type: 'primary',
+ },
+ forceDisabled: true,
+ },
+ {
+ label: '评论显示状态:',
+ id: 'showFlag',
+ component: 'simple-text',
+ readonly: true,
+ el: (row) => ({
+ type: 'primary',
+ text: row.showFlag === 0 ? '显示' : '隐藏',
+ }),
+ forceDisabled: true,
+ },
+ {
+ label: '评价内容:',
+ id: 'comment',
+ type: 'input',
+ readonly: true,
+ },
+ {
+ label: '回复内容:',
+ id: 'replayContent',
+ type: 'input',
+ readonly: true,
+ },
+ {
+ label: '评价时间:',
+ id: 'createTime',
+ type: 'input',
+ readonly: true,
+ },
+ {
+ label: '评价图片:',
+ id: 'commentImages',
+ type: 'bus-upload',
+ readonly: true,
+ el: {
+ listType: 'picture-card',
+ limit: 1,
+ limitSize: 2,
+ },
+ inputFormat: (row) => {
+ if ('commentImages' in row) {
+ return row.commentImages
+ ? JSON.parse(row.commentImages).map((i) => ({ url: i }))
+ : []
+ }
+ },
+ commonFormat: true,
+ forceDisabled: true,
+ },
+ ],
+ },
+ {
+ title: '回复评价',
+ form: [
+ {
+ label: '评价内容:',
+ id: 'comment',
+ type: 'input',
+ readonly: true,
+ },
+ {
+ label: '回复内容:',
+ id: 'replayContent',
+ type: 'input',
+ el: {
+ rows: 6,
+ type: 'textarea',
+ },
+ rules: {
+ required: true,
+ message: '请输入回复内容',
+ trigger: 'blur',
+ },
+ },
+ ],
+ atConfirm: async (val) => {
+ const { code } = await this.$elBusHttp.request(
+ 'flower/api/v2/flower-comment/replay/' + this.evaluationId + '',
+ {
+ method: 'put',
+ data: val,
+ }
+ )
+ if (code === 0) {
+ this.$message.success('回复成功')
+ }
+ },
+ },
+ ],
+ },
+ }
+ },
+ head() {
+ return {
+ title: '评价列表',
+ }
+ },
+ methods: {
+ onHandle(item) {
+ this.evaluationId = item.id
+ this.$refs.crud.$refs.extraDialog[1].show({
+ comment: item.comment,
+ })
+ },
+ async onDetail(item) {
+ const { code, data } = await this.$elBusHttp.request(
+ 'flower/api/v2/flower-comment/list',
+ { params: { id: item.id } }
+ )
+ if (code === 0) {
+ const row = data[0]
+ row.supplierName = row.supplierName+'[ID:'+ row.supplierId +'], 电话:'+row.supplierContactTel
+ row.customerName = row.customerName+'[UID:'+ row.customerId +']'
+ row.commentGrade = row.commentGrade+'星'
+ this.$refs.crud.$refs.extraDialog[0].show(row)
+ }
+ },
+ async onDelete(item) {
+ try {
+ await this.$elBusUtil.confirm(`确定要删除这个商品吗?`)
+ const { code } = await this.$elBusHttp.request(
+ 'flower/api/v2/flower-comment/' + item.id + '',
+ {
+ method: 'delete',
+ }
+ )
+ if (code === 0) {
+ this.$message.success(`删除成功`)
+ this.$refs.crud.getList()
+ } else {
+ return false
+ }
+ } catch (error) {
+ return false
+ }
+ },
+ async onShow(item) {
+ try {
+ await this.$elBusUtil.confirm(`确定要显示这个评价吗?`)
+ const { code } = await this.$elBusHttp.request(
+ 'flower/api/v2/flower-comment/show/' + item.id + '',
+ {
+ method: 'put',
+ data: { showFalg: 0 },
+ }
+ )
+ if (code === 0) {
+ this.$message.success(`显示成功`)
+ this.$refs.crud.getList()
+ }
+ } catch (e) {
+ return false
+ }
+ },
+
+ async onHide(item) {
+ try {
+ await this.$elBusUtil.confirm(`确定要隐藏这个评价吗?`)
+ const { code } = await this.$elBusHttp.request(
+ 'flower/api/v2/flower-comment/show/' + item.id + '',
+ {
+ method: 'put',
+ data: { showFalg: 1 },
+ }
+ )
+ if (code === 0) {
+ this.$message.success(`隐藏成功`)
+ this.$refs.crud.getList()
+ }
+ } catch (e) {
+ return false
+ }
+ },
+ },
+}
+</script>
+
+<style lang="scss">
+.evaluation-drawer-wrapper {
+ position: absolute;
+ right: 0;
+ top: 0;
+ width: 35% !important;
+ margin-top: 0 !important;
+ min-height: 100vh;
+}
+</style>
diff --git a/pages/order/list/_id.vue b/pages/order/list/_id.vue
new file mode 100644
index 0000000..d19da68
--- /dev/null
+++ b/pages/order/list/_id.vue
@@ -0,0 +1,780 @@
+<template>
+ <div v-loading="loading" class="base-page-wrapper order-detail">
+ <el-bus-title title="订单信息" size="small"></el-bus-title>
+ <el-bus-form
+ ref="form"
+ label-width="auto"
+ :content="formContent"
+ readonly
+ class="readonly-form"
+ ></el-bus-form>
+ <template v-if="detail.memberCouponAmount || detail.memberDiscountType">
+ <div class="base-page-wrapper__line"></div>
+ <el-bus-title title="优惠信息" size="small" />
+ <el-bus-form
+ ref="discountForm"
+ label-width="auto"
+ :content="discountForm"
+ readonly
+ class="readonly-form"
+ ></el-bus-form>
+ </template>
+ <div class="base-page-wrapper__line"></div>
+ <el-bus-title title="商品信息" size="small">
+ <template #right>
+ <el-button
+ v-if="detail.couldCheckRefund"
+ type="primary"
+ @click="checkRefund"
+ >质检退款</el-button
+ >
+ </template>
+ </el-bus-title>
+ <el-table :data="goodsList">
+ <el-table-column
+ label="商品名称"
+ prop="flowerName"
+ min-width="150"
+ fixed="left"
+ ></el-table-column>
+ <el-table-column
+ label="商品分类"
+ prop="flowerCategory"
+ min-width="150"
+ ></el-table-column>
+ <el-table-column
+ label="级别"
+ prop="flowerLevelStr"
+ min-width="100"
+ ></el-table-column>
+ <el-table-column
+ label="颜色"
+ prop="flowerColor"
+ min-width="100"
+ ></el-table-column>
+ <el-table-column
+ label="规格"
+ prop="flowerUnit"
+ min-width="100"
+ ></el-table-column>
+ <el-table-column
+ label="数量"
+ prop="num"
+ min-width="100"
+ ></el-table-column>
+ <el-table-column
+ label="会员单价(元)"
+ prop="price"
+ min-width="100"
+ ></el-table-column>
+ <el-table-column
+ label="原价(元)"
+ prop="originalPrice"
+ min-width="100"
+ ></el-table-column>
+ <el-table-column
+ label="券后总金额(元)"
+ prop="realTotal"
+ min-width="120"
+ ></el-table-column>
+ <el-table-column
+ label="券后单价(元)"
+ prop="realPrice"
+ min-width="100"
+ ></el-table-column>
+ <el-table-column
+ label="优惠总金额(元)"
+ prop="couponAmountTotal"
+ min-width="120"
+ ></el-table-column>
+ <el-table-column
+ label="供应商"
+ prop="supplierName"
+ min-width="150"
+ ></el-table-column>
+ <el-table-column
+ label="供应商电话"
+ prop="supplierTel"
+ min-width="150"
+ ></el-table-column>
+ <el-table-column
+ label="集货站"
+ prop="stationName"
+ min-width="150"
+ ></el-table-column>
+ <el-table-column
+ label="花材底价(元)"
+ prop="supplierPrice"
+ min-width="120"
+ ></el-table-column>
+ <el-table-column
+ label="区间加价(元)"
+ prop="markupOne"
+ min-width="120"
+ ></el-table-column>
+ <el-table-column
+ label="平台加价(元)"
+ prop="markupTwo"
+ min-width="120"
+ ></el-table-column>
+ <el-table-column
+ label="合伙人加价(元)"
+ prop="markupPartner"
+ min-width="120"
+ ></el-table-column>
+ <el-table-column
+ label="质检退款(元)"
+ prop="deductAmount"
+ min-width="120"
+ ></el-table-column>
+ <el-table-column
+ label="补货扣款(元)"
+ prop="replaceFee"
+ min-width="120"
+ ></el-table-column>
+ <el-table-column
+ label="降级扣款(元)"
+ prop="checkFee"
+ min-width="120"
+ ></el-table-column>
+ <el-table-column
+ label="缺货扣款(元)"
+ prop="lackFeeSupplier"
+ min-width="120"
+ ></el-table-column>
+ <el-table-column label="质检审核" width="220" fixed="right">
+ <template #default="{ row }">
+ <el-button
+ v-if="buttonShow(row.replaceNum, row.replaceStatus) === 1"
+ type="text"
+ @click="checkItem('replace', row, false)"
+ >补货</el-button
+ >
+ <el-button
+ v-if="buttonShow(row.replaceNum, row.replaceStatus) === 2"
+ type="text"
+ @click="checkItem('replace', row, true)"
+ >补货详情</el-button
+ >
+ <el-button
+ v-if="buttonShow(row.reduceNum, row.reduceStatus) === 1"
+ type="text"
+ @click="checkItem('reduce', row, false)"
+ >降级</el-button
+ >
+ <el-button
+ v-if="buttonShow(row.reduceNum, row.reduceStatus) === 2"
+ type="text"
+ @click="checkItem('reduce', row, true)"
+ >降级详情</el-button
+ >
+ <el-button
+ v-if="buttonShow(row.lackNum, row.lackStatus) === 1"
+ type="text"
+ @click="checkItem('lack', row, false)"
+ >缺货</el-button
+ >
+ <el-button
+ v-if="buttonShow(row.lackNum, row.lackStatus) === 2"
+ type="text"
+ @click="checkItem('lack', row, true)"
+ >缺货详情</el-button
+ >
+ </template>
+ </el-table-column>
+ </el-table>
+ <template v-if="detail.pointGoodsList && detail.pointGoodsList.length > 0">
+ <div class="base-page-wrapper__line"></div>
+ <el-bus-title title="积分兑换商品" size="small" />
+ <el-table :data="detail.pointGoodsList">
+ <el-table-column label="商品图片">
+ <template #default="{ row }">
+ <el-bus-image
+ :src="row.cover"
+ lazy
+ style="width: 50px; height: 50px"
+ />
+ </template>
+ </el-table-column>
+ <el-table-column label="商品名称" prop="name"></el-table-column>
+ <el-table-column label="兑换数量" prop="num"></el-table-column>
+ </el-table>
+ </template>
+ <template v-if="afterSaleList && afterSaleList.length > 0">
+ <div class="base-page-wrapper__line"></div>
+ <el-bus-title title="售后信息" size="small" class="mt-20"></el-bus-title>
+ <el-table :data="afterSaleList">
+ <el-table-column
+ label="商品名称"
+ prop="flowerName"
+ min-width="150"
+ fixed="left"
+ ></el-table-column>
+ <el-table-column
+ label="级别"
+ prop="flowerLevelStr"
+ min-width="120"
+ ></el-table-column>
+ <el-table-column
+ label="颜色"
+ prop="flowerColor"
+ min-width="120"
+ ></el-table-column>
+ <el-table-column
+ label="原因"
+ prop="reason"
+ min-width="200"
+ ></el-table-column>
+ <el-table-column
+ label="售后时间"
+ prop="createTime"
+ min-width="180"
+ ></el-table-column>
+ <el-table-column
+ label="处理时间"
+ prop="auditTime"
+ min-width="180"
+ ></el-table-column>
+ <el-table-column
+ label="处理状态"
+ prop="statusStr"
+ min-width="120"
+ ></el-table-column>
+ <el-table-column
+ label="实际退款"
+ prop="totalFee"
+ min-width="120"
+ ></el-table-column>
+ <el-table-column label="操作" width="120" fixed="right">
+ <template #default="{ row }">
+ <el-button type="text" @click="toDetail(row.id)"
+ >查看详情</el-button
+ >
+ </template>
+ </el-table-column>
+ </el-table>
+ </template>
+ <div class="text-center mt-20">
+ <el-button class="min-w-100" @click="goBack">返回</el-button>
+ </div>
+ <extra-dialog
+ ref="replaceDialog"
+ title="补货信息"
+ confirm-text="通过"
+ cancel-text="不通过"
+ :confirm-button-attrs="{ type: 'success' }"
+ :cancel-button-attrs="{ type: 'danger' }"
+ :form="replaceForm"
+ :dialog-attrs="dialogAttrs"
+ :form-attrs="formAttrs"
+ :at-confirm="onCheckAgree"
+ :at-cancel="onCheckReject"
+ ></extra-dialog>
+ <extra-dialog
+ ref="reduceDialog"
+ title="降级信息"
+ confirm-text="通过"
+ cancel-text="不通过"
+ :confirm-button-attrs="{ type: 'success' }"
+ :cancel-button-attrs="{ type: 'danger' }"
+ :form="reduceForm"
+ :dialog-attrs="dialogAttrs"
+ :form-attrs="formAttrs"
+ :at-confirm="onCheckAgree"
+ :at-cancel="onCheckReject"
+ ></extra-dialog>
+ <extra-dialog
+ ref="lackDialog"
+ title="缺货信息"
+ confirm-text="通过"
+ cancel-text="不通过"
+ :confirm-button-attrs="{ type: 'success' }"
+ :cancel-button-attrs="{ type: 'danger' }"
+ :form="lackForm"
+ :dialog-attrs="dialogAttrs"
+ :form-attrs="formAttrs"
+ :at-confirm="onCheckAgree"
+ :at-cancel="onCheckReject"
+ ></extra-dialog>
+ <extra-dialog
+ ref="refundDialog"
+ title="质检退款"
+ :form="refundForm"
+ :dialog-attrs="{ ...dialogAttrs, width: '70%' }"
+ :form-attrs="formAttrs"
+ confirm-text="确定退款"
+ :at-confirm="onRefundConfirm"
+ >
+ </extra-dialog>
+ </div>
+</template>
+
+<script>
+import CheckAbnormalList from '@/components/order/check-abnormal-list.vue'
+const DialogCommonForm = [
+ {
+ label: '商品名称:',
+ id: 'flowerName',
+ type: 'input',
+ readonly: true,
+ },
+ {
+ label: '级别:',
+ id: 'flowerLevelStr',
+ type: 'input',
+ readonly: true,
+ },
+ {
+ label: '供应商:',
+ id: 'supplierName',
+ type: 'input',
+ readonly: true,
+ },
+ {
+ label: '供应商联系人:',
+ id: 'supplierContact',
+ type: 'input',
+ readonly: true,
+ },
+ {
+ label: '供应商联系电话:',
+ id: 'supplierTel',
+ type: 'input',
+ readonly: true,
+ },
+ {
+ label: '集货站:',
+ id: 'stationName',
+ type: 'input',
+ readonly: true,
+ },
+ {
+ label: '质检人:',
+ id: 'createName',
+ type: 'input',
+ readonly: true,
+ },
+ {
+ label: '备注:',
+ id: 'remarks',
+ type: 'input',
+ span: 24,
+ readonly: true,
+ },
+ {
+ label: '提交时间:',
+ id: 'checkTime',
+ type: 'input',
+ span: 24,
+ readonly: true,
+ },
+]
+const dialogAuditForm = [
+ {
+ label: '审核结果:',
+ id: 'auditStatusStr',
+ type: 'input',
+ hidden: (row) => !row.auditStatusStr,
+ span: 24,
+ readonly: true,
+ },
+ {
+ label: '审核时间:',
+ id: 'auditTime',
+ type: 'input',
+ hidden: (row) => !row.auditStatusStr,
+ span: 24,
+ readonly: true,
+ },
+]
+export default {
+ data() {
+ return {
+ loading: false,
+ detail: {},
+ formContent: [
+ {
+ type: 'row',
+ items: [
+ { label: '订单号:', id: 'orderNo', type: 'input' },
+ { label: '用户账号:', id: 'createName', type: 'input' },
+ { label: '收货人:', id: 'customer', type: 'input' },
+ { label: '收货人电话:', id: 'customerTel', type: 'input' },
+ { label: '收货地址:', id: 'customerWholeAddress', type: 'input' },
+ { label: '下单时间:', id: 'createTime', type: 'input' },
+ { label: '支付时间:', id: 'paymentTime', type: 'input' },
+ { label: '商品金额:', id: 'flowerAmountDesc', type: 'input' },
+ { label: '打包费:', id: 'packingFee', type: 'input' },
+ { label: '运费:', id: 'transportFee', type: 'input' },
+ { label: '订单金额:', id: 'originalPrice', type: 'input' },
+ { label: '实际支付金额:', id: 'totalAmountDesc', type: 'input' },
+ { label: '订单状态:', id: 'statusBackendStr', type: 'input' },
+ { label: '合伙人:', id: 'partnerName', type: 'input' },
+ { label: '库区:', id: 'warehouseName', type: 'input' },
+ { label: '库位:', id: 'warehouseLocationCode', type: 'input' },
+ { label: '特殊需求:', id: 'specialNeedsStr', type: 'input' },
+ { label: '快递号:', id: 'deliveryNo', type: 'input' },
+ {
+ label: '备注:',
+ id: 'remarks',
+ type: 'input',
+ el: { type: 'textarea' },
+ span: 24,
+ },
+ ],
+ },
+ ],
+ discountForm: [
+ {
+ type: 'row',
+ items: [
+ {
+ label: '优惠券类型:',
+ id: 'couponDiscountTypeName',
+ type: 'input',
+ hidden: (row) => !row.memberCouponAmount,
+ },
+ {
+ label: '使用条件:',
+ id: 'minOrderAmount',
+ type: 'input',
+ hidden: (row) => !row.memberCouponAmount,
+ },
+ {
+ label: '优惠券名称:',
+ id: 'memberCouponName',
+ type: 'input',
+ hidden: (row) => !row.memberCouponAmount,
+ },
+ {
+ label: '优惠券金额:',
+ id: 'memberCouponAmount',
+ type: 'input',
+ hidden: (row) => !row.memberCouponAmount,
+ },
+ {
+ label: '会员等级:',
+ id: 'memberName',
+ type: 'input',
+ hidden: (row) => !row.memberDiscountType,
+ },
+ {
+ label: '会员折扣类型:',
+ id: 'memberDiscountType',
+ type: 'input',
+ str: true,
+ hidden: (row) => !row.memberDiscountType,
+ },
+ {
+ label: '会员折扣:',
+ id: 'memberDiscountRatio',
+ type: 'input',
+ unit: '%',
+ hidden: (row) => row.memberDiscountType !== 'ratio',
+ },
+ {
+ label: '会员优惠:',
+ id: 'memberDiscountAmount',
+ type: 'input',
+ unit: '元/扎',
+ hidden: (row) => row.memberDiscountType !== 'amount',
+ },
+ ],
+ },
+ ],
+ goodsList: [],
+ afterSaleList: [],
+ dialogAttrs: {
+ closeOnClickModal: false,
+ },
+ formAttrs: {
+ labelWidth: 'auto',
+ },
+ replaceForm: [
+ {
+ type: 'row',
+ span: 12,
+ items: [
+ ...DialogCommonForm,
+ {
+ label: '补货数量:',
+ id: 'num',
+ type: 'input',
+ readonly: true,
+ },
+ ...dialogAuditForm,
+ ],
+ },
+ ],
+ reduceForm: [
+ {
+ type: 'row',
+ span: 12,
+ items: [
+ ...DialogCommonForm,
+ {
+ label: '降级数量:',
+ id: 'num',
+ type: 'input',
+ readonly: true,
+ span: 8,
+ },
+ {
+ label: '降级等级:',
+ id: 'targetLevelStr',
+ type: 'input',
+ readonly: true,
+ span: 8,
+ },
+ {
+ label: '扣款金额:',
+ id: 'deductAmount',
+ type: 'input',
+ readonly: true,
+ span: 8,
+ },
+ {
+ label: '图片:',
+ id: 'pictureList',
+ type: 'bus-upload',
+ el: {
+ listType: 'picture-card',
+ },
+ readonly: true,
+ forceDisabled: true,
+ span: 24,
+ inputFormat: (row) => {
+ if ('pictureList' in row) {
+ return row.pictureList
+ ? row.pictureList.map((item) => ({
+ url: item,
+ }))
+ : []
+ }
+ },
+ },
+ ...dialogAuditForm,
+ ],
+ },
+ ],
+ lackForm: [
+ {
+ type: 'row',
+ span: 12,
+ items: [
+ ...DialogCommonForm,
+ {
+ label: '缺货数量:',
+ id: 'num',
+ type: 'input',
+ readonly: true,
+ },
+ ...dialogAuditForm,
+ ],
+ },
+ ],
+ refundForm: [
+ {
+ label: '退款总计(元):',
+ id: 'deductAmount',
+ type: 'input',
+ readonly: true,
+ },
+ {
+ label: '异常商品明细:',
+ id: 'items',
+ component: CheckAbnormalList,
+ readonly: true,
+ forceDisabled: true,
+ },
+ ],
+ }
+ },
+ head() {
+ return {
+ title: '订单详情',
+ }
+ },
+ mounted() {
+ this.getDetail()
+ this.getGoodsList()
+ this.getAfterSaleList()
+ },
+ methods: {
+ goBack() {
+ this.$router.back()
+ },
+ async getDetail() {
+ this.loading = true
+ const { code, data } = await this.$elBusHttp.request(
+ 'flower/api/order/list/view',
+ { params: { id: this.$route.params.id } }
+ )
+ if (code === 0) {
+ data.customerWholeAddress = `${data.customerProvince || ''}${
+ data.customerCity || ''
+ }${data.customerRegion || ''}${data.customerAddress || ''}`
+ // 如果享受了会员优惠则显示具体会员优惠
+ data.flowerAmountDesc = data.flowerAmount
+ if (data.memberDiscountType) {
+ if (data.memberDiscountType === 'ratio' && data.memberDiscountRatio) {
+ data.flowerAmountDesc += `(其中享受会员折扣${data.memberDiscountRatio}%)`
+ } else if (
+ data.memberDiscountType === 'amount' &&
+ data.memberDiscountAmount
+ ) {
+ data.flowerAmountDesc += `(其中享受会员优惠每扎减${data.memberDiscountAmount}元)`
+ }
+ }
+ // 如果使用了优惠券则显示优惠券具体信息
+ data.totalAmountDesc = data.totalAmount
+ if (data.memberCouponAmount) {
+ data.totalAmountDesc += `(其中使用了${data.memberCouponAmount}元优惠券)`
+ }
+ data.originalPrice = Number(
+ (
+ (data.flowerAmount || 0) +
+ (data.packingFee || 0) +
+ (data.transportFee || 0)
+ ).toFixed(2)
+ )
+ this.detail = data
+ this.$nextTick(() => {
+ if (this.$refs.discountForm) {
+ this.$refs.discountForm.updateForm(data)
+ }
+ })
+ this.$refs.form.updateForm(data)
+ }
+ this.loading = false
+ },
+ async getGoodsList() {
+ const { code, data } = await this.$elBusHttp.request(
+ 'flower/api/order/item/list',
+ { params: { id: this.$route.params.id } }
+ )
+ if (code === 0) {
+ this.goodsList = data || []
+ }
+ },
+ async getAfterSaleList() {
+ const { code, data } = await this.$elBusHttp.request(
+ 'flower/api/sales/list',
+ { params: { orderId: this.$route.params.id, current: 1, size: 2000 } }
+ )
+ if (code === 0) {
+ this.afterSaleList = data.records || []
+ }
+ },
+ toDetail(id) {
+ this.$router.push(`/order/after-sale/view/${id}`)
+ },
+ // 根据数量以及状态判断按钮显示
+ buttonShow(num, status) {
+ if (!this.$elBusUtil.isEmpty(num)) {
+ return status ? 2 : 1
+ }
+ return null
+ },
+ // 获取补货详情
+ async replaceDetail(orderItemId) {
+ return await this.$elBusHttp.request(
+ 'flower/api/order/list/check/info/replace',
+ { params: { orderItemId } }
+ )
+ },
+ // 获取缺货详情
+ async lackDetail(orderItemId) {
+ return await this.$elBusHttp.request(
+ 'flower/api/order/list/check/info/lack',
+ { params: { orderItemId } }
+ )
+ },
+ // 获取降级详情
+ async reduceDetail(orderItemId) {
+ return await this.$elBusHttp.request(
+ 'flower/api/order/list/check/info/reduce',
+ { params: { orderItemId } }
+ )
+ },
+ // 质检(缺货,补货,降级)审核操作
+ async checkItem(type, row, readonly) {
+ const { code, data } = await this[`${type}Detail`](row.id)
+ if (code === 0) {
+ this.$refs[`${type}Dialog`].show(
+ {
+ ...data,
+ flowerName: row.flowerName,
+ flowerLevelStr: row.flowerLevelStr,
+ supplierName: row.supplierName,
+ supplierContact: row.supplierContact,
+ supplierTel: row.supplierTel,
+ stationName: row.stationName,
+ },
+ readonly ? 'view' : 'edit'
+ )
+ }
+ },
+ // 质检审核通过
+ async onCheckAgree(val) {
+ const { code } = await this.$elBusHttp.request(
+ 'flower/api/order/list/check/info/agree',
+ { params: { id: val.id } }
+ )
+ if (code === 0) {
+ this.$message.success('操作成功')
+ this.getDetail()
+ this.getGoodsList()
+ } else {
+ return false
+ }
+ },
+ // 质检审核不通过
+ async onCheckReject(val) {
+ const { code } = await this.$elBusHttp.request(
+ 'flower/api/order/list/check/info/reject',
+ { params: { id: val.id } }
+ )
+ if (code === 0) {
+ this.$message.success('操作成功')
+ this.getDetail()
+ this.getGoodsList()
+ } else {
+ return false
+ }
+ },
+ // 质检退款确认弹窗展示明细
+ async checkRefund() {
+ const { code, data } = await this.$elBusHttp.request(
+ 'flower/api/order/list/abnormal/details',
+ { params: { id: this.$route.params.id } }
+ )
+ if (code === 0) {
+ this.$refs.refundDialog.show(data)
+ }
+ },
+ // 发起退款
+ async onRefundConfirm() {
+ const { code } = await this.$elBusHttp.request(
+ 'flower/api/order/list/abnormal/process',
+ { params: { id: this.$route.params.id } }
+ )
+ if (code === 0) {
+ this.$message.success('操作成功')
+ this.getDetail()
+ } else {
+ return false
+ }
+ },
+ },
+}
+</script>
+
+<style lang="scss" scoped>
+.order-detail {
+ border-radius: 0;
+ .el-bus-title {
+ margin-bottom: 10px;
+ }
+}
+</style>
diff --git a/pages/order/list/index.vue b/pages/order/list/index.vue
new file mode 100644
index 0000000..c7292c0
--- /dev/null
+++ b/pages/order/list/index.vue
@@ -0,0 +1,508 @@
+<template>
+ <div>
+<!-- <el-bus-crud
+ ref="crud"
+ v-bind="tableConfig"
+ :extra-query="{ levelDown: checkedLevelDown }"
+ >
+ <template #header>
+ <el-checkbox
+ v-model="checkedLevelDown"
+ true-label="1"
+ false-label=""
+ style="float: right"
+ >未处理的质检异常订单</el-checkbox
+ >
+ </template>
+ </el-bus-crud>-->
+ <el-bus-crud
+ ref="crud"
+ v-bind="tableConfig"
+ ></el-bus-crud>
+ <div id="print-container">
+ <print-list ref="printList" :order-list="orderList" />
+ </div>
+ </div>
+</template>
+
+<script>
+import printJS from 'print-js'
+import { getPartnerListConfig } from '@/utils/form-item-config'
+import { dateRangeOptions } from '@/utils/options'
+import CustomDateRange from '@/components/custom-date-range.vue'
+import PrintList from '@/components/order/print-list'
+export default {
+ components: {
+ PrintList,
+ },
+ data() {
+ return {
+ checkedLevelDown: '',
+ orderList: [],
+ tableConfig: {
+ url: 'flower/api/order/list',
+ editUrl: 'flower/api/order/page/update',
+ hasNew: false,
+ hasEdit: true,
+ hasDelete: false,
+ persistSelection: true,
+ hasExport: true,
+ exportUrl: 'flower/api/order/list/export',
+ exportText: '导出订单',
+ onResetView: (row) => {
+ this.$router.push(`${this.$route.path}/${row.id}`)
+ },
+ operationAttrs: {
+ width: 150,
+ fixed: 'right',
+ },
+ beforeRequest: (params) => {
+ const searchForm = this.$refs.crud?.$refs?.searchForm
+ if (searchForm) {
+ const statusComp = searchForm.getComponentById('statusBackend')
+ if (statusComp) {
+ // 组件内部不会修改这个prop直接修改可忽略警告
+ statusComp.extraQuery = { ...params, statusBackend: '' }
+ statusComp.getOtherOptions()
+ }
+ const abnormalOrderStatusComp = searchForm.getComponentById('abnormalOrderStatus')
+ if (abnormalOrderStatusComp) {
+ // 组件内部不会修改这个prop直接修改可忽略警告
+ abnormalOrderStatusComp.extraQuery = { ...params, abnormalOrderStatus: '' }
+ abnormalOrderStatusComp.getOtherOptions()
+ }
+ }
+ },
+ beforeOpen: (row, isNew) => {
+ if (!isNew) {
+ row.districtStr = this.getDistrict(row)
+ }
+ },
+ columns: [
+ { label: '', type: 'selection', minWidth: 60, fixed: 'left' },
+ { label: '订单号', prop: 'orderNo', minWidth: 150, fixed: 'left' },
+ { label: '用户账号', prop: 'createName', minWidth: 120 },
+ { label: '收货人', prop: 'customer', minWidth: 120 },
+ { label: '收货人电话', prop: 'customerTel', minWidth: 120 },
+ {
+ label: '收货地址',
+ formatter: (row) =>
+ `${row.customerProvince || ''}${row.customerCity || ''}${
+ row.customerRegion || ''
+ }${row.customerAddress || ''}`,
+ minWidth: 250,
+ },
+ { label: '订单金额(元)', prop: 'totalAmount', minWidth: 150 },
+ { label: '底价(元)', prop: 'supplierAmount', minWidth: 150 },
+ { label: '销售扎数', prop: 'saleNum', minWidth: 150 },
+ { label: '订单状态', prop: 'statusBackendStr', minWidth: 120 },
+ { label: '下单时间', prop: 'createTime', minWidth: 180 },
+ { label: '支付时间', prop: 'paymentTime', minWidth: 180 },
+ { label: '合伙人', prop: 'partnerName', minWidth: 120 },
+ { label: '库位', prop: 'warehouseLocationCode', minWidth: 120 },
+ { label: '特殊需求', prop: 'specialNeedsStr', minWidth: 120 },
+ {
+ label: '备注',
+ formatter: (row) => (
+ <simple-text value={row.remarks} type="primary"></simple-text>
+ ),
+ minWidth: 200,
+ },
+ { label: '快递号', prop: 'deliveryNo', minWidth: 120 },
+ ],
+ searchFormAttrs: {
+ labelWidth: 'auto',
+ },
+ searchForm: [
+ {
+ type: 'row',
+ id: 'row',
+ items: [
+ {
+ label: '订单状态:',
+ id: 'statusBackend',
+ type: 'bus-radio',
+ el: {
+ hasAll: true,
+ otherInterfaceUri: 'flower/api/order/status/count',
+ childType: 'el-radio-button',
+ filterOptions: (list) => {
+ return list.map((item) => {
+ return {
+ ...item,
+ label: `${item.label}(${item.orderCount})`,
+ }
+ })
+ },
+ // code: 'ORDER_STATUS_BACKEND',
+ },
+ default: this.$route.query.statusBackend || '',
+ span: 24,
+ searchImmediately: true,
+ on: {
+ optionsChange: (e, updateForm, { currentComp }) => {
+ if (Array.isArray(e[0]) && e[0].length > 0) {
+ const totalCount = e[0].reduce((total, current) => {
+ return (total += current.orderCount)
+ }, 0)
+ // 组件内部不会修改这个prop直接修改可忽略警告
+ currentComp.props = {
+ allLabel: `不限(${totalCount})`,
+ }
+ }
+ },
+ },
+ },
+ {
+ label: '异常订单:',
+ id: 'abnormalOrderStatus',
+ type: 'bus-radio',
+ el: {
+ hasAll: true,
+ otherInterfaceUri: 'flower/api/order/abnormal/status/count',
+ childType: 'el-radio-button',
+ filterOptions: (list) => {
+ return list.map((item) => {
+ return {
+ ...item,
+ label: `${item.label}(${item.orderCount})`,
+ }
+ })
+ },
+ // code: 'ORDER_STATUS_BACKEND',
+ },
+ default: this.$route.query.abnormalOrderStatus || '',
+ span: 24,
+ searchImmediately: true,
+ on: {
+ optionsChange: (e, updateForm, { currentComp }) => {
+ if (Array.isArray(e[0]) && e[0].length > 0) {
+ const totalCount = e[0].reduce((total, current) => {
+ return (total += current.orderCount)
+ }, 0)
+ // 组件内部不会修改这个prop直接修改可忽略警告
+ currentComp.props = {
+ allLabel: `不限(${totalCount})`,
+ }
+ }
+ },
+ },
+ },
+ {
+ label: '下单日期:',
+ id: 'dateType',
+ component: CustomDateRange,
+ el: {
+ options: dateRangeOptions,
+ },
+ searchImmediately: true,
+ commonFormat: true,
+ commonFormatProps: [
+ 'dateType',
+ 'createStartDateStr',
+ 'createEndDateStr',
+ ],
+ span: 24,
+ },
+ { label: '订单号:', id: 'orderNo', type: 'input' },
+ { ...getPartnerListConfig() },
+ { label: '商品名称:', id: 'flowerName', type: 'input' },
+ {
+ label: '收货人:',
+ id: 'customer',
+ type: 'input',
+ el: { placeholder: '收货人姓名/手机号' },
+ },
+ { label: '收货地址:', id: 'address', type: 'input' },
+ { label: '库位:', id: 'warehouseLocationCode', type: 'input' },
+ {
+ label: '用户账号:',
+ id: 'createName',
+ type: 'input',
+ el: { placeholder: '用户账号' },
+ rules: {
+ required: false,
+ pattern: /^\d{1,11}$/,
+ message: '请输入合法的用户账号',
+ trigger: 'blur',
+ },
+ },
+ {
+ label: '地区',
+ id: 'province',
+ component: 'el-bus-select-area',
+ el: {
+ clearable: true,
+ },
+ commonFormat: true,
+ commonFormatProps: ['province', 'city', 'region'],
+ customClass: 'in-bus-form',
+ },
+ ],
+ },
+ ],
+ form: [
+ {
+ type: 'row',
+ span: 12,
+ items: [
+ {
+ label: '地区:',
+ id: 'customerProvince',
+ component: 'el-bus-select-area',
+ span: 24,
+ commonFormat: true,
+ commonFormatProps: [
+ 'customerProvince',
+ 'customerCity',
+ 'customerRegion',
+ ],
+ str: true,
+ strKey: 'districtStr',
+ rules: { required: true, message: '请选择地区' },
+ },
+ {
+ label: '详细地址:',
+ id: 'customerAddress',
+ type: 'input',
+ span: 24,
+ rules: {
+ required: true,
+ message: '请输入详细地址且最大不超过50个汉字',
+ trigger: 'blur',
+ max: 50,
+ },
+ },
+ {
+ label: '联系方式:',
+ id: 'customerTel',
+ type: 'input',
+ rules: {
+ required: true,
+ pattern: this.$elBusUtil.REG.MOBILEPHONE,
+ message: '请输入合法的手机号',
+ trigger: 'blur',
+ },
+ },
+ ],
+ },
+ ],
+ headerButtons: [
+ {
+ text: '打印订单',
+ type: 'primary',
+ atClick: async (selected) => {
+ const formValue = this.$refs.crud.$refs.searchForm.getFormValue()
+ if (
+ !formValue.createStartDateStr &&
+ !formValue.createEndDateStr
+ ) {
+ this.$message.warning('请先选择需要打印订单的日期')
+ return false
+ }
+ if (formValue.createStartDateStr !== formValue.createEndDateStr) {
+ this.$message.warning('只能打印某一天的订单')
+ return false
+ }
+ const ids = selected.map((i) => i.id)
+ const { code, data } = await this.$elBusHttp.request(
+ 'flower/api/order/check/location/list',
+ {
+ method: 'post',
+ data: {
+ ...formValue,
+ ids: ids?.length ? ids.join(',') : null,
+ },
+ }
+ )
+ if (code === 0) {
+ const orderList = data || []
+ if (orderList.length !== 0) {
+ this.orderList = orderList
+ // 这边嵌套两个nextTick是因为重写el-table时在nextTick中进行了dom操作
+ this.$nextTick(() => {
+ this.$nextTick(() => {
+ const trs = document.querySelectorAll(
+ '.el-table__footer tr'
+ )
+ if (trs && trs.length > 0) {
+ for (const tr of trs) {
+ const tds = tr.querySelectorAll('td')
+ if (tds && tds.length > 0) {
+ tds[0].colSpan = 8
+ tds[0].style.textAlign = 'center'
+ }
+ }
+ }
+ this.$nextTick(async () => {
+ await printJS({
+ printable: 'print-container',
+ type: 'html',
+ header: '订单明细',
+ headerStyle:
+ 'text-align:center;font-size:24px;color:#333;font-weight:bold;margin-bottom:15px',
+ style: `@media print { @page {size: auto; margin: 20mm 0 10mm 0; } body{margin:10mm} .el-table .el-table__header-wrapper{display: none} .el-table .el-table__body-wrapper thead{display: table-header-group} .break-page {page-break-after:always}}`,
+ css: [
+ `${this.$config.baseUrl}print/index.css`,
+ `${this.$config.baseUrl}print/custom.css`,
+ ],
+ scanStyles: false,
+ })
+ })
+ })
+ })
+ } else {
+ this.$message.warning('没有相关订单')
+ return false
+ }
+ }
+ },
+ },
+ ],
+ extraButtons: [
+ {
+ text: '快递号',
+ show: (row) => !row.partnerName && row.statusBackend === 'SEND',
+ atClick: (row) => {
+ this.$refs.crud.$refs.extraDialog[1].show(row)
+ return false
+ },
+ },
+ {
+ text: '发货',
+ show: (row) => !row.partnerName && row.statusBackend === 'SEND',
+ atClick: (row) => {
+ this.$refs.crud.$refs.extraDialog[0].show(row)
+ return false
+ },
+ },
+ {
+ text: '退款',
+ show: (row) => row.paymentTime && row.statusBackend !== 'REFUND',
+ atClick: async (row) => {
+ try {
+ await this.$elBusUtil.confirm('确定要退款吗?')
+ const { code } = await this.$elBusHttp.request(
+ 'flower/api/order/refund',
+ {
+ params: {
+ id: row.id,
+ },
+ }
+ )
+ if (code === 0) {
+ this.$message.success('退款成功')
+ }
+ } catch (e) {
+ return false
+ }
+ },
+ },
+ ],
+ extraDialogs: [
+ {
+ title: '发货',
+ hiddenReverseItems: [],
+ form: [
+ {
+ label: '物流公司:',
+ id: 'logisticsCompanyCode',
+ type: 'bus-select-dict',
+ readonly: true,
+ el: {
+ code: 'LOGISTICS_COMPANY_CODE',
+ style: 'width:100%',
+ },
+ str: true,
+ rules: {required: true, message: '物流公司'},
+ },
+ {
+ label: '快递号:',
+ id: 'deliveryNo',
+ type: 'text',
+ readonly: true,
+ rules: {
+ required: true,
+ message: '请输入快递号',
+ trigger: 'blur',
+ },
+ },
+ ],
+ atConfirm: async (val) => {
+ const { code } = await this.$elBusHttp.request(
+ 'flower/api/order/list/send',
+ { method: 'post', data: val }
+ )
+ if (code === 0) {
+ this.$message.success('发货成功')
+ }
+ },
+ },
+ {
+ title: '快递号录入',
+ hiddenReverseItems: [],
+ form: [
+ {
+ label: '物流公司:',
+ id: 'logisticsCompanyCode',
+ type: 'bus-select-dict',
+ el: {
+ code: 'LOGISTICS_COMPANY_CODE',
+ style: 'width:100%',
+ },
+ str: true,
+ rules: {required: true, message: '物流公司'},
+ },
+ {
+ label: '快递号:',
+ id: 'deliveryNo',
+ type: 'input',
+ rules: {
+ required: true,
+ message: '请输入快递号',
+ trigger: 'blur',
+ },
+ },
+ ],
+ atConfirm: async (val) => {
+ const { code } = await this.$elBusHttp.request(
+ 'flower/api/order/list/saveDeliveryNo',
+ { method: 'post', data: val }
+ )
+ if (code === 0) {
+ this.$message.success('快递号录入成功')
+ }
+ },
+ },
+ ],
+ },
+ }
+ },
+ head() {
+ return {
+ title: '订单列表',
+ }
+ },
+ watch: {
+ checkedLevelDown() {
+ this.$refs.crud.search()
+ },
+ },
+ methods: {
+ getDistrict(row) {
+ return `${row.customerProvince || ''}${row.customerCity || ''}${
+ row.customerRegion || ''
+ }`
+ },
+ },
+}
+</script>
+
+<style lang="scss" scoped>
+#print-container {
+ width: 190mm;
+ position: absolute;
+ top: 9999px;
+ left: 9999px;
+}
+</style>
diff --git a/pages/partner/list.vue b/pages/partner/list.vue
new file mode 100644
index 0000000..e3fe9df
--- /dev/null
+++ b/pages/partner/list.vue
@@ -0,0 +1,434 @@
+<template>
+ <div>
+ <el-bus-crud ref="crud" v-bind="tableConfig"></el-bus-crud>
+ <el-dialog title="注册手机号修改" :visible.sync="dialogVisible" append-to-body :close-on-click-modal="false"
+ class="form-content">
+ <el-form key="sms" ref="smsForm" size="medium" :model="smsForm" :rules="smsRules">
+ <el-form-item prop="username">
+ <div class="input-wrapper">
+ <el-input v-model="smsForm.username" placeholder="请输入手机号"></el-input>
+ </div>
+ </el-form-item>
+ <el-form-item prop="smsCode">
+ <div class="input-wrapper">
+ <el-input v-model="smsForm.smsCode" placeholder="请输入短信验证码">
+ </el-input>
+ <el-bus-countdown-button send-type="login" :extra-body="{ userType: 'admin' }" :number="smsForm.username"
+ type="text" class="sms-button"></el-bus-countdown-button>
+ </div>
+ </el-form-item>
+ <el-form-item prop="code">
+ <div class="input-wrapper">
+ <el-input v-model="smsForm.code" placeholder="请输入图形验证码">
+ </el-input>
+ <img v-if="smsCaptchaCodeImageSrc" :src="smsCaptchaCodeImageSrc" alt="图形验证码"
+ class="cursor-pointer w-auto h-45 object-contain" @click="getSmsCapacha" />
+ </div>
+ </el-form-item>
+ </el-form>
+ <div slot="footer" class="flex items-center justify-between">
+ <div>
+ <el-button @click="onCancel">取消</el-button>
+ <el-button type="primary" @click="onConfirm">确定</el-button>
+ </div>
+ </div>
+ </el-dialog>
+ </div>
+</template>
+
+<script>
+import { getAuditForm } from '@/utils/form-item-config'
+export default {
+ data() {
+ return {
+ dialogVisible: false,
+ smsForm: {},
+ smsCaptchaCodeImageSrc: "",
+ smsRules: {
+ username: { required: true, message: '请输入手机号', trigger: 'blur' },
+ smsCode: {
+ required: true,
+ message: '请输入短信验证码',
+ trigger: 'blur',
+ },
+ code: { required: true, message: '请输入图形验证码', trigger: 'blur' },
+ },
+ tableConfig: {
+ url: 'flower/api/partner/page',
+ hasNew: false,
+ hasDelete: false,
+ editUrl: 'flower/api/partner/page/change/area',
+ beforeOpen: (row, isNew) => {
+ if (!isNew) {
+ const district = this.getDistrict(row)
+ row.district = district
+ row.districtStr = district
+ }
+ },
+ operationAttrs: {
+ width: '200px',
+ fixed: 'right',
+ },
+ columns: [
+ {
+ label: 'ID',
+ prop: 'id',
+ minWidth: 60,
+ fixed: 'left',
+ },
+ {
+ label: '注册手机号',
+ prop: 'loginName',
+ minWidth: 150,
+ fixed: 'left',
+ },
+ { label: '合伙人名称', prop: 'name', minWidth: 120, fixed: 'left' },
+ {
+ label: '服务地区',
+ formatter: (row) => this.getDistrict(row),
+ minWidth: 200,
+ },
+ {
+ label: '联系方式',
+ prop: 'contactTel',
+ minWidth: 150,
+ },
+ { label: '注册时间', prop: 'createTime', minWidth: '180px' },
+ {
+ label: '审核时间',
+ prop: 'passTime',
+ minWidth: 180,
+ },
+ {
+ label: '状态',
+ prop: 'statusStr',
+ minWidth: 150,
+ },
+ {
+ label: '启用/禁用',
+ formatter: (row) => (
+ <el-switch
+ value={row.isEnabled}
+ onChange={this.onEnabledChange.bind(this, row)}
+ ></el-switch>
+ ),
+ minWidth: 120,
+ fixed: 'right',
+ },
+ ],
+ searchForm: [
+ {
+ type: 'row',
+ items: [
+ {
+ label: '注册手机号',
+ id: 'loginName',
+ type: 'input',
+ },
+
+ {
+ label: '合伙人名称',
+ id: 'name',
+ type: 'input',
+ },
+
+ {
+ label: '手机号',
+ id: 'tel',
+ type: 'input',
+ },
+ {
+ label: '申请日期',
+ component: 'el-bus-date-range',
+ id: 'createDateBeginStr',
+ commonFormat: true,
+ commonFormatProps: ['createDateBeginStr', 'createDateEndStr'],
+ customClass: 'in-bus-form',
+ },
+ {
+ label: '服务地区',
+ id: 'province',
+ component: 'el-bus-select-area',
+ el: {
+ clearable: true,
+ },
+ commonFormat: true,
+ commonFormatProps: ['province', 'city', 'region'],
+ customClass: 'in-bus-form',
+ },
+ {
+ label: '状态',
+ id: 'status',
+ type: 'bus-select-dict',
+ el: {
+ code: 'supplier_status',
+ clearable: true,
+ style: 'width:100%',
+ },
+ },
+ {
+ label: '启用/禁用',
+ id: 'isEnabled',
+ type: 'bus-select-dict',
+ default: '1',
+ el: {
+ code: 'USER_ENABLED_OR_DISABLED',
+ clearable: true,
+ style: 'width:100%',
+ },
+ },
+ ],
+ },
+ ],
+ form: [
+ { label: '合伙人名称:', id: 'name', type: 'input',
+ rules: { required: true, message: '请输入合伙人名称:' },
+ },
+ {
+ label: '联系方式:',id: 'contactTel',type: 'input',
+ rules: [{ required: true, message: '请输入有效的联系方式' ,pattern: /^1[3-9]\d{9}$/},
+ ],
+ },
+ { label: '城市仓名称', id: 'cityWarehouse', type: 'input' ,
+ rules: { required: true, message: '请输入城市仓名称' },
+ },
+ {
+ label: '服务地区:',
+ id: 'district',
+ type: 'bus-cascader',
+ el: {
+ otherInterfaceUri: 'flower/api/pub/china/web/area/json',
+ props: {
+ label: 'name',
+ value: 'code',
+ multiple: true,
+ },
+ filterOptions: (list) => {
+ if (typeof list === 'string') {
+ return JSON.parse(list)
+ }
+ return list
+ },
+ style: 'width:100%',
+ },
+ inputFormat: (row) => {
+ if ('province' in row) {
+ return row.province
+ ? row.province
+ .split(',')
+ .map((item, index) => [
+ item,
+ row.city.split(',')[index],
+ row.region.split(',')[index],
+ ])
+ : []
+ }
+ },
+ outputFormat: (val) => {
+ return Array.isArray(val) && val.length > 0
+ ? {
+ province: val.map((item) => item[0]).join(','),
+ city: val.map((item) => item[1]).join(','),
+ region: val.map((item) => item[2]).join(','),
+ }
+ : { province: '', city: '', region: '' }
+ },
+ str: true,
+ rules: { required: true, message: '请选择服务地区' },
+ },
+ { label: '地址', id: 'address', type: 'input' ,
+ rules: { required: true, message: '请输入地址' },
+ },
+ {
+ label: '身份证正反面:',
+ id: 'idCards',
+ component: 'el-bus-upload',
+ el: {
+ listType: 'picture-card',
+ },
+ commonFormat: true,
+ forceDisabled: true,
+ readonly: false,
+ rules:[
+ { required: true, message: '请上传身份证正反面' },
+ {
+ validator: (rule, value, callback) => {
+ if (!value || value.length < 2) {
+ callback(new Error('请至少上传两张图片'));
+ } else {
+ callback();
+ }
+ },
+ trigger: 'change',
+ },
+ ],
+ },
+ {
+ label: '状态:',
+ id: 'status',
+ type: 'input',
+ str: true,
+ readonly: true,
+ hidden: (row, item, mode) => mode !== 'view',
+ },
+ {
+ label: '不通过原因:',
+ id: 'rejectReason',
+ type: 'input',
+ el: {
+ type: 'textarea',
+ },
+ readonly: true,
+ hidden: (row, item, mode) => mode !== 'view' || row.status !== 'R',
+ },
+ ],
+ extraButtons: [
+ {
+ text: '审核',
+ show: (row) => row.status === 'U',
+ atClick: (row) => {
+ const district = this.getDistrict(row)
+ row.district = district
+ row.districtStr = district
+ this.$refs.crud.$refs.extraDialog[0].show(row)
+ return false
+ },
+ },
+ {
+ text: '下载小程序码',
+ show: (row) => row.status === 'P',
+ atClick: async (row) => {
+ if (row.wechatUrl) {
+ window.open(row.wechatUrl, '_blank')
+ } else {
+ const { code, data } = await this.$elBusHttp.request(
+ 'flower/api/partner/page/upload/code',
+ {
+ method: 'post',
+ data: {
+ id: row.id,
+ },
+ }
+ )
+ if (code === 0 && data) {
+ window.open(data, '_blank')
+ }
+ }
+ },
+ },
+ {
+ text: '注册手机号修改',
+ atClick: (row) => {
+ this.smsForm={}
+ this.smsForm.id=row.id
+ this.getSmsCapacha()
+ this.dialogVisible = true
+ return false
+ },
+ },
+ ],
+ extraDialogs: [
+ {
+ title: '审核',
+ readonly: true,
+ form: getAuditForm(),
+ atConfirm: async (val) => {
+ const { code } = await this.$elBusHttp.request(
+ 'flower/api/partner/page/audit',
+ {
+ method: 'post',
+ data: {
+ ...val,
+ rejectReason: val.auditRejectReason,
+ },
+ }
+ )
+ if (code === 0) {
+ this.$message.success('操作成功')
+ }
+ },
+ },
+
+ ],
+ },
+ }
+ },
+ head() {
+ return {
+ title: '合伙人列表',
+ }
+ },
+ methods: {
+ onCancel() {
+ this.$refs.smsForm.resetFields(); // 重置表单
+ this.dialogVisible = false
+ },
+ async onConfirm() {
+ const param=this.smsForm
+ const { code, data } = await this.$elBusHttp.request(
+ 'flower/api/partner/phone/update',
+ {
+ method: 'post',
+ data:param,
+ }
+ )
+ if (code === 0) {
+ this.$message.success(`更新成功`)
+ this.$refs.crud.getList()
+ this.onCancel()
+ }
+ },
+ async getSmsCapacha() {
+ const { captchaCodeId, imageSrc } =
+ await this.$services.base.createCaptcha()
+ this.smsForm.codeId = captchaCodeId
+ this.smsCaptchaCodeImageSrc = imageSrc
+ },
+ getDistrict(row) {
+ if (row.province) {
+ return row.province
+ .split(',')
+ .map((item, index) =>
+ [
+ item,
+ row.city.split(',')[index],
+ row.region.split(',')[index],
+ ].join('-')
+ )
+ .join(',')
+ }
+ return ''
+ },
+ onEnabledChange(row, e) {
+ const url = 'flower/api/partner/page/isEnable'
+ const text = e ? '启用' : '禁用'
+ this.$elBusUtil
+ .confirm(`确定要${text}这个合伙人吗?`)
+ .then(async () => {
+ const { code } = await this.$elBusHttp.request(url, {
+ params: {
+ id: row.id,
+ },
+ })
+ if (code === 0) {
+ this.$message.success(`${text}成功`)
+ this.$refs.crud.getList()
+ }
+ })
+ .catch(() => { })
+ },
+ },
+}
+</script>
+
+<style lang="scss" scoped>
+.input-wrapper {
+ display: flex;
+ align-items: center;
+
+ // border-bottom: 1px solid #cecece;
+ &:hover {
+ border-color: $primary-color;
+ }
+}
+</style>
diff --git a/pages/regular/config-customer.vue b/pages/regular/config-customer.vue
new file mode 100644
index 0000000..d982470
--- /dev/null
+++ b/pages/regular/config-customer.vue
@@ -0,0 +1,109 @@
+<template>
+ <el-bus-crud v-bind="tableConfig"/>
+</template>
+
+<script>
+export default {
+ data() {
+ return {
+ tableConfig: {
+ url: 'flower/api/configCustomer/list',
+ newUrl: 'flower/api/configCustomer/new',
+ editUrl: 'flower/api/configCustomer/edit',
+ deleteUrl: 'flower/api/configCustomer/delete',
+ columns: [
+ {label: '序号', type: 'index'},
+ {label: '类型', prop: 'typeStr'},
+ {label: '名称', prop: 'name'},
+ {label: '描述', prop: 'description'},
+ {label: '图标内容', prop: 'iconContent'},
+ {
+ label: '图标地址',
+ formatter: (row) =>
+ row.iconUrl ? (
+ <el-bus-image
+ src={row.iconUrl}
+ lazy={true}
+ style="width:50px;height:50px"
+ ></el-bus-image>
+ ) : null,
+ },
+ {label: '微信号', prop: 'weixin'},
+ {label: '联系方式', prop: 'contact'},
+ ],
+
+ searchForm: [
+ {
+ type: 'row',
+ items: [{label: '名称:', id: 'name', type: 'input'},
+ {label: '类型:', id: 'type', type: 'input'}],
+ },
+ ],
+ form: [
+ {
+ label: '名称:',
+ id: 'name',
+ type: 'input',
+ rules: {required: true, message: '请输入客服名称'},
+ },
+ {
+ label: '描述:',
+ id: 'description',
+ type: 'input',
+ rules: {required: true, message: '请输入客服描述'},
+ },
+ {
+ label: '图标内容:',
+ id: 'iconContent',
+ type: 'input',
+ rules: {required: true, message: '请输入客服图标内容'},
+ },
+ {
+ label: '背景图片:',
+ id: 'iconUrl',
+ type: 'bus-upload',
+ el: {
+ listType: 'picture-card',
+ limit: 1,
+ limitSize: 2,
+ tipText: '大小不超过2M',
+ valueType: 'string',
+ },
+ forceDisabled: true,
+ rules: {
+ required: true,
+ message: '请上传背景图片',
+ trigger: 'blur',
+ },
+ },
+ {
+ label: '微信号',
+ id: 'weixin',
+ type: 'input',
+ rules: {required: true, message: '请输入客服关联微信号'},
+ },
+ {
+ label: '类型', id: 'type',
+ type: 'bus-select-dict',
+ el: {
+ code: 'CONFIG_CUSTOMER_CONTACT',
+ style: 'width:100%',
+ },
+ },
+ {
+ label: '联系方式:',
+ id: 'contact',
+ type: 'input',
+ rules: {required: false, message: '请输入联系方式'},
+ },
+ ],
+ },
+ }
+ },
+ head() {
+ return {
+ title: '客服电话',
+ }
+ },
+}
+</script>
diff --git a/pages/regular/config-param-group.vue b/pages/regular/config-param-group.vue
new file mode 100644
index 0000000..fa12bca
--- /dev/null
+++ b/pages/regular/config-param-group.vue
@@ -0,0 +1,64 @@
+<template>
+ <el-bus-crud v-bind="tableConfig"/>
+</template>
+
+<script>
+export default {
+ data() {
+ return {
+ tableConfig: {
+ url: 'flower/v2/config-param-group/group/list',
+ newUrl: 'flower/v2/config-param-group/new',
+ editUrl: 'flower/v2/config-param-group/edit',
+ deleteUrl: 'flower/v2/config-param-group/delete',
+ columns: [
+ {label: '序号', type: 'index'},
+ {label: '变量分组', prop: 'paramGroup'},
+ {label: '变量分组名', prop: 'paramGroupName'},
+ {label: '变量排序号', prop: 'paramOrder'},
+ ],
+
+ searchForm: [
+ {
+ type: 'row',
+ items: [
+ {label: '变量分组名:', id: 'paramGroupName', type: 'input'}],
+ },
+ ],
+ form: [
+ {
+ label: '变量分组:',
+ id: 'paramGroup',
+ type: 'input',
+ rules: {
+ required: true,
+ pattern: /^[a-z]+$/,
+ message: '请输入变量分组,只允许小写英文字母'
+ },
+ },
+ {
+ label: '变量分组名:',
+ id: 'paramGroupName',
+ type: 'input',
+ rules: {required: true, message: '请输入变量分组名'},
+ },
+ {
+ label: '变量排序号:',
+ id: 'paramOrder',
+ type: 'input',
+ rules: {
+ required: true,
+ pattern: /^\d+$/,
+ message: '请输入变量排序号,只允许非负整数'},
+ },
+ ],
+ },
+ }
+ },
+ head() {
+ return {
+ title: '配置系统参数组',
+ }
+ },
+}
+</script>
diff --git a/pages/regular/config-param.vue b/pages/regular/config-param.vue
new file mode 100644
index 0000000..47c22ad
--- /dev/null
+++ b/pages/regular/config-param.vue
@@ -0,0 +1,143 @@
+<template>
+ <el-bus-crud v-bind="tableConfig"/>
+</template>
+
+<script>
+export default {
+ data() {
+ return {
+ tableConfig: {
+ url: 'flower/v2/config-param/config/list',
+ newUrl: 'flower/v2/config-param/new',
+ editUrl: 'flower/v2/config-param/edit',
+ deleteUrl: 'flower/v2/config-param/delete',
+ columns: [
+ {label: '序号', type: 'index'},
+ {label: '变量分组名', prop: 'paramGroupName'},
+ {label: '变量名', prop: 'paramName'},
+ {label: '变量键', prop: 'paramKey'},
+ {label: '变量值', prop: 'paramValue'},
+ {label: '变量规则', prop: 'paramPlaceholder'},
+ {label: '变量提示', prop: 'paramTip'},
+ {label: '变量排序号', prop: 'paramOrder'},
+ {label: '变量值类型', prop: 'paramValueType'},
+ {label: '变量字典', prop: 'paramDict'},
+ {label: '控件类型', prop: 'paramControlType'},
+ {label: '是否是必填', prop: 'paramRequire'},
+ {label: '参数限制数量', prop: 'paramLimit'},
+ ],
+
+ searchForm: [
+ {
+ type: 'row',
+ items: [
+ {label: '变量分组名:', id: 'paramGroupName', type: 'input'}],
+ },
+ ],
+ form: [
+ {
+ label: '变量分组名:',
+ id: 'paramGroupId',
+ type: 'bus-select',
+ el: {
+ interfaceUri: 'flower/v2/config-param-group/group/list',
+ props: {
+ label: 'paramGroupName',
+ value: 'id',
+ dataPath: 'records',
+ },
+ extraQuery: {
+ current: 1,
+ size: 2000,
+ },
+ filterable: true,
+ style: 'width:100%',
+ },
+ rules: { required: true, message: '请选择变量分组' },
+ },
+ {
+ label: '变量名:',
+ id: 'paramName',
+ type: 'input',
+ rules: {required: true, message: '请输入变量名'},
+ },
+ {
+ label: '变量键',
+ id: 'paramKey',
+ type: 'input',
+ rules: {required: true, message: '请输入变量键'},
+ },
+ {
+ label: '变量值',
+ id: 'paramValue',
+ type: 'input',
+ rules: {required: true, message: '请输入变量值'},
+ },
+ {
+ label: '变量规则',
+ id: 'paramPlaceholder',
+ type: 'input',
+ rules: {required: true, message: '请输入变量规则'},
+ },{
+ label: '变量提示',
+ id: 'paramTip',
+ type: 'input',
+ rules: {required: true, message: '请输入变量提示'},
+ },
+ {
+ label: '变量排序号',
+ id: 'paramOrder',
+ type: 'input',
+ rules: {
+ required: true,
+ pattern: /^\d+$/,
+ message: '请输入变量排序号,只允许非负整数'},
+ },
+ {
+ label: '变量值类型',
+ id: 'paramValueType',
+ type: 'input',
+ },{
+ label: '变量字典',
+ id: 'paramDict',
+ type: 'input',
+ },
+ {
+ label: '控件类型',
+ id: 'paramControlType',
+ type: 'bus-select-dict',
+ el: {
+ code: 'PARAM_CONTROL_TYPE',
+ style: 'width:100%',
+ },
+ rules: {required: true, message: '请输入控件类型'},
+ },
+ {
+ label: '是否是必填',
+ id: 'paramRequire',
+ type: 'bus-select-dict',
+ el: {
+ code: 'IS_REQUIRED',
+ style: 'width:100%',
+ },
+ rules: {required: true, message: '请输入是否是必填'},
+ },
+ {
+ label: '参数限制数量',
+ id: 'paramLimit',
+ type: 'input',
+ rules: {required: true, message: '请输入参数限制数量'},
+ },
+
+
+ ],
+ },
+ }
+ },
+ head() {
+ return {
+ title: '配置系统参数',
+ }
+ },
+}
+</script>
diff --git a/pages/regular/sys.vue b/pages/regular/sys.vue
new file mode 100644
index 0000000..47b35bb
--- /dev/null
+++ b/pages/regular/sys.vue
@@ -0,0 +1,357 @@
+<template>
+ <div>
+ <el-card class="box-card">
+ <div slot="header" class="clearfix">
+ <span>系统配置</span>
+ <!-- <el-button style="float: right; padding: 3px 0" type="text">操作按钮</el-button> -->
+ </div>
+
+ <el-tabs v-model="activeName" type="card" class="setupClass-tab" @tab-click="handleClick">
+ <el-tab-pane v-for="(item, index) in tabList" :key="item.id" :label="item.paramGroupName"
+ :name="item.paramGroup">
+
+ <el-form :model="formModels[item.id]" :rules="formRules[item.id]" label-width="120px"
+ :ref="(el) => (formRefs[index] = el)" style="width: 100%">
+
+ <el-form-item v-for="(param) in item.paramList" :key="param.id" :label="param.paramName"
+ :prop="param.paramKey">
+
+ <el-input v-if="param.paramControlType === 'input'"
+ v-model="formModels[item.id][param.paramKey]" :placeholder="param.paramPlaceholder"
+ clearable />
+
+ <el-upload v-if="param.paramControlType === 'image'" :action="uploadUrl"
+ list-type="picture-card" :file-list="formModels[item.id][param.paramKey]"
+ :limit="param.paramLimit"
+ :on-preview="handlePictureCardPreview"
+ :on-remove="(file) => handleRemove(file, param)"
+ :on-success="(response, file, fileList) => handleUploadSuccess(response, file, fileList, param)">
+ <i class="el-icon-plus"></i>
+ </el-upload>
+ <el-switch v-if="param.paramControlType === 'switch'" v-model="formModels[item.id][param.paramKey]"
+ active-text="启用" inactive-text="禁用"></el-switch>
+ <el-radio-group v-if="param.paramControlType === 'radio'"
+ v-model="formModels[item.id][param.paramValue]">
+ <el-radio v-for="option in dictOptions[param.paramDict]" :key="option.value"
+ :label="option.value">
+ {{ option.label }}
+ </el-radio>
+ </el-radio-group>
+ <el-checkbox-group v-if="param.paramControlType === 'checkbox'" v-model="formModels[item.id][param.paramKey]">
+ <el-checkbox v-for="option in dictOptions[param.paramDict]" :key="option.value" :label="option.value">{{ option.label }}</el-checkbox>
+ </el-checkbox-group>
+ </el-form-item>
+
+ <el-form-item v-if="item.paramList && item.paramList.length > 0">
+ <el-button type="primary" @click="submitForm(index)">提交</el-button>
+ <el-button @click="resetForm(index)">重置</el-button>
+ </el-form-item>
+ </el-form>
+ </el-tab-pane>
+ </el-tabs>
+ </el-card>
+
+ <!-- 预览弹窗 -->
+ <el-dialog :visible.sync="previewVisible">
+ <img :src="previewImage" alt="Preview Image" style="width: 100%;" />
+ </el-dialog>
+ </div>
+</template>
+
+<script>
+
+import utils from 'el-business-utils'
+
+export default {
+ data() {
+ return {
+ uploadUrl: '',
+ activeName: 'first',
+ tabList: [],
+ previewVisible: false,
+ previewImage: '',
+ curTab: {},
+ curIndex: 0,
+ formRefs: [],
+ formModels: {}, // 存储每个 tab 的 formModel
+ srcFormModels: {}, // 原始表单数据
+ formRules: {}, // 存储每个 tab 的 formRules
+ dictOptions: [], // 存储字典选项
+ };
+ },
+
+ created() {
+ const config = process.env.config
+ this.uploadUrl = utils.joinPath(config.httpBaseUri, `flower/api/upload/oss/file`)
+ },
+ async mounted() {
+ await this.getConfigParamGroup();
+ await this.getDictOptions(); // 获取字典选项
+ },
+
+ methods: {
+ handleClick(tab, event) {
+ this.chooseTab(tab.index)
+ },
+
+ chooseTab(index) {
+ this.curTab = this.tabList[index];
+ this.curIndex = index;
+ this.getConfigParam();
+ },
+
+ async getConfigParamGroup() {
+ const { code, data } = await this.$elBusHttp.request('flower/v2/config-param-group/list', { params: {} });
+ if (code === 0) {
+ this.tabList = [...data];
+ this.activeName = data[0]?.paramGroup || '';
+ this.tabList.forEach(item => {
+ this.$set(this.formModels, item.id, {});
+ this.$set(this.srcFormModels, item.id, {}); // 初始化 srcFormModels
+ this.$set(this.formRules, item.id, {});
+ });
+ if (data[0]) {
+ this.curTab = this.tabList[0];
+ this.curIndex = 0;
+ this.getConfigParam();
+ }
+
+ }
+ },
+
+ createFormModel(paramList) {
+ // 创建一个空的对象,用于存储参数
+ const model = {};
+ paramList.forEach(param => {
+ // 如果param.paramControlType是image的话,则将值反序列化成ArrayList
+ if (param.paramControlType === 'image') {
+ model[param.paramKey] = this.parseFileList(param.paramValue) || [];
+ } else {
+ // 默认处理为字符串
+ model[param.paramKey] = param.paramValue || '';
+ }
+ });
+ return model;
+ },
+
+ createFormRules(paramList) {
+ const rules = {};
+ paramList.forEach(param => {
+ if (param.paramRequire) {
+ const trigger = param.paramControlType === 'input' ? 'blur' : 'change';
+ const rule = [
+ { required: true, message: `${param.paramPlaceholder}`, trigger }
+ ];
+
+ // 如果param_limit存在且不为null/undefined,添加最大值校验
+ if (param.paramLimit) {
+ // 如果paramControlType是'input',执行最大值校验
+ if (param.paramControlType !== 'image') {
+ rule.push({
+ max: param.paramLimit,
+ message: `${param.paramName}最大值为 ${param.paramLimit}!`,
+ trigger
+ });
+ } else {
+ // 如果是image类型,添加自定义验证,判断数组长度
+ rule.push({
+ validator: (rule, value, callback) => {
+ if (Array.isArray(value) && value.length > param.paramLimit) {
+ callback(new Error(`${param.paramName}最多上传 ${param.paramLimit} 张图片`));
+ } else {
+ callback(); // 验证通过
+ }
+ },
+ trigger
+ });
+ }
+ }
+
+ rules[param.paramKey] = rule;
+ }
+ });
+ return rules;
+ },
+
+ async getConfigParam() {
+ const { code, data } = await this.$elBusHttp.request('flower/v2/config-param/list', {
+ params: { paramGroupId: this.curTab.id },
+ });
+ if (code === 0) {
+ this.tabList[this.curIndex].paramList = [...data];
+
+ // 构造 formModel 和 formRules,并分别存储到对应的对象中
+ const formData = this.createFormModel(data);
+ this.$set(this.formModels, this.curTab.id, { ...formData });
+ this.$set(this.srcFormModels, this.curTab.id, { ...formData }); // 初始化 srcFormModels
+ this.$set(this.formRules, this.curTab.id, this.createFormRules(data));
+ }
+ },
+
+ handleRemove(file, param) {
+ const srcFormModel = this.srcFormModels[this.curTab.id];
+ const currentFormModel = this.formModels[this.curTab.id];
+ if (file?.response?.code === '0') {
+ const data = file?.response?.data;
+ if (data && data[0]) {
+ const removeFile = data[0]
+ const updatedFileList = currentFormModel[param.paramKey].filter(item => item.url !== removeFile.url);
+ // 保存原有的图片控件属性值
+ if (updatedFileList.length === 0) {
+ // 如果文件列表为空,设置为空字符串
+ this.$set(currentFormModel, param.paramKey, []);
+ } else {
+ // 否则,更新为新的文件列表 JSON 字符串
+ this.$set(currentFormModel, param.paramKey, updatedFileList);
+
+ }
+
+ }
+
+ } else if (file && file?.url) {
+ const updatedFileList = currentFormModel[param.paramKey].filter(item => item.url !== file.url);
+ // 保存原有的图片控件属性值
+ if (updatedFileList.length === 0) {
+ // 如果文件列表为空,设置为空字符串
+ this.$set(currentFormModel, param.paramKey, []);
+ } else {
+ // 否则,更新为新的文件列表 JSON 字符串
+ this.$set(currentFormModel, param.paramKey, updatedFileList);
+
+ }
+ }
+
+ },
+
+ parseFileList(fileListString) {
+ try {
+ return JSON.parse(fileListString || '[]');
+ } catch (error) {
+ console.error('Error parsing fileList JSON:', error);
+ return [];
+ }
+ },
+ parseFileListCompare(fileListString, groupId, paramKey) {
+ console.log("parseFileListCompare")
+ try {
+ return JSON.parse(fileListString || '[]');
+ } catch (error) {
+ console.error('Error parsing fileList JSON:', error);
+ return [];
+ }
+
+ // const newVal = this.formModels[groupId][paramKey]
+ // const srcVal = this.srcFormModels[groupId][paramKey]
+ // if (newVal !== srcVal) {
+ // try {
+ // return JSON.parse(fileListString || '[]');
+ // } catch (error) {
+ // console.error('Error parsing fileList JSON:', error);
+ // return [];
+ // }
+ // }
+ },
+
+ handleUploadSuccess(response, file, fileList, param) {
+ if (response.code === '0') {
+ const currentFormModel = this.formModels[this.curTab.id];
+ const existingFileList = currentFormModel[param.paramKey];
+ const newFile = response.data[0];
+ const updatedFileList = [...existingFileList, newFile];
+ // this.$set(currentFormModel, param.paramKey, JSON.stringify(updatedFileList));
+ currentFormModel[param.paramKey] = updatedFileList;
+ } else {
+ this.$message.error('文件上传失败');
+ }
+ },
+
+ handlePictureCardPreview(file) {
+ if (file.url) {
+ this.previewImage = file.url;
+ this.previewVisible = true;
+ } else {
+ this.$message.error('无法预览该文件');
+ }
+ },
+
+ submitForm(index) {
+ console.log("submitForm")
+ console.log(this.formModels[this.curTab.id])
+ console.log(this.formRules[this.curTab.id])
+
+ const formRef = this.formRefs[index];
+ if (formRef) {
+ formRef.validate(async (valid) => {
+ if (valid) {
+
+ // 这里需要将表单的属性匹配到当前的tabList下的paramList的列
+ const tmpParamList = this.tabList[this.curIndex].paramList;
+ // 遍历
+ const submitFormModel = this.formModels[this.curTab.id]
+ // 遍历 submitFormModel 的属性
+ Object.keys(submitFormModel).forEach((key) => {
+ // 在 tmpParamList 中找到 paramKey 与当前属性 key 匹配的记录
+ const paramItem = tmpParamList.find((item) => item.paramKey === key);
+ if (paramItem) {
+ // 将 paramValue 设置为表单中对应属性的值
+ paramItem.paramValue = submitFormModel[key];
+ }
+ });
+ console.log("修改后的值")
+ console.log(tmpParamList)
+ const resultArray = tmpParamList
+ .filter((item) => item.id !== undefined) // 确保 id 存在
+ .map((item) => ({
+ id: item.id,
+ paramValue: item.paramControlType === 'image' ? JSON.stringify(item.paramValue) : item.paramValue
+ }));
+
+ await this.$elBusUtil.confirm('确定要提交吗?')
+ const { code } = await this.$elBusHttp.request(
+ 'flower/v2/config-param/update/batch',
+ {
+ method: 'put',
+ data: {
+ paramList: resultArray,
+ },
+ }
+ )
+ if (code === 0) {
+ await this.getConfigParam()
+ this.$message.success('更新成功')
+
+ }
+
+
+ // this.$message.success('表单校验成功!');
+ // console.log('提交的表单数据: ', this.formModels[this.tabList[index].id]);
+ } else {
+ this.$message.error('表单校验失败,请检查填写内容!');
+ }
+ });
+ } else {
+ console.error(`表单引用未找到: formRefs[${index}]`);
+ }
+ },
+
+ resetForm(index) {
+ // console.log()
+ // const formRef = this.formRefs[index];
+ // if (formRef) {
+ // formRef.resetFields();
+
+ // this.$message.info('表单已重置');
+ // } else {
+ // console.error(`未找到表单引用: formRefs[${index}]`);
+ // }
+ this.chooseTab(index)
+ this.activeName = this.tabList[index]?.paramGroup
+
+ },
+ getDictOptions() {
+ // 模拟 API 调用获取字典选项
+ this.dictOptions = { radioDict: [{ value: '1', label: 'Option 1' }, { value: '2', label: 'Option 2' }] };
+ },
+ },
+};
+</script>
diff --git a/pages/report/finance/_date.vue b/pages/report/finance/_date.vue
new file mode 100644
index 0000000..eb1869a
--- /dev/null
+++ b/pages/report/finance/_date.vue
@@ -0,0 +1,139 @@
+<template>
+ <el-bus-crud ref="crud" v-bind="tableConfig" />
+</template>
+
+<script>
+import { getPartnerListConfig } from '@/utils/form-item-config'
+export default {
+ data() {
+ return {
+ tableConfig: {
+ url: 'flower/v2/report/order/detail/page',
+ hasEdit: false,
+ hasNew: false,
+ hasDelete: false,
+ hasView: false,
+ hasExport: true,
+ hasOperation: false,
+ exportUrl: 'flower/v2/report/order/detail/export',
+ exportText: '导出',
+ columns: [
+ { label: '订单号', prop: 'orderNo', minWidth: 150, fixed: 'left' },
+ {
+ label: '下单用户',
+ prop: 'customer',
+ minWidth: '150px',
+ fixed: 'left',
+ },
+ { label: '收货人地址', prop: 'address', minWidth: '220px' },
+ { label: '合伙人', prop: 'partnerName', minWidth: '120px' },
+ { label: '下单时间', prop: 'orderDate', minWidth: '180px' },
+ { label: '订单金额', prop: 'orderTotal', minWidth: '120px' },
+ { label: '订单金额(实付)', prop: 'totalAmount', minWidth: '120px' },
+ {
+ label: '花农底价',
+ prop: 'orderSupplierPriceAmount',
+ minWidth: '120px',
+ },
+ {
+ label: '平台区间加价',
+ prop: 'orderMarkupOneAmount',
+ minWidth: '120px',
+ },
+ {
+ label: '平台加价',
+ prop: 'orderMarkupTwoAmount',
+ minWidth: '120px',
+ },
+ {
+ label: '平台区域加价',
+ prop: 'platformAreaFeeAmount',
+ minWidth: '120px',
+ },
+ {
+ label: '合伙人加价',
+ prop: 'orderMarkupPartnerAmount',
+ minWidth: '120px',
+ },
+ {
+ label: '合伙人区间加价',
+ prop: 'partnerSectionFeeAmount',
+ minWidth: '120px',
+ },
+
+ { label: '优惠合计', prop: 'orderDiscountTotalFee', minWidth: 120,},
+ { label: '会员折扣', prop: 'orderPriceDiscountAmount', minWidth: 120,},
+ { label: '优惠券', prop: 'orderCouponAmountTotal',minWidth: '100px',},
+
+ { label: '质检总扣款', prop: 'orderCheckTotalFee', minWidth: 120 },
+ { label: '质检降级扣款', prop: 'orderCheckFee', minWidth: '100px' },
+ { label: '质检缺货扣款', prop: 'orderLackFeeSupplier', minWidth: '100px',},
+ { label: '质检补货扣款', prop: 'orderReplaceFee', minWidth: '100px' },
+
+ { label: '售后总扣款', prop: 'orderTotalFee', minWidth: 150 },
+ { label: '售后供应商扣款', prop: 'orderFeeSupplier', minWidth: 150 },
+ { label: '售后平台扣款', prop: 'orderFeePlatform', minWidth: 150 },
+ { label: '售后合伙人扣款', prop: 'orderFeePartner', minWidth: 150 },
+ { label: '售后打包扣款', prop: 'orderFeePlatformPack', minWidth: 150 },
+ { label: '售后质检扣款', prop: 'orderFeePlatformCheck', minWidth: 150 },
+ { label: '售后物流扣款', prop: 'orderFeePlatformTransport', minWidth: 150 },
+ { label: '售后打包运费扣款', prop: 'orderFeePackingTransport', minWidth: 150 },
+
+ {
+ label: '总包干费',
+ prop: 'partnerTotalFeeAmount',
+ minWidth: '100px',
+ },
+ { label: '总销售扎数', prop: 'orderNum', minWidth: '100px' },
+ { label: '实际销售扎数', prop: 'realSaleNum', minWidth: '100px' },
+ { label: '缺货扎数', prop: 'orderLackNum', minWidth: 120 },
+ { label: '降级扎数', prop: 'orderReduceNum', minWidth: 120 },
+ { label: '补货扎数', prop: 'orderReplaceNum', minWidth: 120 },
+
+ {
+ label: '利润',
+ prop: 'profitFeeAmount',
+ minWidth: '100px',
+ fixed: 'right',
+ },
+ {
+ label: '结算状态',
+ prop: 'settleStatusStr',
+ minWidth: '120px',
+ fixed: 'right',
+ },
+ ],
+ searchForm: [
+ {
+ type: 'row',
+ span: 6,
+ items: [
+ {
+ label: '下单日期',
+ id: 'calDate',
+ component: 'el-date-picker',
+ type: 'date',
+ el: {
+ valueFormat: 'yyyy-MM-dd',
+ style: 'width:100%',
+ clearable: false,
+ },
+ default: this.$route.params.date,
+ },
+ {
+ ...getPartnerListConfig(),
+ default: this.$route.query.partnerId || '',
+ },
+ ],
+ },
+ ],
+ },
+ }
+ },
+ head() {
+ return {
+ title: '订单结算明细',
+ }
+ },
+}
+</script>
diff --git a/pages/report/finance/index.vue b/pages/report/finance/index.vue
new file mode 100644
index 0000000..e3c4fd4
--- /dev/null
+++ b/pages/report/finance/index.vue
@@ -0,0 +1,400 @@
+<template>
+ <div>
+ <div v-loading="statisticLoading">
+
+ <el-row :gutter="20">
+ <el-col :span="3" class="mb-2">
+ <el-card>
+ <div class="statistic-title">销售合计(原订单)</div>
+ <div class="statistic-num">{{ statistic.orderTotal || 0 }}</div>
+ </el-card>
+ </el-col>
+ <el-col :span="3" class="mb-2">
+ <el-card>
+ <div class="statistic-title">销售合计(实付)</div>
+ <div class="statistic-num">{{ statistic.totalAmount || 0 }}</div>
+ </el-card>
+ </el-col>
+ <el-col :span="3" class="mb-2">
+ <el-card>
+ <div class="statistic-title">底价合计</div>
+ <div class="statistic-num">
+ {{ statistic.orderSupplierPriceAmount || 0 }}
+ </div>
+ </el-card>
+ </el-col>
+ <el-col :span="3" class="mb-2">
+ <el-card>
+ <div class="statistic-title">区间加价</div>
+ <div class="statistic-num">
+ {{ statistic.orderMarkupOneAmount || 0 }}
+ </div>
+ </el-card>
+ </el-col>
+ <el-col :span="3" class="mb-2">
+ <el-card>
+ <div class="statistic-title">平台加价</div>
+ <div class="statistic-num">
+ {{ statistic.orderMarkupTwoAmount || 0 }}
+ </div>
+ </el-card>
+ </el-col>
+ <el-col :span="3" class="mb-2">
+ <el-card>
+ <div class="statistic-title">合伙人加价</div>
+ <div class="statistic-num">
+ {{ statistic.orderMarkupPartnerAmount || 0 }}
+ </div>
+ </el-card>
+ </el-col>
+ <el-col :span="3" class="mb-2">
+ <el-card>
+ <div class="statistic-title">包干费合计</div>
+ <div class="statistic-num">
+ {{ statistic.partnerTotalFeeAmount || 0 }}
+ </div>
+ </el-card>
+ </el-col>
+ </el-row>
+ <el-row :gutter="20">
+ <el-col :span="3" class="mb-2">
+ <el-card>
+ <div class="statistic-title">质检总扣款</div>
+ <div class="statistic-num">
+ <!-- {{ statistic.checkTotalFee || 0 }} -->
+ {{ statistic.orderCheckTotalFee || 0 }}
+ </div>
+ </el-card>
+ </el-col>
+ <el-col :span="3" class="mb-2">
+ <el-card>
+ <div class="statistic-title">缺货扣款</div>
+ <div class="statistic-num">{{ statistic.orderLackFeeSupplier || 0 }}</div>
+ </el-card>
+ </el-col>
+ <el-col :span="3" class="mb-2">
+ <el-card>
+ <div class="statistic-title">补货扣款</div>
+ <div class="statistic-num">{{ statistic.orderReplaceFee || 0 }}</div>
+ </el-card>
+ </el-col>
+ <el-col :span="3" class="mb-2">
+ <el-card>
+ <div class="statistic-title">降级扣款</div>
+ <div class="statistic-num">{{ statistic.orderCheckFee || 0 }}</div>
+ </el-card>
+ </el-col>
+ </el-row>
+ <el-row :gutter="20">
+ <!-- <el-col :span="3" class="mb-2">
+ <el-card>
+ <div class="statistic-title">售后总扣款</div>
+ <div class="statistic-num">{{ statistic.saleTotalFee || 0 }}</div>
+ </el-card>
+ </el-col> -->
+ <el-col :span="3" class="mb-2">
+ <el-card>
+ <div class="statistic-title">售后总扣款</div>
+ <div class="statistic-num">{{ statistic.orderTotalFee || 0 }}</div>
+ </el-card>
+ </el-col>
+ <el-col :span="3" class="mb-2">
+ <el-card>
+ <div class="statistic-title">售后供应商扣款</div>
+ <div class="statistic-num">{{ statistic.orderFeeSupplier || 0 }}</div>
+ </el-card>
+ </el-col>
+ <el-col :span="3" class="mb-2">
+ <el-card>
+ <div class="statistic-title">售后平台扣款</div>
+ <div class="statistic-num">{{ statistic.orderFeePlatform || 0 }}</div>
+ </el-card>
+ </el-col>
+ <el-col :span="3" class="mb-2">
+ <el-card>
+ <div class="statistic-title">售后合伙人扣款</div>
+ <div class="statistic-num">{{ statistic.orderFeePartner || 0 }}</div>
+ </el-card>
+ </el-col>
+ <el-col :span="3" class="mb-2">
+ <el-card>
+ <div class="statistic-title">售后打包扣款</div>
+ <div class="statistic-num">{{ statistic.orderFeePlatformPack || 0 }}</div>
+ </el-card>
+ </el-col>
+ <el-col :span="3" class="mb-2">
+ <el-card>
+ <div class="statistic-title">售后质检扣款</div>
+ <div class="statistic-num">{{ statistic.orderFeePlatformCheck || 0 }}</div>
+ </el-card>
+ </el-col>
+ <el-col :span="3" class="mb-2">
+ <el-card>
+ <div class="statistic-title">售后物流扣款</div>
+ <div class="statistic-num">{{ statistic.orderFeePlatformTransport || 0 }}</div>
+ </el-card>
+ </el-col>
+ <el-col :span="3" class="mb-2">
+ <el-card>
+ <div class="statistic-title">售后打包运费扣款</div>
+ <div class="statistic-num">{{ statistic.orderFeePackingTransport || 0 }}</div>
+ </el-card>
+ </el-col>
+ </el-row>
+ <el-row :gutter="20">
+ <el-col :span="3" class="mb-2">
+ <el-card>
+ <div class="statistic-title">优惠合计</div>
+ <div class="statistic-num">
+ <!-- {{ statistic.discountTotalFee || 0 }} -->
+ {{ statistic.orderDiscountTotalFee || 0 }}
+ </div>
+ </el-card>
+ </el-col>
+ <el-col :span="3" class="mb-2">
+ <el-card>
+ <div class="statistic-title">会员折扣</div>
+ <div class="statistic-num">
+ {{ statistic.orderPriceDiscountAmount || 0 }}
+ </div>
+ </el-card>
+ </el-col>
+ <el-col :span="3" class="mb-2">
+ <el-card>
+ <div class="statistic-title">优惠券</div>
+ <div class="statistic-num">
+ {{ statistic.orderCouponAmountTotal || 0 }}
+ </div>
+ </el-card>
+ </el-col>
+ </el-row>
+ <el-row :gutter="20">
+ <el-col :span="3" class="mb-2">
+ <el-card>
+ <div class="statistic-title">总销售扎数</div>
+ <div class="statistic-num">{{ statistic.orderNum || 0 }}</div>
+ </el-card>
+ </el-col>
+ <el-col :span="3" class="mb-2">
+ <el-card>
+ <div class="statistic-title">实际销售扎数</div>
+ <div class="statistic-num">{{ statistic.realSaleNum || 0 }}</div>
+ </el-card>
+ </el-col>
+ <el-col :span="3" class="mb-2">
+ <el-card>
+ <div class="statistic-title">缺货扎数</div>
+ <div class="statistic-num">{{ statistic.orderLackNum || 0 }}</div>
+ </el-card>
+ </el-col>
+ <el-col :span="3" class="mb-2">
+ <el-card>
+ <div class="statistic-title">降级扎数</div>
+ <div class="statistic-num">{{ statistic.orderReduceNum || 0 }}</div>
+ </el-card>
+ </el-col>
+ <el-col :span="3" class="mb-2">
+ <el-card>
+ <div class="statistic-title">补货扎数</div>
+ <div class="statistic-num">{{ statistic.orderReplaceNum || 0 }}</div>
+ </el-card>
+ </el-col>
+ </el-row>
+ </div>
+ <el-bus-crud ref="crud" v-bind="tableConfig" />
+ </div>
+</template>
+
+<script>
+import dayjs from 'dayjs'
+import 'dayjs/locale/zh-cn'
+import { getPartnerListConfig } from '@/utils/form-item-config'
+dayjs.locale('zh-cn')
+export default {
+ data() {
+ const defaultDate = `${dayjs().format('YYYY-MM-DD')} 00:00:00`
+ return {
+ statistic: {},
+ statisticLoading: false,
+ tableConfig: {
+ url: 'flower/v2/report/order/sale/page',
+ hasNew: false,
+ hasEdit: false,
+ hasDelete: false,
+ viewText: '明细',
+ hasExport: true,
+ exportUrl: 'flower/v2/report/order/sale/export',
+ exportText: '导出',
+ onResetView: (row) => {
+ const searchFormRef = this.$refs.crud.$refs.searchForm
+ const searchFormValue = searchFormRef.getFormValue()
+ const url = this.$router.resolve(
+ `/report/finance/${row.orderDate}?partnerId=${
+ searchFormValue?.partnerId || ''
+ }`
+ ).href
+ window.open(url, '_blank')
+ },
+ operationAttrs: {
+ width: 80,
+ fixed: 'right',
+ },
+ beforeRequest: async (params) => {
+ this.statisticLoading = true
+ // eslint-disable-next-line
+ let { code, data } = await this.$elBusHttp.request(
+ `flower/v2/report/order/sale/statis`,
+ { params }
+ )
+ if (code === 0) {
+ data = data || {}
+ data.checkTotalFee = Number(
+ (
+ (data.orderCheckFee ?? 0) +
+ (data.orderLackFeeSupplier ?? 0) +
+ (data.orderReplaceFee ?? 0)
+ ).toFixed(2)
+ )
+ data.saleTotalFee = Number(
+ (
+ (data.orderFeePartner ?? 0) +
+ (data.orderFeeSupplier ?? 0) +
+ (data.orderFeePlatform ?? 0)
+ ).toFixed(2)
+ )
+ data.discountTotalFee = Number(
+ (
+ (data.orderPriceDiscountAmount ?? 0) +
+ (data.orderCouponAmountTotal ?? 0)
+ ).toFixed(2)
+ )
+ this.statistic = data || {}
+ }
+ this.statisticLoading = false
+ },
+ columns: [
+ {
+ label: '下单日期',
+ prop: 'orderDate',
+ minWidth: 120,
+ fixed: 'left',
+ },
+ { label: '销售额(原订单)', prop: 'orderTotal', minWidth: 120 },
+ { label: '销售额(实付)', prop: 'totalAmount', minWidth: 120 },
+ {
+ label: '花农底价',
+ prop: 'orderSupplierPriceAmount',
+ minWidth: 120,
+ },
+ {
+ label: '平台区间加价',
+ prop: 'orderMarkupOneAmount',
+ minWidth: 120,
+ },
+ { label: '平台加价', prop: 'orderMarkupTwoAmount', minWidth: 120 },
+ {
+ label: '合伙人加价',
+ prop: 'orderMarkupPartnerAmount',
+ minWidth: 120,
+ },
+ { label: '优惠合计', prop: 'orderDiscountTotalFee', minWidth: 120,},
+ { label: '会员折扣', prop: 'orderPriceDiscountAmount',minWidth: 120,},
+ { label: '优惠券', prop: 'orderCouponAmountTotal', minWidth: 120 },
+
+ { label: '质检总扣款', prop: 'orderCheckTotalFee', minWidth: 120 },
+ { label: '降级扣款', prop: 'orderCheckFee', minWidth: 120 },
+ { label: '缺货扣款', prop: 'orderLackFeeSupplier', minWidth: 120 },
+ { label: '补货扣款', prop: 'orderReplaceFee', minWidth: 120 },
+
+ { label: '售后总扣款', prop: 'orderTotalFee', minWidth: 150 },
+ { label: '售后供应商扣款', prop: 'orderFeeSupplier', minWidth: 150 },
+ { label: '售后平台扣款', prop: 'orderFeePlatform', minWidth: 150 },
+ { label: '售后合伙人扣款', prop: 'orderFeePartner', minWidth: 150 },
+ { label: '售后打包扣款', prop: 'orderFeePlatformPack', minWidth: 150 },
+ { label: '售后质检扣款', prop: 'orderFeePlatformCheck', minWidth: 150 },
+ { label: '售后物流扣款', prop: 'orderFeePlatformTransport', minWidth: 150 },
+ { label: '售后打包运费扣款', prop: 'orderFeePackingTransport', minWidth: 150 },
+
+ { label: '总包干费', prop: 'partnerTotalFeeAmount', minWidth: 120 },
+ { label: '总售扎数', prop: 'orderNum', minWidth: 120 },
+ { label: '实际销售扎数', prop: 'realSaleNum', minWidth: 120 },
+ { label: '缺货扎数', prop: 'orderLackNum', minWidth: 120 },
+ { label: '降级扎数', prop: 'orderReduceNum', minWidth: 120 },
+ { label: '补货扎数', prop: 'orderReplaceNum', minWidth: 120 },
+
+ {
+ label: '利润',
+ prop: 'profitFeeAmount',
+ minWidth: 120,
+ fixed: 'right',
+ },
+ {
+ label: '结算状态',
+ prop: 'settleStatus',
+ minWidth: 120,
+ fixed: 'right',
+ },
+ ],
+ searchForm: [
+ {
+ type: 'row',
+ items: [
+ {
+ label: '下单日期',
+ id: 'startDate',
+ component: 'el-bus-date-range',
+ el: {
+ clearable: false,
+ },
+ // commonFormat: true,
+ // commonFormatProps: ['startDate', 'endDate'],
+ inputFormat: (row) => {
+ if ('startDate' in row || 'endDate' in row) {
+ return [
+ this.$elBusUtil.toDate(row.startDate),
+ this.$elBusUtil.toDate(row.endDate),
+ ]
+ }
+ },
+ outputFormat: (val) => {
+ return {
+ startDate: `${this.$elBusUtil.toDate(val[0])} 00:00:00`,
+ endDate: `${this.$elBusUtil.toDate(val[1])} 23:59:59`,
+ }
+ },
+ customClass: 'in-bus-form',
+ commonRules: true,
+ default: [defaultDate, defaultDate],
+ },
+ { ...getPartnerListConfig(), label: '合伙人' },
+ ],
+ },
+ ],
+ },
+ }
+ },
+ head() {
+ return {
+ title: '财务报表',
+ }
+ },
+}
+</script>
+
+<style lang="scss" scoped>
+@import '@/assets/statistic/index.scss';
+
+.statistic-title {
+ text-align: center;
+ font-size: 16px;
+ color: $main-title-color;
+ font-weight: bold;
+ margin-bottom: 6px;
+}
+.statistic-num {
+ text-align: center;
+ font-size: 16px;
+ color: $primary-color;
+}
+
+</style>
diff --git a/pages/report/partner/_date.vue b/pages/report/partner/_date.vue
new file mode 100644
index 0000000..34cb802
--- /dev/null
+++ b/pages/report/partner/_date.vue
@@ -0,0 +1,143 @@
+<template>
+ <el-bus-crud ref="crud" v-bind="tableConfig" />
+</template>
+
+<script>
+import { getPartnerListConfig } from '@/utils/form-item-config'
+export default {
+ data() {
+ return {
+ tableConfig: {
+ url: 'flower/v2/report/order/detail/page',
+ hasEdit: false,
+ hasNew: false,
+ hasDelete: false,
+ hasView: false,
+ hasExport: true,
+ hasOperation: false,
+ exportUrl: 'flower/v2/report/order/detail/export',
+ exportText: '导出',
+ columns: [
+ { label: '订单号', prop: 'orderNo', minWidth: 150, fixed: 'left' },
+ {
+ label: '下单用户',
+ prop: 'customer',
+ minWidth: '150px',
+ fixed: 'left',
+ },
+ { label: '收货人地址', prop: 'address', minWidth: '220px' },
+ { label: '合伙人', prop: 'partnerName', minWidth: '120px' },
+ { label: '下单时间', prop: 'orderDate', minWidth: '180px' },
+ { label: '订单金额', prop: 'orderTotal', minWidth: '120px' },
+ {
+ label: '花农底价',
+ prop: 'orderSupplierPriceAmount',
+ minWidth: '120px',
+ },
+ {
+ label: '平台区间加价',
+ prop: 'orderMarkupOneAmount',
+ minWidth: '120px',
+ },
+ {
+ label: '平台加价',
+ prop: 'orderMarkupTwoAmount',
+ minWidth: '120px',
+ },
+ {
+ label: '平台区域加价',
+ prop: 'platformAreaFeeAmount',
+ minWidth: '120px',
+ },
+ {
+ label: '合伙人加价',
+ prop: 'orderMarkupPartnerAmount',
+ minWidth: '120px',
+ },
+ {
+ label: '合伙人区间加价',
+ prop: 'partnerSectionFeeAmount',
+ minWidth: '120px',
+ },
+ {
+ label: '会员折扣',
+ prop: 'orderPriceDiscountAmount',
+ minWidth: '100px',
+ },
+ {
+ label: '优惠券',
+ prop: 'orderCouponAmountTotal',
+ minWidth: '100px',
+ },
+ { label: '质检降级扣款', prop: 'orderCheckFee', minWidth: '100px' },
+ {
+ label: '质检缺货扣款',
+ prop: 'orderLackFeeSupplier',
+ minWidth: '100px',
+ },
+ { label: '质检补货扣款', prop: 'orderReplaceFee', minWidth: '100px' },
+ {
+ label: '售后扣合伙人款',
+ prop: 'orderFeePartner',
+ minWidth: '120px',
+ },
+ {
+ label: '售后扣花农款',
+ prop: 'orderFeeSupplier',
+ minWidth: '100px',
+ },
+ {
+ label: '售后扣平台款',
+ prop: 'orderFeePlatform',
+ minWidth: '100px',
+ },
+ {
+ label: '总包干费',
+ prop: 'partnerTotalFeeAmount',
+ minWidth: '100px',
+ },
+ { label: '销售扎数', prop: 'realSaleNum', minWidth: '100px' },
+ {
+ label: '利润',
+ prop: 'profitFeeAmount',
+ minWidth: '100px',
+ fixed: 'right',
+ },
+ {
+ label: '结算状态',
+ prop: 'settleStatusStr',
+ minWidth: '120px',
+ fixed: 'right',
+ },
+ ],
+ searchForm: [
+ {
+ type: 'row',
+ span: 6,
+ items: [
+ {
+ label: '下单日期',
+ id: 'calDate',
+ component: 'el-date-picker',
+ type: 'date',
+ el: {
+ valueFormat: 'yyyy-MM-dd',
+ style: 'width:100%',
+ clearable: false,
+ },
+ default: this.$route.params.date,
+ },
+ { ...getPartnerListConfig() },
+ ],
+ },
+ ],
+ },
+ }
+ },
+ head() {
+ return {
+ title: '订单结算明细',
+ }
+ },
+}
+</script>
diff --git a/pages/report/partner/index.vue b/pages/report/partner/index.vue
new file mode 100644
index 0000000..06b0e71
--- /dev/null
+++ b/pages/report/partner/index.vue
@@ -0,0 +1,254 @@
+<template>
+ <div>
+ <div v-loading="statisticLoading">
+ <el-row :gutter="20">
+ <el-col :span="4" class="mb-10">
+ <el-card>
+ <div class="statistic-title">底价合计</div>
+ <div class="statistic-num">{{ statistic.orderPartnerPriceAmount || 0 }}</div>
+ </el-card>
+ </el-col>
+ <el-col :span="4" class="mb-10">
+ <el-card>
+ <div class="statistic-title">合伙人加价</div>
+ <div class="statistic-num">
+ {{ statistic.orderMarkupPartnerAmount || 0 }}
+ </div>
+ </el-card>
+ </el-col>
+ <el-col :span="4" class="mb-10">
+ <el-card>
+ <div class="statistic-title">会员折扣合计</div>
+ <div class="statistic-num">
+ {{ statistic.orderPriceDiscountAmount || 0 }}
+ </div>
+ </el-card>
+ </el-col>
+ <el-col :span="4" class="mb-10">
+ <el-card>
+ <div class="statistic-title">总销售扎数</div>
+ <div class="statistic-num">
+ {{ statistic.orderNum || 0 }}
+ </div>
+ </el-card>
+ </el-col>
+ <el-col :span="4" class="mb-10">
+ <el-card>
+ <div class="statistic-title">实际销售扎数</div>
+ <div class="statistic-num">
+ {{ statistic.realSaleNum || 0 }}
+ </div>
+ </el-card>
+ </el-col>
+ <el-col :span="4" class="mb-10">
+ <el-card>
+ <div class="statistic-title">缺货扎数</div>
+ <div class="statistic-num">{{ statistic.orderLackNum || 0 }}</div>
+ </el-card>
+ </el-col>
+ <el-col :span="4" class="mb-10">
+ <el-card>
+ <div class="statistic-title">降级扎数</div>
+ <div class="statistic-num">{{ statistic.orderReduceNum || 0 }}</div>
+ </el-card>
+ </el-col>
+ <el-col :span="4" class="mb-10">
+ <el-card>
+ <div class="statistic-title">补货扎数</div>
+ <div class="statistic-num">{{ statistic.orderReplaceNum || 0 }}</div>
+ </el-card>
+ </el-col>
+ <el-col :span="4" class="mb-10">
+ <el-card>
+ <div class="statistic-title">售后扣款合计</div>
+ <div class="statistic-num">
+ {{ statistic.orderFeePartner || 0 }}
+ </div>
+ </el-card>
+ </el-col>
+ <el-col :span="4" class="mb-10">
+ <el-card>
+ <div class="statistic-title">优惠券合计</div>
+ <div class="statistic-num">{{ statistic.orderCouponAmountTotal || 0 }}</div>
+ </el-card>
+ </el-col>
+ <el-col :span="4" class="mb-10">
+ <el-card>
+ <div class="statistic-title">包干费合计</div>
+ <div class="statistic-num">
+ {{ statistic.partnerTotalFeeAmount || 0 }}
+ </div>
+ </el-card>
+ </el-col>
+ </el-row>
+ </div>
+ <el-bus-crud v-bind="tableConfig" />
+ </div>
+</template>
+
+<script>
+import dayjs from 'dayjs'
+import 'dayjs/locale/zh-cn'
+import { getPartnerListNameWithIdConfig } from '@/utils/form-item-config'
+dayjs.locale('zh-cn')
+export default {
+ data() {
+ const paymentDateStart = `${dayjs().format('YYYY-MM-DD')}`
+ const paymentDateEnd = `${dayjs().format('YYYY-MM-DD')}`
+ return {
+ statistic: {},
+ statisticLoading: false,
+ tableConfig: {
+ url: 'flower/v2/report/order/partner/sale/page',
+ hasNew: false,
+ hasEdit: false,
+ hasDelete: false,
+ // viewText: '明细',
+ hasExport: true,
+ hasOperation: false,
+ exportUrl: 'flower/v2/report/order/partner/sale/export',
+ exportText: '导出',
+ onResetView: (row) => {
+ const url = this.$router.resolve(
+ `/report/finance/${row.orderDate}`
+ ).href
+ window.open(url, '_blank')
+ },
+ operationAttrs: {
+ width: 80,
+ fixed: 'right',
+ },
+ beforeRequest: async (params) => {
+ this.statisticLoading = true
+ // eslint-disable-next-line
+ let { code, data } = await this.$elBusHttp.request(
+ `flower/v2/report/order/partner/sale/statis`,
+ { params }
+ )
+ if (code === 0) {
+ data = data || {}
+ data.checkTotalFee = Number(
+ (
+ (data.orderCheckFee ?? 0) +
+ (data.orderLackFeeSupplier ?? 0) +
+ (data.orderReplaceFee ?? 0)
+ ).toFixed(2)
+ )
+ data.saleTotalFee = Number(
+ (
+ (data.orderFeePartner ?? 0) +
+ (data.orderFeeSupplier ?? 0) +
+ (data.orderFeePlatform ?? 0)
+ ).toFixed(2)
+ )
+ data.discountTotalFee = Number(
+ (
+ (data.orderPriceDiscountAmount ?? 0) +
+ (data.orderCouponAmountTotal ?? 0)
+ ).toFixed(2)
+ )
+ this.statistic = data || {}
+ }
+ this.statisticLoading = false
+ },
+ columns: [
+ {
+ label: '下单日期',
+ prop: 'orderDate',
+ minWidth: 120,
+ fixed: 'left',
+ },
+ { label: '合伙人ID', prop: 'partnerId', minWidth: 120 },
+ {
+ label: '合伙人',
+ prop: 'partnerName',
+ minWidth: 120,
+ },
+ {
+ label: '底价',
+ prop: 'orderPartnerPriceAmount',
+ minWidth: 120,
+ },
+ {
+ label: '合伙人加价',
+ prop: 'orderMarkupPartnerAmount',
+ minWidth: 120,
+ },
+ {
+ label: '会员折扣',
+ prop: 'orderPriceDiscountAmount',
+ minWidth: 120,
+ },
+ { label: '优惠券', prop: 'orderCouponAmountTotal', minWidth: 120 },
+ { label: '售后扣合伙人款', prop: 'orderFeePartner', minWidth: 120 },
+
+ { label: '总包干费', prop: 'partnerTotalFeeAmount', minWidth: 120 },
+
+ { label: '总售扎数', prop: 'orderNum', minWidth: 120 },
+ { label: '实际销售扎数', prop: 'realSaleNum', minWidth: 120 },
+ { label: '缺货扎数', prop: 'orderLackNum', minWidth: 120 },
+ { label: '降级扎数', prop: 'orderReduceNum', minWidth: 120 },
+ { label: '补货扎数', prop: 'orderReplaceNum', minWidth: 120 },
+
+ // { label: '实际销售扎数', prop: 'realSaleNum', minWidth: 120 },
+ ],
+ searchForm: [
+ {
+ type: 'row',
+ items: [
+ {
+ label: '下单日期',
+ id: 'paymentDateStart',
+ component: 'el-bus-date-range',
+ el: {
+ clearable: false,
+ },
+ // commonFormat: true,
+ // commonFormatProps: ['paymentDateStart', 'paymentDateEnd'],
+ inputFormat: (row) => {
+ if ('paymentDateStart' in row || 'paymentDateEnd' in row) {
+ return [
+ this.$elBusUtil.toDate(row.paymentDateStart),
+ this.$elBusUtil.toDate(row.paymentDateEnd),
+ ]
+ }
+ },
+ outputFormat: (val) => {
+ return {
+ paymentDateStart: `${this.$elBusUtil.toDate(val[0])}`,
+ paymentDateEnd: `${this.$elBusUtil.toDate(val[1])}`,
+ }
+ },
+ customClass: 'in-bus-form',
+ commonRules: true,
+ default: [paymentDateStart, paymentDateEnd],
+ },
+ { ...getPartnerListNameWithIdConfig(), label: '合伙人' },
+ ],
+ },
+ ],
+ },
+ }
+ },
+ head() {
+ return {
+ title: '财务报表',
+ }
+ },
+}
+</script>
+
+<style lang="scss" scoped>
+.statistic-title {
+ text-align: center;
+ font-size: 20px;
+ color: $main-title-color;
+ font-weight: bold;
+ margin-bottom: 6px;
+}
+.statistic-num {
+ text-align: center;
+ font-size: 16px;
+ color: $primary-color;
+}
+</style>
diff --git a/pages/report/supplier.vue b/pages/report/supplier.vue
new file mode 100644
index 0000000..72616af
--- /dev/null
+++ b/pages/report/supplier.vue
@@ -0,0 +1,188 @@
+<template>
+ <div>
+ <div v-loading="statisticLoading">
+ <el-row :gutter="20">
+ <el-col :span="4" class="mb-10">
+ <el-card>
+ <div class="statistic-title">底价合计</div>
+ <div class="statistic-num">{{ statistic.orderSupplierPriceAmount || 0 }}</div>
+ </el-card>
+ </el-col>
+ <el-col :span="4" class="mb-10">
+ <el-card>
+ <div class="statistic-title">降级扣款</div>
+ <div class="statistic-num">
+ {{ statistic.orderCheckFee || 0 }}
+ </div>
+ </el-card>
+ </el-col>
+ <el-col :span="4" class="mb-10">
+ <el-card>
+ <div class="statistic-title">缺货扣款</div>
+ <div class="statistic-num">
+ {{ statistic.orderLackFeeSupplier || 0 }}
+ </div>
+ </el-card>
+ </el-col>
+ <el-col :span="4" class="mb-10">
+ <el-card>
+ <div class="statistic-title">售后扣款</div>
+ <div class="statistic-num">
+ {{ statistic.salesFeeSupplier || 0 }}
+ </div>
+ </el-card>
+ </el-col>
+ <el-col :span="4" class="mb-10">
+ <el-card>
+ <div class="statistic-title">总销售扎数</div>
+ <div class="statistic-num">
+ {{ statistic.orderNum || 0 }}
+ </div>
+ </el-card>
+ </el-col>
+ <el-col :span="4" class="mb-10">
+ <el-card>
+ <div class="statistic-title">实际销售扎数</div>
+ <div class="statistic-num">{{ statistic.realSaleNum || 0 }}</div>
+ </el-card>
+ </el-col>
+ <el-col :span="4" class="mb-10">
+ <el-card>
+ <div class="statistic-title">缺货扎数</div>
+ <div class="statistic-num">{{ statistic.orderLackNum || 0 }}</div>
+ </el-card>
+ </el-col>
+ <el-col :span="4" class="mb-10">
+ <el-card>
+ <div class="statistic-title">降级扎数</div>
+ <div class="statistic-num">{{ statistic.orderReduceNum || 0 }}</div>
+ </el-card>
+ </el-col>
+ <el-col :span="4" class="mb-10">
+ <el-card>
+ <div class="statistic-title">补货扎数</div>
+ <div class="statistic-num">
+ {{ statistic.orderReplaceNum || 0 }}
+ </div>
+ </el-card>
+ </el-col>
+ <el-col :span="4" class="mb-10">
+ <el-card>
+ <div class="statistic-title">结算合计</div>
+ <div class="statistic-num">{{ statistic.profitFeeAmount || 0 }}</div>
+ </el-card>
+ </el-col>
+ </el-row>
+ </div>
+ <el-bus-crud v-bind="tableConfig"></el-bus-crud>
+ </div>
+</template>
+
+<script>
+import { getSupplierListConfig } from '@/utils/form-item-config'
+export default {
+ data() {
+ const currentDate = this.$elBusUtil.toDate(new Date())
+ return {
+ statisticLoading: false,
+ statistic: {},
+ tableConfig: {
+ url: 'flower/v2/report/order/supplier/page',
+ hasNew: false,
+ hasOperation: false,
+ hasExport: true,
+ exportUrl: 'flower/v2/report/order/supplier/export',
+ exportText: '导出',
+ beforeRequest: async (params) => {
+ this.statisticLoading = true
+ // eslint-disable-next-line
+ let { code, data } = await this.$elBusHttp.request(
+ `flower/v2/report/order/supplier/count`,
+ { params }
+ )
+ if (code === 0) {
+ this.statistic = data || {}
+ }
+ this.statisticLoading = false
+ },
+ columns: [
+ { label: '日期', prop: 'dateinfo', fixed: 'left', minWidth: 120 },
+ {
+ label: '供应商ID',
+ prop: 'supplierId',
+ fixed: 'left',
+ minWidth: 80,
+ },
+ {
+ label: '供应商',
+ prop: 'supplierName',
+ fixed: 'left',
+ minWidth: 120,
+ },
+ {
+ label: '花农底价',
+ prop: 'orderSupplierPriceAmount',
+ minWidth: 120,
+ },
+ { label: '降级扣款', prop: 'orderCheckFee', minWidth: 120 },
+ {
+ label: '缺货扣款(缺货+补货)',
+ prop: 'orderLackFeeSupplier',
+ minWidth: 150,
+ },
+ { label: '售后扣花农款', prop: 'salesFeeSupplier', minWidth: 120 },
+
+ { label: '总售扎数', prop: 'orderNum', minWidth: 120 },
+ { label: '实际销售扎数', prop: 'realSaleNum', minWidth: 120 },
+ { label: '缺货扎数', prop: 'orderLackNum', minWidth: 120 },
+ { label: '降级扎数', prop: 'orderReduceNum', minWidth: 120 },
+ { label: '补货扎数', prop: 'orderReplaceNum', minWidth: 120 },
+
+ {
+ label: '结算费用',
+ prop: 'profitFeeAmount',
+ fixed: 'right',
+ minWidth: 120,
+ },
+ {
+ label: '订单状态',
+ prop: 'settleStatus',
+ fixed: 'right',
+ minWidth: 120,
+ },
+ ],
+ searchForm: [
+ {
+ type: 'row',
+ items: [
+ {
+ label: '下单日期',
+ id: 'startDate',
+ component: 'el-bus-date-range',
+ el: {
+ clearable: false,
+ },
+ commonFormat: true,
+ commonFormatProps: ['startDate', 'endDate'],
+ customClass: 'in-bus-form',
+ commonRules: true,
+ default: [currentDate, currentDate],
+ },
+ { ...getSupplierListConfig(), label: '供应商' },
+ ],
+ },
+ ],
+ },
+ }
+ },
+ head() {
+ return {
+ title: '花农结算报表',
+ }
+ },
+}
+</script>
+
+<style lang="scss" scoped>
+@import '@/assets/statistic/index.scss';
+</style>
diff --git a/pages/setting/freight/_id.vue b/pages/setting/freight/_id.vue
new file mode 100644
index 0000000..51efcca
--- /dev/null
+++ b/pages/setting/freight/_id.vue
@@ -0,0 +1,184 @@
+<template>
+ <el-bus-crud v-bind="tableConfig" />
+</template>
+
+<script>
+export default {
+ data() {
+ return {
+ tableConfig: {
+ url: 'flower/api/transport/fee/list',
+ hasPagination: false,
+ dialogNeedRequest: true,
+ operationAttrs: {
+ width: 150,
+ fixed: 'right',
+ },
+ columns: [
+ { label: '运费配置类型', prop: 'typeStr', minWidth: 100 },
+ { label: '首重(kg)', prop: 'firstWeight', minWidth: 100 },
+ { label: '首重起步价(元)', prop: 'firstWeightFee', minWidth: 100 },
+ { label: '续重(kg)', prop: 'addedWeight', minWidth: 100 },
+ { label: '续重价(元)', prop: 'addedWeightFee', minWidth: 100 },
+ {
+ label: '地区',
+ formatter: (row) => this.formatDistrict(row),
+ minWidth: 400,
+ },
+ ],
+ extraQuery: {
+ id: this.$route.params.id,
+ },
+ extraBody: {
+ transportId: this.$route.params.id,
+ },
+ form: [
+ {
+ type: 'row',
+ span: 12,
+ items: [
+ {
+ label: '运费配置类型:',
+ id: 'type',
+ type: 'bus-radio',
+ el: {
+ code: 'freight_template_type',
+ style: 'width:100%',
+ },
+ default: '0',
+ str: true,
+ rules: { required: true, message: '请选择运费配置类型' },
+ on: {
+ change: (e, updateForm) => {
+
+ },
+ },
+ },
+ {
+ label: '首重:',
+ id: 'firstWeight',
+ type: 'input-number',
+ el: {
+ precision: 2,
+ min: 0,
+ controls: false,
+ },
+ unit: 'kg',
+ rules: {
+ required: true,
+ message: '请输入首重',
+ trigger: 'blur',
+ },
+ hidden: (row) => row.type !== '0',
+ },
+ {
+ label: '首重起步价:',
+ id: 'firstWeightFee',
+ type: 'input-number',
+ el: {
+ precision: 2,
+ min: 0,
+ controls: false,
+ },
+ unit: '元',
+ rules: {
+ required: true,
+ message: '请输入首重起步价',
+ trigger: 'blur',
+ },
+ hidden: (row) => row.type !== '0',
+ },
+ {
+ label: '续重:',
+ id: 'addedWeight',
+ type: 'input-number',
+ el: {
+ precision: 2,
+ min: 0,
+ controls: false,
+ },
+ unit: 'kg',
+ rules: {
+ required: true,
+ message: '请输入续重',
+ trigger: 'blur',
+ },
+ hidden: (row) => row.type !== '0',
+ },
+ {
+ label: '续重价:',
+ id: 'addedWeightFee',
+ type: 'input-number',
+ el: {
+ precision: 2,
+ min: 0,
+ controls: false,
+ },
+ unit: '元',
+ rules: {
+ required: true,
+ message: '请输入续重价',
+ trigger: 'blur',
+ },
+ hidden: (row) => row.type !== '0',
+ },
+ {
+ label: '地区:',
+ id: 'areas',
+ component: 'area-select',
+ span: 24,
+ forceDisabled: true,
+ rules: {
+ required: true,
+ message: '请选择地区',
+ },
+ hidden: (row) => row.type !== '0',
+ },
+ ],
+ },
+ ],
+ },
+ }
+ },
+ head() {
+ return {
+ title: '运费配置',
+ }
+ },
+ methods: {
+ formatDistrict(row) {
+ if (Array.isArray(row.areas) && row.areas.length > 0) {
+ return (
+ <div>
+ {row.areas.slice(0, 5).map((item) => {
+ return (
+ <el-tag type="primary" class="mr-4 mb-4">
+ {item.province}-{item.city}
+ </el-tag>
+ )
+ })}
+ {row.areas.length > 5 ? (
+ <el-tooltip
+ placement="top"
+ popper-class="freight-popper"
+ content={row.areas
+ .map((i) => `${i.province}-${i.city}`)
+ .join(',')}
+ >
+ <span class="text-primary">查看更多</span>
+ </el-tooltip>
+ ) : null}
+ </div>
+ )
+ }
+ return ''
+ },
+ },
+}
+</script>
+
+<style>
+.freight-popper {
+ max-width: 60%;
+}
+</style>
diff --git a/pages/setting/freight/index.vue b/pages/setting/freight/index.vue
new file mode 100644
index 0000000..896256a
--- /dev/null
+++ b/pages/setting/freight/index.vue
@@ -0,0 +1,68 @@
+<template>
+ <el-bus-crud v-bind="tableConfig" />
+</template>
+
+<script>
+export default {
+ data() {
+ return {
+ tableConfig: {
+ url: 'flower/api/transport/list',
+ newText: '新增物流',
+ columns: [
+ { label: '物流名称', prop: 'name' },
+ { label: '英文名称', prop: 'enName' },
+ { label: '联系人', prop: 'contacts' },
+ { label: '联系方式', prop: 'contactsTel' },
+ ],
+ searchForm: [
+ {
+ type: 'row',
+ items: [{ label: '物流名称', id: 'name', type: 'input' }],
+ },
+ ],
+ form: [
+ {
+ label: '物流名称:',
+ id: 'name',
+ type: 'input',
+ rules: {
+ required: true,
+ message: '请输入物流名称',
+ trigger: 'blur',
+ },
+ },
+ {
+ label: '英文名称:',
+ id: 'enName',
+ type: 'input',
+ },
+ {
+ label: '联系人:',
+ id: 'contacts',
+ type: 'input',
+ },
+ {
+ label: '联系方式:',
+ id: 'contactsTel',
+ type: 'input',
+ },
+ ],
+ extraButtons: [
+ {
+ text: '运费配置',
+ atClick: (row) => {
+ this.$router.push(`${this.$route.path}/${row.id}`)
+ },
+ },
+ ],
+ },
+ }
+ },
+ head() {
+ return {
+ title: '运费管理',
+ }
+ },
+}
+</script>
diff --git a/pages/setting/service-charge.vue b/pages/setting/service-charge.vue
new file mode 100644
index 0000000..004be04
--- /dev/null
+++ b/pages/setting/service-charge.vue
@@ -0,0 +1,76 @@
+<template>
+ <el-bus-crud v-bind="tableConfig" />
+</template>
+
+<script>
+export default {
+ data() {
+ return {
+ tableConfig: {
+ url: 'flower/api/fee/config/list',
+ hasPagination: false,
+ columns: [
+ { label: '序号', type: 'index' },
+ { label: '销量区间', formatter: this.formatRange },
+ { label: '服务费比例(%)', prop: 'feeRate' },
+ ],
+ beforeOpen: (row, isNew) => {
+ if (!isNew) {
+ row.lowerNumStr = this.formatRange(row)
+ }
+ },
+ form: [
+ {
+ label: '销量区间:',
+ id: 'lowerNum',
+ component: 'el-bus-number-range',
+ el: {
+ unit: '扎',
+ min: 0,
+ precision: 0,
+ },
+ commonFormat: true,
+ commonFormatProps: ['lowerNum', 'upperNum'],
+ commonRules: true,
+ commonRulesLevel: 1,
+ str: true,
+ },
+ {
+ label: '服务费比例:',
+ id: 'feeRate',
+ type: 'input-number',
+ el: {
+ precision: 1,
+ min: 0,
+ },
+ unit: '%',
+ rules: {
+ required: true,
+ message: '请输入服务费比例',
+ trigger: 'blur',
+ },
+ },
+ ],
+ },
+ }
+ },
+ head() {
+ return {
+ title: '服务费管理',
+ }
+ },
+ methods: {
+ formatRange(row) {
+ let str = ''
+ if (!this.$elBusUtil.isTrueEmpty(row.lowerNum)) {
+ str += `${row.lowerNum}扎<`
+ }
+ str += '销量'
+ if (!this.$elBusUtil.isTrueEmpty(row.upperNum)) {
+ str += `≤${row.upperNum}扎`
+ }
+ return str
+ },
+ },
+}
+</script>
diff --git a/pages/settlement/list/_id.vue b/pages/settlement/list/_id.vue
new file mode 100644
index 0000000..a7b8198
--- /dev/null
+++ b/pages/settlement/list/_id.vue
@@ -0,0 +1,191 @@
+<template>
+ <div class="base-page-wrapper settlement-detail">
+ <el-bus-title title="结算信息" size="small"></el-bus-title>
+ <el-bus-form
+ ref="form"
+ label-width="auto"
+ :content="formContent"
+ readonly
+ class="readonly-form"
+ ></el-bus-form>
+ <template v-if="goodsList && goodsList.length > 0">
+ <el-bus-title
+ title="结算商品明细"
+ size="small"
+ class="mt-20"
+ ></el-bus-title>
+ <el-table :data="goodsList">
+ <el-table-column
+ label="商品名称"
+ prop="flowerName"
+ min-width="150"
+ fixed="left"
+ ></el-table-column>
+ <el-table-column
+ label="级别"
+ prop="flowerLevelStr"
+ min-width="80"
+ ></el-table-column>
+ <el-table-column
+ label="结算单价(元)"
+ prop="price"
+ min-width="120"
+ ></el-table-column>
+ <el-table-column
+ label="数量"
+ prop="num"
+ min-width="120"
+ ></el-table-column>
+ <el-table-column
+ label="结算合计(元)"
+ prop="totalAmount"
+ min-width="120"
+ ></el-table-column>
+ <el-table-column
+ label="降级扣款(元)"
+ prop="checkFee"
+ min-width="120"
+ ></el-table-column>
+ <el-table-column
+ label="缺货扣款(元)"
+ prop="lackFee"
+ min-width="120"
+ ></el-table-column>
+ <el-table-column
+ label="补货扣款(元)"
+ prop="replaceFee"
+ min-width="120"
+ ></el-table-column>
+ <el-table-column
+ label="售后理赔(元)"
+ prop="salesFee"
+ min-width="120"
+ ></el-table-column>
+ <el-table-column
+ label="集货站运费(元)"
+ prop="stationFee"
+ min-width="120"
+ ></el-table-column>
+ <el-table-column
+ label="订单号"
+ prop="orderNo"
+ min-width="180"
+ fixed="right"
+ >
+ <template #default="{ row }">
+ <el-link
+ href="javascript:void(0)"
+ type="primary"
+ @click.native="toOrderDetail(row)"
+ >{{ row.orderNo }}</el-link
+ >
+ </template>
+ </el-table-column>
+ <el-table-column
+ label="收货日期"
+ prop="receiveTime"
+ min-width="150"
+ fixed="right"
+ ></el-table-column>
+ <el-table-column
+ label="质检日期"
+ prop="checkTime"
+ min-width="150"
+ fixed="right"
+ ></el-table-column>
+ </el-table>
+ </template>
+ <div class="text-center mt-20">
+ <el-button class="min-w-100" @click="goBack">返回</el-button>
+ </div>
+ </div>
+</template>
+
+<script>
+export default {
+ data() {
+ return {
+ goodsList: [],
+ formContent: [
+ {
+ type: 'row',
+ items: [
+ { label: '结算人:', id: 'userName', type: 'input' },
+ { label: '订单数量:', id: 'orderNum', type: 'input' },
+ { label: '买家数量:', id: 'customerNum', type: 'input' },
+ { label: '商品数量:', id: 'flowerNum', type: 'input' },
+ {
+ label: '结算合计:',
+ id: 'totalAmount',
+ type: 'input',
+ unit: '元',
+ },
+ { label: '结算均价:', id: 'price', type: 'input', unit: '元' },
+ { label: '降级扣款:', id: 'checkFee', type: 'input', unit: '元' },
+ { label: '缺货扣款:', id: 'lackFee', type: 'input', unit: '元' },
+ {
+ label: '补货扣款:',
+ id: 'replaceFee',
+ type: 'input',
+ unit: '元',
+ },
+ { label: '售后理赔:', id: 'salesFee', type: 'input', unit: '元' },
+ { label: '服务费:', id: 'serviceFee', type: 'input', unit: '元' },
+ {
+ label: '集货站运费:',
+ id: 'stationFee',
+ type: 'input',
+ unit: '元',
+ },
+ {
+ label: '结算金额:',
+ id: 'settlementAmount',
+ type: 'input',
+ unit: '元',
+ },
+ { label: '结算类型:', id: 'typeStr', type: 'input' },
+ { label: '结算状态:', id: 'statusStr', type: 'input' },
+ { label: '结算时间:', id: 'transferTime', type: 'input' },
+ ],
+ },
+ ],
+ }
+ },
+ head() {
+ return {
+ title: '结算详情',
+ }
+ },
+ mounted() {
+ this.getDetail()
+ },
+ methods: {
+ goBack() {
+ this.$router.back()
+ },
+ async getDetail() {
+ const { code, data } = await this.$elBusHttp.request(
+ 'flower/api/settlement/list/view',
+ { params: { id: this.$route.params.id } }
+ )
+ if (code === 0) {
+ this.$refs.form.updateForm(data)
+ this.goodsList = data?.details || []
+ }
+ },
+ toOrderDetail(row) {
+ if (row.orderId) {
+ this.$router.push(`/order/list/${row.orderId}`)
+ }
+ },
+ },
+}
+</script>
+
+<style lang="scss" scoped>
+.settlement-detail {
+ .el-bus-title {
+ margin-bottom: 10px;
+ }
+}
+</style>
diff --git a/pages/settlement/list/index.vue b/pages/settlement/list/index.vue
new file mode 100644
index 0000000..fac1145
--- /dev/null
+++ b/pages/settlement/list/index.vue
@@ -0,0 +1,143 @@
+<template>
+ <el-bus-crud v-bind="tableConfig" />
+</template>
+
+<script>
+import { dateRangeOptions } from '@/utils/options'
+import CustomDateRange from '@/components/custom-date-range.vue'
+export default {
+ data() {
+ return {
+ tableConfig: {
+ url: 'flower/api/settlement/list',
+ hasNew: false,
+ hasEdit: false,
+ hasDelete: false,
+ hasExport: true,
+ exportUrl: 'flower/api/settlement/export',
+ onResetView: (row) => {
+ this.$router.push(`${this.$route.path}/${row.id}`)
+ },
+ operationAttrs: {
+ width: 120,
+ fixed: 'right',
+ },
+ columns: [
+ {
+ label: '结算人',
+ prop: 'userName',
+ minWidth: 150,
+ fixed: 'left',
+ },
+ {
+ label: '结算金额(元)',
+ prop: 'settlementAmount',
+ minWidth: 120,
+ fixed: 'left',
+ },
+ { label: '订单数量', prop: 'orderNum', minWidth: 100 },
+ { label: '买家数量', prop: 'customerNum', minWidth: 100 },
+ { label: '商品数量', prop: 'flowerNum', minWidth: 100 },
+ { label: '结算合计(元)', prop: 'totalAmount', minWidth: 120 },
+ { label: '结算均价(元)', prop: 'price', minWidth: 120 },
+ { label: '降级扣款(元)', prop: 'checkFee', minWidth: 120 },
+ { label: '缺货扣款(元)', prop: 'lackFee', minWidth: 120 },
+ { label: '补货扣款(元)', prop: 'replaceFee', minWidth: 120 },
+ { label: '售后理赔(元)', prop: 'salesFee', minWidth: 120 },
+ { label: '服务费(元)', prop: 'serviceFee', minWidth: 120 },
+ { label: '集货站运费(元)', prop: 'stationFee', minWidth: 120 },
+ { label: '结算类型', prop: 'typeStr', minWidth: 120 },
+ { label: '结算状态', prop: 'statusStr', minWidth: 120 },
+ { label: '结算时间', prop: 'transferTime', minWidth: 180 },
+ ],
+ searchFormAttrs: {
+ labelWidth: 'auto',
+ },
+ searchForm: [
+ {
+ type: 'row',
+ items: [
+ {
+ label: '结算类型:',
+ id: 'type',
+ type: 'bus-radio',
+ el: {
+ hasAll: true,
+ childType: 'el-radio-button',
+ code: 'SETTLEMENT_TYPE',
+ },
+ default: '',
+ span: 24,
+ searchImmediately: true,
+ },
+ {
+ label: '结算状态:',
+ id: 'status',
+ type: 'bus-radio',
+ el: {
+ hasAll: true,
+ childType: 'el-radio-button',
+ code: 'SETTLEMENT_STATUS',
+ },
+ default: '',
+ span: 24,
+ searchImmediately: true,
+ },
+ {
+ label: '结算日期:',
+ id: 'dateType',
+ component: CustomDateRange,
+ el: {
+ options: dateRangeOptions,
+ },
+ searchImmediately: true,
+ commonFormat: true,
+ commonFormatProps: ['dateType', 'startDateStr', 'endDateStr'],
+ span: 24,
+ },
+ { label: '结算人:', id: 'userName', type: 'input' },
+ ],
+ },
+ ],
+ extraButtons: [
+ {
+ text: '结算',
+ show: (row) => row.status === 'PENDING' || row.status === 'FAILED',
+ atClick: async (row) => {
+ try {
+ await this.$elBusUtil.confirm('确定要结算吗?')
+ const { code } = await this.$elBusHttp.request(
+ 'flower/api/settlement/list/transfer',
+ {
+ params: {
+ id: row.id,
+ },
+ }
+ )
+ if (code === 0) {
+ this.$message.success('结算成功')
+ }
+ } catch (e) {
+ return false
+ }
+ },
+ },
+ ],
+ },
+ }
+ },
+ head() {
+ return {
+ title: '结算列表',
+ }
+ },
+}
+</script>
+
+<style lang="scss" scoped>
+::v-deep {
+ .el-bus-crud__filter__action {
+ //display: none;
+ }
+}
+</style>
diff --git a/pages/shop/list.vue b/pages/shop/list.vue
new file mode 100644
index 0000000..97cf21b
--- /dev/null
+++ b/pages/shop/list.vue
@@ -0,0 +1,154 @@
+<template>
+ <el-bus-crud ref="crud" v-bind="tableConfig" />
+</template>
+
+<script>
+import { getPartnerListConfig } from '@/utils/form-item-config'
+export default {
+ data() {
+ return {
+ tableConfig: {
+ url: 'flower/api/customer/page',
+ hasNew: false,
+ hasEdit: false,
+ hasDelete: false,
+ operationAttrs: {
+ width: 150,
+ fixed: 'right',
+ },
+ beforeOpen: (data, isNew) => {
+ if (!isNew) {
+ data.area = this.getDistrict(data)
+ }
+ },
+ columns: [
+ { label: '商户名称', prop: 'name', minWidth: 150, fixed: 'left' },
+ { label: '商户昵称', prop: 'nickName', minWidth: 150 },
+ { label: '所属合伙人', prop: 'partnerName', minWidth: 150 },
+ { label: '下单次数', prop: 'orderNum', minWidth: 150 },
+ {
+ label: '地址',
+ formatter: (row) => this.getDistrict(row),
+ minWidth: 250,
+ },
+ { label: '联系方式', prop: 'tel', minWidth: 150 },
+ { label: '注册时间', prop: 'createTime', minWidth: 180 },
+ {
+ label: '启用/禁用',
+ formatter: (row) => (
+ <el-switch
+ value={row.isEnabled}
+ onChange={this.onEnabledChange.bind(this, row)}
+ ></el-switch>
+ ),
+ minWidth: 120,
+ fixed: 'right',
+ },
+ ],
+ searchForm: [
+ {
+ type: 'row',
+ items: [
+ { label: '商户名称', id: 'name', type: 'input' },
+ {
+ ...getPartnerListConfig(),
+ label: '合伙人',
+ },
+ {
+ label: '所属地区',
+ id: 'area',
+ component: 'el-bus-select-area',
+ commonFormat: true,
+ commonFormatProps: ['province', 'city', 'region'],
+ customClass: 'in-bus-form',
+ },
+ { label: '手机号', id: 'tel', type: 'input' },
+ {
+ label: '启用/禁用',
+ id: 'isEnabled',
+ type: 'bus-select-dict',
+ default: '1',
+ el: {
+ code: 'USER_ENABLED_OR_DISABLED',
+ clearable: true,
+ style: 'width:100%',
+ },
+ },
+ ],
+ },
+ ],
+ form: [
+ { label: '商户名称:', id: 'name', type: 'input' },
+ { label: '商户昵称:', id: 'nickName', type: 'input' },
+ { label: '所属合伙人:', id: 'partnerName', type: 'input' },
+ { label: '地址:', id: 'area', type: 'input' },
+ { label: '联系方式:', id: 'tel', type: 'input' },
+ ],
+ extraDialogs: [
+ {
+ title: '变更合伙人',
+ hiddenReverseItems: [],
+ form: [
+ {
+ ...getPartnerListConfig(),
+ label: '所属合伙人:',
+ },
+ ],
+ atConfirm: async (val) => {
+ const { code } = await this.$elBusHttp.request(
+ 'flower/api/customer/change/partner',
+ {
+ method: 'post',
+ data: val,
+ }
+ )
+ if (code === 0) {
+ this.$message.success('变更合伙人成功')
+ }
+ },
+ },
+ ],
+ extraButtons: [
+ {
+ text: '变更合伙人',
+ atClick: (row) => {
+ this.$refs.crud.$refs.extraDialog[0].show(row)
+ return false
+ },
+ },
+ ],
+ },
+ }
+ },
+ head() {
+ return {
+ title: '商户列表',
+ }
+ },
+ methods: {
+ getDistrict(row) {
+ return `${row.province || ''}${row.city || ''}${row.region || ''}${
+ row.address || ''
+ }`
+ },
+ onEnabledChange(row, e) {
+ const url = 'flower/api/customer/page/isEnable'
+ const text = e ? '启用' : '禁用'
+ this.$elBusUtil
+ .confirm(`确定要${text}这个商户吗?`)
+ .then(async () => {
+ const { code } = await this.$elBusHttp.request(url, {
+ params: {
+ id: row.id,
+ },
+ })
+ if (code === 0) {
+ this.$message.success(`${text}成功`)
+ this.$refs.crud.getList()
+ }
+ })
+ .catch(() => {})
+ },
+ },
+}
+</script>
diff --git a/pages/sms/send-batch/_id.vue b/pages/sms/send-batch/_id.vue
new file mode 100644
index 0000000..0dec0e2
--- /dev/null
+++ b/pages/sms/send-batch/_id.vue
@@ -0,0 +1,135 @@
+<template>
+ <div class="base-page-wrapper coupon-detail">
+ <el-bus-title title="基本信息" size="small" />
+ <!-- <el-bus-form ref="form" label-width="auto" :content="formContent" readonly class="readonly-form" /> -->
+ <el-form ref="form" label-width="100px">
+ <el-form-item label="模板名称:"> {{ statisticsData.smsTaskName || '' }} </el-form-item>
+ <el-form-item label="号码数量:"> {{ statisticsData.phoneNum || 0 }} </el-form-item>
+ </el-form>
+
+ <div class="base-page-wrapper__line"></div>
+ <el-bus-title title="发送结果" size="small" />
+ <div><el-row :gutter="20">
+ <el-col :span="3" class="mb-2">
+ <el-card>
+ <div class="statistic-title">发送号码数量</div>
+ <div class="statistic-num">{{ statisticsData.totalNum || 0 }}</div>
+ </el-card>
+ </el-col>
+ <el-col :span="3" class="mb-2">
+ <el-card>
+ <div class="statistic-title">成功</div>
+ <div class="statistic-num">{{ statisticsData.successNum || 0 }}</div>
+ </el-card>
+ </el-col>
+ <el-col :span="3" class="mb-2">
+ <el-card>
+ <div class="statistic-title">失败</div>
+ <div class="statistic-num">{{ statisticsData.failureNum || 0 }}</div>
+ </el-card>
+ </el-col>
+ <el-col :span="3" class="mb-2">
+ <el-card>
+ <div class="statistic-title">发送中</div>
+ <div class="statistic-num"> {{ statisticsData.sendingNum || 0 }} </div>
+ </el-card>
+ </el-col>
+
+ </el-row></div>
+ <div class="base-page-wrapper__line"></div>
+ <el-bus-title title="发放记录" size="small" />
+ <el-bus-crud v-bind="recordTableConfig" />
+ <!-- <div class="text-center mt-20">
+ <el-button class="min-w-100" @click="goBack">返回</el-button>
+ </div> -->
+ </div>
+</template>
+
+<script>
+export default {
+ data() {
+ return {
+ statisticsData:{},
+ recordTableConfig: {
+ url: `flower/v2/sms-task-detail/list`,
+ hasOperation: false,
+ hasNew: false,
+ extraQuery: {
+ smsTaskId: this.$route.params.id,
+ },
+ columns: [
+ { label: '接收号码', prop: 'phone' },
+ { label: '发送时间', prop: 'createTime' },
+ { label: '发送结果', prop: 'resultStr' },
+ { label: '失败原因', prop: 'failReason' },
+ ],
+ searchForm: [
+ {
+ type: 'row',
+ items: [
+ { label: '接收号码', id: 'phone', type: 'input', searchImmediately: true, },
+ {
+ label: '发送结果',
+ id: 'result',
+ type: 'bus-select-dict',
+ el: {
+ code: 'SMS_SEND_RESULT',
+ multiple: false,
+ style: 'width:100%',
+ clearable: true,
+ },
+ searchImmediately: true,
+ },
+ ],
+ },
+ ],
+ },
+ }
+ },
+ head() {
+ return {
+ title: '批量发送短信详情',
+ }
+ },
+ mounted() {
+ this.getInitData()
+ },
+ methods: {
+ async getInitData() {
+ const { code, data } = await this.$elBusHttp.request(
+ `flower/v2/sms-task-detail/taskStatistics/${this.$route.params.id}`,
+ {
+ method: 'get',
+ // params: {
+ // id: this.$route.params.id
+ // }
+ }
+ )
+ if (code === 0) {
+ console.log("data")
+ console.log(data)
+ this.statisticsData = data
+ }
+ },
+ },
+}
+</script>
+
+<style lang="scss" scoped>
+@import '@/assets/coupon/detail.scss';
+@import '@/assets/statistic/index.scss';
+
+.statistic-title {
+ text-align: center;
+ font-size: 16px;
+ color: $main-title-color;
+ font-weight: bold;
+ margin-bottom: 6px;
+}
+
+.statistic-num {
+ text-align: center;
+ font-size: 16px;
+ color: $primary-color;
+}
+</style>
diff --git a/pages/sms/send-batch/index.vue b/pages/sms/send-batch/index.vue
new file mode 100644
index 0000000..7e639aa
--- /dev/null
+++ b/pages/sms/send-batch/index.vue
@@ -0,0 +1,353 @@
+<template>
+ <el-bus-crud ref="curd" v-bind="tableConfig" />
+</template>
+
+<script>
+import dayjs from 'dayjs'
+import 'dayjs/locale/zh-cn'
+import SelectAllUser from '@/components/sms/select-all-user'
+import CopyTextarea from '@/components/sms/copy-textarea'
+import TemplateDownload from '@/components/sms/template-download'
+export default {
+ data() {
+ const defaultDate = `${dayjs().format('YYYY-MM-DD')} 00:00:00`
+ return {
+ tableConfig: {
+ url: 'flower/v2/sms-task/list',
+ newUrl: 'flower/v2/sms-task/new',
+ editUrl: 'flower/v2/sms-task/edit',
+ viewUrl: 'flower/v2/sms-task',
+ viewOnPath: true,
+ deleteUrl: 'flower/v2/sms-task/delete',
+ hasNew: true,
+ newText: '添加发送任务',
+ dialogNeedRequest: true,
+ canEdit: (row) => row.status === 'wait_publish',
+ canDelete: (row) => row.status === 'wait_publish',
+ extraButtons: [
+ {
+ text: '发布',
+ show: (row) => {
+ return row.status === 'wait_publish';
+ },
+ atClick: async (row) => {
+ try {
+ await this.$elBusUtil.confirm('确定要发布吗?')
+ const { code } = await this.$elBusHttp.request(
+ `flower/v2/sms-task/publish`,
+ {
+ method: 'post',
+ data: {
+ id: row.id,
+ }
+ }
+ )
+ if (code === 0) {
+ this.$message.success('发布成功')
+ }
+ } catch (e) {
+ return false
+ }
+ },
+ },
+ ],
+ onResetView: (row) => {
+ // this.$router.push(`${this.$route.path}/${row.id}`)
+ this.$router.push(`${this.$route.path}/${row.id}`)
+
+ // const url = this.$router.resolve(
+ // `/sms/send-batch/${row.id}`
+ // ).href
+ // window.open(url, '_blank')
+
+ },
+ columns: [
+ { label: '任务名称', prop: 'name' },
+ { label: '模板名称', prop: 'smsTemplateName' },
+ { label: '模板描述', prop: 'smsTemplateDesc' },
+ { label: '任务状态', prop: 'statusStr' },
+ { label: '创建时间', prop: 'createTime' },
+ ],
+ searchForm: [
+ {
+ type: 'row',
+ items: [
+ { label: '任务名称', id: 'name', type: 'input' },
+ { label: '模板名称', id: 'smsTemplateName', type: 'input' },
+ {
+ label: '任务状态',
+ id: 'status',
+ type: 'bus-select-dict',
+ el: {
+ code: 'SMS_TASK_STATUS',
+ multiple: false,
+ style: 'width:100%',
+ },
+ },
+ {
+ label: '创建时间',
+ id: 'startDate',
+ component: 'el-bus-date-range',
+ el: {
+ clearable: true,
+ },
+ // commonFormat: true,
+ // commonFormatProps: ['startDate', 'endDate'],
+ inputFormat: (row) => {
+ if ('startDate' in row || 'endDate' in row) {
+ return [
+ this.$elBusUtil.toDate(row.startDate),
+ this.$elBusUtil.toDate(row.endDate),
+ ]
+ }
+ },
+ outputFormat: (val) => {
+ return {
+ startDate: val[0] ? `${this.$elBusUtil.toDate(val[0])} 00:00:00` : undefined,
+ endDate: val[1] ? `${this.$elBusUtil.toDate(val[1])} 23:59:59` : undefined,
+ }
+ },
+ customClass: 'in-bus-form',
+ // commonRules: true,
+ // default: [defaultDate, defaultDate],
+ },
+
+ ],
+ },
+ ],
+ form: [
+ {
+ label: '任务名称',
+ id: 'name',
+ type: 'input',
+ rules: {
+ required: true,
+ message: '请输入任务名称',
+ trigger: 'blur',
+ },
+ },
+ {
+ label: '短信模板:',
+ id: 'smsTemplateId',
+ type: 'bus-select',
+ el: {
+ interfaceUri: 'flower/v2/sms-template/templateName/all',
+ extraQuery: {
+ current: 1,
+ size: 2000,
+ },
+ props: {
+ label: 'name',
+ value: 'id',
+ // dataPath: 'data',
+ },
+ filterable: true,
+ multiple: false,
+ style: 'width:100%',
+ },
+ rules: {
+ required: true,
+ message: '请选择短信模板',
+ trigger: 'change',
+ },
+ },
+ {
+ label: '接收号码:',
+ id: 'type',
+ type: 'bus-radio',
+ el: {
+ code: 'SMS_RECEIVE_TYPE',
+ // hasAll: false,
+ // childType: 'el-radio-button',
+ },
+ str: true,
+ on: {
+ change: (e, updateForm, obj) => {
+ // updateForm({
+ // // fileUrl: undefined,
+ // // fileUrlDesc: undefined,
+ // // pointCostomIdList: undefined,
+ // // input: undefined,
+ // })
+ },
+ },
+ default: this.$route.query.status || '',
+ span: 24,
+ searchImmediately: true,
+ rules: {
+ required: true,
+ message: '请输入接收号码',
+ trigger: 'change',
+ },
+ },
+ {
+ label: '导入接收文件',
+ id: 'fileUrl',
+ component: 'el-bus-upload',
+ el: {
+ // listType: 'text',
+ accept: ".xls,.xlsx",
+ limit: 1
+ },
+ commonFormat: true,
+ forceDisabled: true,
+ hidden: (row) => {
+ return row.type !== 'IMPORT'
+ },
+ readonly: false,
+ rules: [
+ { required: true, message: '请上传文件' },
+ {
+ validator: (rule, value, callback) => {
+ if (!value || value.length > 1) {
+ callback(new Error('只能上传一个文件'));
+ } else {
+ callback();
+ }
+ },
+ trigger: 'change',
+ },
+ ],
+ // outputFormat: (val) => {
+ // console.log(val)
+ // return '';
+ // },
+ },
+ {
+ label: '',
+ id: 'fileUrlDesc',
+ component: TemplateDownload,
+ hidden: (row) => row.type !== 'IMPORT',
+ },
+ {
+ label: '手动输入:',
+ id: 'phones',
+ component: CopyTextarea,
+ el: {
+ type: 'textarea',
+ },
+ // hidden: (row) => row.discountType !== 'ratio',
+ hidden: (row) => row.type !== 'INPUT',
+ readonly: false,
+ span: 24,
+ rules: [
+ { required: true, message: '请输入号码', trigger: 'blur,change', },
+ // {
+ // validator: (rule, value, callback) => {
+ // // 如果值为空,直接返回错误
+ // if (!value || value.trim() === '') {
+ // callback(new Error('请输入电话号码,每个号码后跟换行符'));
+ // return;
+ // }
+
+ // // 正则表达式:只匹配中国大陆手机号格式
+ // const phoneRegex = /^1[3-9]\d{9}$/;
+ // const lines = value.split('\n'); // 按换行符分割文本
+
+ // // 遍历每一行并校验
+ // for (let i = 0; i < lines.length; i++) {
+ // const line = lines[i]; // 每一行去除空格
+ // if (line && !phoneRegex.test(line)) {
+ // // 如果当前行的电话号码格式不正确,提示出错的行号
+ // callback(new Error(`第 ${i + 1} 行电话号码格式不正确,请检查输入, 如 电话号码后面有空格等`));
+ // return; // 一旦发现不符合的号码格式,就终止校验
+ // }
+ // }
+
+ // if(lines.length>100){
+ // callback(new Error(`手动输入最多支持100个号码`));
+ // }
+
+ // // 所有行都符合格式,执行 callback()
+ // callback();
+ // },
+ // trigger: 'blur',
+ // }
+ {
+ validator: (rule, value, callback) => {
+ // 如果值为空,直接返回错误
+ if (!value || value.trim() === '') {
+ callback(new Error('请输入电话号码,每个号码后跟换行符'));
+ return;
+ }
+
+
+
+ const phoneRegex = /^1[3-9]\d{9}$/; // 校验手机号格式
+ const lines = value.split('\n'); // 按换行符分割文本
+ const phoneCount = {}; // 用来统计电话号码出现次数
+
+ if (lines.length > 100) {
+ callback(new Error(`手动输入最多支持100个号码`));
+ }
+
+ // 校验每一行的电话号码
+ for (let i = 0; i < lines.length; i++) {
+ const line = lines[i].trim();
+ if (line) {
+ // 如果当前行不是空的,校验其格式
+ if (!phoneRegex.test(line)) {
+ callback(new Error(`第 ${i + 1} 行电话号码格式不正确,请检查输入`));
+ return;
+ }
+
+ // 统计号码出现的次数
+ phoneCount[line] = (phoneCount[line] || 0) + 1;
+ }
+ }
+
+
+ // 收集所有重复的电话号码
+ const duplicates = [];
+ for (const phone in phoneCount) {
+ if (phoneCount[phone] > 1) {
+ duplicates.push(`${phone} 重复了 ${phoneCount[phone]} 次`);
+ }
+ }
+
+
+ // 如果有重复号码,返回错误并列出所有重复的号码
+ if (duplicates.length > 0) {
+ callback(new Error(`以下电话号码重复:\n${duplicates.join('\n')}`));
+ return;
+ }
+
+ // 校验通过
+ callback();
+ },
+ trigger: 'blur',
+ }
+
+ ],
+
+ },
+
+ {
+ label: '选择用户列表',
+ id: 'smsUserDTOS',
+ component: SelectAllUser,
+ hidden: (row) => row.type !== 'SELECT',
+ rules: { required: true, message: '请选择领取用户' },
+ inputFormat: (row) => {
+ if ('smsUserDTOS' in row && row.smsUserDTOS && row.smsUserDTOS.length>0) {
+ return row.smsUserDTOS.filter((i) => i)
+ }
+ },
+ outputFormat: (val) => {
+ return val?.length ? val.map((i) => {return {userId:i.userId,userPhone:i.tel} }) : []
+
+ },
+ forceDisabled: true,
+ },
+ ],
+ },
+ }
+ },
+ head() {
+ return {
+ title: '批量发送短信',
+ }
+ },
+
+}
+</script>
diff --git a/pages/sms/template/index.vue b/pages/sms/template/index.vue
new file mode 100644
index 0000000..2db0779
--- /dev/null
+++ b/pages/sms/template/index.vue
@@ -0,0 +1,123 @@
+<template>
+ <el-bus-crud v-bind="tableConfig" />
+</template>
+
+<script>
+import dayjs from 'dayjs'
+import 'dayjs/locale/zh-cn'
+export default {
+ data() {
+ const defaultDate = `${dayjs().format('YYYY-MM-DD')} 00:00:00`
+ return {
+ tableConfig: {
+ url: 'flower/v2/sms-template/list',
+ newUrl: 'flower/v2/sms-template/new',
+ deleteUrl: 'flower/v2/sms-template/delete',
+ editUrl: 'flower/v2/sms-template/edit',
+ columns: [
+ { label: 'ID', prop: 'id' },
+ { label: 'CODE', prop: 'code' },
+ { label: '模板名称', prop: 'name' },
+ { label: '模板描述', prop: 'description' },
+ { label: '创建时间', prop: 'createTime' },
+ ],
+ searchForm: [
+ {
+ type: 'row',
+ items: [
+ { label: 'ID', id: 'id', type: 'input' },
+ { label: 'CODE', id: 'code', type: 'input' },
+ { label: '模板名称', id: 'name', type: 'input' },
+ {
+ label: '创建时间',
+ id: 'startDate',
+ component: 'el-bus-date-range',
+ el: {
+ clearable: true,
+ },
+ // commonFormat: true,
+ commonFormatProps: ['startDate', 'endDate'],
+ inputFormat: (row) => {
+ if ('startDate' in row || 'endDate' in row) {
+ return [
+ this.$elBusUtil.toDate(row.startDate),
+ this.$elBusUtil.toDate(row.endDate),
+ ]
+ }
+ },
+ outputFormat: (val) => {
+ return {
+ startDate:val[0] ? `${this.$elBusUtil.toDate(val[0])} 00:00:00`: undefined,
+ endDate: val[1] ?`${this.$elBusUtil.toDate(val[1])} 23:59:59`: undefined,
+ }
+ },
+ customClass: 'in-bus-form',
+ // commonRules: true,
+ // default: [defaultDate, defaultDate],
+ },
+ ],
+ },
+ ],
+ form: [
+ {
+ label: 'CODE:',
+ id: 'code',
+ type: 'bus-select',
+ el: {
+ interfaceUri: 'flower/v2/sms-template/aliyun/list',
+ extraQuery: {
+ current: 1,
+ size: 2000,
+ },
+ props: {
+ label: 'templateName',
+ value: 'templateCode',
+ // dataPath: 'records',
+ },
+ filterable: true,
+ multiple: false,
+ style: 'width:100%',
+ },
+ rules: {
+ required: true,
+ message: '请选择CODE',
+ trigger: 'blur',
+ },
+ },
+
+ {
+ label: '模板名称:',
+ id: 'name',
+ type: 'input',
+ rules: {
+ required: true,
+ message: '请输入模板名称',
+ trigger: 'blur',
+ },
+ },
+ {
+ label: '模板描述:',
+ id: 'description',
+ type: 'input',
+ el: {
+ type: 'textarea',
+ rows: 6,
+ },
+ rules: {
+ required: true,
+ message: '请输入模板描述',
+ trigger: 'blur',
+ },
+ },
+
+ ],
+ },
+ }
+ },
+ head() {
+ return {
+ title: '短信模板维护',
+ }
+ },
+}
+</script>
diff --git a/pages/statistics-analysis/flower-material/index.vue b/pages/statistics-analysis/flower-material/index.vue
new file mode 100644
index 0000000..3d1afba
--- /dev/null
+++ b/pages/statistics-analysis/flower-material/index.vue
@@ -0,0 +1,266 @@
+<template>
+ <div>
+ <div v-loading="statisticLoading">
+
+ <el-row :gutter="20">
+ <el-col :span="4" class="mb-10">
+ <el-card>
+ <div class="statistic-title">供应商数量</div>
+ <div class="statistic-num">
+ <!-- {{ statistic.discountTotalFee || 0 }} -->
+ {{ statistic.supplierAmount || 0 }}
+ </div>
+ </el-card>
+ </el-col>
+ <el-col :span="4" class="mb-10">
+ <el-card>
+ <div class="statistic-title">商品总数</div>
+ <div class="statistic-num">
+ {{ statistic.flowerAmount || 0 }}
+ </div>
+ </el-card>
+ </el-col>
+ <el-col :span="4" class="mb-10">
+ <el-card>
+ <div class="statistic-title">库存</div>
+ <div class="statistic-num">
+ {{ statistic.flowerStockAmount || 0 }}
+ </div>
+ </el-card>
+ </el-col>
+ </el-row>
+
+ </div>
+ <el-bus-crud ref="crud" v-bind="tableConfig"
+ :extra-query="extraQuery"
+ >
+ <template #header>
+ <div style="float: right;">
+ <el-select v-model="extraQuery.orderField" placeholder="排序字段" @change="changeQuery" size="mini" clearable >
+ <el-option v-for="item in dict.orderField" :key="item.value" :label="item.label" :value="item.value">
+ </el-option>
+ </el-select>
+ <el-select v-model="extraQuery.orderType" placeholder="排序方式" @change="changeQuery" size="mini" clearable>
+ <el-option v-for="item in dict.orderType" :key="item.value" :label="item.label" :value="item.value">
+ </el-option>
+ </el-select>
+ </div>
+ </template>
+ </el-bus-crud>
+ </div>
+</template>
+
+<script>
+import dayjs from 'dayjs'
+import 'dayjs/locale/zh-cn'
+import { getSupplierListWithIdConfig, getStationListConfig } from '@/utils/form-item-config'
+dayjs.locale('zh-cn')
+export default {
+
+
+
+ data() {
+ return {
+ extraQuery:{orderField:'', orderType: ''},
+ dict:{
+ orderFieldVal:'',
+ orderTypeVal:'',
+ orderField:[],
+ orderType:[],
+ },
+ statistic: {},
+ statisticLoading: false,
+ tableConfig: {
+ url: 'flower/v2/statistic-analysis/flower-material/page',
+ hasNew: false,
+ hasEdit: false,
+ hasDelete: false,
+ viewText: '明细',
+ hasExport: true,
+ hasOperation: false,
+ exportUrl: 'flower/v2/statistic-analysis/flower-material/export',
+ exportText: '导出',
+ onResetView: (row) => {
+ const searchFormRef = this.$refs.crud.$refs.searchForm
+ const searchFormValue = searchFormRef.getFormValue()
+ const url = this.$router.resolve(
+ `/report/finance/${row.orderDate}?partnerId=${searchFormValue?.partnerId || ''
+ }`
+ ).href
+ window.open(url, '_blank')
+ },
+ // operationAttrs: {
+ // width: 80,
+ // fixed: 'right',
+ // },
+ beforeRequest: async (params) => {
+ this.statisticLoading = true
+ // eslint-disable-next-line
+ let { code, data } = await this.$elBusHttp.request(
+ `flower/v2/statistic-analysis/flower-material/statis`,
+ { params }
+ )
+ if (code === 0) {
+ data = data || {}
+ this.statistic = data || {}
+ }
+ this.statisticLoading = false
+ },
+ columns: [
+ { label: '供应商ID', prop: 'supplierId', minWidth: '120px' },
+ {
+ label: '供应商名称', prop: 'supplierName', minWidth: '120px',
+ // fixed: 'left',
+ },
+ { label: '注册手机号', prop: 'loginName', minWidth: '120px' },
+ { label: '联系方式', prop: 'contactTel', minWidth: '120px' },
+ { label: '所属集货站', prop: 'stationName', minWidth: '120px' },
+ // { label: '品类', prop: 'categoryName', minWidth: '120px' },
+ { label: '品类', prop: 'parentCategoryName', minWidth: '120px' },
+
+ { label: '商品名称', prop: 'flowerName', minWidth: 150, },
+ { label: '等级', prop: 'flowerLevelStr', minWidth: 80 },
+ { label: '商品规格', prop: 'flowerUnit', minWidth: 80 },
+ { label: '价格', prop: 'flowerPrice', minWidth: 120 },
+ { label: '库存', prop: 'flowerStock', minWidth: 120 },
+ { label: '状态', prop: 'flowerStatusStr', minWidth: 120 },
+
+ ],
+ searchFormAttrs: {
+ labelWidth: 'auto',
+ },
+ searchForm: [
+ {
+ type: 'row',
+ items: [
+ {
+ label: '商品状态:',
+ id: 'flowerStatus',
+ type: 'bus-radio',
+ el: {
+ code: 'FLOWER_STATUS',
+ hasAll: true,
+ childType: 'el-radio-button',
+ },
+ default: this.$route.query.status || '',
+ span: 24,
+ searchImmediately: true,
+ },
+ // { ...getSupplierListWithIdConfig(), label: '供应商' },
+ { label: '供应商名称', id: 'supplierName', type: 'input' },
+ { label: '供应商ID', id: 'supplierId', type: 'input' },
+ { label: '注册手机号', id: 'loginName', type: 'input' },
+ { label: '联系方式', id: 'contactTel', type: 'input' },
+ {
+ ...getStationListConfig(),
+ label: '所属集货站',
+ },
+ {
+ label: '商品分类',
+ id: 'flowerCategory',
+ type: 'bus-cascader',
+ el: {
+ otherInterfaceUri: 'flower/api/flower/category/tree',
+ props: {
+ label: 'name',
+ value: 'id',
+ emitPath: false,
+ checkStrictly: true,
+ },
+ clearable: true,
+ filterable: true,
+ style: 'width:100%',
+ },
+ },
+ {
+ label: '等级',
+ id: 'flowerLevel',
+ type: 'bus-select-dict',
+ el: {
+ code: 'FLOWER_LEVEL',
+ // multiple: true,
+ clearable: true,
+ filterable: true,
+ style: 'width:100%',
+ },
+
+ },
+ // {
+ // label: '排序字段',
+ // id: 'orderField',
+ // type: 'bus-select-dict',
+ // el: {
+ // code: 'FLOWER_MATERIAL_FIELD',
+ // // multiple: true,
+ // clearable: true,
+ // filterable: true,
+ // style: 'width:100%',
+ // },
+
+ // },
+ // {
+ // label: '排序方式',
+ // id: 'orderType',
+ // type: 'bus-select-dict',
+ // el: {
+ // code: 'ORDER_BY',
+ // // multiple: true,
+ // clearable: true,
+ // filterable: true,
+ // style: 'width:100%',
+ // },
+
+ // },
+
+ ],
+ },
+ ],
+ },
+ }
+ },
+
+ async mounted() {
+ this.dict.orderField=await this.getDictByType('FLOWER_MATERIAL_FIELD');
+ this.dict.orderType=await this.getDictByType('ORDER_BY');
+ },
+ methods: {
+
+ changeQuery(){
+ this.$refs.crud.getList()
+ },
+ async getDictByType(typename) {
+ const resp = await this.$elBusHttp.request('flower/api/code/value', {
+ params: {type:typename},
+ });
+ if (resp.code === 0) {
+ return resp.data
+ }
+ },
+
+ },
+
+ head() {
+ return {
+ title: '财务报表',
+ }
+ },
+}
+</script>
+
+<style lang="scss" scoped>
+@import '@/assets/statistic/index.scss';
+
+.statistic-title {
+ text-align: center;
+ font-size: 16px;
+ color: $main-title-color;
+ font-weight: bold;
+ margin-bottom: 6px;
+}
+
+.statistic-num {
+ text-align: center;
+ font-size: 16px;
+ color: $primary-color;
+}
+</style>
diff --git a/pages/statistics-analysis/flower-sale/index.vue b/pages/statistics-analysis/flower-sale/index.vue
new file mode 100644
index 0000000..c4cbd86
--- /dev/null
+++ b/pages/statistics-analysis/flower-sale/index.vue
@@ -0,0 +1,301 @@
+<template>
+ <div>
+ <div v-loading="statisticLoading">
+
+ <el-row :gutter="20">
+ <el-col :span="4" class="mb-10">
+ <el-card>
+ <div class="statistic-title">销售金额</div>
+ <div class="statistic-num">
+ <!-- {{ statistic.discountTotalFee || 0 }} -->
+ {{ statistic.saleAmount || 0 }}
+ </div>
+ </el-card>
+ </el-col>
+ <el-col :span="4" class="mb-10">
+ <el-card>
+ <div class="statistic-title">销售扎数</div>
+ <div class="statistic-num">
+ {{ statistic.saleNum || 0 }}
+ </div>
+ </el-card>
+ </el-col>
+ <el-col :span="4" class="mb-10">
+ <el-card>
+ <div class="statistic-title">商品总数</div>
+ <div class="statistic-num">
+ {{ statistic.goodsNum || 0 }}
+ </div>
+ </el-card>
+ </el-col>
+ <el-col :span="4" class="mb-10">
+ <el-card>
+ <div class="statistic-title">缺货扎数</div>
+ <div class="statistic-num">
+ {{ statistic.lackNum || 0 }}
+ </div>
+ </el-card>
+ </el-col>
+ <el-col :span="4" class="mb-10">
+ <el-card>
+ <div class="statistic-title">补货扎数</div>
+ <div class="statistic-num">
+ {{ statistic.replaceNum || 0 }}
+ </div>
+ </el-card>
+ </el-col>
+ <el-col :span="4" class="mb-10">
+ <el-card>
+ <div class="statistic-title">降级扎数</div>
+ <div class="statistic-num">
+ {{ statistic.reduceNum || 0 }}
+ </div>
+ </el-card>
+ </el-col>
+ </el-row>
+
+ </div>
+ <el-bus-crud ref="crud" v-bind="tableConfig"
+ :extra-query="extraQuery"
+ >
+ <template #header>
+ <div style="float: right;">
+ <el-select v-model="extraQuery.orderField" placeholder="排序字段" @change="changeQuery" size="mini" clearable >
+ <el-option v-for="item in dict.orderField" :key="item.value" :label="item.label" :value="item.value">
+ </el-option>
+ </el-select>
+ <el-select v-model="extraQuery.orderType" placeholder="排序方式" @change="changeQuery" size="mini" clearable>
+ <el-option v-for="item in dict.orderType" :key="item.value" :label="item.label" :value="item.value">
+ </el-option>
+ </el-select>
+ </div>
+ </template>
+ </el-bus-crud>
+ </div>
+</template>
+
+<script>
+import dayjs from 'dayjs'
+import 'dayjs/locale/zh-cn'
+import {getStationListConfig} from '@/utils/form-item-config'
+
+dayjs.locale('zh-cn')
+export default {
+ data() {
+ const currentDate = this.$elBusUtil.toDate(new Date())
+ return {
+ extraQuery:{orderField:'', orderType: ''},
+ dict:{
+ orderFieldVal:'',
+ orderTypeVal:'',
+ orderField:[],
+ orderType:[],
+ },
+ statistic: {},
+ statisticLoading: false,
+ tableConfig: {
+ url: 'flower/v2/statistic-analysis/flower-sale/page',
+ hasNew: false,
+ hasEdit: false,
+ hasDelete: false,
+ hasOperation: false,
+ hasExport: true,
+ exportUrl: 'flower/v2/statistic-analysis/flower-sale/export',
+ exportText: '导出',
+ onResetView: (row) => {
+
+ },
+ // operationAttrs: {
+ // width: 80,
+ // fixed: 'right',
+ // },
+ beforeRequest: async (params) => {
+ this.statisticLoading = true
+ // eslint-disable-next-line
+ let {code, data} = await this.$elBusHttp.request(
+ `flower/v2/statistic-analysis/flower-sale/statistics`,
+ {params}
+ )
+ if (code === 0) {
+ data = data || {}
+ this.statistic = data || {}
+ }
+ this.statisticLoading = false
+ },
+ columns: [
+ {label: '供应商ID', prop: 'supplierId', minWidth: 120},
+ {label: '供应商名称', prop: 'supplierName', minWidth: 120},
+ {label: '注册手机号', prop: 'registerTel', minWidth: 120},
+ {label: '联系方式', prop: 'registerTel', minWidth: 120},
+ {label: '集货站', prop: 'stationName', minWidth: 120},
+ {label: '品类', prop: 'flowerCategoryName', minWidth: 160},
+ {label: '商品名称', prop: 'flowerName', minWidth: 150},
+ {label: '等级', prop: 'flowerLevel', minWidth: 80},
+ {label: '规格', prop: 'flowerUnit', minWidth: 80},
+ {label: '底价', prop: 'supplierPrice', minWidth: 120},
+ {label: '售价', prop: 'price', minWidth: 120},
+ {label: '销售扎数', prop: 'num', minWidth: 120},
+ {label: '销售地址', prop: 'address', minWidth: 220},
+ {label: '支付时间', prop: 'paymentTime', minWidth: 160},
+ {
+ label: '订单号',
+ prop: 'orderNo',
+ minWidth: 180,
+ formatter: (row) => (
+ <el-link
+ type="primary"
+ onClick={() => this.handleOrderClick(row.orderId)}
+ >
+ {row.orderNo}
+ </el-link>
+ ),
+ },
+
+ {label: '缺货扎数', prop: 'lackNum', minWidth: 120},
+ {label: '补货扎数', prop: 'replaceNum', minWidth: 120},
+ {label: '降级扎数', prop: 'reduceNum', minWidth: 120},
+
+ ],
+ searchFormAttrs: {
+ labelWidth: 'auto',
+ },
+ searchForm: [
+ {
+ type: 'row',
+ items: [
+ {
+ label: '供应商ID', id: 'supplierId', type: 'input',
+ rules: {
+ required: false,
+ pattern: /^\d*$/,
+ message: '请输入合法的供应商ID',
+ trigger: 'blur',
+ },
+ },
+ {label: '供应商名称', id: 'supplierName', type: 'input'},
+ {
+ label: '注册手机号', id: 'registerTel', type: 'input',
+ },
+ {
+ label: '联系方式', id: 'contactTel', type: 'input',
+ },
+ {
+ ...getStationListConfig(),
+ label: '所属集货站',
+ },
+ {
+ label: '商品分类',
+ id: 'flowerCategory',
+ type: 'bus-cascader',
+ el: {
+ otherInterfaceUri: 'flower/api/flower/category/tree',
+ props: {
+ label: 'name',
+ value: 'id',
+ emitPath: false,
+ checkStrictly: true,
+ },
+ clearable: true,
+ filterable: true,
+ style: 'width:100%',
+ },
+ },
+ {
+ label: '等级:',
+ id: 'flowerLevel',
+ type: 'bus-select-dict',
+ el: {
+ code: 'FLOWER_LEVEL',
+ // multiple: true,
+ clearable: true,
+ filterable: true,
+ style: 'width:100%',
+ },
+
+ },
+ {label: '订单号', id: 'orderNo', type: 'input'},
+ {
+ label: '日期',
+ id: 'createDateBeginStr',
+ component: 'el-bus-date-range',
+ el: {
+ clearable: false,
+ },
+ commonFormat: true,
+ commonFormatProps: ['createStartDateStr', 'createEndDateStr'],
+ customClass: 'in-bus-form',
+ default: [currentDate, currentDate],
+ },
+ {
+ label: '地区:',
+ id: 'customerProvince',
+ component: 'el-bus-select-area',
+ span: 24,
+ commonFormat: true,
+ commonFormatProps: [
+ 'customerProvince',
+ 'customerCity',
+ 'customerRegion',
+ ],
+ str: true,
+ strKey: 'districtStr',
+ rules: {required: false, message: '请选择地区'},
+ },
+
+
+ ],
+ },
+ ],
+ },
+ }
+ },
+ async mounted() {
+ this.dict.orderField=await this.getDictByType('FLOWER_SALE_FIELD');
+ this.dict.orderType=await this.getDictByType('ORDER_BY');
+ },
+ methods: {
+
+ changeQuery(){
+ this.$refs.crud.getList()
+ },
+ async getDictByType(typename) {
+ const resp = await this.$elBusHttp.request('flower/api/code/value', {
+ params: {type:typename},
+ });
+ if (resp.code === 0) {
+ return resp.data
+ }
+ },
+ handleOrderClick(orderId) {
+ if (orderId) {
+ this.$router.push(`/order/list/${orderId}`)
+ }
+ },
+
+ },
+ head() {
+ return {
+ title: '花材销售统计',
+ }
+ },
+}
+</script>
+
+<style lang="scss" scoped>
+@import '@/assets/statistic/index.scss';
+
+.statistic-title {
+ text-align: center;
+ font-size: 16px;
+ color: $main-title-color;
+ font-weight: bold;
+ margin-bottom: 6px;
+}
+
+.statistic-num {
+ text-align: center;
+ font-size: 16px;
+ color: $primary-color;
+}
+
+</style>
diff --git a/pages/supplier/collection-station.vue b/pages/supplier/collection-station.vue
new file mode 100644
index 0000000..9b30d30
--- /dev/null
+++ b/pages/supplier/collection-station.vue
@@ -0,0 +1,146 @@
+<template>
+ <el-bus-crud v-bind="tableConfig" />
+</template>
+
+<script>
+export default {
+ data() {
+ return {
+ tableConfig: {
+ url: 'flower/api/station/page',
+ newUrl: 'flower/api/station/add',
+ editUrl: 'flower/api/station/update',
+ deleteUrl: 'flower/api/station/delete',
+ deleteOnPath: true,
+ deleteMethodType: 'post',
+ operationAttrs: {
+ width: 150,
+ fixed: 'right',
+ },
+ columns: [
+ { label: '集货站名称', prop: 'name', minWidth: 150, fixed: 'left' },
+ { label: '集货站类型', prop: 'typeStr', minWidth: 100 },
+ { label: '地址', prop: 'address', minWidth: 200 },
+ { label: '运费(元)', prop: 'freight', minWidth: 100 },
+ { label: '质检人员', prop: 'userNames', minWidth: 150 },
+ { label: '联系人', prop: 'contactName', minWidth: 100 },
+ { label: '联系方式', prop: 'contactTel', minWidth: 120 },
+ ],
+ searchForm: [
+ {
+ type: 'row',
+ items: [{ label: '集货站名称', id: 'name', type: 'input' }],
+ },
+ ],
+ form: [
+ {
+ label: '集货站名称:',
+ id: 'name',
+ type: 'input',
+ rules: {
+ required: true,
+ message: '请输入集货站名称',
+ trigger: 'blur',
+ },
+ },
+ {
+ label: '集货站类型:',
+ id: 'type',
+ type: 'bus-radio',
+ el: {
+ code: 'station_type',
+ style: 'width:100%',
+ },
+ str: true,
+ rules: { required: true, message: '请选择集货站类型' },
+ on: {
+ change: (e, updateForm) => {
+ updateForm({ freight: undefined })
+ },
+ },
+ },
+ {
+ label: '集货站地址:',
+ id: 'address',
+ type: 'input',
+ rules: {
+ required: true,
+ message: '请输入集货站地址',
+ trigger: 'blur',
+ },
+ },
+ {
+ label: '运费:',
+ id: 'freight',
+ type: 'input-number',
+ el: {
+ controls: false,
+ min: 0,
+ precision: 2,
+ },
+ unit: '元',
+ rules: { required: true, message: '请输入运费', trigger: 'blur' },
+ hidden: (row) => row.type !== '1',
+ },
+ {
+ label: '质检人员:',
+ id: 'userIds',
+ type: 'bus-select',
+ el: {
+ interfaceUri: 'flower/api/user/list',
+ extraQuery: {
+ current: 1,
+ size: 2000,
+ },
+ props: {
+ label: 'nickName',
+ value: 'id',
+ dataPath: 'records',
+ },
+ filterable: true,
+ multiple: true,
+ style: 'width:100%',
+ },
+ inputFormat: (row) => {
+ if ('userIds' in row) {
+ return row.userIds ? row.userIds.split(',') : []
+ }
+ },
+ outputFormat: (val) => {
+ return Array.isArray(val) && val.length > 0 ? val.join(',') : null
+ },
+ str: true,
+ strKey: 'userNames',
+ rules: { required: true, message: '请选择质检人员' },
+ },
+ {
+ label: '联系人:',
+ id: 'contactName',
+ type: 'input',
+ rules: {
+ required: true,
+ message: '请输入联系人',
+ trigger: 'blur',
+ },
+ },
+ {
+ label: '联系方式:',
+ id: 'contactTel',
+ type: 'input',
+ rules: {
+ required: true,
+ message: '请输入联系方式',
+ trigger: 'blur',
+ },
+ },
+ ],
+ },
+ }
+ },
+ head() {
+ return {
+ title: '集货站管理',
+ }
+ },
+}
+</script>
diff --git a/pages/supplier/list.vue b/pages/supplier/list.vue
new file mode 100644
index 0000000..ef76953
--- /dev/null
+++ b/pages/supplier/list.vue
@@ -0,0 +1,393 @@
+<template>
+ <el-bus-crud ref="crud" v-bind="tableConfig" />
+</template>
+
+<script>
+import {
+ getStationListConfig,
+ getAuditForm,
+ getSupplierTypeListConfig,
+} from '@/utils/form-item-config'
+export default {
+ data() {
+ return {
+ tableConfig: {
+ url: 'flower/api/supplier/page',
+ editUrl: 'flower/api/supplier/page/update',
+ hasNew: false,
+ hasDelete: false,
+ operationAttrs: {
+ width: '200px',
+ fixed: 'right',
+ },
+ beforeOpen: (row, isNew) => {
+ if (!isNew) {
+ row.districtStr = this.getDistrict(row)
+ }
+ },
+ columns: [
+ { label: '供应商ID', prop: 'id', minWidth: '120px' },
+ {
+ label: '供应商名称',
+ prop: 'name',
+ minWidth: '120px',
+ // fixed: 'left',
+ },
+ { label: '供应商类型', prop: 'typeName', minWidth: '100px' },
+ {
+ label: '地区',
+ formatter: (row) =>
+ `${row.province || ''}${row.city || ''}${row.region || ''}${
+ row.address || ''
+ }`,
+ minWidth: '200px',
+ },
+ { label: '联系人', prop: 'contactName', minWidth: '100px' },
+ { label: '联系方式', prop: 'contactTel', minWidth: '120px' },
+ { label: '注册手机号', prop: 'registerTel', minWidth: '120px' },
+ { label: '注册时间', prop: 'createTime', minWidth: '180px' },
+ { label: '审核通过时间', prop: 'passTime', minWidth: '180px' },
+ { label: '所属集货站', prop: 'stationName', minWidth: '120px' },
+ { label: '状态', prop: 'statusStr', minWidth: '100px' },
+ {
+ label: '是否显示',
+ formatter: (row) => (
+ <el-switch
+ value={row.showed}
+ onChange={this.onShownChange.bind(this, row)}
+ ></el-switch>
+ ),
+ minWidth: 120,
+ fixed: 'right',
+ },
+ {
+ label: '启用/禁用',
+ formatter: (row) => (
+ <el-switch
+ value={row.isEnabled}
+ onChange={this.onEnabledChange.bind(this, row)}
+ ></el-switch>
+ ),
+ minWidth: 120,
+ fixed: 'right',
+ },
+ ],
+ searchForm: [
+ {
+ type: 'row',
+ items: [
+ {
+ label: '供应商ID', id: 'id', type: 'input',
+ rules: {
+ required: false,
+ pattern: /^\d*$/,
+ message: '请输入合法的供应商ID',
+ trigger: 'blur',
+ },
+ },
+ { label: '供应商名称', id: 'name', type: 'input' },
+ { label: '手机号', id: 'tel', type: 'input' },
+ {
+ label: '申请日期',
+ id: 'createDateBeginStr',
+ component: 'el-bus-date-range',
+ commonFormat: true,
+ commonFormatProps: ['createDateBeginStr', 'createDateEndStr'],
+ customClass: 'in-bus-form',
+ },
+ {
+ label: '审核状态',
+ id: 'status',
+ type: 'bus-select-dict',
+ el: {
+ code: 'supplier_status',
+ clearable: true,
+ style: 'width:100%',
+ },
+ },
+ {
+ ...getStationListConfig(),
+ label: '所属集货站',
+ },
+ {
+ label: '启用/禁用',
+ id: 'isEnabled',
+ type: 'bus-select-dict',
+ default: '1',
+ el: {
+ code: 'USER_ENABLED_OR_DISABLED',
+ clearable: true,
+ style: 'width:100%',
+ },
+ },
+ ],
+ },
+ ],
+ form: [
+ {
+ type: 'row',
+ span: 12,
+ items: [
+ {
+ label: '供应商名称:',
+ id: 'name',
+ type: 'input',
+ rules: {
+ required: true,
+ message: '请输入供应商名称',
+ trigger: 'blur',
+ },
+ },
+ {
+ ...getSupplierTypeListConfig(),
+ str: true,
+ strKey: 'typeName',
+ rules: {
+ required: true,
+ message: '请选择供应商类型',
+ },
+ },
+ {
+ label: '供应商头像:',
+ id: 'cover',
+ type: 'bus-upload',
+ el: {
+ listType: 'picture-card',
+ valueType: 'string',
+ limit: 1,
+ limitSize: 2,
+ tipText: '大小不超过2M',
+ },
+ forceDisabled: true,
+ rules: {
+ required: true,
+ message: '请上传供应商头像',
+ },
+ },
+ {
+ label: '地区:',
+ id: 'province',
+ component: 'el-bus-select-area',
+ span: 24,
+ commonFormat: true,
+ commonFormatProps: ['province', 'city', 'region'],
+ str: true,
+ strKey: 'districtStr',
+ rules: { required: true, message: '请选择地区' },
+ },
+ {
+ label: '详细地址:',
+ id: 'address',
+ type: 'input',
+ span: 24,
+ rules: {
+ required: true,
+ message: '请输入详细地址',
+ trigger: 'blur',
+ },
+ },
+ {
+ label: '联系人:',
+ id: 'contactName',
+ type: 'input',
+ rules: {
+ required: true,
+ message: '请输入联系人',
+ trigger: 'blur',
+ },
+ },
+ {
+ label: '联系方式:',
+ id: 'contactTel',
+ type: 'input',
+ rules: {
+ required: true,
+ message: '请输入联系方式',
+ trigger: 'blur',
+ },
+ },
+ {
+ ...getStationListConfig(),
+ rules: { required: true, message: '请选择所属集货站' },
+ },
+ {
+ label: '店铺简介:',
+ id: 'description',
+ type: 'input',
+ el: {
+ type: 'textarea',
+ rows: 4,
+ },
+ span: 24,
+ rules: {
+ required: true,
+ message: '请输入店铺简介',
+ trigger: 'blur',
+ },
+ },
+ {
+ id: 'idcardType',
+ type: 'input',
+ hidden: () => true,
+ },
+ {
+ label: '身份证正反面:',
+ id: 'idCards',
+ component: 'el-bus-upload',
+ el: {
+ listType: 'picture-card',
+ },
+ forceDisabled: true,
+ commonFormat: true,
+ span: 24,
+ hidden: (row) => row.idcardType !== '1',
+ rules: { required: true, message: '请上传身份证正反面' },
+ },
+ {
+ label: '营业执照:',
+ id: 'pictures',
+ component: 'el-bus-upload',
+ el: {
+ listType: 'picture-card',
+ },
+ forceDisabled: true,
+ commonFormat: true,
+ span: 24,
+ hidden: (row) => row.idcardType !== '2',
+ rules: { required: true, message: '请上传营业执照' },
+ },
+ ],
+ },
+ {
+ label: '状态:',
+ id: 'status',
+ type: 'input',
+ str: true,
+ readonly: true,
+ hidden: (row, item, mode) => mode !== 'view',
+ span: 24,
+ },
+ {
+ label: '不通过原因:',
+ id: 'rejectReason',
+ type: 'input',
+ el: {
+ type: 'textarea',
+ },
+ readonly: true,
+ hidden: (row, item, mode) => mode !== 'view' || row.status !== 'R',
+ span: 24,
+ },
+ ],
+ extraButtons: [
+ {
+ text: '审核',
+ show: (row) => row.status === 'U',
+ atClick: (row) => {
+ row.districtStr = this.getDistrict(row)
+ this.$refs.crud.$refs.extraDialog[0].show(row)
+ return false
+ },
+ },
+ {
+ text: '修改集货站',
+ atClick: (row) => {
+ this.$refs.crud.$refs.extraDialog[1].show(row)
+ return false
+ },
+ },
+ ],
+ extraDialogs: [
+ {
+ title: '审核',
+ readonly: true,
+ form: getAuditForm(),
+ atConfirm: async (val) => {
+ const { code } = await this.$elBusHttp.request(
+ 'flower/api/supplier/audit',
+ {
+ method: 'post',
+ data: {
+ ...val,
+ rejectReason: val.auditRejectReason,
+ },
+ }
+ )
+ if (code === 0) {
+ this.$message.success('操作成功')
+ }
+ },
+ },
+ {
+ title: '修改集货站',
+ hiddenReverseItems: [],
+ form: [
+ {
+ ...getStationListConfig(),
+ },
+ ],
+ atConfirm: async (val) => {
+ const { code } = await this.$elBusHttp.request(
+ 'flower/api/supplier/change/station',
+ {
+ method: 'post',
+ data: val,
+ }
+ )
+ if (code === 0) {
+ this.$message.success('操作成功')
+ }
+ },
+ },
+ ],
+ },
+ }
+ },
+ head() {
+ return {
+ title: '供应商列表',
+ }
+ },
+ methods: {
+ getDistrict(row) {
+ return `${row.province || ''}${row.city || ''}${row.region || ''}`
+ },
+ onShownChange(row, e) {
+ const url = 'flower/api/supplier/page/showed'
+ const text = e ? '显示' : '隐藏'
+ this.$elBusUtil
+ .confirm(`确定要${text}这个供应商的商品吗?`)
+ .then(async () => {
+ const { code } = await this.$elBusHttp.request(url, {
+ params: {
+ id: row.id,
+ },
+ })
+ if (code === 0) {
+ this.$message.success(`${text}成功`)
+ this.$refs.crud.getList()
+ }
+ })
+ .catch(() => {})
+ },
+ onEnabledChange(row, e) {
+ const url = 'flower/api/supplier/page/isEnable'
+ const text = e ? '启用' : '禁用'
+ this.$elBusUtil
+ .confirm(`确定要${text}这个供应商吗?`)
+ .then(async () => {
+ const { code } = await this.$elBusHttp.request(url, {
+ params: {
+ id: row.id,
+ },
+ })
+ if (code === 0) {
+ this.$message.success(`${text}成功`)
+ this.$refs.crud.getList()
+ }
+ })
+ .catch(() => {})
+ },
+ },
+}
+</script>
diff --git a/pages/supplier/sub-list.vue b/pages/supplier/sub-list.vue
new file mode 100644
index 0000000..0723fdd
--- /dev/null
+++ b/pages/supplier/sub-list.vue
@@ -0,0 +1,236 @@
+<template>
+ <el-bus-crud ref="crud" v-bind="tableConfig" />
+</template>
+
+<script>
+export default {
+ data() {
+ return {
+ tableConfig: {
+ url: 'flower/api/supplierSub/page',
+ editUrl: 'flower/api/supplierSub/addOrUpdate',
+ deleteUrl: 'flower/api/supplierSub/delete',
+ deleteOnPath: true,
+ deleteMethodType: 'post',
+ hasNew: false,
+ hasDelete: true,
+ operationAttrs: {
+ width: '200px',
+ fixed: 'right',
+ },
+ columns: [
+ { label: '序号', type: 'index' },
+ { label: '供应商ID', prop: 'supplierId', minWidth: '120px' },
+ {
+ label: '供应商名称',
+ prop: 'supplierName',
+ minWidth: '120px',
+ },
+ { label: '供应商联系人', prop: 'contactName', minWidth: '100px' },
+ { label: '主账号手机号', prop: 'contactTel', minWidth: '120px' },
+ { label: '子账号手机号', prop: 'phone', minWidth: '120px' },
+ { label: '子账号名', prop: 'name', minWidth: '120px' },
+ { label: '子账号联系人', prop: 'contact', minWidth: '120px' },
+ { label: '创建时间', prop: 'createTime', minWidth: '120px' },
+ {
+ label: '启用/禁用',
+ formatter: (row) => (
+ <el-switch
+ value={row.isEnabled}
+ onChange={this.onEnabledChange.bind(this, row)}
+ ></el-switch>
+ ),
+ minWidth: 120,
+ fixed: 'right',
+ },
+ ],
+ searchForm: [
+ {
+ type: 'row',
+ items: [
+ {
+ label: '供应商ID', id: 'supplierId', type: 'input',
+ rules: {
+ required: false,
+ pattern: /^\d*$/,
+ message: '请输入合法的供应商ID',
+ trigger: 'blur',
+ },
+ },
+ { label: '供应商名称', id: 'supplierName', type: 'input' },
+ { label: '主账号手机号', id: 'supplierPhone', type: 'input',
+ rules: {
+ required: false,
+ pattern: this.$elBusUtil.REG.MOBILEPHONE,
+ message: '请输入合法的手机号',
+ trigger: 'blur',
+ },
+ },
+ { label: '子账号手机号', id: 'phone', type: 'input',
+ rules: {
+ required: false,
+ pattern: this.$elBusUtil.REG.MOBILEPHONE,
+ message: '请输入合法的手机号',
+ trigger: 'blur',
+ },
+ },
+ {
+ label: '启用/禁用',
+ id: 'isEnabled',
+ type: 'bus-select-dict',
+ default: '1',
+ el: {
+ code: 'USER_ENABLED_OR_DISABLED',
+ clearable: true,
+ style: 'width:100%',
+ },
+ },
+ ],
+ },
+ ],
+ form: [
+ {
+ label: '供应商ID:',
+ id: 'supplierId',
+ type: 'input',
+ span: 12,
+ hidden: (row, item, mode) => mode !== 'view',
+ },
+ {
+ label: '供应商名称:',
+ id: 'supplierName',
+ type: 'input',
+ span: 12,
+ hidden: (row, item, mode) => mode !== 'view',
+ },
+ {
+ label: '供应商联系人:',
+ id: 'contactName',
+ type: 'input',
+ span: 12,
+ hidden: (row, item, mode) => mode !== 'view',
+ },
+ {
+ label: '主账号手机号:',
+ id: 'contactTel',
+ type: 'input',
+ span: 12,
+ hidden: (row, item, mode) => mode !== 'view',
+ },
+ {
+ type: 'row',
+ span: 12,
+ items: [
+ {
+ label: '子账号手机号:',
+ id: 'phone',
+ type: 'input',
+ rules: {
+ required: true,
+ pattern: this.$elBusUtil.REG.MOBILEPHONE,
+ message: '请输入合法的手机号',
+ trigger: 'blur',
+ },
+ },
+ {
+ label: '子账号名:',
+ id: 'name',
+ type: 'input',
+ rules: {
+ required: true,
+ message: '请输入子账号名',
+ trigger: 'blur',
+ },
+ },
+ {
+ label: '子账号联系人:',
+ id: 'contact',
+ type: 'input',
+ rules: {
+ required: true,
+ message: '请输入子账号联系人',
+ trigger: 'blur',
+ },
+ },
+ {
+ id: 'type',
+ default: '1',
+ },
+ ],
+ },
+
+ ],
+ extraButtons: [
+ {
+ text: '密码修改',
+ atClick: (row) => {
+ this.$refs.crud.$refs.extraDialog[0].show(row)
+ return false
+ },
+ },
+ ],
+ extraDialogs: [
+ {
+ title: '密码修改',
+ hiddenReverseItems: [],
+ form: [
+ {
+ label: '请输入新密码:',
+ id: 'password',
+ type: 'input',
+ rules: {
+ required: true,
+ pattern: /^(?:(?=\S*\d)(?=\S*[A-Z])(?=\S*[a-z])(?=\S*[-_!@#$%^&*? ]))\S{8,20}$/,
+ message: '请输入正确的密码(8-20位,包括至少1个大写字母,1个小写字母,1个数字,1个特殊字符)',
+ trigger: 'blur',
+ },
+ },
+ {
+ id: 'type',
+ default: '1',
+ },
+ ],
+ atConfirm: async (val) => {
+ const { code } = await this.$elBusHttp.request(
+ 'flower/api/supplierSub/addOrUpdate',
+ {
+ method: 'post',
+ data: val,
+ }
+ )
+ if (code === 0) {
+ this.$message.success('操作成功')
+ }
+ },
+ },
+ ],
+ },
+ }
+ },
+ head() {
+ return {
+ title: '子账号列表',
+ }
+ },
+ methods: {
+ onEnabledChange(row, e) {
+ const url = 'flower/api/supplierSub/page/isEnable'
+ const text = e ? '启用' : '禁用'
+ this.$elBusUtil
+ .confirm(`确定要${text}这个供应商吗?`)
+ .then(async () => {
+ const { code } = await this.$elBusHttp.request(url, {
+ params: {
+ id: row.id,
+ },
+ })
+ if (code === 0) {
+ this.$message.success(`${text}成功`)
+ this.$refs.crud.getList()
+ }
+ })
+ .catch(() => {})
+ },
+ },
+}
+</script>
diff --git a/pages/supplier/type.vue b/pages/supplier/type.vue
new file mode 100644
index 0000000..9932f2b
--- /dev/null
+++ b/pages/supplier/type.vue
@@ -0,0 +1,56 @@
+<template>
+ <el-bus-crud v-bind="tableConfig"></el-bus-crud>
+</template>
+
+<script>
+export default {
+ data() {
+ return {
+ tableConfig: {
+ url: 'flower/api/supplier/type/page',
+ newUrl: 'flower/api/supplier/type/add',
+ editUrl: 'flower/api/supplier/type/update',
+ deleteUrl: 'flower/api/supplier/type/delete',
+ deleteOnPath: true,
+ deleteMethodType: 'post',
+ columns: [
+ { label: '供应商类型', prop: 'name' },
+ { label: '类型说明', prop: 'description' },
+ ],
+ searchForm: [
+ {
+ type: 'row',
+ items: [{ label: '供应商类型', id: 'name', type: 'input' }],
+ },
+ ],
+ form: [
+ {
+ label: '供应商类型:',
+ id: 'name',
+ type: 'input',
+ rules: {
+ required: true,
+ message: '请输入供应商类型',
+ trigger: 'blur',
+ },
+ },
+ {
+ label: '类型说明:',
+ id: 'description',
+ type: 'input',
+ el: {
+ type: 'textarea',
+ rows: 6,
+ },
+ },
+ ],
+ },
+ }
+ },
+ head() {
+ return {
+ title: '供应商类型管理',
+ }
+ },
+}
+</script>
diff --git a/pages/sys/app-menu.vue b/pages/sys/app-menu.vue
new file mode 100644
index 0000000..e18e7e4
--- /dev/null
+++ b/pages/sys/app-menu.vue
@@ -0,0 +1,149 @@
+<template>
+ <div class="custom-crud-page">
+ <el-bus-crud ref="crud" v-bind="crudConfig"></el-bus-crud>
+ </div>
+</template>
+
+<script>
+export default {
+ data() {
+ return {
+ crudConfig: {
+ url: 'flower/api/app/menu/list',
+ hasPagination: false,
+ saveQuery: false,
+ isTree: true,
+ hasView: false,
+ deleteMessage: () => '此操作将会删除所有子菜单, 是否继续?',
+ beforeOpen(row, isNew) {
+ if (isNew && row.menuName) {
+ row.parentName = row.menuName
+ }
+ if (!isNew) {
+ row.parentName = ''
+ }
+ },
+ extraParentKeys: ['parentName'],
+ tableAttrs: {
+ rowKey: 'id',
+ },
+ columns: [
+ { label: '菜单名称', prop: 'menuName' },
+ {
+ label: '前端地址',
+ prop: 'menuHref',
+ },
+ {
+ label: '权限唯一标识',
+ prop: 'permissionUq',
+
+ },
+ {
+ label: '子账号权限',
+ formatter: (row) => (
+ <el-switch
+ value={row.subaccountAccessFlag===1}
+ onChange={this.onShownChange.bind(this, row)}
+ ></el-switch>
+ ),
+ },
+ {
+ label: '图标',
+ formatter: (row) =>
+ row.menuIcon ? (
+ <i class={row.menuIcon} aria-hidden="true" />
+ ) : null,
+ },
+ { label: '排序', prop: 'seq' },
+ ],
+ form: [
+ {
+ label: '父级节点:',
+ id: 'parentName',
+ type: 'input',
+ readonly: true,
+ hidden: (row) => !row.parentName,
+ },
+ {
+ label: '标题:',
+ id: 'menuName',
+ type: 'input',
+ el: { placeholder: '请输入标题' },
+ rules: { required: true, message: '请输入标题', trigger: 'blur' },
+ },
+ {
+ label: '权限唯一标识:',
+ id: 'permissionUq',
+ type: 'input',
+ el: { placeholder: '请输入权限唯一标识' },
+ rules: { required: true, message: '请输入权限唯一标识', trigger: 'blur' },
+ },
+ /* {
+ label: '子账号权限:',
+ formatter: (row) => (
+ <el-switch
+ value={row.subaccountAccessFlag===1}
+ onChange={this.onShownChange.bind(this, row)}
+ ></el-switch>
+ ),
+ }, */
+ {
+ label: '图标:',
+ id: 'menuIcon',
+ component: 'base-menu-icon',
+ },
+ {
+ label: '排序:',
+ id: 'seq',
+ type: 'input-number',
+ el: {
+ min: 0,
+ precision: 0,
+ controlsPosition: 'right',
+ placeholder: '请输入排序',
+ },
+ },
+ {
+ label: '前端地址:',
+ id: 'menuHref',
+ type: 'input',
+ el: { placeholder: '请输入前端地址' },
+ rules: {
+ required: true,
+ message: '请输入前端地址',
+ trigger: 'blur',
+ },
+ },
+ ],
+ },
+ }
+ },
+ head() {
+ return {
+ title: '菜单管理',
+ }
+ },
+ methods: {
+ onShownChange(row, e) {
+ const url = e
+ ? 'flower/api/app/menu/tree/shown'
+ : 'flower/api/app/menu/tree/hidden'
+ const text = e ? '显示' : '隐藏'
+ this.$elBusUtil
+ .confirm(`确定要${text}这个菜单吗?`)
+ .then(async () => {
+ const { code } = await this.$elBusHttp.request(url, {
+ params: {
+ id: row.id,
+ },
+ })
+ if (code === 0) {
+ this.$message.success(`${text}成功`)
+ this.$refs.crud.getList()
+ }
+ })
+ .catch(() => {})
+ },
+ },
+}
+</script>
diff --git a/pages/sys/dict/_id.vue b/pages/sys/dict/_id.vue
new file mode 100644
index 0000000..325a798
--- /dev/null
+++ b/pages/sys/dict/_id.vue
@@ -0,0 +1,76 @@
+<template>
+ <div class="custom-crud-page">
+ <el-bus-crud ref="crud" v-bind="tableConfig"></el-bus-crud>
+ </div>
+</template>
+
+<script>
+export default {
+ data() {
+ return {
+ tableConfig: {
+ url: 'flower/api/code/value',
+ newUrl: 'flower/api/code/value/add',
+ editUrl: 'flower/api/code/value/edit',
+ deleteUrl: 'flower/api/code/value/delete',
+ extraQuery: {
+ type: this.$route.params.id,
+ },
+ extraBody: {
+ typeCode: this.$route.params.id,
+ },
+ hasPagination: false,
+ columns: [
+ { label: '序号', type: 'index' },
+ { label: '类型', prop: 'typeCode' },
+ { label: '数据值', prop: 'value' },
+ { label: '标签名', prop: 'label' },
+ { label: '描述', prop: 'description' },
+ { label: '更新时间', prop: 'updatedDate' },
+ ],
+ form: [
+ {
+ label: '类型:',
+ id: 'typeCode',
+ type: 'input',
+ readonly: true,
+ default: this.$route.params.id,
+ },
+ {
+ label: '数据值:',
+ id: 'value',
+ type: 'input',
+ rules: { required: true, message: '请输入数据值', trigger: 'blur' },
+ },
+ {
+ label: '标签名:',
+ id: 'label',
+ type: 'input',
+ rules: { required: true, message: '请输入标签名', trigger: 'blur' },
+ },
+ {
+ label: '描述:',
+ id: 'description',
+ type: 'input',
+ el: {
+ type: 'textarea',
+ rows: '6',
+ },
+ },
+ ],
+ },
+ }
+ },
+ head() {
+ return {
+ title: '字典项',
+ }
+ },
+}
+</script>
+
+<style scoped lang="scss">
+.el-bus-crud {
+ padding-top: 20px;
+}
+</style>
diff --git a/pages/sys/dict/index.vue b/pages/sys/dict/index.vue
new file mode 100644
index 0000000..0f3acdc
--- /dev/null
+++ b/pages/sys/dict/index.vue
@@ -0,0 +1,87 @@
+<template>
+ <div class="custom-crud-page">
+ <el-bus-crud v-bind="tableConfig"></el-bus-crud>
+ </div>
+</template>
+
+<script>
+export default {
+ data() {
+ return {
+ tableConfig: {
+ url: 'flower/api/code/type/list',
+ newUrl: 'flower/api/code/type/add',
+ editUrl: 'flower/api/code/type/edit',
+ deleteUrl: 'flower/api/code/type/delete',
+ deleteMessage: () => '此操作将永久删除该字典及所有字典项,是否继续?',
+ extraButtons: [
+ {
+ text: '字典项',
+ atClick: (row) => {
+ return new Promise((resolve) => {
+ this.$router.push(`${this.$route.path}/${row.code}`)
+ resolve(false)
+ })
+ },
+ },
+ ],
+ columns: [
+ { label: '序号', type: 'index' },
+ { label: '名称', prop: 'name' },
+ { label: '类型', prop: 'code' },
+ { label: '备注信息', prop: 'description' },
+ { label: '更新时间', prop: 'updateTime' },
+ ],
+ searchForm: [
+ {
+ type: 'row',
+ span: 6,
+ items: [
+ {
+ label: '名称',
+ id: 'name',
+ type: 'input',
+ el: { placeholder: '请输入名称' },
+ },
+ {
+ label: '类型',
+ id: 'code',
+ type: 'input',
+ el: { placeholder: '请输入类型' },
+ },
+ ],
+ },
+ ],
+ form: [
+ {
+ label: '名称:',
+ id: 'name',
+ type: 'input',
+ rules: { required: true, message: '请输入名称', trigger: 'blur' },
+ },
+ {
+ label: '类型:',
+ id: 'code',
+ type: 'input',
+ rules: { required: true, message: '请输入类型', trigger: 'blur' },
+ },
+ {
+ label: '备注:',
+ id: 'description',
+ type: 'input',
+ el: {
+ type: 'textarea',
+ rows: '6',
+ },
+ },
+ ],
+ },
+ }
+ },
+ head() {
+ return {
+ title: '字典管理',
+ }
+ },
+}
+</script>
diff --git a/pages/sys/menu.vue b/pages/sys/menu.vue
new file mode 100644
index 0000000..596d6b1
--- /dev/null
+++ b/pages/sys/menu.vue
@@ -0,0 +1,97 @@
+<template>
+ <div class="custom-crud-page">
+ <el-bus-crud ref="crud" v-bind="crudConfig"></el-bus-crud>
+ </div>
+</template>
+
+<script>
+export default {
+ data() {
+ return {
+ crudConfig: {
+ url: 'flower/api/menu/list',
+ hasPagination: false,
+ saveQuery: false,
+ isTree: true,
+ hasView: false,
+ deleteMessage: () => '此操作将会删除所有子菜单, 是否继续?',
+ beforeOpen(row, isNew) {
+ if (isNew && row.menuName) {
+ row.parentName = row.menuName
+ }
+ if (!isNew) {
+ row.parentName = ''
+ }
+ },
+ extraParentKeys: ['parentName'],
+ tableAttrs: {
+ rowKey: 'id',
+ },
+ columns: [
+ { label: '菜单名称', prop: 'menuName' },
+ {
+ label: '前端地址',
+ prop: 'menuHref',
+ },
+ {
+ label: '图标',
+ formatter: (row) =>
+ row.menuIcon ? (
+ <i class={row.menuIcon} aria-hidden="true" />
+ ) : null,
+ },
+ { label: '排序', prop: 'seq' },
+ ],
+ form: [
+ {
+ label: '父级节点:',
+ id: 'parentName',
+ type: 'input',
+ readonly: true,
+ hidden: (row) => !row.parentName,
+ },
+ {
+ label: '标题:',
+ id: 'menuName',
+ type: 'input',
+ el: { placeholder: '请输入标题' },
+ rules: { required: true, message: '请输入标题', trigger: 'blur' },
+ },
+ {
+ label: '图标:',
+ id: 'menuIcon',
+ component: 'base-menu-icon',
+ },
+ {
+ label: '排序:',
+ id: 'seq',
+ type: 'input-number',
+ el: {
+ min: 0,
+ precision: 0,
+ controlsPosition: 'right',
+ placeholder: '请输入排序',
+ },
+ },
+ {
+ label: '前端地址:',
+ id: 'menuHref',
+ type: 'input',
+ el: { placeholder: '请输入前端地址' },
+ rules: {
+ required: true,
+ message: '请输入前端地址',
+ trigger: 'blur',
+ },
+ },
+ ],
+ },
+ }
+ },
+ head() {
+ return {
+ title: '菜单管理',
+ }
+ },
+}
+</script>
diff --git a/pages/sys/partner-menu.vue b/pages/sys/partner-menu.vue
new file mode 100644
index 0000000..22b4af3
--- /dev/null
+++ b/pages/sys/partner-menu.vue
@@ -0,0 +1,97 @@
+<template>
+ <div class="custom-crud-page">
+ <el-bus-crud ref="crud" v-bind="crudConfig"></el-bus-crud>
+ </div>
+</template>
+
+<script>
+export default {
+ data() {
+ return {
+ crudConfig: {
+ url: 'flower/api/menu/partner/list',
+ hasPagination: false,
+ saveQuery: false,
+ isTree: true,
+ hasView: false,
+ deleteMessage: () => '此操作将会删除所有子菜单, 是否继续?',
+ beforeOpen(row, isNew) {
+ if (isNew && row.menuName) {
+ row.parentName = row.menuName
+ }
+ if (!isNew) {
+ row.parentName = ''
+ }
+ },
+ extraParentKeys: ['parentName'],
+ tableAttrs: {
+ rowKey: 'id',
+ },
+ columns: [
+ { label: '菜单名称', prop: 'menuName' },
+ {
+ label: '前端地址',
+ prop: 'menuHref',
+ },
+ {
+ label: '图标',
+ formatter: (row) =>
+ row.menuIcon ? (
+ <i class={row.menuIcon} aria-hidden="true" />
+ ) : null,
+ },
+ { label: '排序', prop: 'seq' },
+ ],
+ form: [
+ {
+ label: '父级节点:',
+ id: 'parentName',
+ type: 'input',
+ readonly: true,
+ hidden: (row) => !row.parentName,
+ },
+ {
+ label: '标题:',
+ id: 'menuName',
+ type: 'input',
+ el: { placeholder: '请输入标题' },
+ rules: { required: true, message: '请输入标题', trigger: 'blur' },
+ },
+ {
+ label: '图标:',
+ id: 'menuIcon',
+ component: 'base-menu-icon',
+ },
+ {
+ label: '排序:',
+ id: 'seq',
+ type: 'input-number',
+ el: {
+ min: 0,
+ precision: 0,
+ controlsPosition: 'right',
+ placeholder: '请输入排序',
+ },
+ },
+ {
+ label: '前端地址:',
+ id: 'menuHref',
+ type: 'input',
+ el: { placeholder: '请输入前端地址' },
+ rules: {
+ required: true,
+ message: '请输入前端地址',
+ trigger: 'blur',
+ },
+ },
+ ],
+ },
+ }
+ },
+ head() {
+ return {
+ title: '合伙人菜单管理',
+ }
+ },
+}
+</script>
diff --git a/pages/sys/role.vue b/pages/sys/role.vue
new file mode 100644
index 0000000..11c7f76
--- /dev/null
+++ b/pages/sys/role.vue
@@ -0,0 +1,80 @@
+<template>
+ <div class="custom-crud-page">
+ <el-bus-crud ref="crud" v-bind="crudConfig"></el-bus-crud>
+ </div>
+</template>
+
+<script>
+export default {
+ data() {
+ return {
+ crudConfig: {
+ url: 'flower/api/role/list',
+ dialogNeedRequest: true,
+ canEdit: (row) => {
+ return row.isSys !== 'Y'
+ },
+ canDelete: (row) => {
+ return row.isSys !== 'Y'
+ },
+ beforeOpen(row, isNew) {
+ if (!isNew) {
+ row.menuIdsView = row.menuIds
+ row.roleDescription = row.roleDesc
+ }
+ },
+ dialogAttrs: {
+ destroyOnClose: true,
+ },
+ columns: [
+ { label: '序号', type: 'index' },
+ { label: '角色名称', prop: 'roleName' },
+ { label: '角色描述', prop: 'roleDesc' },
+ { label: '创建时间', prop: 'createdDate' },
+ ],
+ form: [
+ {
+ label: '角色名称:',
+ id: 'roleName',
+ type: 'input',
+ rules: [
+ { required: true, message: '请输入角色名称', trigger: 'blur' },
+ { min: 1, max: 50, message: '要求长度不大于50字符' },
+ ],
+ },
+ {
+ label: '角色描述:',
+ id: 'roleDesc',
+ type: 'input',
+ rules: { min: 0, max: 100, message: '要求长度不大于100字符' },
+ },
+ {
+ label: '菜单权限',
+ id: 'menuIds',
+ component: 'base-role-permission-tree',
+ rules: {
+ required: true,
+ type: 'array',
+ message: '请至少选择一个菜单权限',
+ trigger: 'change',
+ },
+ hidden: (row, item, mode) => mode === 'view',
+ },
+ {
+ label: '菜单权限',
+ id: 'menuIdsView',
+ component: 'base-role-permission-tree',
+ hidden: (row, item, mode) => mode !== 'view',
+ forceDisabled: true,
+ },
+ ],
+ },
+ }
+ },
+ head() {
+ return {
+ title: '角色管理',
+ }
+ },
+}
+</script>
diff --git a/pages/sys/user.vue b/pages/sys/user.vue
new file mode 100644
index 0000000..3c364d0
--- /dev/null
+++ b/pages/sys/user.vue
@@ -0,0 +1,297 @@
+<template>
+ <div class="custom-crud-page">
+ <el-bus-crud ref="crud" v-bind="crudConfig"></el-bus-crud>
+ </div>
+</template>
+
+<script>
+const passwordPattern =
+ /^(?:(?=\S*\d)(?=\S*[A-Z])(?=\S*[a-z])(?=\S*[-_!@#$%^&*? ]))\S{8,20}$/
+const passwordPatternMessage =
+ '请输入正确的密码(8-20位,包括至少1个大写字母,1个小写字母,1个数字,1个特殊字符)'
+export default {
+ data() {
+ return {
+ crudConfig: {
+ url: 'flower/api/user/list',
+ canEdit: (row) => row.isSys !== 'Y',
+ canDelete: (row) => row.isSys !== 'Y',
+ dialogNeedRequest: true,
+ operationAttrs: {
+ width: '200px',
+ fixed: 'right',
+ },
+ beforeOpen: (row, isNew) => {
+ if (!isNew) {
+ if (!row.employeeDTO) {
+ row.employeeDTO = {}
+ }
+ }
+ },
+ extraButtons: [
+ {
+ text: '重置密码',
+ show: (row) => row.isSys !== 'Y',
+ atClick: (row) => {
+ this.$prompt('请输入新密码', '提示', {
+ confirmButtonText: '确定',
+ cancelButtonText: '取消',
+ inputPattern: passwordPattern,
+ inputErrorMessage: passwordPatternMessage,
+ })
+ .then(async ({ value }) => {
+ const { code } = await this.$elBusHttp.request(
+ 'flower/api/user/reset/password',
+ {
+ method: 'post',
+ data: {
+ userId: row.id,
+ password: value,
+ },
+ }
+ )
+ if (code === 0) {
+ this.$message.success('重置密码成功')
+ }
+ })
+ .catch(() => {})
+ },
+ },
+ ],
+ columns: [
+ { label: '序号', type: 'index', width: 60 },
+ { label: '姓名', prop: 'nickName', minWidth: 120 },
+ { label: '性别', prop: 'genderStr', minWidth: 60 },
+ { label: '职位', prop: 'postName', minWidth: 120 },
+ { label: '工作内容', prop: 'workContent', minWidth: 180 },
+ { label: '手机号', prop: 'tel', minWidth: 120 },
+ { label: '角色', prop: 'roleDesc', minWidth: 100 },
+ {
+ label: '状态',
+ prop: 'statusStr',
+ formatter: (row) => {
+ return (
+ <el-switch
+ value={row.status === 'A'}
+ onChange={this.changeStatus.bind(this, row)}
+ >
+ 正常
+ </el-switch>
+ )
+ },
+ minWidth: 100,
+ },
+ { label: '创建时间', prop: 'createdDate', minWidth: 180 },
+ { label: '创建者', prop: 'createdName', minWidth: 120 },
+ ],
+ searchForm: [
+ {
+ type: 'row',
+ span: 6,
+ items: [
+ {
+ label: '用户名',
+ id: 'loginName',
+ type: 'input',
+ el: { placeholder: '用户名/姓名/手机号' },
+ },
+ {
+ label: '状态',
+ id: 'status',
+ type: 'bus-select-dict',
+ el: {
+ clearable: true,
+ code: 'USER_STATUS',
+ style: 'width:100%',
+ placeholder: '全部',
+ },
+ },
+ ],
+ },
+ ],
+ form: [
+ {
+ label: '手机号:',
+ id: 'tel',
+ type: 'input',
+ rules: [
+ {
+ pattern: this.$elBusUtil.REG.MOBILEPHONE,
+ message: '请输入合法的手机号',
+ trigger: 'blur',
+ },
+ ],
+ },
+ {
+ label: '用户名:',
+ id: 'loginName',
+ type: 'input',
+ rules: { required: true, message: '请输入用户名', trigger: 'blur' },
+ },
+ {
+ label: '姓名:',
+ id: 'nickName',
+ type: 'input',
+ rules: { required: true, message: '请输入姓名', trigger: 'blur' },
+ },
+ {
+ type: 'group',
+ id: 'employeeDTO',
+ items: [
+ {
+ label: '性别:',
+ id: 'gender',
+ type: 'bus-select-dict',
+ el: { code: 'gender', clearable: true },
+ str: true,
+ },
+ {
+ label: '出生年月日:',
+ id: 'birthday',
+ type: 'date-picker',
+ el: {
+ valueFormat: 'yyyy-MM-dd',
+ placeholder: '请选择',
+ },
+ },
+ {
+ label: '身份证:',
+ id: 'idCard',
+ type: 'input',
+ },
+ {
+ label: '职位:',
+ id: 'postName',
+ type: 'input',
+ },
+ {
+ label: '工作内容:',
+ id: 'workContent',
+ type: 'input',
+ },
+ {
+ label: '入职时间:',
+ id: 'inDate',
+ type: 'date-picker',
+ el: {
+ valueFormat: 'yyyy-MM-dd',
+ placeholder: '请选择',
+ },
+ },
+ {
+ label: '薪资待遇:',
+ id: 'salary',
+ type: 'input-number',
+ el: {
+ precision: 0,
+ min: 0,
+ },
+ unit: '元/月',
+ },
+ ],
+ },
+ {
+ label: '密码:',
+ id: 'password',
+ type: 'input',
+ rules: (row, mode) => [
+ {
+ required: mode === 'new',
+ message: '请输入密码',
+ trigger: 'blur',
+ },
+ {
+ pattern: passwordPattern,
+ message: passwordPatternMessage,
+ trigger: 'blur',
+ },
+ ],
+ hidden: (row, _, mode) => mode !== 'new',
+ },
+ {
+ label: '确认密码:',
+ id: 'confirmPassword',
+ type: 'input',
+ rules: (row, mode) => [
+ {
+ required: mode === 'new',
+ message: '请输入确认密码',
+ trigger: 'blur',
+ },
+ {
+ validator: (rule, value, callback) => {
+ if (row.password) {
+ if (value === '' || !value) {
+ callback(new Error('请重复输入密码!'))
+ } else if (row.password !== value) {
+ callback(new Error('重复输入密码不一致!'))
+ } else {
+ callback()
+ }
+ } else {
+ callback()
+ }
+ },
+ trigger: 'blur',
+ },
+ ],
+ hidden: (row, _, mode) => mode !== 'new',
+ },
+ {
+ label: '角色:',
+ id: 'roleIds',
+ str: true,
+ strKey: 'roleDesc',
+ type: 'bus-select',
+ el: {
+ interfaceUri: 'flower/api/role/list',
+ immediate: true,
+ multiple: true,
+ props: {
+ label: 'roleName',
+ value: 'id',
+ dataPath: 'records',
+ },
+ extraQuery: {
+ size: 2000,
+ },
+ style: 'width:100%',
+ },
+ rules: { required: true, message: '请选择角色' },
+ },
+ {
+ label: '状态:',
+ id: 'status',
+ str: true,
+ type: 'bus-select-dict',
+ el: {
+ code: 'COMMON_STATUS',
+ placeholder: '请选择状态',
+ style: 'width:100%',
+ },
+ rules: { required: true, message: '请选择状态' },
+ },
+ ],
+ },
+ }
+ },
+ head() {
+ return {
+ title: '员工管理',
+ }
+ },
+ methods: {
+ async changeStatus(row, e) {
+ const url = e
+ ? `flower/api/user/enable/${row.id}`
+ : `flower/api/user/disable/${row.id}`
+ const action = e ? '启用' : '禁用'
+ const { code } = await this.$elBusHttp.request(url, { method: 'post' })
+ if (code === 0) {
+ this.$message.success(`${action}成功`)
+ this.$refs.crud.getList()
+ }
+ },
+ },
+}
+</script>
diff --git a/pages/wallet/supplier-finance.vue b/pages/wallet/supplier-finance.vue
new file mode 100644
index 0000000..1dfe451
--- /dev/null
+++ b/pages/wallet/supplier-finance.vue
@@ -0,0 +1,93 @@
+<template>
+ <div>
+ <el-bus-crud ref="crud" v-bind="tableConfig" />
+ </div>
+</template>
+
+<script>
+
+export default {
+ data() {
+ return {
+ tableConfig: {
+ url: 'flower/v2/wallet-bill-record/list',
+ hasNew: false,
+ hasEdit: false,
+ hasDelete: false,
+ hasView: false,
+ hasExport: true,
+ exportUrl: 'flower/v2/wallet-bill-record/export',
+ exportText: '导出',
+ hasOperation:false,
+ columns: [
+ {label: '供应商信息',
+ minWidth: 120,
+ formatter: (row) => `${row.supplierName || ''}:[ID:${row.supplierId || ''}]`},
+ {label: '变动类型', prop: 'typeName', minWidth: 100},
+ {label: '原金额', prop: 'originalAmount', minWidth: 100},
+ {
+ label: '变动金额',
+ formatter: (row) => (row.method ==='add' ? '+'+row.changeAmount : '-'+row.changeAmount),
+ minWidth: 120
+ },
+ {label: '现余额', prop: 'balance', minWidth: 120},
+ {label: '提交时间', prop: 'createTime', minWidth: 120},
+ {label: '审核时间', prop: 'approveTime', minWidth: 80},
+ {label: '备注', prop: 'remark', minWidth: 160},
+ {label: '操作人', prop: 'approveName', minWidth: 120},
+ ],
+ searchFormAttrs: {
+ labelWidth: 'auto',
+ },
+ searchForm: [
+ {
+ type: 'row',
+ items: [
+
+ {label: '供应商ID:', id: 'supplierId', type: 'input'},
+ {label: '供应商名称:', id: 'supplierName', type: 'input'},
+ {
+ label: '提交时间',
+ id: 'createStartDate',
+ component: 'el-bus-date-range',
+ commonFormat: true,
+ commonFormatProps: ['createStartDate', 'endEndDate'],
+ customClass: 'in-bus-form',
+ },
+ {
+ label: '审核时间',
+ id: 'approveStartDate',
+ component: 'el-bus-date-range',
+ commonFormat: true,
+ commonFormatProps: ['approveStartDate', 'approveEndDate'],
+ customClass: 'in-bus-form',
+ },
+ {
+ label: '变动类型',
+ id: 'type',
+ type: 'bus-select-dict',
+ el: {
+ code: 'BILL_CHANGE_TYPE',
+ clearable: true,
+ style: 'width:100%',
+ },
+ },
+ {label: '订单号:', id: 'orderNo', type: 'input'},
+
+ ],
+ },
+ ],
+ },
+ }
+ },
+ head() {
+ return {
+ title: '供应商财务',
+ }
+ },
+}
+
+</script>
+
+
+
diff --git a/pages/wallet/withdraw-audit.vue b/pages/wallet/withdraw-audit.vue
new file mode 100644
index 0000000..24417a8
--- /dev/null
+++ b/pages/wallet/withdraw-audit.vue
@@ -0,0 +1,166 @@
+<template>
+ <div>
+ <el-bus-crud ref="crud" v-bind="tableConfig" />
+ </div>
+</template>
+
+<script>
+
+export default {
+ data() {
+ return {
+ tableConfig: {
+ url: 'flower/v2/withdraw-record/list',
+ hasNew: false,
+ hasEdit: false,
+ hasDelete: false,
+ hasView: false,
+ columns: [
+ {label: '供应商信息',
+ minWidth: 120,
+ formatter: (row) => `${row.supplierName || ''}:[ID:${row.supplierId || ''}]`},
+ {label: '申请时间', prop: 'createTime', minWidth: 100},
+ {label: '提现类型', prop: 'withdrawTypeStr', minWidth: 100},
+ {label: '提现金额(元)', prop: 'amount', minWidth: 120},
+ {label: '提现状态', prop: 'withdrawStateStr', minWidth: 120},
+ {label: '提现方式', prop: 'methodStr', minWidth: 120},
+ {label: '审核状态', prop: 'approveStateStr', minWidth: 120},
+ {label: '审核时间', prop: 'approveTime', minWidth: 120},
+ {label: '拒绝原因', prop: 'rejectReason', minWidth: 120},
+ {label: '操作人', prop: 'approveName', minWidth: 120},
+ ],
+ searchFormAttrs: {
+ labelWidth: 'auto',
+ },
+ searchForm: [
+ {
+ type: 'row',
+ items: [
+ {
+ label: '审核状态:',
+ id: 'approveState',
+ type: 'bus-radio',
+ el: {
+ hasAll: true,
+ childType: 'el-radio-button',
+ code: 'WALLET_APPROVE_STATE',
+ },
+ default: '',
+ span: 24,
+ searchImmediately: true,
+ },
+ {
+ label: '提现状态:',
+ id: 'withdrawState',
+ type: 'bus-radio',
+ el: {
+ hasAll: true,
+ childType: 'el-radio-button',
+ code: 'BILL_WITHDRAW_TYPE',
+ },
+ default: '',
+ span: 24,
+ searchImmediately: true,
+ },
+ {label: '供应商ID:', id: 'supplierId', type: 'input'},
+ {label: '供应商名称:', id: 'supplierName', type: 'input'},
+ {
+ label: '提交时间',
+ id: 'createStartDate',
+ component: 'el-bus-date-range',
+ commonFormat: true,
+ commonFormatProps: ['createStartDate', 'endEndDate'],
+ customClass: 'in-bus-form',
+ },
+ {
+ label: '审核时间',
+ id: 'approveStartDate',
+ component: 'el-bus-date-range',
+ commonFormat: true,
+ commonFormatProps: ['approveStartDate', 'approveEndDate'],
+ customClass: 'in-bus-form',
+ },
+
+ ],
+ },
+ ],
+ extraDialogs: [
+ {
+ title: '提现拒绝',
+ form: [
+ {
+ label: '原因:',
+ id: 'rejectReason',
+ type: 'input',
+ el: {
+ type: 'textarea',
+ rows: 6,
+ },
+ rules: {
+ required: true,
+ message: '请输入原因',
+ trigger: 'blur',
+ },
+ },
+ ],
+ atConfirm: async (val) => {
+ const { code } = await this.$elBusHttp.request(
+ 'flower/v2/withdraw-record/refuse',
+ {
+ method: 'post',
+ data: val,
+ }
+ )
+ if (code === 0) {
+ this.$message.success('拒绝操作成功')
+ }
+ },
+ },
+ ],
+ extraButtons: [
+ {
+ text: '通过',
+ show: (row) => row.approveState === 'WAITING',
+ atClick: async (row) => {
+ try {
+ await this.$elBusUtil.confirm('确定要通过吗?')
+ const {code} = await this.$elBusHttp.request(
+ 'flower/v2/withdraw-record/pass',
+ {
+ method: 'post',
+ data: {
+ id: row.id,
+ },
+ }
+ )
+ if (code === 0) {
+ this.$message.success('已通过')
+ }
+ } catch (e) {
+ return false
+ }
+ },
+ },
+ {
+ text: '拒绝',
+ show: (row) => row.approveState === 'WAITING',
+ atClick: (row) => {
+ this.$refs.crud.$refs.extraDialog[0].show(row)
+ return false
+ },
+ },
+ ],
+ },
+ }
+ },
+ head() {
+ return {
+ title: '供应商提现审核',
+ }
+ },
+}
+
+</script>
+
+
+
diff --git a/pages/warehouse.vue b/pages/warehouse.vue
new file mode 100644
index 0000000..a69bf7c
--- /dev/null
+++ b/pages/warehouse.vue
@@ -0,0 +1,291 @@
+<template>
+ <div class="flex w-full h-full overflow-hidden">
+ <content-wrapper title="区" class="w-250 mr-20 overflow-auto">
+ <template #header-right>
+ <el-button
+ circle
+ icon="el-icon-plus"
+ type="primary"
+ @click="newArea"
+ ></el-button>
+ </template>
+ <el-bus-crud ref="areaCrudRef" v-bind="areaTableConfig">
+ <template #table="{ list }">
+ <template v-if="list && list.length > 0">
+ <div
+ v-for="item in list"
+ :key="item.id"
+ class="area-item"
+ :class="{ 'is-active': selectedArea === item.id }"
+ @click="onSelectArea(item.id)"
+ >
+ <span class="area-item__label">{{ item.name }}</span>
+ <el-dropdown>
+ <i class="el-icon-more-outline"></i>
+ <el-dropdown-menu slot="dropdown">
+ <el-dropdown-item @click.native="editArea(item)"
+ >编辑</el-dropdown-item
+ >
+ <el-dropdown-item @click.native="deleteArea(item)"
+ >删除</el-dropdown-item
+ >
+ </el-dropdown-menu>
+ </el-dropdown>
+ </div>
+ </template>
+ <el-bus-empty v-else />
+ </template>
+ </el-bus-crud>
+ </content-wrapper>
+ <content-wrapper title="仓位" class="flex-1 overflow-auto">
+ <template #header-right>
+ <el-button
+ circle
+ icon="el-icon-plus"
+ type="primary"
+ @click="newLocation"
+ ></el-button>
+ </template>
+ <el-bus-crud
+ ref="locationCrudRef"
+ v-bind="locationTableConfig"
+ :key="selectedArea"
+ :extra-query="locationExtra"
+ >
+ <template #table="{ list }">
+ <el-row v-if="list && list.length > 0" :gutter="20">
+ <el-col v-for="item in list" :key="item.id" :span="8">
+ <location-item
+ :info="item"
+ @edit="onEditLocation(item)"
+ @delete="onDeleteLocation(item)"
+ @addOrder="addOrder(item)"
+ ></location-item>
+ </el-col>
+ </el-row>
+ <el-bus-empty v-else />
+ </template>
+ </el-bus-crud>
+ </content-wrapper>
+ </div>
+</template>
+
+<script>
+import { getSortConfig } from '@/utils/form-item-config'
+import LocationItem from '@/components/warehouse/location-item.vue'
+import SelectOrder from '@/components/warehouse/select-order.vue'
+export default {
+ components: {
+ LocationItem,
+ },
+ data() {
+ return {
+ selectedArea: null,
+ areaTableConfig: {
+ url: 'flower/api/warehouse/list',
+ hasNew: false,
+ newText: '新增区',
+ hasPagination: false,
+ form: [
+ {
+ label: '区号:',
+ id: 'name',
+ type: 'input',
+ rules: { required: true, message: '请输入区号', trigger: 'blur' },
+ },
+ {
+ ...getSortConfig('seq'),
+ },
+ ],
+ },
+ locationTableConfig: {
+ url: 'flower/api/warehouse/location/list',
+ hasNew: false,
+ newText: '新增仓位',
+ hasPagination: false,
+ extraParentKeys: ['warehouseId'],
+ afterRequest: (list) => {
+ return list.map((item) => {
+ const orderList = item.orderDTO || []
+ const goodsItems = orderList.reduce((total, current) => {
+ total = total.concat(
+ current.items.map((i) => ({
+ ...i,
+ orderNo: current.orderNo,
+ }))
+ )
+ return total
+ }, [])
+ return { ...item, goodsItems }
+ })
+ },
+ searchForm: [
+ {
+ type: 'row',
+ items: [{ label: '仓位号', id: 'code', type: 'input' }],
+ },
+ ],
+ form: [
+ {
+ label: '区号:',
+ id: 'warehouseId',
+ type: 'bus-select',
+ el: {
+ interfaceUri: 'flower/api/warehouse/list',
+ props: {
+ label: 'name',
+ value: 'id',
+ },
+ style: 'width:100%',
+ },
+ rules: { required: true, message: '请选择区号' },
+ },
+ {
+ label: '仓位号:',
+ id: 'code',
+ type: 'input',
+ rules: { required: true, message: '请输入仓位号', trigger: 'blur' },
+ },
+ {
+ ...getSortConfig('seq'),
+ },
+ ],
+ extraDialogs: [
+ {
+ title: '添加订单',
+ hiddenReverseItems: [],
+ dialogAttrs: {
+ width: '80%',
+ destroyOnClose: true,
+ },
+ form: [
+ {
+ label: '',
+ id: 'orderId',
+ component: SelectOrder,
+ rules: { required: true, message: '请选择一个订单' },
+ },
+ ],
+ atConfirm: async (val) => {
+ const { code } = await this.$elBusHttp.request(
+ 'flower/api/warehouse/location/list/addOrder',
+ {
+ params: {
+ ...val,
+ warehouseLocationId: val.id,
+ },
+ }
+ )
+ if (code === 0) {
+ this.$message.success('添加订单成功')
+ }
+ },
+ },
+ ],
+ },
+ }
+ },
+ head() {
+ return {
+ title: '仓库管理',
+ }
+ },
+ computed: {
+ locationExtra() {
+ return {
+ warehouseId: this.selectedArea,
+ }
+ },
+ },
+ methods: {
+ onSelectArea(id) {
+ if (this.selectedArea === id) {
+ this.selectedArea = null
+ } else {
+ this.selectedArea = id
+ }
+ },
+ newArea() {
+ if (this.$refs.areaCrudRef) {
+ this.$refs.areaCrudRef.onDefaultNew()
+ }
+ },
+ editArea(item) {
+ if (this.$refs.areaCrudRef) {
+ this.$refs.areaCrudRef.onDefaultEdit(item)
+ }
+ },
+ deleteArea(item) {
+ if (this.$refs.areaCrudRef) {
+ this.$refs.areaCrudRef.onDefaultDelete(item)
+ }
+ },
+ newLocation() {
+ if (this.$refs.locationCrudRef) {
+ if (this.selectedArea) {
+ this.$refs.locationCrudRef.onDefaultNew(
+ { warehouseId: this.selectedArea },
+ true
+ )
+ } else {
+ this.$refs.locationCrudRef.onDefaultNew()
+ }
+ }
+ },
+ onEditLocation(item) {
+ if (this.$refs.locationCrudRef) {
+ this.$refs.locationCrudRef.onDefaultEdit(item)
+ }
+ },
+ onDeleteLocation(item) {
+ if (this.$refs.locationCrudRef) {
+ this.$refs.locationCrudRef.onDefaultDelete(item)
+ }
+ },
+ addOrder(item) {
+ this.$refs.locationCrudRef.$refs.extraDialog[0].show(item)
+ },
+ },
+}
+</script>
+
+<style lang="scss" scoped>
+::v-deep {
+ .el-bus-crud {
+ &__card,
+ &__body {
+ padding: 0;
+ }
+ &__filter {
+ padding-top: 0;
+ border-bottom: none;
+ }
+ }
+}
+.area-item {
+ height: 40px;
+ line-height: 40px;
+ cursor: pointer;
+ padding: 0 10px;
+ color: $main-title-color;
+ font-size: 14px;
+ display: flex;
+ align-items: center;
+ &__label {
+ flex: 1;
+ }
+ .el-icon-more-outline {
+ color: $primary-color;
+ display: none;
+ }
+ &:hover {
+ background-color: #f5f7fa;
+ .el-icon-more-outline {
+ display: block;
+ }
+ }
+ &.is-active {
+ background-color: #edf0ff;
+ }
+}
+</style>
diff --git a/plugins/el-business.js b/plugins/el-business.js
new file mode 100644
index 0000000..455c387
--- /dev/null
+++ b/plugins/el-business.js
@@ -0,0 +1,57 @@
+import Vue from 'vue'
+import ElBusiness from 'el-business'
+import cacheUtil from 'el-business-cache-utils'
+import zhCNLocale from 'el-business/src/locale/lang/zh-CN'
+import enLocale from 'el-business/src/locale/lang/en'
+import enHttpLocale from './httpLang/en'
+
+export default (ctx) => {
+ const enableCache = ctx.$config.enableCache
+ const locale = {
+ 'zh-CN': zhCNLocale,
+ en: enLocale,
+ }
+ const currentLocale = ctx.i18n.getLocaleCookie() || ctx.i18n.defaultLocale
+ Vue.use(ElBusiness, {
+ httpBaseUri: ctx.$config.httpBaseUri,
+ dictInterfaceUri: 'flower/api/code/value',
+ uploadInterfaceUri: 'flower/api/upload/oss/file',
+ downloadInterfaceUri: 'flower/api/download/file',
+ areaInterfaceUri: 'flower/api/pub/china/web/area/json',
+ smsInterfaceUri: 'flower/api/sms/send/code',
+ crudDialogAttrs: {
+ closeOnClickModal: false,
+ },
+ enableCache,
+ locale: locale[currentLocale],
+ })
+ ctx.$elBusHttp.options.beforeRequest = (config) => {
+ config.headers['Accept-Language'] = currentLocale
+ }
+ const httpLocale = {
+ en: enHttpLocale,
+ }
+ ctx.$elBusHttp.options.locale = httpLocale[currentLocale] || null
+ if (process.client) {
+ // if (!ctx.store.state.app.platformInfo) {
+ // await ctx.store.dispatch('app/getPlatformInfo')
+ // const logo = ctx.store?.state?.app?.platformInfo?.logo
+ // if (logo) {
+ // const link =
+ // document.querySelector("link[rel*='icon']") ||
+ // document.createElement('link')
+ // link.type = 'image/x-icon'
+ // link.rel = 'shortcut icon'
+ // link.href = logo
+ // document.getElementsByTagName('head')[0].appendChild(link)
+ // }
+ // }
+ // 缓存
+ if (enableCache) {
+ const cacheVersion = ctx.store?.state?.app?.platformInfo?.cache_version
+ if (cacheVersion) {
+ cacheUtil.init(cacheVersion)
+ }
+ }
+ }
+}
diff --git a/plugins/element-ui.js b/plugins/element-ui.js
new file mode 100644
index 0000000..5a8e1f8
--- /dev/null
+++ b/plugins/element-ui.js
@@ -0,0 +1,18 @@
+import Vue from 'vue'
+import Element from 'element-ui'
+import zhCNLocale from 'element-ui/lib/locale/lang/zh-CN'
+import enLocale from 'element-ui/lib/locale/lang/en'
+import cssVars from 'css-vars-ponyfill'
+
+const fontSizeList = ['mini', 'small', 'medium']
+export default (ctx) => {
+ const size = ctx.$elBusCookie.get('size') || 'small'
+ ctx.store.commit('app/SET_SIZE', size)
+ const locale = {
+ 'zh-CN': zhCNLocale,
+ en: enLocale,
+ }
+ const currentLocale = ctx.i18n.getLocaleCookie() || ctx.i18n.defaultLocale
+ ctx.i18n.setLocale(currentLocale)
+ Vue.use(Element, { locale: locale[currentLocale], size })
+}
diff --git a/plugins/httpLang/en.js b/plugins/httpLang/en.js
new file mode 100644
index 0000000..42be54c
--- /dev/null
+++ b/plugins/httpLang/en.js
@@ -0,0 +1,7 @@
+export default {
+ apiNotfound: 'Api not found',
+ serverError: 'Server error',
+ networkError: 'Network error',
+ connectTimeout: 'Request timeout',
+ frequentError: 'System operation is too frequent, please try again later!',
+}
diff --git a/plugins/icons.js b/plugins/icons.js
new file mode 100644
index 0000000..bfeec19
--- /dev/null
+++ b/plugins/icons.js
@@ -0,0 +1,500 @@
+export const COMMON_ICONS = [
+ 'fa fa-address-book',
+ 'fa fa-address-book-o',
+ 'fa fa-address-card',
+ 'fa fa-address-card-o',
+ 'fa fa-adjust',
+ 'fa fa-american-sign-language-interpreting',
+ 'fa fa-anchor',
+ 'fa fa-archive',
+ 'fa fa-arrows',
+ 'fa fa-arrows-h',
+ 'fa fa-arrows-v',
+ 'fa fa-asl-interpreting',
+ 'fa fa-assistive-listening-systems',
+ 'fa fa-asterisk',
+ 'fa fa-at',
+ 'fa fa-audio-description',
+ 'fa fa-automobile',
+ 'fa fa-balance-scale',
+ 'fa fa-ban',
+ 'fa fa-bank',
+ 'fa fa-barcode',
+ 'fa fa-bars',
+ 'fa fa-bath',
+ 'fa fa-bathtub',
+ 'fa fa-battery',
+ 'fa fa-battery-0',
+ 'fa fa-battery-1',
+ 'fa fa-battery-2',
+ 'fa fa-battery-3',
+ 'fa fa-battery-4',
+ 'fa fa-battery-empty',
+ 'fa fa-battery-full',
+ 'fa fa-battery-half',
+ 'fa fa-battery-quarter',
+ 'fa fa-battery-three-quarters',
+ 'fa fa-bed',
+ 'fa fa-beer',
+ 'fa fa-bell',
+ 'fa fa-bell-o',
+ 'fa fa-bell-slash',
+ 'fa fa-bell-slash-o',
+ 'fa fa-bicycle',
+ 'fa fa-binoculars',
+ 'fa fa-birthday-cake',
+ 'fa fa-blind',
+ 'fa fa-bluetooth',
+ 'fa fa-bluetooth-b',
+ 'fa fa-bolt',
+ 'fa fa-bomb',
+ 'fa fa-book',
+ 'fa fa-bookmark',
+ 'fa fa-bookmark-o',
+ 'fa fa-braille',
+ 'fa fa-briefcase',
+ 'fa fa-bug',
+ 'fa fa-building',
+ 'fa fa-building-o',
+ 'fa fa-bullhorn',
+ 'fa fa-bullseye',
+ 'fa fa-bus',
+ 'fa fa-cab',
+ 'fa fa-calculator',
+ 'fa fa-calendar',
+ 'fa fa-calendar-check-o',
+ 'fa fa-calendar-minus-o',
+ 'fa fa-calendar-o',
+ 'fa fa-calendar-plus-o',
+ 'fa fa-calendar-times-o',
+ 'fa fa-camera',
+ 'fa fa-camera-retro',
+ 'fa fa-car',
+ 'fa fa-caret-square-o-down',
+ 'fa fa-caret-square-o-left',
+ 'fa fa-caret-square-o-right',
+ 'fa fa-caret-square-o-up',
+ 'fa fa-cart-arrow-down',
+ 'fa fa-cart-plus',
+ 'fa fa-cc',
+ 'fa fa-certificate',
+ 'fa fa-check',
+ 'fa fa-check-circle',
+ 'fa fa-check-circle-o',
+ 'fa fa-child',
+ 'fa fa-circle-o-notch',
+ 'fa fa-circle-thin',
+ 'fa fa-clock-o',
+ 'fa fa-clone',
+ 'fa fa-close',
+ 'fa fa-cloud',
+ 'fa fa-cloud-download',
+ 'fa fa-cloud-upload',
+ 'fa fa-code',
+ 'fa fa-code-fork',
+ 'fa fa-coffee',
+ 'fa fa-cog',
+ 'fa fa-cogs',
+ 'fa fa-comment',
+ 'fa fa-comment-o',
+ 'fa fa-commenting',
+ 'fa fa-commenting-o',
+ 'fa fa-comments',
+ 'fa fa-comments-o',
+ 'fa fa-compass',
+ 'fa fa-copyright',
+ 'fa fa-creative-commons',
+ 'fa fa-credit-card',
+ 'fa fa-credit-card-alt',
+ 'fa fa-crop',
+ 'fa fa-crosshairs',
+ 'fa fa-cube',
+ 'fa fa-cubes',
+ 'fa fa-cutlery',
+ 'fa fa-dashboard',
+ 'fa fa-database',
+ 'fa fa-deaf',
+ 'fa fa-deafness',
+ 'fa fa-desktop',
+ 'fa fa-diamond',
+ 'fa fa-download',
+ 'fa fa-drivers-license',
+ 'fa fa-drivers-license-o',
+ 'fa fa-edit',
+ 'fa fa-ellipsis-h',
+ 'fa fa-ellipsis-v',
+ 'fa fa-envelope',
+ 'fa fa-envelope-o',
+ 'fa fa-envelope-open',
+ 'fa fa-envelope-open-o',
+ 'fa fa-envelope-square',
+ 'fa fa-exchange',
+ 'fa fa-exclamation',
+ 'fa fa-exclamation-circle',
+ 'fa fa-exclamation-triangle',
+ 'fa fa-external-link',
+ 'fa fa-external-link-square',
+ 'fa fa-eye',
+ 'fa fa-eye-slash',
+ 'fa fa-eyedropper',
+ 'fa fa-fax',
+ 'fa fa-feed',
+ 'fa fa-female',
+ 'fa fa-fighter-jet',
+ 'fa fa-film',
+ 'fa fa-filter',
+ 'fa fa-fire',
+ 'fa fa-fire-extinguisher',
+ 'fa fa-flag',
+ 'fa fa-flag-checkered',
+ 'fa fa-flag-o',
+ 'fa fa-flash',
+ 'fa fa-flask',
+ 'fa fa-folder',
+ 'fa fa-folder-o',
+ 'fa fa-folder-open',
+ 'fa fa-folder-open-o',
+ 'fa fa-frown-o',
+ 'fa fa-futbol-o',
+ 'fa fa-gamepad',
+ 'fa fa-gavel',
+ 'fa fa-gear',
+ 'fa fa-gears',
+ 'fa fa-gift',
+ 'fa fa-glass',
+ 'fa fa-globe',
+ 'fa fa-graduation-cap',
+ 'fa fa-group',
+ 'fa fa-hand-grab-o',
+ 'fa fa-hand-lizard-o',
+ 'fa fa-hand-paper-o',
+ 'fa fa-hand-peace-o',
+ 'fa fa-hand-pointer-o',
+ 'fa fa-hand-rock-o',
+ 'fa fa-hand-scissors-o',
+ 'fa fa-hand-spock-o',
+ 'fa fa-hand-stop-o',
+ 'fa fa-handshake-o',
+ 'fa fa-hard-of-hearing',
+ 'fa fa-hashtag',
+ 'fa fa-hdd-o',
+ 'fa fa-headphones',
+ 'fa fa-heart',
+ 'fa fa-heart-o',
+ 'fa fa-heartbeat',
+ 'fa fa-history',
+ 'fa fa-home',
+ 'fa fa-hotel',
+ 'fa fa-hourglass',
+ 'fa fa-hourglass-1',
+ 'fa fa-hourglass-2',
+ 'fa fa-hourglass-3',
+ 'fa fa-hourglass-end',
+ 'fa fa-hourglass-half',
+ 'fa fa-hourglass-o',
+ 'fa fa-hourglass-start',
+ 'fa fa-i-cursor',
+ 'fa fa-id-badge',
+ 'fa fa-id-card',
+ 'fa fa-id-card-o',
+ 'fa fa-image',
+ 'fa fa-inbox',
+ 'fa fa-industry',
+ 'fa fa-info',
+ 'fa fa-info-circle',
+ 'fa fa-institution',
+ 'fa fa-key',
+ 'fa fa-keyboard-o',
+ 'fa fa-language',
+ 'fa fa-laptop',
+ 'fa fa-leaf',
+ 'fa fa-legal',
+ 'fa fa-lemon-o',
+ 'fa fa-level-down',
+ 'fa fa-level-up',
+ 'fa fa-life-bouy',
+ 'fa fa-life-buoy',
+ 'fa fa-life-ring',
+ 'fa fa-life-saver',
+ 'fa fa-lightbulb-o',
+ 'fa fa-location-arrow',
+ 'fa fa-lock',
+ 'fa fa-low-vision',
+ 'fa fa-magic',
+ 'fa fa-magnet',
+ 'fa fa-mail-forward',
+ 'fa fa-mail-reply',
+ 'fa fa-mail-reply-all',
+ 'fa fa-male',
+ 'fa fa-map',
+ 'fa fa-map-marker',
+ 'fa fa-map-o',
+ 'fa fa-map-pin',
+ 'fa fa-map-signs',
+ 'fa fa-meh-o',
+ 'fa fa-microchip',
+ 'fa fa-microphone',
+ 'fa fa-microphone-slash',
+ 'fa fa-minus',
+ 'fa fa-minus-circle',
+ 'fa fa-mobile',
+ 'fa fa-mobile-phone',
+ 'fa fa-money',
+ 'fa fa-moon-o',
+ 'fa fa-mortar-board',
+ 'fa fa-motorcycle',
+ 'fa fa-mouse-pointer',
+ 'fa fa-music',
+ 'fa fa-navicon',
+ 'fa fa-newspaper-o',
+ 'fa fa-object-group',
+ 'fa fa-object-ungroup',
+ 'fa fa-paint-brush',
+ 'fa fa-paper-plane',
+ 'fa fa-paper-plane-o',
+ 'fa fa-paw',
+ 'fa fa-pencil',
+ 'fa fa-pencil-square',
+ 'fa fa-pencil-square-o',
+ 'fa fa-percent',
+ 'fa fa-phone',
+ 'fa fa-phone-square',
+ 'fa fa-photo',
+ 'fa fa-picture-o',
+ 'fa fa-plane',
+ 'fa fa-plug',
+ 'fa fa-plus',
+ 'fa fa-plus-circle',
+ 'fa fa-podcast',
+ 'fa fa-power-off',
+ 'fa fa-print',
+ 'fa fa-puzzle-piece',
+ 'fa fa-qrcode',
+ 'fa fa-question',
+ 'fa fa-question-circle',
+ 'fa fa-question-circle-o',
+ 'fa fa-quote-left',
+ 'fa fa-quote-right',
+ 'fa fa-random',
+ 'fa fa-recycle',
+ 'fa fa-refresh',
+ 'fa fa-registered',
+ 'fa fa-remove',
+ 'fa fa-reorder',
+ 'fa fa-reply',
+ 'fa fa-reply-all',
+ 'fa fa-retweet',
+ 'fa fa-road',
+ 'fa fa-rocket',
+ 'fa fa-rss',
+ 'fa fa-rss-square',
+ 'fa fa-s15',
+ 'fa fa-search',
+ 'fa fa-search-minus',
+ 'fa fa-search-plus',
+ 'fa fa-send',
+ 'fa fa-send-o',
+ 'fa fa-server',
+ 'fa fa-share',
+ 'fa fa-share-alt',
+ 'fa fa-share-alt-square',
+ 'fa fa-share-square',
+ 'fa fa-share-square-o',
+ 'fa fa-shield',
+ 'fa fa-ship',
+ 'fa fa-shopping-bag',
+ 'fa fa-shopping-basket',
+ 'fa fa-shopping-cart',
+ 'fa fa-shower',
+ 'fa fa-sign-in',
+ 'fa fa-sign-language',
+ 'fa fa-sign-out',
+ 'fa fa-signal',
+ 'fa fa-signing',
+ 'fa fa-sitemap',
+ 'fa fa-sliders',
+ 'fa fa-smile-o',
+ 'fa fa-snowflake-o',
+ 'fa fa-soccer-ball-o',
+ 'fa fa-sort',
+ 'fa fa-sort-alpha-asc',
+ 'fa fa-sort-alpha-desc',
+ 'fa fa-sort-amount-asc',
+ 'fa fa-sort-amount-desc',
+ 'fa fa-sort-asc',
+ 'fa fa-sort-desc',
+ 'fa fa-sort-down',
+ 'fa fa-sort-numeric-asc',
+ 'fa fa-sort-numeric-desc',
+ 'fa fa-sort-up',
+ 'fa fa-space-shuttle',
+ 'fa fa-spinner',
+ 'fa fa-spoon',
+ 'fa fa-star',
+ 'fa fa-star-half',
+ 'fa fa-star-half-empty',
+ 'fa fa-star-half-full',
+ 'fa fa-star-half-o',
+ 'fa fa-star-o',
+ 'fa fa-sticky-note',
+ 'fa fa-sticky-note-o',
+ 'fa fa-street-view',
+ 'fa fa-suitcase',
+ 'fa fa-sun-o',
+ 'fa fa-support',
+ 'fa fa-tablet',
+ 'fa fa-tachometer',
+ 'fa fa-tag',
+ 'fa fa-tags',
+ 'fa fa-tasks',
+ 'fa fa-taxi',
+ 'fa fa-television',
+ 'fa fa-terminal',
+ 'fa fa-thermometer',
+ 'fa fa-thermometer-0',
+ 'fa fa-thermometer-1',
+ 'fa fa-thermometer-2',
+ 'fa fa-thermometer-3',
+ 'fa fa-thermometer-4',
+ 'fa fa-thermometer-empty',
+ 'fa fa-thermometer-full',
+ 'fa fa-thermometer-half',
+ 'fa fa-thermometer-quarter',
+ 'fa fa-thermometer-three-quarters',
+ 'fa fa-thumb-tack',
+ 'fa fa-thumbs-down',
+ 'fa fa-thumbs-o-down',
+ 'fa fa-thumbs-o-up',
+ 'fa fa-thumbs-up',
+ 'fa fa-ticket',
+ 'fa fa-times',
+ 'fa fa-times-circle',
+ 'fa fa-times-circle-o',
+ 'fa fa-times-rectangle',
+ 'fa fa-times-rectangle-o',
+ 'fa fa-tint',
+ 'fa fa-toggle-down',
+ 'fa fa-toggle-left',
+ 'fa fa-toggle-off',
+ 'fa fa-toggle-on',
+ 'fa fa-toggle-right',
+ 'fa fa-toggle-up',
+ 'fa fa-trademark',
+ 'fa fa-trash',
+ 'fa fa-trash-o',
+ 'fa fa-tree',
+ 'fa fa-trophy',
+ 'fa fa-truck',
+ 'fa fa-tty',
+ 'fa fa-tv',
+ 'fa fa-umbrella',
+ 'fa fa-universal-access',
+ 'fa fa-university',
+ 'fa fa-unlock',
+ 'fa fa-unlock-alt',
+ 'fa fa-unsorted',
+ 'fa fa-upload',
+ 'fa fa-user',
+ 'fa fa-user-circle',
+ 'fa fa-user-circle-o',
+ 'fa fa-user-o',
+ 'fa fa-user-plus',
+ 'fa fa-user-secret',
+ 'fa fa-user-times',
+ 'fa fa-users',
+ 'fa fa-vcard',
+ 'fa fa-vcard-o',
+ 'fa fa-video-camera',
+ 'fa fa-volume-control-phone',
+ 'fa fa-volume-down',
+ 'fa fa-volume-off',
+ 'fa fa-volume-up',
+ 'fa fa-warning',
+ 'fa fa-wheelchair',
+ 'fa fa-wheelchair-alt',
+ 'fa fa-wifi',
+ 'fa fa-window-close',
+ 'fa fa-window-close-o',
+ 'fa fa-window-maximize',
+ 'fa fa-window-minimize',
+ 'fa fa-window-restore',
+ 'fa fa-wrench',
+]
+export const FILE_ICONS = [
+ 'fa fa-file',
+ 'fa fa-file-archive-o',
+ 'fa fa-file-audio-o',
+ 'fa fa-file-code-o',
+ 'fa fa-file-excel-o',
+ 'fa fa-file-image-o',
+ 'fa fa-file-movie-o',
+ 'fa fa-file-o',
+ 'fa fa-file-pdf-o',
+ 'fa fa-file-photo-o',
+ 'fa fa-file-picture-o',
+ 'fa fa-file-powerpoint-o',
+ 'fa fa-file-sound-o',
+ 'fa fa-file-text',
+ 'fa fa-file-text-o',
+ 'fa fa-file-video-o',
+ 'fa fa-file-word-o',
+ 'fa fa-file-zip-o',
+]
+export const CHART_ICONS = [
+ 'fa fa-area-chart',
+ 'fa fa-bar-chart',
+ 'fa fa-bar-chart-o',
+ 'fa fa-line-chart',
+ 'fa fa-pie-chart',
+]
+export const EDITOR_ICONS = [
+ 'fa fa-align-center',
+ 'fa fa-align-justify',
+ 'fa fa-align-left',
+ 'fa fa-align-right',
+ 'fa fa-bold',
+ 'fa fa-chain',
+ 'fa fa-chain-broken',
+ 'fa fa-clipboard',
+ 'fa fa-columns',
+ 'fa fa-copy',
+ 'fa fa-cut',
+ 'fa fa-dedent',
+ 'fa fa-eraser',
+ 'fa fa-file',
+ 'fa fa-file-o',
+ 'fa fa-file-text',
+ 'fa fa-file-text-o',
+ 'fa fa-files-o',
+ 'fa fa-floppy-o',
+ 'fa fa-font',
+ 'fa fa-header',
+ 'fa fa-indent',
+ 'fa fa-italic',
+ 'fa fa-link',
+ 'fa fa-list',
+ 'fa fa-list-alt',
+ 'fa fa-list-ol',
+ 'fa fa-list-ul',
+ 'fa fa-outdent',
+ 'fa fa-paperclip',
+ 'fa fa-paragraph',
+ 'fa fa-paste',
+ 'fa fa-repeat',
+ 'fa fa-rotate-left',
+ 'fa fa-rotate-right',
+ 'fa fa-save',
+ 'fa fa-scissors',
+ 'fa fa-strikethrough',
+ 'fa fa-subscript',
+ 'fa fa-superscript',
+ 'fa fa-table',
+ 'fa fa-text-height',
+ 'fa fa-text-width',
+ 'fa fa-th',
+ 'fa fa-th-large',
+ 'fa fa-th-list',
+ 'fa fa-underline',
+ 'fa fa-undo',
+ 'fa fa-unlink',
+]
diff --git a/plugins/mixins/coupon-detail.vue b/plugins/mixins/coupon-detail.vue
new file mode 100644
index 0000000..89194b7
--- /dev/null
+++ b/plugins/mixins/coupon-detail.vue
@@ -0,0 +1,27 @@
+<script>
+export default {
+ data() {
+ return {
+ detailUrl: '',
+ }
+ },
+ mounted() {
+ this.getCouponDetail()
+ },
+ methods: {
+ async getCouponDetail() {
+ const { code, data } = await this.$elBusHttp.request(
+ `${this.detailUrl}/${this.$route.params.id}`
+ )
+ if (code === 0) {
+ if (this.$refs.form) {
+ this.$refs.form.updateForm(data)
+ }
+ }
+ },
+ goBack() {
+ this.$router.back()
+ },
+ },
+}
+</script>
diff --git a/plugins/utils.js b/plugins/utils.js
new file mode 100644
index 0000000..506b579
--- /dev/null
+++ b/plugins/utils.js
@@ -0,0 +1,104 @@
+import path from 'path'
+
+const utils = {
+ /**
+ * @description 铺平树形结构为一维数组
+ * @function flatten
+ * @param {Object|Object[]} arr 树节点或树节点数组
+ * @param {string} childKey=children 树子节点数组属性
+ * @returns {Object[]}
+ */
+ flatten: (arr, childKey = 'children') => {
+ const flattenArray = (arr, childKey) => {
+ if (Array.isArray(arr))
+ return Array.prototype.concat.apply(
+ [],
+ arr.map((i) => flattenArray(i, childKey))
+ )
+ else if (Reflect.has(arr, childKey))
+ return [arr, ...flattenArray(arr[childKey], childKey)]
+ return [arr]
+ }
+ return flattenArray(arr, childKey)
+ },
+ /**
+ * @description 去除菜单中的按钮,符合渲染左侧菜单的树型结构,直接修改源数据,并加上完整的路径
+ * @function filterMenu
+ * @param {array} array 后台返回的包括按钮的树形结构
+ */
+ filterMenu: (array, superPath = '/') => {
+ array.forEach((item) => {
+ item.fullPath = utils.getFullPath(superPath, item.menuHref)
+ item.iconClass = item.menuIcon || null
+ if (item.children && item.children.length > 0) {
+ if (item.children.find((child) => child.menuType === 'BUTTON')) {
+ item.children = []
+ } else {
+ utils.filterMenu(item.children, item.fullPath)
+ }
+ }
+ })
+ },
+ /**
+ * @description 将后台返回的树型结构转化为只包含叶子菜单的一维数组结构并去除按钮,且加上该叶子菜单的完整路径
+ * @function filterMenu2LeafArray
+ * @param {array} menus 后台返回的包括按钮的树形结构
+ * @param {array} init 用于递归的返回值
+ * @param {string} superPath 上级路由,用于递归时拼接完整路径
+ * @return {Array} 返回符合要求的一维数组
+ */
+ filterMenu2LeafArray: (menus, init = [], superPath = '/') => {
+ menus.forEach((menu) => {
+ if (menu && menu.children && menu.children.length > 0) {
+ if (menu.children.find((child) => child.menuType === 'BUTTON')) {
+ init = init.concat({
+ ...menu,
+ fullPath: utils.getFullPath(superPath, menu.menuHref),
+ })
+ } else {
+ init = utils.filterMenu2LeafArray(
+ menu.children,
+ init,
+ utils.getFullPath(superPath, menu.menuHref)
+ )
+ }
+ } else {
+ init = init.concat({
+ ...menu,
+ fullPath: utils.getFullPath(superPath, menu.menuHref),
+ })
+ }
+ })
+ return init
+ },
+ /**
+ * @description 将后台返回的树型结构转化为只包含按钮权限的一维数组
+ * @param {array} menus 后台返回的包括按钮的树形结构
+ * @param {array} init 用于递归的返回值
+ * @return {array} 返回符合要求的一维数组
+ */
+ filterMenuPermissions: (menus, init = []) => {
+ menus.forEach((menu) => {
+ if (menu && menu.menuPermission) {
+ if (!init.includes(menu.menuPermission)) {
+ init.push(menu.menuPermission)
+ }
+ }
+ if (menu && menu.children && menu.children.length > 0) {
+ init = utils.filterMenuPermissions(menu.children, init)
+ }
+ })
+ return init
+ },
+ getFullPath: (superPath, currentPath) => {
+ currentPath = currentPath || ''
+ if (currentPath.startsWith('http')) {
+ return currentPath
+ }
+ return currentPath.startsWith('/')
+ ? currentPath
+ : path.join(superPath, currentPath).replace(/\\/g, '/')
+ },
+}
+
+export default utils
diff --git a/services/auth.js b/services/auth.js
new file mode 100644
index 0000000..c6802b8
--- /dev/null
+++ b/services/auth.js
@@ -0,0 +1,25 @@
+export default function (http) {
+ return {
+ login(data) {
+ return http.request('flower/api/login/admin', {
+ method: 'post',
+ data,
+ })
+ },
+ smsLogin(data) {
+ return http.request('flower/api/login/admin/phone', {
+ method: 'post',
+ data,
+ })
+ },
+ getUserInfo() {
+ return http.request('flower/api/current/user')
+ },
+ changePassword(data) {
+ return http.request('flower/api/current/user/password/change', {
+ method: 'post',
+ data,
+ })
+ },
+ }
+}
diff --git a/services/base.js b/services/base.js
new file mode 100644
index 0000000..13bc2f5
--- /dev/null
+++ b/services/base.js
@@ -0,0 +1,25 @@
+import utils from 'el-business-utils'
+import { v4 as uuidv4 } from 'uuid'
+export default function (http) {
+ return {
+ createCaptcha() {
+ const uuid = uuidv4()
+ const config = process.env.config
+ return {
+ imageSrc: utils.joinPath(
+ config.httpBaseUri,
+ `flower/api/pub/captcha/${uuid}`
+ ),
+ captchaCodeId: uuid,
+ }
+ },
+ getAreaJson(){
+ return http.request('flower/api/pub/china/web/area/json')
+ },
+ getBaseInfo(){
+ return http.request('flower/v2/config-param/base/info')
+ }
+
+
+ }
+}
diff --git a/services/index.js b/services/index.js
new file mode 100644
index 0000000..af699b1
--- /dev/null
+++ b/services/index.js
@@ -0,0 +1,20 @@
+import Vue from 'vue'
+
+const context = require.context('./', false, /\.js$/)
+// eslint-disable-next-line
+let services = null
+export default (ctx, inject) => {
+ services = context
+ .keys()
+ .filter((key) => key !== './index.js')
+ .reduce(
+ (result, key) => ({
+ ...result,
+ [key.match(/([^/]+)\.js$/)[1]]: context(key).default(ctx.$elBusHttp),
+ }),
+ {}
+ )
+ Vue.prototype.$services = services
+ inject('services', services)
+}
+export { services }
--
Gitblit v1.9.3