This commit is contained in:
ylj20011123 2025-10-24 14:51:57 +08:00
parent 188282c4f0
commit 7cc6a538e7
8 changed files with 267 additions and 105 deletions

View File

@ -45,7 +45,7 @@
<view class="chart-content"> <view class="chart-content">
<view class="pie-chart-container"> <view class="pie-chart-container">
<QiunDataCharts type="pie" :opts="pieChartOpts" :chartData="pieChartData" :canvas2d="true" <QiunDataCharts type="pie" :opts="pieChartOpts" :chartData="pieChartData" :canvas2d="true"
:inScrollView="true" canvasId="inventoryStructurePieChart" /> :inScrollView="true" canvasId="inventoryStructurePieChart" tooltipFormat="ShopTypeNumberRate" />
</view> </view>
</view> </view>
</view> </view>
@ -156,7 +156,8 @@ export default {
padding: [5, 5, 5, 5], padding: [5, 5, 5, 5],
dataLabel: true, dataLabel: true,
legend: { legend: {
show: true show: true,
lineHeight: 30
}, },
extra: { extra: {
pie: { pie: {

View File

@ -72,14 +72,8 @@
</view> </view>
<view class="chart-content"> <view class="chart-content">
<view class="line-chart-container"> <view class="line-chart-container">
<QiunDataCharts <QiunDataCharts type="line" :opts="timeDistributionOpts" :chartData="timeDistributionChartData"
type="line" :canvas2d="true" :inScrollView="true" canvasId="timeDistributionChart" />
:opts="timeDistributionOpts"
:chartData="timeDistributionChartData"
:canvas2d="true"
:inScrollView="true"
canvasId="timeDistributionChart"
/>
</view> </view>
</view> </view>
</view> </view>
@ -92,21 +86,8 @@
</view> </view>
<view class="chart-content"> <view class="chart-content">
<view class="map-chart-container"> <view class="map-chart-container">
<QiunDataCharts <QiunDataCharts type="pie" :opts="regionDistributionOpts" :chartData="regionDistributionData" :canvas2d="true"
type="pie" :inScrollView="true" canvasId="regionDistributionChart" />
:opts="regionDistributionOpts"
:chartData="regionDistributionData"
:canvas2d="true"
:inScrollView="true"
canvasId="regionDistributionChart"
/>
<view class="region-legend">
<view class="legend-item" v-for="(item, index) in regionData" :key="index">
<view class="legend-color" :style="{ backgroundColor: item.color }"></view>
<text class="legend-name">{{ item.name }}</text>
<text class="legend-value">¥{{ formatMoney(item.amount) }}</text>
</view>
</view>
</view> </view>
</view> </view>
</view> </view>
@ -119,14 +100,8 @@
</view> </view>
<view class="chart-content"> <view class="chart-content">
<view class="bar-chart-container"> <view class="bar-chart-container">
<QiunDataCharts <QiunDataCharts type="column" :opts="salesVolumeOpts" :chartData="salesVolumeChartData" :canvas2d="true"
type="column" :inScrollView="true" canvasId="salesVolumeChart" />
:opts="salesVolumeOpts"
:chartData="salesVolumeChartData"
:canvas2d="true"
:inScrollView="true"
canvasId="salesVolumeChart"
/>
</view> </view>
</view> </view>
</view> </view>
@ -139,14 +114,8 @@
</view> </view>
<view class="chart-content"> <view class="chart-content">
<view class="bar-chart-container"> <view class="bar-chart-container">
<QiunDataCharts <QiunDataCharts type="column" :opts="salesAmountOpts" :chartData="salesAmountChartData" :canvas2d="true"
type="column" :inScrollView="true" canvasId="salesAmountChart" />
:opts="salesAmountOpts"
:chartData="salesAmountChartData"
:canvas2d="true"
:inScrollView="true"
canvasId="salesAmountChart"
/>
</view> </view>
</view> </view>
</view> </view>
@ -154,7 +123,9 @@
</template> </template>
<script> <script>
import { wrapTreeNode } from '../../../util/dateTime';
import QiunDataCharts from './qiun-data-charts/components/qiun-data-charts/qiun-data-charts.vue' import QiunDataCharts from './qiun-data-charts/components/qiun-data-charts/qiun-data-charts.vue'
import request from "@/util/index.js";
export default { export default {
components: { components: {
@ -171,38 +142,18 @@ export default {
dealUsers: 8834, dealUsers: 8834,
avgOrderValue: 5136, avgOrderValue: 5136,
// //
timeDistributionData: { timeDistributionData: {
categories: ['00:00', '02:00', '04:00', '06:00', '08:00', '10:00', '12:00', '14:00', '16:00', '18:00', '20:00', '22:00'], categories: [],
transactionData: [234, 156, 89, 123, 567, 1234, 2345, 1876, 1567, 2890, 2456, 1876], transactionData: [],
amountData: [12345, 8234, 4567, 6789, 34567, 67890, 123456, 98765, 82345, 156789, 123456, 98765] amountData: []
}, },
// //
regionData: [ regionData: [],
{ name: '云南省', amount: 5678901, percentage: 28.5, color: '#576EFF' },
{ name: '广东省', amount: 3456789, percentage: 17.3, color: '#52C41A' },
{ name: '北京市', amount: 2345678, percentage: 11.8, color: '#FAAD14' },
{ name: '上海市', amount: 1987654, percentage: 10.0, color: '#FF7875' },
{ name: '四川省', amount: 1567890, percentage: 7.9, color: '#B37FEB' },
{ name: '浙江省', amount: 1234567, percentage: 6.2, color: '#13C2C2' },
{ name: '江苏省', amount: 987654, percentage: 5.0, color: '#722ED1' },
{ name: '其他', amount: 2567890, percentage: 13.3, color: '#999999' }
],
// //
salesVolumeData: [ salesVolumeData: [],
{ name: '云南白药套装', volume: 3456 },
{ name: '普洱茶礼盒', volume: 2890 },
{ name: '鲜花饼组合', volume: 2345 },
{ name: '三七粉精品', volume: 1876 },
{ name: '云南咖啡豆', volume: 1567 },
{ name: '玉石手镯', volume: 1234 },
{ name: '民族服饰', volume: 987 },
{ name: '鲜花精油', volume: 876 },
{ name: '手工皂套装', volume: 654 },
{ name: '银饰项链', volume: 543 }
],
// //
salesAmountData: [ salesAmountData: [
@ -227,12 +178,12 @@ export default {
categories: this.timeDistributionData.categories, categories: this.timeDistributionData.categories,
series: [ series: [
{ {
name: '交易量', name: '客单量',
data: this.timeDistributionData.transactionData data: this.timeDistributionData.transactionData
}, },
{ {
name: '交易额(÷100)', name: '交易额',
data: this.timeDistributionData.amountData.map(v => v / 100) data: this.timeDistributionData.amountData
} }
] ]
} }
@ -245,7 +196,7 @@ export default {
padding: [15, 15, 15, 15], padding: [15, 15, 15, 15],
dataLabel: false, dataLabel: false,
legend: { legend: {
show: false show: true
}, },
xAxis: { xAxis: {
disableGrid: true disableGrid: true
@ -279,7 +230,7 @@ export default {
series: [{ series: [{
data: this.regionData.map(item => ({ data: this.regionData.map(item => ({
name: item.name, name: item.name,
value: item.amount value: item.value
})) }))
}] }]
} }
@ -288,11 +239,10 @@ export default {
// //
regionDistributionOpts() { regionDistributionOpts() {
return { return {
color: this.regionData.map(item => item.color),
padding: [5, 5, 5, 5], padding: [5, 5, 5, 5],
dataLabel: true, dataLabel: true,
legend: { legend: {
show: false show: true
}, },
extra: { extra: {
pie: { pie: {
@ -316,7 +266,7 @@ export default {
), ),
series: [{ series: [{
name: '销售量', name: '销售量',
data: this.salesVolumeData.map(item => item.volume) data: this.salesVolumeData.map(item => item.value)
}] }]
} }
}, },
@ -406,8 +356,142 @@ export default {
} }
} }
}, },
onReady() {
//
this.handleGetAllData()
},
methods: { methods: {
//
handleGetAllData() {
//
this.handleGetTradingHoursData()
//
this.handleGetDistributionOfRegion()
//
this.hanleGetShopSalesVolumeData()
},
//
async hanleGetShopSalesVolumeData() {
const req = {
action_type: "getCommoditySaleSort",
province_code: 5564,
rowNum: 5
}
const data = await request.$cloudUrlGet(req);
console.log('datadatadatadatadata', data);
let list = data.COMMODITYSALE_DESC
let res = []
if (list && list.length > 0) {
list.forEach((item) => {
res.push({
name: item.COMMODITY_NAME,
value: item.SELLCOUNT,
})
})
}
this.salesVolumeData = res
//
// salesVolumeData: [
// { name: '', value: 3456 },
// { name: '', value: 2890 },
// ]
},
//
async handleGetDistributionOfRegion() {
const serviceReq = {
Province_Code: "530000"
}
const serviceList = await request.$apiGet(
"CommercialApi/BaseInfo/GetServerpartList",
serviceReq
);
console.log('serviceListserviceListserviceList', serviceList);
let serviceLists = serviceList.Result_Data.List
let allService = ""
if (serviceLists && serviceLists.length > 0) {
serviceLists.forEach((item) => {
if (allService) {
allService += `,${item.SERVERPART_ID}`
} else {
allService = `${item.SERVERPART_ID}`
}
})
}
// id id
const req = {
StartDate: "2025-04-01",
EndDate: "2025-04-30",
DataType: 1,
ServerpartIds: allService,
DataSourceType: 1,
}
const data = await request.$apiGet(
"EShangApiMain/Revenue/GetRevenueReport",
req
);
let list = wrapTreeNode(data.Result_Data.List)
console.log('交易地域分布', list);
let res = []
if (list && list.length > 0) {
list.forEach((item) => {
if (item.children && item.children.length > 0) {
item.children.forEach((subItem) => {
res.push({ name: subItem.Serverpart_Name, value: subItem.TotalRevenue.Revenue_Amount })
})
}
})
}
this.regionData = res
//
// regionData: [
// { name: '', value: 5678901 },
// { name: '广', value: 3456789 },
// ],
},
//
async handleGetTradingHoursData() {
const req = {
Province_Code: '530000',
Statistics_Date: '2025-09-01',
Serverpart_ID: '',
TimeSpan: 1
}
const data = await request.$apiGet(
"CommercialApi/Revenue/GetTransactionTimeAnalysis",
req
);
let list = data.Result_Data.CommonScatterList
console.log('交易时间分布', list);
let categories = []
let transactionData = [] //
let amountData = [] //
if (list && list.length > 0) {
list.forEach((item) => {
let hour = Number(item.name)
if (hour % 4 === 0 || hour === 0) {
categories.push(`${item.name}`)
}
// let hour = Number(item.name) < 10 ? `0${item.name}:00` : `${item.name}:00`
transactionData.push(item.data)
amountData.push(item.key)
})
}
this.timeDistributionData = {
categories: categories,
transactionData: transactionData,
amountData: amountData
}
//
// timeDistributionData: {
// categories: ['00:00', '02:00', '04:00', '06:00', '08:00', '10:00', '12:00', '14:00', '16:00', '18:00', '20:00', '22:00'],
// transactionData: [234, 156, 89, 123, 567, 1234, 2345, 1876, 1567, 2890, 2456, 1876],
// amountData: [12345, 8234, 4567, 6789, 34567, 67890, 123456, 98765, 82345, 156789, 123456, 98765]
// }
},
formatNumber(num) { formatNumber(num) {
return num.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",") return num.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",")
}, },
@ -498,32 +582,80 @@ export default {
&.total-amount { &.total-amount {
background: linear-gradient(135deg, #1890ff, #40a9ff); background: linear-gradient(135deg, #1890ff, #40a9ff);
&::after { content: '📊'; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); font-size: 24rpx; }
&::after {
content: '📊';
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
font-size: 24rpx;
}
} }
&.total-money { &.total-money {
background: linear-gradient(135deg, #52c41a, #73d13d); background: linear-gradient(135deg, #52c41a, #73d13d);
&::after { content: '💰'; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); font-size: 24rpx; }
&::after {
content: '💰';
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
font-size: 24rpx;
}
} }
&.conversion-rate { &.conversion-rate {
background: linear-gradient(135deg, #faad14, #ffc53d); background: linear-gradient(135deg, #faad14, #ffc53d);
&::after { content: '📈'; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); font-size: 24rpx; }
&::after {
content: '📈';
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
font-size: 24rpx;
}
} }
&.order-users { &.order-users {
background: linear-gradient(135deg, #722ed1, #9254de); background: linear-gradient(135deg, #722ed1, #9254de);
&::after { content: '👥'; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); font-size: 24rpx; }
&::after {
content: '👥';
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
font-size: 24rpx;
}
} }
&.deal-users { &.deal-users {
background: linear-gradient(135deg, #eb2f96, #f759ab); background: linear-gradient(135deg, #eb2f96, #f759ab);
&::after { content: '✅'; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); font-size: 24rpx; }
&::after {
content: '✅';
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
font-size: 24rpx;
}
} }
&.avg-order { &.avg-order {
background: linear-gradient(135deg, #13c2c2, #36cfc9); background: linear-gradient(135deg, #13c2c2, #36cfc9);
&::after { content: '🛒'; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); font-size: 24rpx; }
&::after {
content: '🛒';
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
font-size: 24rpx;
}
} }
} }

View File

@ -46,7 +46,7 @@
<view class="chart-content"> <view class="chart-content">
<view class="pie-chart-container"> <view class="pie-chart-container">
<QiunDataCharts type="pie" :opts="pieChartOpts" :chartData="pieChartData" :canvas2d="true" <QiunDataCharts type="pie" :opts="pieChartOpts" :chartData="pieChartData" :canvas2d="true"
:inScrollView="true" canvasId="productTypePieChart" /> :inScrollView="true" canvasId="productTypePieChart" tooltipFormat="ShopTypeDistribution" />
</view> </view>
</view> </view>
</view> </view>
@ -384,9 +384,6 @@ export default {
this.salesRankingData = res this.salesRankingData = res
this.productList = list this.productList = list
}, },
// //
getScreenWidth() { getScreenWidth() {
try { try {

View File

@ -77,7 +77,7 @@
<view class="chart-content"> <view class="chart-content">
<view class="trend-chart-container"> <view class="trend-chart-container">
<QiunDataCharts type="line" :opts="trendChartOpts" :chartData="trendChartData" :canvas2d="true" <QiunDataCharts type="line" :opts="trendChartOpts" :chartData="trendChartData" :canvas2d="true"
:inScrollView="true" canvasId="trendChart" /> :inScrollView="true" canvasId="trendChart" tooltipFormat="tradingTrendData" />
</view> </view>
</view> </view>
</view> </view>

View File

@ -95,6 +95,20 @@ const cfu = {
"option": {}, "option": {},
//下面是自定义format配置因除H5端外的其他端无法通过props传递函数只能通过此属性对应下标的方式来替换 //下面是自定义format配置因除H5端外的其他端无法通过props传递函数只能通过此属性对应下标的方式来替换
"formatter": { "formatter": {
"ShopTypeNumberRate": function (item, category, index, opts) {
console.log('', item);
console.log('', category);
console.log('', index);
console.log('', opts);
return `${item.name}${item.data}`
},
"tradingTrendData": function (item, category, index, opts) {
return `${category}${item.name} ${item.data}${item.name === '订单量' ? '笔' : '元'}`
},
"ShopTypeDistribution": function (item, category, index, opts) {
return `${item.name}${item.data}`
},
'SalesRankingOfProducts': function (item, category, index, opts) { 'SalesRankingOfProducts': function (item, category, index, opts) {
// console.log('', item); // console.log('', item);
// console.log('', category); // console.log('', category);

View File

@ -1,6 +1,7 @@
<template> <template>
<page-meta :page-style="'overflow-x:hidden'"></page-meta> <page-meta :page-style="'overflow-x:hidden'"></page-meta>
<scroll-view scroll-y @scroll="handleScroll" class="digital-dashboard"> <scroll-view scroll-y @scroll="handleScroll" class="digital-dashboard" :scroll-into-view="scrollIntoView"
:scroll-with-animation="true">
<!-- Tab切换区域 --> <!-- Tab切换区域 -->
<view class="tab-container"> <view class="tab-container">
<view class="tab-list"> <view class="tab-list">
@ -31,7 +32,7 @@
</view> </view>
</view> </view>
</view> </view>
<view id="top"> </view>
<!-- 内容展示区域 --> <!-- 内容展示区域 -->
<view class="content-container"> <view class="content-container">
<!-- 经营数据分析 --> <!-- 经营数据分析 -->
@ -182,7 +183,7 @@ export default {
}, },
data() { data() {
return { return {
activeTab: 1, activeTab:2,
tabList: [ tabList: [
{ name: '经营数据分析', key: 'business' }, { name: '经营数据分析', key: 'business' },
{ name: '供应链数据分析', key: 'supply' }, { name: '供应链数据分析', key: 'supply' },
@ -227,7 +228,8 @@ export default {
isNavCollapsed: true, isNavCollapsed: true,
// //
sessionData: {}, sessionData: {},
pageScrollTop: 0 pageScrollTop: 0,
scrollIntoView: ""
} }
}, },
computed: { computed: {
@ -257,6 +259,7 @@ export default {
}, },
methods: { methods: {
switchTab(index) { switchTab(index) {
this.scrollIntoView = 'top'
this.activeTab = index; this.activeTab = index;
// //
@ -273,21 +276,23 @@ export default {
// //
scrollToComponent(componentId) { scrollToComponent(componentId) {
this.scrollIntoView = componentId
this.activeNavItem = componentId; this.activeNavItem = componentId;
setTimeout(() => { // setTimeout(() => {
uni.createSelectorQuery().select('#' + componentId).boundingClientRect((data) => { // uni.createSelectorQuery().select('#' + componentId).boundingClientRect((data) => {
if (data) { // if (data) {
uni.createSelectorQuery().selectViewport().scrollOffset((scrollData) => { // uni.createSelectorQuery().selectViewport().scrollOffset((scrollData) => {
const targetScrollTop = scrollData.scrollTop + data.top - 80; // const targetScrollTop = scrollData.scrollTop + data.top - 80;
uni.pageScrollTo({ // uni.pageScrollTo({
scrollTop: Math.max(0, targetScrollTop), // scrollTop: Math.max(0, targetScrollTop),
duration: 300 // duration: 300
}); // });
}).exec(); // }).exec();
} // }
}).exec(); // }).exec();
}, 100); // }, 100);
}, },
// //
@ -334,11 +339,13 @@ export default {
.tab-container { .tab-container {
background: @bg-white; background: @bg-white;
box-shadow: @shadow-light; box-shadow: @shadow-light;
position: sticky; // position: sticky;
position: fixed;
top: 0; top: 0;
z-index: 100; z-index: 100;
.tab-list { .tab-list {
height: 80rpx;
display: flex; display: flex;
padding: 0 32rpx; padding: 0 32rpx;
box-sizing: border-box; box-sizing: border-box;
@ -417,6 +424,7 @@ export default {
.content-container { .content-container {
padding: 32rpx; padding: 32rpx;
padding-top: 112rpx;
.tab-content { .tab-content {
/* 移除切换动画 */ /* 移除切换动画 */

View File

@ -10,6 +10,7 @@ export default {
// EshangUrl: 'https://eshangtech.com/', // EshangUrl: 'https://eshangtech.com/',
// apiurl: 'https://erysfeipeng.oicp.net/', // web api // apiurl: 'https://erysfeipeng.oicp.net/', // web api
testApiurl: 'http://dev.eshangtech.com:8001/', // web api测试接口地址 testApiurl: 'http://dev.eshangtech.com:8001/', // web api测试接口地址
apiEsUrl: "https://api.eshangtech.com/",
mobUrl: 'http://192.168.11.125:8000/Coop.Merchant/Handler/handler_ajax.ashx', // 接口 mobUrl: 'http://192.168.11.125:8000/Coop.Merchant/Handler/handler_ajax.ashx', // 接口
testURL1: 'http://192.168.10.123:8000', // 测试ip testURL1: 'http://192.168.10.123:8000', // 测试ip

View File

@ -31,6 +31,15 @@ export default {
data.action_type = controller data.action_type = controller
return this.post(data) return this.post(data)
}, },
$apiGet: function (controller, data) {
return Api.request('GET', ApiPath.apiEsUrl + controller, data || {}, true)
},
$apiPost: function (controller, data) {
return Api.request('POST', ApiPath.apiEsUrl + controller, data || {}, true)
},
$posGet: function (controller, data) {
return Api.request('GET', ApiPath.posApiurl + controller, data || {}, true)
},
$posPost: function (controller, data) { $posPost: function (controller, data) {
return Api.request('POST', ApiPath.posApiurl + controller, data || {}, true) return Api.request('POST', ApiPath.posApiurl + controller, data || {}, true)
}, },