Przeglądaj źródła

feat: ai商情列表模块开发

周玉环 3 dni temu
rodzic
commit
cfbf42c326

+ 15 - 1
xinkeaboard-admin/config/router.config.js

@@ -519,7 +519,7 @@ export default [
           },
         ],
       },
-      // 订单管理
+      // 询盘管理
       {
         path: '/manage_order',
         icon: 'form',
@@ -568,8 +568,22 @@ export default [
             name: 'enquiry_receive_mail_setting',
             component: './manage/order/enquiry/receive_mail_setting',
           },
+          // ai商情分析列表
+          {
+            path: '/manage_order/ai_business_intelligence',
+            name: 'ai_business_intelligence',
+            component: './manage/order/enquiry/ai_business_intelligence',
+          },
         ],
       },
+      // 订单管理
+      {
+        path: '/manage_order/order_manage_list',
+        icon: 'form',
+        name: 'manage_order_list',
+        component: './manage/order_manage/order_list',
+        // routes: []
+      },
       // 结算管理
       {
         path: '/manage_bill',

+ 5 - 1
xinkeaboard-admin/src/components/SiderMenu/index.less

@@ -70,7 +70,7 @@
 
 :global {
   .ant-menu-item {
-    padding-left: 40px !important;
+    padding-left: 20px !important;
   }
 
   .top-nav-menu li.ant-menu-item {
@@ -113,6 +113,10 @@
 
   .ant-menu-dark .ant-menu-inline.ant-menu-sub {
     background: #222;
+
+    .ant-menu-item {
+      padding-left: 40px !important;
+    }
   }
 
   .ant-layout-sider {

+ 2 - 0
xinkeaboard-admin/src/locales/zh-CN/menu.js

@@ -62,11 +62,13 @@ export default {
   'menu.agreement': '协议管理',
   'menu.agreement.lists': '协议管理',
   'menu.order': '询盘管理',
+  'menu.manage_order_list': '订单管理',
   'menu.order.order_lists': '全部订单',
   'menu.order.service': '售后管理',
   'menu.order.evaluation': '评价管理',
   'menu.order.enquiry': '询盘管理',
   'menu.order.enquiry_receive_mail_setting': '询盘邮箱设置',
+  'menu.order.ai_business_intelligence': 'ai商情分析列表',
   'menu.express': '物流管理',
   'menu.express.express_lists': '物流公司',
   'menu.express.express': '物流配置',

+ 5 - 0
xinkeaboard-admin/src/pages/manage/models/order.js

@@ -206,5 +206,10 @@ export default {
         const response = yield call(sldCommonService, payload, 'post', 'v3/seller/admin/enquiry/cancle/garbage');
         if (callback) callback(response);
       },
+      // ai商情报告列表
+      *get_ai_business_list({ payload, callback }, { call }) {
+        const response = yield call(sldCommonService, payload, 'get', 'analysis/aiList');
+        if (callback) callback(response);
+      }
     },
 };

+ 275 - 0
xinkeaboard-admin/src/pages/manage/order/enquiry/ai_business_intelligence.js

@@ -0,0 +1,275 @@
+import { connect } from "dva/index";
+import React, { Component, Fragment } from "react";
+import { Form, Spin, Switch } from "antd";
+import {
+  sldIconBtn,
+  failTip,
+  sucTip,
+  getSldEmptyH,
+  dragSldTableColumn,
+  sldHandlePaginationData,
+  formItemLayoutModal,
+  getTableNum,
+  sldComLanguage,
+  getSldCopyData,
+  sldtbaleOpeBtnText,
+  sldPopConfirmDiy,
+  mobile_reg,
+  showMoreHelpTip,
+  list_com_page_size_10,
+  validatorNumbe,
+  list_com_page_more,
+  getSldComShowMoreTtex,
+  sldLlineRtextAddGoods,
+  sldLlineRtextAddGoodsAddMargin,
+} from "@/utils/utils";
+import global from "@/global.less";
+import StandardTable from "@/components/StandardTable";
+import SldModal from "@/components/SldModal/SldModal";
+import Search from "@/components/Search/Search";
+import Link from "umi/link";
+
+let pageSize = list_com_page_size_10;
+@connect(({ order, common, global }) => ({
+  order,
+  common,
+  global,
+}))
+@Form.create()
+export default class EnquiryLists extends Component {
+  constructor(props) {
+    super(props);
+    this.state = {
+      initLoading: false,
+      show_foot: false,
+      data: {}, //列表数据
+      title: "",
+      params: { pageSize: pageSize }, //搜索条件
+      operateData: [], //操作的数据
+      formValues: {}, //搜索条件、
+      columns: [
+        {
+          title: "序号",
+          dataIndex: "id",
+          align: "center",
+          width: 55,
+          render: (text, record, index) =>
+            getTableNum(this.state.params, pageSize, index),
+        },
+        {
+          title: `${sldComLanguage("公司名称")}`,
+          dataIndex: "companyName",
+          align: "center",
+          width: 100,
+        },
+        {
+          title: `${sldComLanguage("手机号")}`,
+          dataIndex: "phone",
+          align: "center",
+          width: 100,
+        },
+        {
+          title: `${sldComLanguage("月份")}`,
+          dataIndex: "email",
+          align: "center",
+          width: 80,
+        },
+        {
+          title: `${sldComLanguage("当月已消耗次数")}`,
+          dataIndex: "usedCount",
+          align: "center",
+          width: 80,
+        },
+        {
+          title: `${sldComLanguage("当月剩余次数")}`,
+          dataIndex: "leftCount",
+          align: "center",
+          width: 80,
+        },
+        {
+          title: `${sldComLanguage("报告获取时间")}`,
+          dataIndex: "createTime",
+          align: "center",
+          width: 100,
+        },
+        {
+          title: `${sldComLanguage("操作")}`,
+          width: 80,
+          align: "center",
+        //   fixed: "right",
+          render: (text, record) => (
+            <Fragment>
+              {sldtbaleOpeBtnText(`${sldComLanguage("查看报告")}`, () =>
+                this.detailRecord(record)
+              )}
+            </Fragment>
+          ),
+        },
+      ],
+      search_data: [
+        {
+          type: "input",
+          label: `${sldComLanguage("公司名称")}`,
+          name: "companyName",
+          placeholder: `${sldComLanguage("公司名称")}`,
+        },
+        {
+          type: "input",
+          label: `${sldComLanguage("手机号")}`,
+          name: "phone",
+          placeholder: `${sldComLanguage("请输入手机号")}`,
+        },
+      ],
+    };
+  }
+
+  componentDidMount() {
+    this.get_list({ pageSize: pageSize });
+  }
+
+  detailRecord = () => {
+    
+  }
+
+  //获取数据列表
+  get_list = (params) => {
+    this.setState({ initLoading: true });
+    const { dispatch } = this.props;
+    dispatch({
+      type: "order/get_ai_business_list",
+      payload: { ...params },
+      callback: (res) => {
+        this.setState({ initLoading: false });
+        if (res.state == 200) {
+          if (
+            (res.data.list == null || res.data.list.length == 0) &&
+            this.state.params.current > 1
+          ) {
+            params.current = params.current - 1;
+            this.get_list(params);
+          } else {
+            this.setState({
+              data: res.data,
+            });
+          }
+        }
+      },
+    });
+  };
+
+  handleTablePagination = (pagination, filtersArg, sorter, type = "main") => {
+    const { formValues } = this.state;
+    if (type == "main") {
+      const params = sldHandlePaginationData(
+        pagination,
+        filtersArg,
+        sorter,
+        formValues
+      );
+      pageSize = params.pageSize;
+      this.setState({ params });
+      this.get_list(params);
+    }
+  };
+
+  //表格拖动
+  resizeTable = (index, size, type, data) => {
+    let datas = dragSldTableColumn(index, size, data);
+    this.setState({ [type]: datas });
+  };
+
+  //搜索框内容的变化
+  sldSearChange = (val) => {
+    this.setState({
+      search_con: val.target.value,
+    });
+  };
+
+  //清空搜索内容
+  sldSearClear = () => {
+    this.setState({
+      search_con: "",
+    });
+    this.sldSearch("");
+  };
+
+  //搜索事件
+  search = (data) => {
+    const values = { ...data };
+    for (let i in values) {
+      if (values[i] == "") {
+        delete values[i];
+      }
+    }
+    this.setState({
+      formValues: values,
+      params: { pageSize: pageSize },
+    });
+    this.get_list({ pageSize: pageSize, ...values });
+  };
+  //搜索重置事件
+  seaReset = () => {
+    //搜索条件置为空
+    this.setState({
+      formValues: {},
+      params: { pageSize: pageSize },
+    });
+    this.get_list({ pageSize: pageSize });
+  };
+
+  render() {
+    const {
+      search_data,
+      columns,
+      initLoading,
+      data,
+      submiting,
+      title,
+      show_foot,
+    } = this.state;
+    const renderSerchData = search_data.filter((item) => !item.hide);
+    return (
+      <div className={global.common_page} style={{ flex: 1 }}>
+        {sldLlineRtextAddGoodsAddMargin(
+          "#69A2F2",
+          `${sldComLanguage("ai商情分析列表")}`,
+          0,
+          0,
+          10
+        )}
+        <div className={global.tableListForm}>
+          <Search
+            search_data={renderSerchData}
+            seaSubmit={(data) => this.search(data)}
+            seaReset={() => this.seaReset()}
+          />
+        </div>
+
+        <Spin spinning={initLoading}>
+          <div className={global.self_enquiry_list_wrap}>
+            {/*标准表格-start*/}
+            <StandardTable
+              data={data}
+              rowKey={"id"}
+              isCheck={false}
+              columns={columns}
+              onChange={(pagination, filtersArg, sorter) =>
+                this.handleTablePagination(
+                  pagination,
+                  filtersArg,
+                  sorter,
+                  "main"
+                )
+              }
+              resizeTable={(index, size) =>
+                this.resizeTable(index, size, "columns", columns)
+              }
+              isColumnResize={true}
+            />
+            {/*标准表格-end*/}
+          </div>
+        </Spin>
+      </div>
+    );
+  }
+}

+ 24 - 0
xinkeaboard-admin/src/pages/manage/order_manage/order_list.js

@@ -0,0 +1,24 @@
+import { Component } from "react";
+import router from "umi/router";
+
+export default class BasicIframe extends Component {
+  constructor(props) {
+    super(props);
+  }
+
+  render() {
+    return (
+      <div style={{ width: "100%", height: "100%" }}>
+        <iframe
+          src={
+            "https://xinke.sutextech.com/admin/order/orderby9710/?token=7d591e1b1bd66c936f9b3b5bb153ca7a7f786626"
+          }
+          width="100%"
+          height="100%"
+          frameBorder="0"
+          allowFullScreen
+        />
+      </div>
+    );
+  }
+}

+ 226 - 0
xinkeaboard-admin/src/pages/statistics/bigscreen/components/BarLineChart.js

@@ -0,0 +1,226 @@
+import React from "react";
+import * as echarts from "echarts";
+import topIcon from "../../../../assets/bigscreen/bar-head.svg";
+
+class BarLineChart extends React.Component {
+  constructor(props) {
+    super(props);
+    this.chartRef = React.createRef();
+    this.chartInstance = null;
+  }
+
+  componentDidMount() {
+    this.initChart();
+    window.addEventListener("resize", this.chartResize);
+  }
+
+  componentDidUpdate(prevProps) {
+    this.initChart();
+  }
+
+  componentWillUnmount() {
+    if (this.chartInstance) {
+      window.removeEventListener("resize", this.chartResize);
+      this.chartInstance.dispose();
+    }
+  }
+
+  chartResize() {
+    if (this.chartInstance) {
+      this.chartInstance.resize();
+    }
+  }
+
+  initChart() {
+    if (!this.chartInstance) {
+      this.chartInstance = echarts.init(this.chartRef.current);
+    }
+    const option = {
+      tooltip: {
+        trigger: "axis",
+        textStyle: {
+          fontSize: 25, // 设置字体大小
+          fontWeight: "bold", // 可选:加粗
+          // color: "#fff", // 可选:字体颜色
+        },
+        // formatter: (params) => {
+        //     console.log(params, 'params')
+        //   return `${params[0].name} <br/>${params.value[2]}`;
+        // },
+        // axisPointer: {
+        //   type: "cross",
+        //   crossStyle: {
+        //     type: "dashed",
+        //     color: "#fff",
+        //     width: 0.3,
+        //   },
+        // },
+      },
+      toolbox: {
+        feature: {
+          //   dataView: { show: true, readOnly: false },
+          //   magicType: { show: true, type: ["line", "bar"] },
+          //   restore: { show: true },
+          //   saveAsImage: { show: true },
+        },
+      },
+      legend: {
+        // data: ["总订单数", "总订单金额($)"],
+        data: [
+          {
+            name: "总订单数",
+          },
+          {
+            name: "总订单金额($)",
+            // 单独改 legend 圆点颜色
+            itemStyle: {
+              color: "rgba(41, 241, 250, 1)",
+            },
+          },
+        ],
+        bottom: 0,
+        textStyle: { color: "#fff", fontSize: "12px" },
+      },
+      grid: {
+        left: "4%",
+        right: "4%",
+        bottom: "12%",
+        top: "10%",
+        containLabel: true,
+      },
+      xAxis: [
+        {
+          type: "category",
+          data: this.props.xAxisdata,
+          axisPointer: {
+            type: "shadow",
+          },
+          axisLabel: {
+            show: true,
+            fontWeight: "bold",
+            fontSize: 12,
+            color: "#FFFFFF",
+          },
+        },
+      ],
+      yAxis: [
+        {
+          type: "value",
+          name: "总订单数",
+          //   min: 0,
+          //   max: 250,
+          //   interval: 50,
+          nameTextStyle: {
+            fontWeight: "bold",
+            fontSize: 12,
+            color: "#FFFFFF",
+          },
+          axisLabel: {
+            formatter: "{value}",
+            fontWeight: "bold",
+            fontSize: 12,
+            color: "#FFFFFF",
+          },
+          splitLine: {
+            // y 轴竖直方向虚线
+            show: true,
+            lineStyle: {
+              type: "dashed",
+              color: "#ccc",
+              width: 0.3,
+            },
+          },
+        },
+        {
+          type: "value",
+          name: "总订单金额($)",
+          //   min: 0,
+          //   max: 25,
+          //   interval: 5,
+          nameTextStyle: {
+            fontWeight: "bold",
+            fontSize: 12,
+            color: "#FFFFFF",
+          },
+          axisLabel: {
+            formatter: "{value}",
+            fontWeight: "bold",
+            fontSize: 12,
+            color: "#FFFFFF",
+          },
+          splitLine: {
+            // y 轴竖直方向虚线
+            show: false,
+            lineStyle: {
+              type: "dashed",
+              color: "#ccc",
+              width: 0.3,
+            },
+          },
+        },
+      ],
+      series: [
+        {
+          name: "总订单数",
+          type: "bar",
+          tooltip: {
+            valueFormatter: function(value) {
+              return value;
+            },
+          },
+          barWidth: 28,
+          itemStyle: {
+            color: new echarts.graphic.LinearGradient(
+              0,
+              0,
+              0,
+              1, // 0,0到0,1表示从上到下
+              [
+                { offset: 0, color: "#125CB2" }, // 顶部颜色
+                { offset: 1, color: "rgba(18,92,178,0)" }, // 底部透明
+              ]
+            ),
+          },
+          data: this.props.orderData,
+        },
+
+        {
+          name: "总订单金额($)",
+          type: "line",
+          smooth: true, // ✅ 曲线
+          symbol: "none",
+          yAxisIndex: 1,
+          tooltip: {
+            valueFormatter: function(value) {
+              return value;
+            },
+          },
+          lineStyle: {
+            color: "rgba(41, 241, 250, 1)",
+            width: 4,
+          },
+          data: this.props.amountData
+        },
+        {
+          type: "pictorialBar",
+          symbol: `image://${topIcon}`, // 图片 URL
+          symbolSize: [30, 30], // 图片大小
+          symbolPosition: "end", // 关键:自动到柱子最高点
+          symbolOffset: [0, -15], // 向上偏移,让图片在柱子顶部
+          tooltip: { show: false }, // ✅ 不显示 tooltip
+          data: this.props.orderData.map((item) => (item == 0 ? null : item)),
+          z: 4,
+        },
+      ],
+    };
+    this.chartInstance.setOption(option);
+  }
+
+  render() {
+    return (
+      <div style={{ width: "100%", height: "100%" }} ref={this.chartRef} />
+    );
+  }
+}
+
+export default BarLineChart;

+ 12 - 9
xinkeaboard-admin/src/pages/statistics/bigscreen/components/Order.js

@@ -2,32 +2,35 @@ import React from "react";
 import { Spin } from "antd";
 import { connect } from "dva";
 import PanelNav from "./PanelNav";
-// import BarChart from "./BarChart";
+import BarLineChart from "./BarLineChart";
 import RadioButtonGroup from "./RadioButtonGroup";
 import styles from "../styles/common.less";
 
 const OrderBasic = ({ data, options, current, loading, dispatch }) => {
   const onChange = (val) => {
     dispatch({
-      type: "bigscreen/setEnquireData",
+      type: "bigscreen/setOrderData",
       payload: { current: val },
     });
     dispatch({
-      type: "bigscreen/load_enquire_data",
+      type: "bigscreen/load_order_basic",
     });
   };
   const parseData = (barData) => {
     const xAxisdata = [];
-    const seriesData = [];
+    const orderData = [];
+    const amountData = [];
 
     barData.forEach((item) => {
-      xAxisdata.push(item.month);
-      seriesData.push(item.newMemberNum);
-    });
+      xAxisdata.push(item.date);
+      orderData.push(item.order_count);
+      amountData.push(item.total_amount)
+    }); 
 
     return {
       xAxisdata,
-      seriesData,
+      orderData,
+      amountData
     };
   };
 
@@ -45,7 +48,7 @@ const OrderBasic = ({ data, options, current, loading, dispatch }) => {
           </div>
         </div>
         <div className={styles.common_content}>
-          {/* <BarChart {...parseData(data)} /> */}
+          <BarLineChart {...parseData(data)} />
         </div>
       </div>
     </Spin>

+ 1 - 1
xinkeaboard-admin/src/pages/statistics/bigscreen/index.less

@@ -47,7 +47,7 @@
     }
 
     .ant-spin-nested-loading > div > .ant-spin {
-      top: 85px;
+      top: 25px;
     }
 
     .ant-spin-dot {

+ 30 - 21
xinkeaboard-admin/src/pages/statistics/models/bigscreen.js

@@ -1,4 +1,4 @@
-import { sldCommonService } from "@/utils/utils";
+import { sldCommonService, safeJsonParse } from "@/utils/utils";
 import moment from "moment";
 
 export default {
@@ -193,29 +193,11 @@ export default {
       options: [
         {
           label: "近7日",
-          value: {
-            startTime:
-              moment()
-                .subtract(7, "days")
-                .format("YYYY-MM-DD") + " 00:00:00",
-            endTime:
-              moment()
-                .subtract(1, "days")
-                .format("YYYY-MM-DD") + " 23:59:59:999",
-          },
+          value: "7",
         },
         {
           label: "近30日",
-          value: {
-            startTime:
-              moment()
-                .subtract(30, "days")
-                .format("YYYY-MM-DD") + " 00:00:00",
-            endTime:
-              moment()
-                .subtract(1, "days")
-                .format("YYYY-MM-DD") + " 23:59:59:999",
-          },
+          value: "30",
         },
       ],
       current: "近7日",
@@ -440,6 +422,32 @@ export default {
       });
     },
 
+    // 订单概况
+    *load_order_basic({ payload }, { put, call, select }) {
+      const current = yield select(
+        (state) => state.bigscreen.orderData.current
+      );
+      const options = yield select(
+        (state) => state.bigscreen.orderData.options
+      );
+      const condition = options.filter((item) => item.label == current)[0].value;
+      payload = { ...payload, day: condition };
+      yield put({
+        type: "setOrderData",
+        payload: { loading: true },
+      });
+      const response = yield call(
+        sldCommonService,
+        payload,
+        "get",
+        "v3/business/admin/orderInfo/orderList"
+      );
+      yield put({
+        type: "setOrderData",
+        payload: { data: safeJsonParse(response.msg, []), loading: false },
+      });
+    },
+
     // 初始化数据
     *load_data({ payload }, { put, call, all }) {
       // 更新时间
@@ -465,6 +473,7 @@ export default {
         put({ type: "load_search_rank" }),
         put({ type: "load_store_traffic" }),
         put({ type: "load_world_map" }),
+        put({ type: 'load_order_basic' })
       ]);
     },
   },

+ 8 - 0
xinkeaboard-admin/src/utils/utils.js

@@ -1409,6 +1409,14 @@ export async function sldCommonService(params, method, url, data_type = '') {
   }
 }
 
+export const safeJsonParse = (val, defaultValue) => {
+  try {
+    return JSON.parse(val);
+  } catch {
+    return defaultValue ?? {};
+  }
+};
+
 async function refreshToken() {
   let param = new FormData();
   param.append('grant_type', 'refresh_token');

+ 9 - 2
xinkeaboard-promotion-portal/src/components/LoginDialog.vue

@@ -89,7 +89,7 @@ const validatePhone = (rule: any, value: any, callback: any) => {
   if (value === '') {
     callback(new Error('请输入手机号'));
   } else {
-    if (/(1[3-9]\d{9}$)/.test(value)) {
+    if (!/(1[3-9]\d{9}$)/.test(value)) {
       callback(new Error('请输入正确的手机号'));
     } else {
       callback();
@@ -139,7 +139,14 @@ const rules = reactive<FormRules<RuleForm>>({
 });
 
 const acceptCode = () => {
-  modalVisible.value = true;
+  if (ruleFormRef.value) {
+    ruleFormRef.value.validateField(['phone'], (isValidate) => {
+      console.log(isValidate, 'isValidate');
+      if (isValidate) {
+        modalVisible.value = true;
+      }
+    });
+  }
 };
 
 const closed = () => {

+ 3 - 0
xinkeaboard-promotion-portal/src/utils/api.ts

@@ -31,3 +31,6 @@ export const analysisRival = (payload: AnalysisRival) => http.post('/analysis/ri
 // 定性分析接口
 export const analysisQualitative = (payload: string) =>
   http.get(`/analysis/qualitative?keyword=${payload}`);
+
+// 获取验证码
+export const verificationCode = () => http.post('v3/member/front/active/verification/code');

+ 1 - 1
xinkeaboard-promotion-portal/src/utils/pdf.ts

@@ -22,7 +22,7 @@ export const downloadPDF = async (pdfContent?: HTMLElement) => {
   });
 
   try {
-    if (!pdfContent) pdfContent = document.querySelector('.record-wrap') as HTMLElement;
+    if (!pdfContent) pdfContent = document.querySelector('.record') as HTMLElement;
 
     if (!expanded.value) {
       mainStore.setExpanded(true);