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