ソースを参照

feat(agent): 新增设计师其他销售信息功能

- 添加其他销售信息页面,用于记录和展示设计师的其他销售数据
- 新增相关 API 接口和数据模型- 优化销售信息统计展示逻辑
- 增加获奖照片查看功能
EvilDragon 3 ヶ月 前
コミット
dbb39e53f7

+ 12 - 0
packages/app/src/core/libs/models.ts

@@ -874,6 +874,18 @@ export interface DesignerPointsStatistics {
    */
   obtainedYearCount: number
 }
+export interface DesignerOrderSaleOther {
+  id: number
+  supplierName: string
+  brandName: string
+  saleTime: string
+  projectName: string
+  customerName: string
+  customerPhone: string
+  orderAmount: number
+  createTime: string
+  userId: number
+}
 export interface Broker {
   createTime: string
   updateTime: string

+ 63 - 1
packages/merchant/src/core/libs/agent-requests.ts

@@ -12,6 +12,7 @@ import {
   DesignerAward,
   DesignerPointsStatistics,
   PointsOrder,
+  DesignerOrderSaleOther,
 } from '@designer-hub/app/src/core/libs/models'
 import dayjs from 'dayjs'
 /**
@@ -196,6 +197,7 @@ export const getSalesOrders = (query = {}) =>
       customerName: string
       customerPhone: string
       orderMoney: number
+      createTime: number
     }>
   >('/app-api/member/stylist-other-sales/pageByDate', query)
 /**
@@ -204,11 +206,71 @@ export const getSalesOrders = (query = {}) =>
 export const getPointsCount = (query = {}) =>
   httpGet<DesignerPointsStatistics>('/app-api/member/points-details/getPointsCount', query)
 /**
- * /app-api/member/points-order/pageDitch 设计师积分订单
+ * 设计师积分订单
  */
 export const getPointsOrders = (query = {}) =>
   httpGet<ResPageData<PointsOrder>>('/app-api/member/points-order/pageDitch', query)
 /**
+ * 获取设计师销售订单统计
+ */
+export const getSalesOrdersCount = (query = {}) =>
+  httpGet<{
+    /**
+     * 今年订单成交数量
+     */
+    orderCountYear: number
+    /**
+     * 今年成交金额
+     */
+    salesAmountYtd: number
+    /**
+     * 类型订单成交数量
+     */
+    orderCount: number
+    /**
+     * 累计成交金额
+     */
+    salesAmount: number
+    /**
+     * 其他订单数量
+     */
+    otherSale: number
+  }>('/app-api/member/stylist-other-sales/get', query)
+/**
+ * 其他销售列表
+ */
+export const getOtherSalesPage = (query = {}) =>
+  httpGet<ResPageData<DesignerOrderSaleOther>>(
+    '/app-api/member/stylist-other-sales/OtherSalesPage',
+    query,
+  )
+/**
+ * /app-api/member/stylist-other-sales/save 创建其他销售
+ */
+export const saveOtherSales = (data: Partial<DesignerOrderSaleOther>) =>
+  httpPost('/app-api/member/stylist-other-sales/save', data)
+/**
+ * 删除其他销售
+ */
+export const deleteOtherSales = (id: number) =>
+  httpDelete('/app-api/member/stylist-other-sales/delete', { id })
+/**
+ * 更新其他销售
+ */
+export const updateOtherSales = (data: Partial<DesignerOrderSaleOther>) =>
+  httpPost('/app-api/member/stylist-other-sales/update', data)
+export const getSalesOrdersCounts = (query = {}) =>
+  getSalesOrdersCount(query).then((res) => ({
+    ...res,
+    data: [
+      { label: '今年成交订单数', value: res.data.orderCountYear ?? 0, userId: '' },
+      { label: '今年成交金额', value: res.data.salesAmountYtd ?? 0 },
+      { label: '累计成交订单数', value: res.data.orderCount ?? 0 },
+      { label: '累计成交金额', value: res.data.salesAmount ?? 0 },
+      { label: '其他销售信息', value: `${res.data.otherSale ?? 0}条` },
+    ],
+  }))
+/**
  * 获取设计师积分统计数组
  */
 export const getPointsCounts = (query = {}) =>

+ 12 - 0
packages/merchant/src/core/libs/messages.ts

@@ -69,5 +69,17 @@ export const messages = {
       awardsFileUrl: '附件',
       createTime: '创建时间',
     },
+    designerOrderSaleOther: {
+      id: 'ID',
+      supplierName: '材料商名称',
+      brandName: '品牌名称',
+      saleTime: '销售时间',
+      projectName: '项目名称',
+      customerName: '客户名称',
+      customerPhone: '客户电话',
+      orderAmount: '订单金额',
+      createTime: '创建时间',
+      userId: '用户ID',
+    },
   },
 }

+ 16 - 0
packages/merchant/src/pages.json

@@ -228,6 +228,22 @@
         "navigationBarTitleText": "订单详情",
         "navigationBarBackgroundColor": "#fff"
       }
+    },
+    {
+      "path": "pages/agent/designer/archives/award/photos/index",
+      "type": "page",
+      "style": {
+        "navigationBarTitleText": "获奖照片",
+        "navigationBarBackgroundColor": "#fff"
+      }
+    },
+    {
+      "path": "pages/agent/designer/archives/sale-info/others/index",
+      "type": "page",
+      "style": {
+        "navigationBarTitleText": "其他销售信息",
+        "navigationBarBackgroundColor": "#fff"
+      }
     }
   ],
   "subPackages": []

+ 20 - 0
packages/merchant/src/pages/agent/designer/archives/award/photos/index.vue

@@ -0,0 +1,20 @@
+<route lang="json">
+{ "style": { "navigationBarTitleText": "获奖照片", "navigationBarBackgroundColor": "#fff" } }
+</route>
+<script setup lang="ts">
+const urlsStr = ref()
+const urls = computed(() => urlsStr.value?.split(','))
+onLoad((query?: Record<string | 'id', string>) => {
+  urlsStr.value = query?.urls
+})
+</script>
+
+<template>
+  <div class="flex-grow bg-white grid grid-cols-2 gap-4 p-4">
+    <template v-for="(it, index) in urls" :key="index">
+      <div><wd-img width="100%" mode="widthFix" :src="it"></wd-img></div>
+    </template>
+  </div>
+</template>
+
+<style scoped lang="scss"></style>

+ 22 - 29
packages/merchant/src/pages/agent/designer/archives/index.vue

@@ -14,6 +14,7 @@ import {
   getDesignerBasicInfo,
   getDesignerExtraEvents,
   getDesignerFamilyInfo,
+  getSalesOrdersCounts,
   saveDesignerFamilyInfo,
 } from '../../../../core/libs/agent-requests'
 import { messages } from '../../../../core/libs/messages'
@@ -113,6 +114,7 @@ const handleAddAward = async () => {
       type: 'TimePick',
       label: messages.objects.designerAward.awardsTime,
       props: {
+        defaultValue: dayjs().toDate(),
         placeholder: messages.objects.designerAward.awardsTimePlaceHolder,
       },
     },
@@ -150,6 +152,7 @@ const handleSubmit = async () => {
         )
         if (code === 0) {
           actionSheetStatus.value = false
+          formData.value = {}
           awardsListRef.value?.reload()
         }
       }
@@ -216,17 +219,13 @@ onLoad(async (query?: Record<string | 'id', any>) => {
               </wd-button>
             </div>
           </div>
-          <ListHelperEvo
-            ref="awardsListRef"
-            :request="getAwards"
-            :query="{ userId: id }"
-            :mock-list="[
-              { awardsName: '123', awardsRank: '123' },
-              {
-                awardsName: '筑巢奖',
-              },
-            ]"
-          >
+          <!--          :mock-list="[-->
+          <!--          { awardsName: '123', awardsRank: '123' },-->
+          <!--          {-->
+          <!--          awardsName: '筑巢奖',-->
+          <!--          },-->
+          <!--          ]"-->
+          <ListHelperEvo ref="awardsListRef" :request="getAwards" :query="{ userId: id }">
             <template #default="{ item, isLast }">
               <div class="flex flex-col gap-4 py-4">
                 <SectionHeading
@@ -236,10 +235,14 @@ onLoad(async (query?: Record<string | 'id', any>) => {
                 ></SectionHeading>
                 <SectionHeading
                   title="奖项日期"
-                  :end-text="dayjs(item.awardsTime).format('YYYY-MM-DD')"
+                  :end-text="item.awardsTime && dayjs(item.awardsTime).format('YYYY-MM-DD')"
                 ></SectionHeading>
                 <SectionHeading title="奖项名次" :end-text="item.awardsRank"></SectionHeading>
-                <SectionHeading title="奖项照片" end-arrow></SectionHeading>
+                <SectionHeading
+                  title="奖项照片"
+                  end-arrow
+                  :path="`/pages/agent/designer/archives/award/photos/index?urls=${item.awardsFileUrl ?? ''}`"
+                ></SectionHeading>
                 <wd-button type="text" @click="handleDeleteAward(item)">删除</wd-button>
                 <div v-if="!isLast" class="w-full h-1 bg-[#dadada]"></div>
               </div>
@@ -272,21 +275,7 @@ onLoad(async (query?: Record<string | 'id', any>) => {
             <!--              </wd-button>-->
             <!--            </div>-->
           </div>
-          <ListHelperEvo
-            ref="saleListRef"
-            :items="[
-              { label: '', value: 0, userId: '' },
-              { label: '', value: '' },
-            ]"
-            :query="{ userId: id }"
-            :mock-list="[
-              { label: '今年成交订单数', value: 6 },
-              { label: '今年成交金额', value: 100000 },
-              { label: '累计成交订单数', value: 6 },
-              { label: '累计成交金额', value: 100000 },
-              { label: '其他销售信息', value: '2条' },
-            ]"
-          >
+          <ListHelperEvo ref="saleListRef" :request="getSalesOrdersCounts" :query="{ userId: id }">
             <template #default="{ item, isLast }">
               <div class="flex flex-col gap-4 py-4">
                 <div v-if="isLast" class="w-full h-1 bg-[#dadada]"></div>
@@ -295,7 +284,11 @@ onLoad(async (query?: Record<string | 'id', any>) => {
                   size="base"
                   :end-text="String(item.value)"
                   end-arrow
-                  path="/pages/agent/designer/archives/sale-info/index"
+                  :path="
+                    !isLast
+                      ? `/pages/agent/designer/archives/sale-info/index?id=${id}`
+                      : `/pages/agent/designer/archives/sale-info/others/index?id=${id}`
+                  "
                 ></SectionHeading>
                 <!--                <SectionHeading-->
                 <!--                  title="奖项日期"-->

+ 50 - 57
packages/merchant/src/pages/agent/designer/archives/sale-info/index.vue

@@ -15,65 +15,31 @@ import PageHelper from '@/components/page-helper.vue'
 import dayjs from 'dayjs'
 import PageHelperEvo from '@/components/page-helper-evo.vue'
 import { useUserStore } from '@/store'
-import { getSalesOrders } from '@/core/libs/agent-requests'
+import { getSalesOrders, getSalesOrdersCount } from '@/core/libs/agent-requests'
 
 const userStore = useUserStore()
 const { userInfo } = storeToRefs(userStore)
+const id = ref()
 const current = ref('累计')
-const request =
-  ref<
-    () => Promise<IResData<{ shareCount: number; viewCount: number; winCustomerCount: number }>>
-  >()
-const data = ref()
 const info = computed(() => [
-  { label: '订单数', value: data.value?.shareCount || 0, unit: '' },
-  { label: '订单金额', value: data.value?.viewCount || 0, unit: '¥' },
+  {
+    label: '订单数',
+    value:
+      current.value === '累计' ? (data.value?.orderCount ?? 0) : (data.value?.orderCountYear ?? 0),
+    unit: '',
+  },
+  {
+    label: '订单金额',
+    value:
+      current.value === '累计' ? (data.value?.salesAmount ?? 0) : (data.value?.salesAmountYtd ?? 0),
+    unit: '¥',
+  },
 ])
-const tab = ref('分享')
-const tabs = ref([
-  { label: '分享明细', value: '分享' },
-  { label: '浏览明细', value: '浏览' },
-  { label: '获客明细', value: '获客' },
-])
-const query = computed(() => ({}))
-const setData = async ({ value }) => {
-  console.log(1111)
-  console.log(value)
-
-  // request.value = {
-  //   累计: () =>
-  //     getDesignerInfo(userInfo.value.userId).then((res) => ({
-  //       code: res.code,
-  //       msg: res.msg,
-  //       data: {
-  //         shareCount: res.data.shareCount,
-  //         viewCount: res.data.viewCount,
-  //         winCustomerCount: res.data.winCustomerCount,
-  //       },
-  //     })),
-  //   本年: () =>
-  //     countThisYear({ userId: userInfo.value.userId, year: new Date().getFullYear() }).then(
-  //       (res) => ({
-  //         code: res.code,
-  //         msg: res.msg,
-  //         data: {
-  //           shareCount: res.data.find((it) => it.bizType === '1')?.quantity || 0,
-  //           viewCount: res.data.find((it) => it.bizType === '2')?.quantity || 0,
-  //           winCustomerCount: res.data.find((it) => it.bizType === '3')?.quantity || 0,
-  //         },
-  //       }),
-  //     ),
-  // }[value]
-  // const { data: resData } = await request.value()
-  // data.value = resData
-  // console.log(data.value)
-}
-onMounted(async () => {
-  console.log(1111)
-
-  await setData({ value: current.value })
-  console.log(data.value)
-  // await countThisYear({ userId: userInfo.value.userId, year: new Date().getFullYear() })
+const query = computed(() => ({ isYear: current.value === '本年', userId: id.value }))
+const { data, run: setData } = useRequest(() => getSalesOrdersCount({ userId: id.value }))
+onLoad(async (query?: Record<string | 'id', string>) => {
+  id.value = query?.id
+  await setData()
 })
 </script>
 <template>
@@ -108,11 +74,38 @@ onMounted(async () => {
         </template>
       </div>
     </Card>
-    <PageHelperEvo :request="getSalesOrders">
+    <PageHelperEvo :request="getSalesOrders" :query="query">
       <template #default="{ source }">
-        <template v-for="(it, index) in source?.list" :key="index">
-          <Card>{{ it }}</Card>
-        </template>
+        <div class="flex flex-col gap-4">
+          <template v-for="(it, index) in source?.list" :key="index">
+            <Card>
+              <div class="grid grid-cols-[90px_1fr] gap-2.5">
+                <template
+                  v-for="(item, i) in [
+                    { label: '材料商', value: it.materials },
+                    { label: '品牌', value: it.materialsBrand },
+                    { label: '项目名称', value: it.projectName },
+                    { label: '客户姓名', value: it.customerName },
+                    { label: '客户电话', value: it.customerPhone },
+                    { label: '订单金额', value: it.orderMoney + '元' },
+                  ]"
+                  :key="i"
+                >
+                  <div class="text-black/40 text-sm font-normal font-['PingFang SC'] leading-none">
+                    {{ item.label }}
+                  </div>
+                  <div class="text-black/60 text-sm font-normal font-['PingFang SC'] leading-none">
+                    {{ item.value }}
+                  </div>
+                </template>
+              </div>
+              <div class="bg-[#f4f4f4] h-.25 my-4"></div>
+              <div class="text-black/60 text-sm font-normal font-['PingFang SC'] leading-normal">
+                {{ dayjs(it.createTime).format('YYYY-MM-DD HH:mm') }}
+              </div>
+            </Card>
+          </template>
+        </div>
       </template>
     </PageHelperEvo>
   </div>

+ 197 - 0
packages/merchant/src/pages/agent/designer/archives/sale-info/others/index.vue

@@ -0,0 +1,197 @@
+<route lang="json">
+{ "style": { "navigationBarTitleText": "其他销售信息", "navigationBarBackgroundColor": "#fff" } }
+</route>
+<script setup lang="ts">
+import {
+  getOtherSalesPage,
+  saveOtherSales,
+  deleteOtherSales,
+  updateOtherSales,
+} from '@/core/libs/agent-requests'
+import dayjs from 'dayjs'
+import Card from '@/components/card.vue'
+import PageHelperEvo from '@/components/page-helper-evo.vue'
+import BottomAppBar from '@/components/bottom-app-bar.vue'
+import DataForm from '@/components/data-form.vue'
+import { DataFormSchema } from '@/components/data-form'
+import { DesignerOrderSaleOther } from '@designer-hub/app/src/core/libs/models'
+import { ComponentExposed } from 'vue-component-type-helpers'
+import { requestToast } from '@designer-hub/app/src/core/utils/common'
+import { messages } from '@/core/libs/messages'
+
+const id = ref()
+const actionSheetStatus = ref(false)
+const formData = ref({})
+const schema = ref<DataFormSchema<Omit<DesignerOrderSaleOther, 'id' | 'createTime' | 'userId'>>>({
+  saleTime: {
+    type: 'TimePick',
+    label: messages.objects.designerOrderSaleOther.saleTime,
+    required: true,
+    props: {
+      defaultValue: new Date(),
+    },
+  },
+  supplierName: {
+    type: 'TextField',
+    label: messages.objects.designerOrderSaleOther.supplierName,
+    required: true,
+  },
+  brandName: {
+    type: 'TextField',
+    label: messages.objects.designerOrderSaleOther.brandName,
+    required: true,
+  },
+  projectName: {
+    type: 'TextField',
+    label: messages.objects.designerOrderSaleOther.projectName,
+    required: true,
+  },
+  customerName: {
+    type: 'TextField',
+    label: messages.objects.designerOrderSaleOther.customerName,
+    required: true,
+  },
+  customerPhone: {
+    type: 'TextField',
+    label: messages.objects.designerOrderSaleOther.customerPhone,
+  },
+  orderAmount: {
+    type: 'TextField',
+    label: messages.objects.designerOrderSaleOther.orderAmount,
+    required: true,
+  },
+})
+const rules = ref({
+  supplierName: [{ required: true, message: '请输入材料商' }],
+  brandName: [{ required: true, message: '请输入品牌' }],
+  projectName: [{ required: true, message: '请输入项目名称' }],
+  customerName: [{ required: true, message: '请输入客户姓名' }],
+  // customerPhone: [{ required: true, message: '请输入客户电话' }],
+  orderAmount: [{ required: true, message: '请输入订单金额' }],
+  saleTime: [{ required: true, message: '请输入销售时间' }],
+})
+const formRef = ref<ComponentExposed<typeof DataForm>>()
+const pageHelperRef = ref<ComponentExposed<typeof PageHelperEvo>>()
+const query = computed(() => ({ userId: id.value }))
+const handleSubmit = async () => {
+  const { valid } = await formRef.value!.validate()
+  if (!valid) return
+  if (Object.keys(formData.value).includes('id')) {
+    await requestToast(() => updateOtherSales(formData.value), {
+      success: true,
+      successTitle: '保存成功',
+    })
+  } else {
+    await requestToast(
+      () =>
+        saveOtherSales({
+          ...formData.value,
+          userId: Number(id.value),
+        }),
+      { success: true, successTitle: '保存成功' },
+    )
+  }
+  actionSheetStatus.value = false
+  formData.value = {}
+  await pageHelperRef.value?.reload()
+}
+const handleEdit = (item: DesignerOrderSaleOther) => {
+  formData.value = item
+  actionSheetStatus.value = true
+}
+const handleDelete = async (item: DesignerOrderSaleOther) => {
+  await requestToast(() => deleteOtherSales(item.id), { success: true, successTitle: '删除成功' })
+  await pageHelperRef.value?.reload()
+}
+onLoad((query?: Record<string | 'id', string>) => {
+  id.value = query?.id
+})
+</script>
+
+<template>
+  <div class="flex-grow flex flex-col">
+    <PageHelperEvo
+      ref="pageHelperRef"
+      :request="getOtherSalesPage"
+      :query="query"
+      class="flex-grow"
+    >
+      <template #default="{ source }">
+        <div class="flex flex-col gap-4 p-4">
+          <template v-for="(it, index) in source?.list" :key="index">
+            <Card>
+              <div class="grid grid-cols-[90px_1fr] gap-2.5">
+                <template
+                  v-for="(item, i) in [
+                    { label: '材料商', value: it.supplierName },
+                    { label: '品牌', value: it.brandName },
+                    { label: '项目名称', value: it.projectName },
+                    { label: '客户姓名', value: it.customerName },
+                    { label: '客户电话', value: it.customerPhone },
+                    { label: '订单金额', value: it.orderAmount + '元' },
+                  ]"
+                  :key="i"
+                >
+                  <div class="text-black/40 text-sm font-normal font-['PingFang_SC'] leading-none">
+                    {{ item.label }}
+                  </div>
+                  <div class="text-black/60 text-sm font-normal font-['PingFang_SC'] leading-none">
+                    {{ item.value }}
+                  </div>
+                </template>
+              </div>
+              <div class="bg-[#f4f4f4] h-.25 my-4"></div>
+              <div class="flex justify-between">
+                <div class="text-black/60 text-sm font-normal font-['PingFang_SC'] leading-normal">
+                  {{ dayjs(it.createTime).format('YYYY-MM-DD HH:mm') }}
+                </div>
+                <div class="flex gap-4">
+                  <wd-button plain :round="false" size="small" @click="handleEdit(it)">
+                    修改
+                  </wd-button>
+                  <wd-button
+                    type="error"
+                    plain
+                    :round="false"
+                    size="small"
+                    @click="handleDelete(it)"
+                  >
+                    删除
+                  </wd-button>
+                </div>
+              </div>
+            </Card>
+          </template>
+        </div>
+      </template>
+    </PageHelperEvo>
+    <div class="py-2 bg-[#f0f4ff]">
+      <div
+        class="text-center text-[#2357e9] text-xs font-normal font-['PingFang_SC'] leading-normal"
+      >
+        其他销售信息不参与线上销售统计
+      </div>
+    </div>
+    <BottomAppBar fixed placeholder>
+      <div class="w-full">
+        <wd-button block :round="false" @click="((actionSheetStatus = true), (formData = {}))">
+          添加
+        </wd-button>
+      </div>
+    </BottomAppBar>
+    <wd-action-sheet v-model="actionSheetStatus">
+      <div class="p-4">
+        <DataForm
+          ref="formRef"
+          :rules="rules"
+          :schema="schema"
+          :direction="'horizontal'"
+          v-model="formData"
+        ></DataForm>
+        <wd-button :round="false" block @click="handleSubmit">保存</wd-button>
+      </div>
+    </wd-action-sheet>
+  </div>
+</template>
+
+<style scoped lang="scss"></style>

+ 3 - 1
packages/merchant/src/types/uni-pages.d.ts

@@ -25,7 +25,9 @@ interface NavigateToOptions {
        "/pages/mine/agent/settings/index" |
        "/pages/agent/designer/archives/basic-info/index" |
        "/pages/agent/designer/archives/sale-info/index" |
-       "/pages/mine/merchant/orders/detail/index";
+       "/pages/mine/merchant/orders/detail/index" |
+       "/pages/agent/designer/archives/award/photos/index" |
+       "/pages/agent/designer/archives/sale-info/others/index";
 }
 interface RedirectToOptions extends NavigateToOptions {}