From 4202adf80c8b50d2184472fe4b8a6dc8f4fc53c0 Mon Sep 17 00:00:00 2001 From: Swanky <413564165@qq.com> Date: Mon, 15 Jun 2026 00:53:14 +0800 Subject: [PATCH] Refactor dashboard API endpoints and update data sources. Changed data retrieval from `yak_sn_order` to `gov_count_order_total` for various statistics, including trading data, sales types, and market monitoring. Updated SQL queries and descriptions to reflect new data structure and metrics. Enhanced response formats and added new fields for better data representation. --- .../交易中心实时服务信息.ms | 91 +++++------ .../交易所牦牛成交数据.ms | 48 +++--- .../api/大屏数据/地图迁徙数据.ms | 72 +++++---- .../api/大屏数据/实时交易统计.ms | 131 ++++++++------- .../api/大屏数据/市场实时监控.ms | 84 ++++------ .../市场实时监控播放配置.ms | 62 ++----- .../api/大屏数据/市场环境监控.ms | 114 ++++++------- .../大屏数据/活牛鲜肉价格趋势.ms | 57 ++++--- .../大屏数据/牦牛销售类型统计.ms | 45 ++---- .../api/大屏数据/综合销售统计.ms | 153 +++++++++--------- .../大屏数据/采购商户来源分析.ms | 30 ++-- magic-api-dashboard-interfaces.txt | 130 ++++++++------- 12 files changed, 490 insertions(+), 527 deletions(-) diff --git a/data/magic-api/api/大屏数据/交易中心实时服务信息.ms b/data/magic-api/api/大屏数据/交易中心实时服务信息.ms index 96f2813..4cca8a3 100644 --- a/data/magic-api/api/大屏数据/交易中心实时服务信息.ms +++ b/data/magic-api/api/大屏数据/交易中心实时服务信息.ms @@ -5,7 +5,7 @@ "groupId" : "f8e3d2c1b0a94e5f8a7b6c5d4e3f2a1", "name" : "交易中心实时服务信息", "createTime" : 1780877300000, - "updateTime" : null, + "updateTime" : 1781373000000, "lock" : null, "createBy" : "admin", "updateBy" : "admin", @@ -17,62 +17,63 @@ "headers" : [ ], "paths" : [ ], "responseBody" : null, - "description" : "交易中心实时服务信息:牦牛供应/待售/已售、剩余车位、进场车辆、供应商数量(只读)。牦牛=yak_trade_ear_tag_inventory;车位=yak_car_parking_zone;车辆=yak_car_record+yak_trade_entry_record;供应商=yak_sn_customer(SELLER)。", + "description" : "交易中心实时服务信息:gov_count_real_info,group_item=jygy,source_system=yzt。key=mngyzl/dsmn/ysmn/sycw/jccl/gyssl。", "requestBodyDefinition" : null, "responseBodyDefinition" : null } ================================ -// 只读查询,不修改任何数据 +// gov_count_real_info(group_item=jygy, source_system=yzt) +// mngyzl 牦牛供应总量 +// dsmn 待售牦牛 +// ysmn 已售牦牛 +// sycw 剩余车位 +// jccl 进场车辆 +// gyssl 供应商数量 var sql = """ -SELECT - (SELECT COUNT(*) - FROM yak_trade_ear_tag_inventory) AS total_supply, - (SELECT COUNT(*) - FROM yak_trade_ear_tag_inventory - WHERE status IN ('AVAILABLE', 'LOCKED')) AS for_sale_yaks, - (SELECT COUNT(*) - FROM yak_trade_ear_tag_inventory - WHERE status = 'SOLD') AS sold_yaks, - (SELECT COALESCE(SUM(total_capacity - current_count), 0) - FROM yak_car_parking_zone - WHERE status = 'NORMAL') AS remaining_parking, - (SELECT COUNT(*) - FROM ( - SELECT plate_no AS vehicle_no - FROM yak_car_record - WHERE del_flag = '0' - AND entry_time >= CURRENT_DATE - UNION - SELECT vehicle_no - FROM yak_trade_entry_record - WHERE entered_at >= CURRENT_DATE - ) v) AS entering_vehicles, - (SELECT COUNT(*) - FROM yak_sn_customer - WHERE del_flag = '0' - AND customer_type = 'SELLER') AS supplier_count +SELECT key, name, value, tag, unit +FROM gov_count_real_info +WHERE group_item = 'jygy' + AND source_system = 'yzt' """ var rows = db.select(sql) -var row = rows && rows.length > 0 ? rows[0] : null -if (!row) { - return { - totalSupply: 0, - forSaleYaks: 0, - soldYaks: 0, - remainingParking: 0, - enteringVehicles: 0, - supplierCount: 0 +var valueMap = {} +var tagMap = {} +var unitMap = {} + +for (row in rows) { + valueMap[row.key] = row.value != null ? row.value : 0 + if (row.tag) { + tagMap[row.key] = row.tag + } + if (row.unit) { + unitMap[row.key] = row.unit } } +var pick = (key) => valueMap[key] != null ? valueMap[key] : 0 +var pickTag = (key) => tagMap[key] +var pickUnit = (key) => unitMap[key] + return { - totalSupply: row.totalSupply ? row.totalSupply : 0, - forSaleYaks: row.forSaleYaks ? row.forSaleYaks : 0, - soldYaks: row.soldYaks ? row.soldYaks : 0, - remainingParking: row.remainingParking ? row.remainingParking : 0, - enteringVehicles: row.enteringVehicles ? row.enteringVehicles : 0, - supplierCount: row.supplierCount ? row.supplierCount : 0 + totalSupply: pick('mngyzl'), + forSaleYaks: pick('dsmn'), + soldYaks: pick('ysmn'), + remainingParking: pick('sycw'), + enteringVehicles: pick('jccl'), + supplierCount: pick('gyssl'), + totalSupplyTag: pickTag('mngyzl'), + forSaleYaksTag: pickTag('dsmn'), + soldYaksTag: pickTag('ysmn'), + remainingParkingTag: pickTag('sycw'), + enteringVehiclesTag: pickTag('jccl'), + supplierCountTag: pickTag('gyssl'), + totalSupplyUnit: pickUnit('mngyzl'), + forSaleYaksUnit: pickUnit('dsmn'), + soldYaksUnit: pickUnit('ysmn'), + remainingParkingUnit: pickUnit('sycw'), + enteringVehiclesUnit: pickUnit('jccl'), + supplierCountUnit: pickUnit('gyssl') } diff --git a/data/magic-api/api/大屏数据/交易所牦牛成交数据.ms b/data/magic-api/api/大屏数据/交易所牦牛成交数据.ms index 33195b4..6d977cc 100644 --- a/data/magic-api/api/大屏数据/交易所牦牛成交数据.ms +++ b/data/magic-api/api/大屏数据/交易所牦牛成交数据.ms @@ -5,7 +5,7 @@ "groupId" : "f8e3d2c1b0a94e5f8a7b6c5d4e3f2a1", "name" : "交易所牦牛成交数据", "createTime" : 1780877000000, - "updateTime" : 1780817847278, + "updateTime" : 1781369000000, "lock" : null, "createBy" : "admin", "updateBy" : "admin", @@ -28,27 +28,31 @@ "requestBody" : "", "headers" : [ ], "paths" : [ ], - "responseBody" : "{\n \"code\": -1,\n \"message\": \"系统内部出现错误\",\n \"data\": null,\n \"timestamp\": 1780817836665,\n \"executeTime\": 4\n}", - "description" : "交易所牦牛成交数据:近6个时间段的牦牛交易数量(头)与成交订单数量(单)趋势,数据源 yak_sn_order 已完成订单(只读查询)", + "responseBody" : null, + "description" : "交易所牦牛成交数据:gov_count_order_total,一条记录一单,SUM(yak_number) 为成交头数,COUNT(*) 为订单数。", "requestBodyDefinition" : null, "responseBodyDefinition" : null } ================================ +// gov_count_order_total:一条记录 = 一笔订单 +// 牦牛成交头数:SUM(yak_number) +// 成交订单数:COUNT(*) +// 时间维度按 update_time 分桶(count_date 多为空) var buildSeries = (rows) => { var labels = [] - var yakTradingVolume = [] + var yakNumber = [] var orderCount = [] for (row in rows) { labels.push(row.label) - yakTradingVolume.push(row.yakVolume ? row.yakVolume : 0) - orderCount.push(row.orderCount ? row.orderCount : 0) + yakNumber.push(row.yakNumber != null ? row.yakNumber : 0) + orderCount.push(row.orderCount != null ? row.orderCount : 0) } return { labels: labels, - yakTradingVolume: yakTradingVolume, + yakNumber: yakNumber, orderCount: orderCount } } @@ -56,17 +60,15 @@ var buildSeries = (rows) => { var daySql = """ SELECT TO_CHAR(d.bucket_date, 'FMMM/FMDD') AS label, - COALESCE(SUM(o.quantity), 0) AS yak_volume, + COALESCE(SUM(o.yak_number), 0) AS yak_number, COUNT(o.id) AS order_count FROM ( SELECT (CURRENT_DATE - offs)::date AS bucket_date, offs FROM generate_series(5, 0, -1) AS offs ) d -LEFT JOIN yak_sn_order o - ON o.del_flag = '0' - AND o.status = 'COMPLETED' - AND o.transaction_time >= d.bucket_date - AND o.transaction_time < d.bucket_date + INTERVAL '1 day' +LEFT JOIN gov_count_order_total o + ON o.update_time >= d.bucket_date + AND o.update_time < d.bucket_date + INTERVAL '1 day' GROUP BY d.bucket_date, d.offs ORDER BY d.offs DESC """ @@ -74,17 +76,15 @@ ORDER BY d.offs DESC var weekSql = """ SELECT TO_CHAR(d.anchor_date, 'FMMM/FMDD') || '-' || TO_CHAR(d.anchor_date + 6, 'FMMM/FMDD') AS label, - COALESCE(SUM(o.quantity), 0) AS yak_volume, + COALESCE(SUM(o.yak_number), 0) AS yak_number, COUNT(o.id) AS order_count FROM ( SELECT (CURRENT_DATE - offs * 7)::date AS anchor_date, offs FROM generate_series(5, 0, -1) AS offs ) d -LEFT JOIN yak_sn_order o - ON o.del_flag = '0' - AND o.status = 'COMPLETED' - AND o.transaction_time >= d.anchor_date - AND o.transaction_time < d.anchor_date + INTERVAL '7 days' +LEFT JOIN gov_count_order_total o + ON o.update_time >= d.anchor_date + AND o.update_time < d.anchor_date + INTERVAL '7 days' GROUP BY d.anchor_date, d.offs ORDER BY d.offs DESC """ @@ -92,17 +92,15 @@ ORDER BY d.offs DESC var monthSql = """ SELECT TO_CHAR(d.month_start, 'YYYY/FMMM') AS label, - COALESCE(SUM(o.quantity), 0) AS yak_volume, + COALESCE(SUM(o.yak_number), 0) AS yak_number, COUNT(o.id) AS order_count FROM ( SELECT (date_trunc('month', CURRENT_DATE) - (offs || ' months')::interval)::date AS month_start, offs FROM generate_series(5, 0, -1) AS offs ) d -LEFT JOIN yak_sn_order o - ON o.del_flag = '0' - AND o.status = 'COMPLETED' - AND o.transaction_time >= d.month_start - AND o.transaction_time < d.month_start + INTERVAL '1 month' +LEFT JOIN gov_count_order_total o + ON o.update_time >= d.month_start + AND o.update_time < d.month_start + INTERVAL '1 month' GROUP BY d.month_start, d.offs ORDER BY d.offs DESC """ diff --git a/data/magic-api/api/大屏数据/地图迁徙数据.ms b/data/magic-api/api/大屏数据/地图迁徙数据.ms index 24ae4d5..329ebc7 100644 --- a/data/magic-api/api/大屏数据/地图迁徙数据.ms +++ b/data/magic-api/api/大屏数据/地图迁徙数据.ms @@ -5,7 +5,7 @@ "groupId" : "f8e3d2c1b0a94e5f8a7b6c5d4e3f2a1", "name" : "地图迁徙数据", "createTime" : 1780882000000, - "updateTime" : 1781360000000, + "updateTime" : 1781377000000, "lock" : null, "createBy" : "admin", "updateBy" : "admin", @@ -17,12 +17,16 @@ "headers" : [ ], "paths" : [ ], "responseBody" : null, - "description" : "中央地图迁徙数据:销售网络/源地供应/红原本地出栏,数据源 yak_sn_order + yak_sn_customer(只读)。枢纽名称需与系统配置 mapHub.name 一致。", + "description" : "中央地图迁徙数据:gov_count_order_total。销售网络=origin_place含红原;源地供应=destination_place含红原;红原出栏=起终点均含红原。头数SUM(yak_number)。", "requestBodyDefinition" : null, "responseBodyDefinition" : null } ================================ -// 只读统计已完成订单;hubName 需与系统配置 mapHub.name 保持一致 +// gov_count_order_total:一条记录 = 一笔订单,头数 SUM(yak_number) +// outflow 销售网络:origin_place 含「红原」,按 destination_place 聚合 +// inflow 源地供应:destination_place 含「红原」,按 origin_place 聚合 +// local 红原出栏:destination_place 含「红原」且 origin_place 含「红原」,按 origin_place 乡镇聚合 +// hubName 需与系统配置 mapHub.name 保持一致 var hubName = '红原县' @@ -140,51 +144,55 @@ var buildDirectionalFlows = (rows, direction) => { var outflowSql = """ SELECT - COALESCE(NULLIF(TRIM(c.region_name), ''), NULLIF(TRIM(o.destination_place), ''), '未知') AS place_name, - COALESCE(SUM(o.quantity), 0) AS value, - MAX(COALESCE(NULLIF(TRIM(c.region_name), ''), NULLIF(TRIM(o.destination_place), ''), '未知')) AS sample_place -FROM yak_sn_order o -LEFT JOIN yak_sn_customer c ON c.id = o.buyer_id AND c.del_flag = '0' -WHERE o.del_flag = '0' - AND o.status = 'COMPLETED' -GROUP BY COALESCE(NULLIF(TRIM(c.region_name), ''), NULLIF(TRIM(o.destination_place), ''), '未知') -HAVING COALESCE(SUM(o.quantity), 0) > 0 + COALESCE(NULLIF(TRIM(destination_place), ''), '未知') AS place_name, + COALESCE(SUM(yak_number), 0) AS value, + MAX(destination_place) AS sample_place +FROM gov_count_order_total +WHERE origin_place IS NOT NULL + AND position('红原' in origin_place) > 0 + AND destination_place IS NOT NULL + AND TRIM(destination_place) <> '' +GROUP BY COALESCE(NULLIF(TRIM(destination_place), ''), '未知') +HAVING COALESCE(SUM(yak_number), 0) > 0 ORDER BY value DESC, place_name """ var inflowSql = """ SELECT - COALESCE(NULLIF(TRIM(c.region_name), ''), NULLIF(TRIM(o.origin_place), ''), '未知') AS place_name, - COALESCE(SUM(o.quantity), 0) AS value, - MAX(COALESCE(NULLIF(TRIM(c.region_name), ''), NULLIF(TRIM(o.origin_place), ''), '未知')) AS sample_place -FROM yak_sn_order o -LEFT JOIN yak_sn_customer c ON c.id = o.seller_id AND c.del_flag = '0' -WHERE o.del_flag = '0' - AND o.status = 'COMPLETED' -GROUP BY COALESCE(NULLIF(TRIM(c.region_name), ''), NULLIF(TRIM(o.origin_place), ''), '未知') -HAVING COALESCE(SUM(o.quantity), 0) > 0 + COALESCE(NULLIF(TRIM(origin_place), ''), '未知') AS place_name, + COALESCE(SUM(yak_number), 0) AS value, + MAX(origin_place) AS sample_place +FROM gov_count_order_total +WHERE destination_place IS NOT NULL + AND position('红原' in destination_place) > 0 + AND origin_place IS NOT NULL + AND TRIM(origin_place) <> '' +GROUP BY COALESCE(NULLIF(TRIM(origin_place), ''), '未知') +HAVING COALESCE(SUM(yak_number), 0) > 0 ORDER BY value DESC, place_name """ var localSql = """ SELECT COALESCE( - NULLIF((regexp_match(o.origin_place, '([^省市区县]+(?:镇|乡|街道))'))[1], ''), - NULLIF(TRIM(o.origin_place), ''), + NULLIF((regexp_match(origin_place, '([^省市区县]+(?:镇|乡|街道))'))[1], ''), + NULLIF(TRIM(origin_place), ''), '未知' ) AS place_name, - COALESCE(SUM(o.quantity), 0) AS value, - MAX(o.origin_place) AS sample_place -FROM yak_sn_order o -WHERE o.del_flag = '0' - AND o.status = 'COMPLETED' - AND position('红原' in o.origin_place) > 0 + COALESCE(SUM(yak_number), 0) AS value, + MAX(origin_place) AS sample_place +FROM gov_count_order_total +WHERE destination_place IS NOT NULL + AND position('红原' in destination_place) > 0 + AND origin_place IS NOT NULL + AND position('红原' in origin_place) > 0 + AND TRIM(origin_place) <> '' GROUP BY COALESCE( - NULLIF((regexp_match(o.origin_place, '([^省市区县]+(?:镇|乡|街道))'))[1], ''), - NULLIF(TRIM(o.origin_place), ''), + NULLIF((regexp_match(origin_place, '([^省市区县]+(?:镇|乡|街道))'))[1], ''), + NULLIF(TRIM(origin_place), ''), '未知' ) -HAVING COALESCE(SUM(o.quantity), 0) > 0 +HAVING COALESCE(SUM(yak_number), 0) > 0 ORDER BY value DESC, place_name """ diff --git a/data/magic-api/api/大屏数据/实时交易统计.ms b/data/magic-api/api/大屏数据/实时交易统计.ms index 0a26799..5fcd976 100644 --- a/data/magic-api/api/大屏数据/实时交易统计.ms +++ b/data/magic-api/api/大屏数据/实时交易统计.ms @@ -5,7 +5,7 @@ "groupId" : "f8e3d2c1b0a94e5f8a7b6c5d4e3f2a1", "name" : "实时交易统计", "createTime" : 1780876800000, - "updateTime" : 1780803706100, + "updateTime" : 1781365000000, "lock" : null, "createBy" : "admin", "updateBy" : "admin", @@ -14,7 +14,7 @@ "parameters" : [ { "name" : "dimension", "value" : null, - "description" : "时间维度:day(当天)/week(近一周)/month(近一月)/year(当年),不传则返回全部", + "description" : "时间维度:day(最新统计日)/week(近7天)/month(近30天),不传则返回全部", "required" : false, "dataType" : "String", "type" : null, @@ -29,82 +29,97 @@ "headers" : [ ], "paths" : [ ], "responseBody" : null, - "description" : "实时交易统计:牦牛交易总量、订单交易总量、销售商户数量、采购商户数量,按当天/近一周/近一月/当年统计(只读查询)", + "description" : "实时交易统计:数据源 gov_count_item(只读)。key=mnjyzl/jdjyzl/xsshsl/cgshsl,按 count_date 汇总。", "requestBodyDefinition" : null, "responseBodyDefinition" : null } ================================ -// 只读统计已完成订单,不修改任何数据 -var sql = """ -SELECT - dim, - COALESCE(SUM(quantity), 0) AS yak_total_volume, - COUNT(*) AS order_total_volume, - COUNT(DISTINCT seller_id) AS seller_count, - COUNT(DISTINCT buyer_id) AS buyer_count -FROM ( - SELECT 'day' AS dim, quantity, seller_id, buyer_id - FROM yak_sn_order - WHERE del_flag = '0' - AND status = 'COMPLETED' - AND transaction_time >= CURRENT_DATE - AND transaction_time < CURRENT_DATE + INTERVAL '1 day' - - UNION ALL - - SELECT 'week' AS dim, quantity, seller_id, buyer_id - FROM yak_sn_order - WHERE del_flag = '0' - AND status = 'COMPLETED' - AND transaction_time >= CURRENT_DATE - INTERVAL '6 days' - AND transaction_time < CURRENT_DATE + INTERVAL '1 day' - - UNION ALL +// gov_count_item 指标 key: +// mnjyzl 牦牛交易总量 +// jdjyzl 订单交易总量 +// xsshsl 销售商户数量 +// cgshsl 采购商户数量 +// 同一 key + count_date 可能有多条,取 MAX(value); +// 交易量类(mnjyzl/jdjyzl)在 week/month 内按日求和,商户数类取区间内最大值。 - SELECT 'month' AS dim, quantity, seller_id, buyer_id - FROM yak_sn_order - WHERE del_flag = '0' - AND status = 'COMPLETED' - AND transaction_time >= CURRENT_DATE - INTERVAL '29 days' - AND transaction_time < CURRENT_DATE + INTERVAL '1 day' - - UNION ALL - - SELECT 'year' AS dim, quantity, seller_id, buyer_id - FROM yak_sn_order - WHERE del_flag = '0' - AND status = 'COMPLETED' - AND transaction_time >= DATE_TRUNC('year', CURRENT_DATE) - AND transaction_time < CURRENT_DATE + INTERVAL '1 day' -) t -GROUP BY dim -ORDER BY dim +var sql = """ +WITH daily AS ( + SELECT + key, + count_date, + MAX(value) AS value + FROM gov_count_item + WHERE TRIM(name) IN ( + '牦牛交易总量', + '订单交易总量', + '销售商户数量', + '采购商户数量' + ) + GROUP BY key, count_date +), +anchor AS ( + SELECT MAX(count_date) AS latest_date FROM daily +), +day_stats AS ( + SELECT d.key, d.value + FROM daily d + CROSS JOIN anchor a + WHERE d.count_date = a.latest_date +), +week_stats AS ( + SELECT + d.key, + CASE + WHEN d.key IN ('mnjyzl', 'jdjyzl') THEN SUM(d.value) + ELSE MAX(d.value) + END AS value + FROM daily d + CROSS JOIN anchor a + WHERE d.count_date >= a.latest_date - INTERVAL '6 days' + GROUP BY d.key +), +month_stats AS ( + SELECT + d.key, + CASE + WHEN d.key IN ('mnjyzl', 'jdjyzl') THEN SUM(d.value) + ELSE MAX(d.value) + END AS value + FROM daily d + CROSS JOIN anchor a + WHERE d.count_date >= a.latest_date - INTERVAL '29 days' + GROUP BY d.key +) +SELECT 'day' AS dim, key, value FROM day_stats +UNION ALL +SELECT 'week' AS dim, key, value FROM week_stats +UNION ALL +SELECT 'month' AS dim, key, value FROM month_stats +ORDER BY dim, key """ var rows = db.select(sql) var createEmptyStats = () => { return { - yakTotalVolume: 0, - orderTotalVolume: 0, - sellerCount: 0, - buyerCount: 0 + mnjyzl: 0, + jdjyzl: 0, + xsshsl: 0, + cgshsl: 0 } } var result = { day: createEmptyStats(), week: createEmptyStats(), - month: createEmptyStats(), - year: createEmptyStats() + month: createEmptyStats() } for (row in rows) { - result[row.dim] = { - yakTotalVolume: row.yakTotalVolume, - orderTotalVolume: row.orderTotalVolume, - sellerCount: row.sellerCount, - buyerCount: row.buyerCount + var dim = row.dim + var metricKey = row.key + if (result[dim]) { + result[dim][metricKey] = row.value != null ? row.value : 0 } } diff --git a/data/magic-api/api/大屏数据/市场实时监控.ms b/data/magic-api/api/大屏数据/市场实时监控.ms index d16ff20..fb9cc10 100644 --- a/data/magic-api/api/大屏数据/市场实时监控.ms +++ b/data/magic-api/api/大屏数据/市场实时监控.ms @@ -5,7 +5,7 @@ "groupId" : "f8e3d2c1b0a94e5f8a7b6c5d4e3f2a1", "name" : "市场实时监控", "createTime" : 1781199600000, - "updateTime" : null, + "updateTime" : 1781378000000, "lock" : null, "createBy" : "admin", "updateBy" : "admin", @@ -17,12 +17,14 @@ "headers" : [ ], "paths" : [ ], "responseBody" : null, - "description" : "市场实时监控:视频监控设备列表,数据源 iot_device_video + iot_device_video_data 最新一条(只读)。", + "description" : "市场实时监控:iot_device_video + iot_video_account,萤石 ezopen 播放地址与 accessToken。", "requestBodyDefinition" : null, "responseBodyDefinition" : null } ================================ -// 只读查询,不修改任何数据 +// iot_device_video + iot_video_account(萤石云) +// play_url / hd_play_url:ezopen://open.ys7.com/{serial}/{channel}.live +// accessToken:iot_video_account.token var sql = """ SELECT @@ -32,31 +34,21 @@ SELECT v.location, v.address, v.status, + v.serial_number, + v.channel_number, v.play_url, v.hd_play_url, v.preview_img_url, v.img, - v.channel_number, + v.video_account_id, v."index" AS sort_index, v.last_capture_time, - d.stream_url AS latest_stream_url, - d.snapshot_url AS latest_snapshot_url, - d.online_status AS latest_online_status, - d.stream_status AS latest_stream_status, - d.fault_code AS latest_fault_code + a.app_key, + a.token AS access_token FROM iot_device_video v -LEFT JOIN LATERAL ( - SELECT - stream_url, - snapshot_url, - online_status, - stream_status, - fault_code - FROM iot_device_video_data - WHERE device_id = v.id - ORDER BY collect_time DESC NULLS LAST - LIMIT 1 -) d ON true +LEFT JOIN iot_video_account a + ON a.id::text = v.video_account_id + AND COALESCE(a.del_flag, '0') = '0' WHERE COALESCE(v.del_flag, '0') = '0' AND COALESCE(v.is_show, true) = true ORDER BY v."index" NULLS LAST, v.name @@ -87,8 +79,6 @@ var toUpperText = (text) => { var mapStatus = (row) => { var deviceStatus = pickText(row, 'status', 'status') - var onlineStatus = pickText(row, 'latestOnlineStatus', 'latest_online_status') - var faultCode = pickText(row, 'latestFaultCode', 'latest_fault_code') var deviceUpper = toUpperText(deviceStatus) if (deviceUpper === 'OFFLINE') { @@ -97,22 +87,10 @@ var mapStatus = (row) => { if (deviceUpper === 'ERROR' || deviceUpper === 'FAULT') { return 'error' } - if (faultCode) { - return 'error' - } - if (onlineStatus) { - var onlineUpper = toUpperText(onlineStatus) - if (onlineUpper === 'OFFLINE') { - return 'offline' - } - if (onlineUpper === 'ERROR' || onlineUpper === 'FAULT') { - return 'error' - } - } return 'online' } -var pickStreamUrl = (row) => { +var pickEzopenUrl = (row) => { var hd = pickText(row, 'hdPlayUrl', 'hd_play_url') if (hd) { return hd @@ -121,15 +99,16 @@ var pickStreamUrl = (row) => { if (play) { return play } - return pickText(row, 'latestStreamUrl', 'latest_stream_url') -} -var pickHdStreamUrl = (row) => { - return pickText(row, 'hdPlayUrl', 'hd_play_url') -} - -var pickPlayUrl = (row) => { - return pickText(row, 'playUrl', 'play_url') + var serial = pickText(row, 'serialNumber', 'serial_number') + var channel = row.channelNumber != null ? row.channelNumber : row.channel_number + if (channel == null) { + channel = 1 + } + if (serial) { + return 'ezopen://open.ys7.com/' + serial + '/' + channel + '.hd.live' + } + return '' } var pickPreviewUrl = (row) => { @@ -137,11 +116,7 @@ var pickPreviewUrl = (row) => { if (preview) { return preview } - var img = pickText(row, 'img', 'img') - if (img) { - return img - } - return pickText(row, 'latestSnapshotUrl', 'latest_snapshot_url') + return pickText(row, 'img', 'img') } if (rows && rows.length > 0) { @@ -152,14 +127,19 @@ if (rows && rows.length > 0) { number: pickText(row, 'number', 'number'), location: pickText(row, 'location', 'location'), address: pickText(row, 'address', 'address'), + serialNumber: pickText(row, 'serialNumber', 'serial_number'), channelNumber: row.channelNumber != null ? row.channelNumber : row.channel_number, + videoAccountId: pickText(row, 'videoAccountId', 'video_account_id'), sortIndex: row.sortIndex != null ? row.sortIndex : row.sort_index, status: mapStatus(row), resolution: '1920x1080', + url: pickPreviewUrl(row), preview: pickPreviewUrl(row), - hdStreamUrl: pickHdStreamUrl(row), - playUrl: pickPlayUrl(row), - streamUrl: pickStreamUrl(row) + playUrl: pickText(row, 'playUrl', 'play_url'), + hdPlayUrl: pickText(row, 'hdPlayUrl', 'hd_play_url'), + ezopenUrl: pickEzopenUrl(row), + accessToken: pickText(row, 'accessToken', 'access_token'), + appKey: pickText(row, 'appKey', 'app_key') }) } } diff --git a/data/magic-api/api/大屏数据/市场实时监控播放配置.ms b/data/magic-api/api/大屏数据/市场实时监控播放配置.ms index 171c7be..7ad7e39 100644 --- a/data/magic-api/api/大屏数据/市场实时监控播放配置.ms +++ b/data/magic-api/api/大屏数据/市场实时监控播放配置.ms @@ -5,7 +5,7 @@ "groupId" : "f8e3d2c1b0a94e5f8a7b6c5d4e3f2a1", "name" : "市场实时监控播放配置", "createTime" : 1781203200000, - "updateTime" : null, + "updateTime" : 1781378000000, "lock" : null, "createBy" : "admin", "updateBy" : "admin", @@ -17,61 +17,21 @@ "headers" : [ ], "paths" : [ ], "responseBody" : null, - "description" : "市场实时监控播放配置:直播流格式识别规则与播放器参数(HLS/FLV/MP4 等)。", + "description" : "市场实时监控播放配置:萤石云 EZUIKit 播放器参数。", "requestBodyDefinition" : null, "responseBodyDefinition" : null } ================================ -// 直播流地址格式配置,供前端 hls.js / flv.js 自动选型 +// 萤石云 EZUIKit 播放器配置 return { - defaultProtocol: 'hls', - urlPriority: ['hdStreamUrl', 'streamUrl', 'playUrl'], - formatRules: [ - { - type: 'hls', - match: '.m3u8', - library: 'hls.js', - description: 'HLS 直播(萤石 open.ys7.com 等)' - }, - { - type: 'flv', - match: '.flv', - library: 'flv.js', - description: 'HTTP-FLV 直播(萤石 rtmp*open.ys7.com 等)' - }, - { - type: 'mp4', - match: '.mp4', - library: 'native', - description: 'MP4 点播/回放' - }, - { - type: 'webm', - match: '.webm', - library: 'native', - description: 'WebM 点播' - } - ], - playerOptions: { - hls: { - enableWorker: true, - lowLatencyMode: true - }, - flv: { - isLive: true, - hasAudio: true, - hasVideo: true - }, - flvMedia: { - enableWorker: true, - enableStashBuffer: false - } - }, - ys7Templates: { - hdHls: 'https://open.ys7.com/v3/openlive/{deviceSerial}_{channelNo}_1.m3u8', - hls: 'https://open.ys7.com/v3/openlive/{deviceSerial}_{channelNo}_2.m3u8', - hdFlv: 'https://rtmp12open.ys7.com:9188/v3/openlive/{deviceSerial}_{channelNo}_1.flv', - flv: 'https://rtmp12open.ys7.com:9188/v3/openlive/{deviceSerial}_{channelNo}_2.flv' + playerType: 'ezviz', + staticPath: '/ezuikit_static', + urlPriority: ['hdPlayUrl', 'playUrl', 'ezopenUrl'], + ezviz: { + template: 'simple', + scaleMode: 1, + audio: false, + defaultQuality: 'hd.live' } } diff --git a/data/magic-api/api/大屏数据/市场环境监控.ms b/data/magic-api/api/大屏数据/市场环境监控.ms index 0baedcd..b0bb633 100644 --- a/data/magic-api/api/大屏数据/市场环境监控.ms +++ b/data/magic-api/api/大屏数据/市场环境监控.ms @@ -5,7 +5,7 @@ "groupId" : "f8e3d2c1b0a94e5f8a7b6c5d4e3f2a1", "name" : "市场环境监控", "createTime" : 1781196000000, - "updateTime" : null, + "updateTime" : 1781374000000, "lock" : null, "createBy" : "admin", "updateBy" : "admin", @@ -17,79 +17,71 @@ "headers" : [ ], "paths" : [ ], "responseBody" : null, - "description" : "市场环境监控:温湿度(iot_device_env_data)+ 气象(iot_device_weather_data)最新一条,只读。", + "description" : "市场环境监控:gov_count_real_info,group_item=env-monitor,source_system=yzt。温湿度/气象八项指标及 tag、unit。", "requestBodyDefinition" : null, "responseBodyDefinition" : null } ================================ -// 只读查询,不修改任何数据 +// gov_count_real_info(group_item=env-monitor, source_system=yzt) +// temperature 温度 +// humidity 湿度 +// aqi 空气质量 +// pressure 大气压强 +// uv 紫外线 +// rainfall 降雨量 +// wind_direction 风向(value=角度,tag=风向名) +// wind_power 风力(value=级数) -var envSql = """ -SELECT - temperature, - humidity, - to_char(collect_time, 'YYYY-MM-DD HH24:MI:SS') AS collect_time -FROM iot_device_env_data -ORDER BY collect_time DESC NULLS LAST -LIMIT 1 +var sql = """ +SELECT key, name, value, tag, unit +FROM gov_count_real_info +WHERE group_item = 'env-monitor' + AND source_system = 'yzt' """ -var weatherSql = """ -SELECT - air_pressure, - pm25, - pm10, - uv_index, - rainfall, - wind_speed, - wind_direction, - to_char(collect_time, 'YYYY-MM-DD HH24:MI:SS') AS collect_time -FROM iot_device_weather_data -ORDER BY collect_time DESC NULLS LAST -LIMIT 1 -""" +var rows = db.select(sql) -var envRows = db.select(envSql) -var weatherRows = db.select(weatherSql) -var env = envRows && envRows.length > 0 ? envRows[0] : null -var weather = weatherRows && weatherRows.length > 0 ? weatherRows[0] : null +var valueMap = {} +var tagMap = {} +var unitMap = {} -var pickNum = (row, camelKey, snakeKey) => { - if (!row) { - return null - } - if (row[camelKey] != null) { - return row[camelKey] +for (row in rows) { + valueMap[row.key] = row.value != null ? row.value : null + if (row.tag) { + tagMap[row.key] = row.tag } - if (row[snakeKey] != null) { - return row[snakeKey] + if (row.unit) { + unitMap[row.key] = row.unit } - return null } -var pickText = (row, camelKey, snakeKey) => { - if (!row) { - return '' - } - if (row[camelKey]) { - return row[camelKey] - } - if (row[snakeKey]) { - return row[snakeKey] - } - return '' -} +var pick = (key) => valueMap[key] != null ? valueMap[key] : null +var pickTag = (key) => tagMap[key] +var pickUnit = (key) => unitMap[key] return { - temperature: pickNum(env, 'temperature', 'temperature'), - humidity: pickNum(env, 'humidity', 'humidity'), - envCollectTime: pickText(env, 'collectTime', 'collect_time'), - airPressure: pickNum(weather, 'airPressure', 'air_pressure'), - pm25: pickNum(weather, 'pm25', 'pm25'), - pm10: pickNum(weather, 'pm10', 'pm10'), - uvIndex: pickNum(weather, 'uvIndex', 'uv_index'), - rainfall: pickNum(weather, 'rainfall', 'rainfall'), - windSpeed: pickNum(weather, 'windSpeed', 'wind_speed'), - windDirection: pickNum(weather, 'windDirection', 'wind_direction'), - weatherCollectTime: pickText(weather, 'collectTime', 'collect_time') + temperature: pick('temperature'), + humidity: pick('humidity'), + aqi: pick('aqi'), + airPressure: pick('pressure'), + uvIndex: pick('uv'), + rainfall: pick('rainfall'), + windDirection: pick('wind_direction'), + windPower: pick('wind_power'), + temperatureTag: pickTag('temperature'), + humidityTag: pickTag('humidity'), + aqiTag: pickTag('aqi'), + airPressureTag: pickTag('pressure'), + uvIndexTag: pickTag('uv'), + rainfallTag: pickTag('rainfall'), + windDirectionTag: pickTag('wind_direction'), + windPowerTag: pickTag('wind_power'), + temperatureUnit: pickUnit('temperature'), + humidityUnit: pickUnit('humidity'), + aqiUnit: pickUnit('aqi'), + airPressureUnit: pickUnit('pressure'), + uvIndexUnit: pickUnit('uv'), + rainfallUnit: pickUnit('rainfall'), + windDirectionUnit: pickUnit('wind_direction'), + windPowerUnit: pickUnit('wind_power') } diff --git a/data/magic-api/api/大屏数据/活牛鲜肉价格趋势.ms b/data/magic-api/api/大屏数据/活牛鲜肉价格趋势.ms index 6c5ecb0..8357016 100644 --- a/data/magic-api/api/大屏数据/活牛鲜肉价格趋势.ms +++ b/data/magic-api/api/大屏数据/活牛鲜肉价格趋势.ms @@ -5,7 +5,7 @@ "groupId" : "f8e3d2c1b0a94e5f8a7b6c5d4e3f2a1", "name" : "活牛鲜肉价格趋势", "createTime" : 1780877200000, - "updateTime" : null, + "updateTime" : 1781372000000, "lock" : null, "createBy" : "admin", "updateBy" : "admin", @@ -17,17 +17,20 @@ "headers" : [ ], "paths" : [ ], "responseBody" : null, - "description" : "活牛/鲜肉价格趋势:近8个月市场采集均价。数据源 yak_trade_market_price,活牛=LIVE_YAK,鲜肉=FRESH_MEAT,直接使用 price 字段及 unit 单位,不做重量折算。", + "description" : "活牛/鲜肉价格趋势:近8个月采集均价。数据源 gov_count_price,活牛=price_key hx,鲜肉=mnr/mnt/mnp 月均,直接使用 value 与 unit,不做重量折算。", "requestBodyDefinition" : null, "responseBodyDefinition" : null } ================================ -// 只读查询,不修改任何数据 -// 数据源:yak_trade_market_price(市场采集价格,已含 price + unit) -// price_type: LIVE_YAK=活牛, FRESH_MEAT=鲜肉/牛肉 +// gov_count_price 价格指标 price_key: +// hx 活畜(活牛) +// mnr/mnt/mnp 鲜肉(牦牛肉/腿/排) +// 按 year + month 对各区域采集价取 AVG(value);无数据月份返回 null var monthBucketSql = """ SELECT + EXTRACT(YEAR FROM d.month_start)::int AS year, + EXTRACT(MONTH FROM d.month_start)::int AS month, d.month_start, d.offs, TO_CHAR(d.month_start, 'FMMM') || '月' AS label @@ -42,30 +45,30 @@ ORDER BY d.offs DESC var livePriceSql = """ SELECT - date_trunc('month', p.price_date)::date AS month_start, - ROUND(AVG(p.price)::numeric, 2) AS live_cattle_price -FROM yak_trade_market_price p -WHERE p.price_type = 'LIVE_YAK' - AND p.price_date >= date_trunc('month', CURRENT_DATE) - INTERVAL '7 months' -GROUP BY date_trunc('month', p.price_date)::date + year, + month, + ROUND(AVG(value)::numeric, 2) AS live_cattle_price +FROM gov_count_price +WHERE price_key = 'hx' +GROUP BY year, month """ var beefPriceSql = """ SELECT - date_trunc('month', p.price_date)::date AS month_start, - ROUND(AVG(p.price)::numeric, 2) AS beef_price -FROM yak_trade_market_price p -WHERE p.price_type = 'FRESH_MEAT' - AND p.price_date >= date_trunc('month', CURRENT_DATE) - INTERVAL '7 months' -GROUP BY date_trunc('month', p.price_date)::date + year, + month, + ROUND(AVG(value)::numeric, 2) AS beef_price +FROM gov_count_price +WHERE price_key IN ('mnr', 'mnt', 'mnp') +GROUP BY year, month """ var unitSql = """ SELECT - MAX(CASE WHEN price_type = 'LIVE_YAK' THEN unit END) AS live_unit, - MAX(CASE WHEN price_type = 'FRESH_MEAT' THEN unit END) AS beef_unit -FROM yak_trade_market_price -WHERE price_type IN ('LIVE_YAK', 'FRESH_MEAT') + MAX(CASE WHEN price_key = 'hx' THEN unit END) AS live_unit, + MAX(CASE WHEN price_key IN ('mnr', 'mnt', 'mnp') THEN unit END) AS beef_unit +FROM gov_count_price +WHERE price_key IN ('hx', 'mnr', 'mnt', 'mnp') """ var buckets = db.select(monthBucketSql) @@ -77,15 +80,17 @@ var liveMap = {} var beefMap = {} for (row in liveRows) { - liveMap[row.monthStart] = row.liveCattlePrice + var key = row.year + '-' + row.month + liveMap[key] = row.liveCattlePrice } for (row in beefRows) { - beefMap[row.monthStart] = row.beefPrice + var key = row.year + '-' + row.month + beefMap[key] = row.beefPrice } -var liveUnit = '元/公斤' -var beefUnit = '元/公斤' +var liveUnit = '元/kg' +var beefUnit = '元/kg' if (unitRows && unitRows.length > 0) { if (unitRows[0].liveUnit) { liveUnit = unitRows[0].liveUnit @@ -100,7 +105,7 @@ var liveCattlePrice = [] var beefPrice = [] for (bucket in buckets) { - var monthKey = bucket.monthStart + var monthKey = bucket.year + '-' + bucket.month labels.push(bucket.label) liveCattlePrice.push(liveMap[monthKey] != null ? liveMap[monthKey] : null) beefPrice.push(beefMap[monthKey] != null ? beefMap[monthKey] : null) diff --git a/data/magic-api/api/大屏数据/牦牛销售类型统计.ms b/data/magic-api/api/大屏数据/牦牛销售类型统计.ms index cc43759..ebadfec 100644 --- a/data/magic-api/api/大屏数据/牦牛销售类型统计.ms +++ b/data/magic-api/api/大屏数据/牦牛销售类型统计.ms @@ -5,7 +5,7 @@ "groupId" : "f8e3d2c1b0a94e5f8a7b6c5d4e3f2a1", "name" : "牦牛销售类型统计", "createTime" : 1780880400000, - "updateTime" : null, + "updateTime" : 1781375000000, "lock" : null, "createBy" : "admin", "updateBy" : "admin", @@ -17,54 +17,41 @@ "headers" : [ ], "paths" : [ ], "responseBody" : null, - "description" : "牦牛销售类型统计:按订单 purpose 归类为屠宰/养殖/其他,统计已完成订单牦牛头数与占比(只读)。", + "description" : "牦牛销售类型统计:gov_count_order_total 按 purpose 分组,SUM(yak_number) 为成交头数,一条记录一单。", "requestBodyDefinition" : null, "responseBodyDefinition" : null } ================================ -// 只读查询,不修改任何数据 -// 数据源 yak_sn_order.purpose,按用途关键词归类 +// gov_count_order_total:一条记录 = 一笔订单 +// 成交头数:SUM(yak_number) +// 销售类型:purpose(屠宰 / 养殖 / 其他 等) var sql = """ -SELECT category AS name, COALESCE(SUM(quantity), 0) AS value -FROM ( - SELECT - o.quantity, - CASE - WHEN TRIM(COALESCE(o.purpose, '')) ~* '(屠宰|餐饮|肉食|宰杀)' THEN '屠宰用途' - WHEN TRIM(COALESCE(o.purpose, '')) ~* '(养殖|繁育|种|批发|转售)' THEN '养殖用途' - ELSE '其他用途' - END AS category - FROM yak_sn_order o - WHERE o.del_flag = '0' - AND o.status = 'COMPLETED' -) t -GROUP BY category +SELECT + COALESCE(NULLIF(TRIM(purpose), ''), '其他') AS name, + COALESCE(SUM(yak_number), 0) AS value +FROM gov_count_order_total +GROUP BY COALESCE(NULLIF(TRIM(purpose), ''), '其他') +ORDER BY value DESC """ var rows = db.select(sql) -var categories = ['屠宰用途', '养殖用途', '其他用途'] -var valueMap = {} - -for (row in rows) { - valueMap[row.name] = row.value ? row.value : 0 -} var total = 0 -for (cat in categories) { - var count = valueMap[cat] ? valueMap[cat] : 0 +for (row in rows) { + var count = row.value != null ? row.value : 0 total = total + count } var result = [] -for (cat in categories) { - var count = valueMap[cat] ? valueMap[cat] : 0 +for (row in rows) { + var count = row.value != null ? row.value : 0 var percent = 0 if (total > 0) { percent = (count * 100.0) / total } result.push({ - name: cat, + name: row.name, value: count, percent: percent }) diff --git a/data/magic-api/api/大屏数据/综合销售统计.ms b/data/magic-api/api/大屏数据/综合销售统计.ms index 98a8b96..96168b9 100644 --- a/data/magic-api/api/大屏数据/综合销售统计.ms +++ b/data/magic-api/api/大屏数据/综合销售统计.ms @@ -5,7 +5,7 @@ "groupId" : "f8e3d2c1b0a94e5f8a7b6c5d4e3f2a1", "name" : "综合销售统计", "createTime" : 1780877100000, - "updateTime" : null, + "updateTime" : 1781368000000, "lock" : null, "createBy" : "admin", "updateBy" : "admin", @@ -29,31 +29,58 @@ "headers" : [ ], "paths" : [ ], "responseBody" : null, - "description" : "综合销售统计:本月销售/总体销售/采购地区三维饼图数据,数据源 yak_sn_order 已完成订单(只读)", + "description" : "综合销售统计:数据源 gov_count_order_total(只读)。销售按 origin_place,采购地区按 buyer_place,头数 yak_number。", "requestBodyDefinition" : null, "responseBodyDefinition" : null } ================================ -// 数据源 yak_sn_order + yak_sn_customer -// value = 牦牛交易头数 quantity +// gov_count_order_total +// 本月/总体销售:origin_place + SUM(yak_number) +// 采购地区:buyer_place + SUM(yak_number)(库表字段 buyer_place) -var mapRows = (rows) => { +var mapOriginRows = (rows) => { var total = 0 var result = [] for (row in rows) { - total = total + (row.value ? row.value : 0) + var qty = row.yakNumber != null ? row.yakNumber : 0 + total = total + qty } for (row in rows) { - var value = row.value ? row.value : 0 + var qty = row.yakNumber != null ? row.yakNumber : 0 var percent = 0 if (total > 0) { - percent = (value * 100) / total + percent = (qty * 100) / total } result.push({ - name: row.name, - value: value, + originPlace: row.originPlace ? row.originPlace : '未知地区', + yakNumber: qty, + percent: percent + }) + } + + return result +} + +var mapBuyerRows = (rows) => { + var total = 0 + var result = [] + + for (row in rows) { + var qty = row.yakNumber != null ? row.yakNumber : 0 + total = total + qty + } + + for (row in rows) { + var qty = row.yakNumber != null ? row.yakNumber : 0 + var percent = 0 + if (total > 0) { + percent = (qty * 100) / total + } + result.push({ + buyerPlace: row.buyerPlace ? row.buyerPlace : '未知地区', + yakNumber: qty, percent: percent }) } @@ -62,80 +89,48 @@ var mapRows = (rows) => { } var monthlySql = """ -SELECT town AS name, COALESCE(SUM(quantity), 0) AS value -FROM ( - SELECT - o.quantity, - COALESCE( - NULLIF((regexp_match(o.origin_place, '([^省市区县]+(?:镇|乡|街道))'))[1], ''), - NULLIF(TRIM(o.origin_place), ''), - '未知地区' - ) AS town - FROM yak_sn_order o - CROSS JOIN ( - SELECT CASE - WHEN EXISTS ( - SELECT 1 FROM yak_sn_order x - WHERE x.del_flag = '0' - AND x.status = 'COMPLETED' - AND x.transaction_time >= date_trunc('month', CURRENT_DATE) - AND x.transaction_time < date_trunc('month', CURRENT_DATE) + INTERVAL '1 month' - ) THEN date_trunc('month', CURRENT_DATE) - ELSE date_trunc('month', ( - SELECT MAX(transaction_time) FROM yak_sn_order - WHERE del_flag = '0' AND status = 'COMPLETED' - )) - END AS month_start - ) m - WHERE o.del_flag = '0' - AND o.status = 'COMPLETED' - AND o.transaction_time >= m.month_start - AND o.transaction_time < m.month_start + INTERVAL '1 month' -) t -GROUP BY town -ORDER BY value DESC +WITH anchor AS ( + SELECT year, month + FROM gov_count_order_total + WHERE year IS NOT NULL AND month IS NOT NULL + ORDER BY year DESC, month DESC + LIMIT 1 +) +SELECT + TRIM(o.origin_place) AS origin_place, + COALESCE(SUM(o.yak_number), 0) AS yak_number +FROM gov_count_order_total o +CROSS JOIN anchor a +WHERE o.year = a.year + AND o.month = a.month + AND o.origin_place IS NOT NULL + AND TRIM(o.origin_place) <> '' +GROUP BY TRIM(o.origin_place) +ORDER BY yak_number DESC, origin_place LIMIT 5 """ var overallSql = """ -SELECT town AS name, COALESCE(SUM(quantity), 0) AS value -FROM ( - SELECT - o.quantity, - COALESCE( - NULLIF((regexp_match(o.origin_place, '([^省市区县]+(?:镇|乡|街道))'))[1], ''), - NULLIF(TRIM(o.origin_place), ''), - '未知地区' - ) AS town - FROM yak_sn_order o - WHERE o.del_flag = '0' - AND o.status = 'COMPLETED' -) t -GROUP BY town -ORDER BY value DESC +SELECT + TRIM(origin_place) AS origin_place, + COALESCE(SUM(yak_number), 0) AS yak_number +FROM gov_count_order_total +WHERE origin_place IS NOT NULL + AND TRIM(origin_place) <> '' +GROUP BY TRIM(origin_place) +ORDER BY yak_number DESC, origin_place LIMIT 5 """ var purchaseSql = """ -SELECT region AS name, COALESCE(SUM(quantity), 0) AS value -FROM ( - SELECT - o.quantity, - COALESCE( - NULLIF(TRIM(b.region_name), ''), - NULLIF((regexp_match(o.destination_place, '([^省市区县]+(?:市|州|盟|县|区))'))[1], ''), - NULLIF(TRIM(o.destination_place), ''), - '未知地区' - ) AS region - FROM yak_sn_order o - LEFT JOIN yak_sn_customer b - ON b.id = o.buyer_id - AND b.del_flag = '0' - WHERE o.del_flag = '0' - AND o.status = 'COMPLETED' -) t -GROUP BY region -ORDER BY value DESC +SELECT + TRIM(buyer_place) AS buyer_place, + COALESCE(SUM(yak_number), 0) AS yak_number +FROM gov_count_order_total +WHERE buyer_place IS NOT NULL + AND TRIM(buyer_place) <> '' +GROUP BY TRIM(buyer_place) +ORDER BY yak_number DESC, buyer_place LIMIT 5 """ @@ -144,9 +139,9 @@ var overallRows = db.select(overallSql) var purchaseRows = db.select(purchaseSql) var result = { - monthlySales: mapRows(monthlyRows), - overallSalesDistribution: mapRows(overallRows), - purchaseRegionDistribution: mapRows(purchaseRows) + monthlySales: mapOriginRows(monthlyRows), + overallSalesDistribution: mapOriginRows(overallRows), + purchaseRegionDistribution: mapBuyerRows(purchaseRows) } var t = type diff --git a/data/magic-api/api/大屏数据/采购商户来源分析.ms b/data/magic-api/api/大屏数据/采购商户来源分析.ms index 228819a..9a6cf44 100644 --- a/data/magic-api/api/大屏数据/采购商户来源分析.ms +++ b/data/magic-api/api/大屏数据/采购商户来源分析.ms @@ -5,7 +5,7 @@ "groupId" : "f8e3d2c1b0a94e5f8a7b6c5d4e3f2a1", "name" : "采购商户来源分析", "createTime" : 1780881000000, - "updateTime" : null, + "updateTime" : 1781376000000, "lock" : null, "createBy" : "admin", "updateBy" : "admin", @@ -17,26 +17,26 @@ "headers" : [ ], "paths" : [ ], "responseBody" : null, - "description" : "采购商户来源分析:按地区统计采购商户(BUYER)数量 Top9,数据源 yak_sn_customer(只读)。", + "description" : "采购商户来源分析:gov_count_order_total 按 buyer_place 统计采购商户数 Top9,一条记录一单。", "requestBodyDefinition" : null, "responseBodyDefinition" : null } ================================ -// 只读查询,不修改任何数据 +// gov_count_order_total:一条记录 = 一笔订单 +// 采购地区:buyer_place +// 采购商户数:COUNT(DISTINCT buyer_name),buyer_name 为空时按 id 计 1 户 var sql = """ SELECT - region_name AS name, - region_name AS full_name, - COUNT(*) AS value, - region_name || '采购商户' AS description -FROM yak_sn_customer c -WHERE c.del_flag = '0' - AND c.customer_type = 'BUYER' - AND c.region_name IS NOT NULL - AND TRIM(c.region_name) <> '' -GROUP BY region_name -ORDER BY value DESC, region_name + buyer_place AS name, + buyer_place AS full_name, + COUNT(DISTINCT COALESCE(NULLIF(TRIM(buyer_name), ''), id)) AS value, + buyer_place || '采购商户' AS description +FROM gov_count_order_total +WHERE buyer_place IS NOT NULL + AND TRIM(buyer_place) <> '' +GROUP BY buyer_place +ORDER BY value DESC, buyer_place LIMIT 9 """ @@ -46,7 +46,7 @@ var result = [] for (row in rows) { result.push({ name: row.name, - value: row.value ? row.value : 0, + value: row.value != null ? row.value : 0, fullName: row.fullName ? row.fullName : (row.full_name ? row.full_name : ''), description: row.description ? row.description : '采购商户' }) diff --git a/magic-api-dashboard-interfaces.txt b/magic-api-dashboard-interfaces.txt index 53cee84..61aecf5 100644 --- a/magic-api-dashboard-interfaces.txt +++ b/magic-api-dashboard-interfaces.txt @@ -23,13 +23,13 @@ GET /dashboard/system-config GET /dashboard/real-time-stats 文件:实时交易统计.ms | 前端:RealTimeStats.vue -业务:按时间维度统计交易所已完成订单的交易量、订单数、买卖商户数。 +业务:按日/周/月读取政务统计指标(牦牛交易量、订单量、买卖商户数)。 -参数:dimension(可选)day / week / month / year,不传返回全部 +参数:dimension(可选)day / week / month,不传返回全部 -表:yak_sn_order -字段:quantity, seller_id, buyer_id, transaction_time, status, del_flag -条件:del_flag='0',status='COMPLETED' +表:gov_count_item +字段:key(mnjyzl/jdjyzl/xsshsl/cgshsl), name, value, count_date +口径:day=最新 count_date;week=近7天;month=近30天;mnjyzl/jdjyzl 按日求和,xsshsl/cgshsl 取区间内最大值 -------------------------------------------------------------------------------- @@ -38,13 +38,14 @@ GET /dashboard/real-time-stats GET /dashboard/yak-trading-data 文件:交易所牦牛成交数据.ms | 前端:YakTradingData.vue -业务:近 6 个日/周/月时间桶的牦牛头数与订单数趋势。 +业务:近 6 个日/周/月时间桶的牦牛成交头数与订单数趋势(一条记录 = 一单)。 参数:period(可选)day / week / month,不传返回全部 -表:yak_sn_order -字段:id, quantity, transaction_time, status, del_flag -条件:del_flag='0',status='COMPLETED' +表:gov_count_order_total +字段:id, yak_number, update_time +口径:SUM(yak_number) 为成交头数,COUNT(*) 为订单数;按 update_time 分桶 +返回:labels, yakNumber, orderCount -------------------------------------------------------------------------------- @@ -53,15 +54,12 @@ GET /dashboard/yak-trading-data GET /dashboard/comprehensive-sales-stats 文件:综合销售统计.ms | 前端:ComprehensiveSalesStats.vue -业务:三个饼图——本月销售、总体销售(按产地乡镇 Top5)、采购地区(Top5)。 +业务:三个饼图——本月销售、总体销售(按 origin_place Top5)、采购地区(按 buyer_place Top5)。 参数:type(可选)monthlySales / overallSalesDistribution / purchaseRegionDistribution -表:yak_sn_order;采购地区 LEFT JOIN yak_sn_customer -字段: - yak_sn_order — quantity, origin_place, destination_place, buyer_id, transaction_time, status, del_flag - yak_sn_customer — id, region_name, del_flag -条件:del_flag='0',status='COMPLETED' +表:gov_count_order_total +字段:origin_place, buyer_place, yak_number, year, month -------------------------------------------------------------------------------- @@ -70,10 +68,14 @@ GET /dashboard/comprehensive-sales-stats GET /dashboard/price-trend 文件:活牛鲜肉价格趋势.ms | 前端:YakPriceTrend.vue -业务:近 8 个月活牛、鲜肉市场采集均价(不做重量折算)。 +业务:近 8 个月活牛、鲜肉采集均价(不做重量折算)。 -表:yak_trade_market_price -字段:price_date, price_type(LIVE_YAK / FRESH_MEAT), price, unit +表:gov_count_price +字段:year, month, price_key, value, unit +口径: + 活牛 — price_key = hx(活畜),各区域 AVG(value) + 鲜肉 — price_key IN (mnr, mnt, mnp)(牦牛肉/腿/排),各区域 AVG(value) +返回:labels, liveCattlePrice, beefPrice, liveUnit, beefUnit -------------------------------------------------------------------------------- @@ -82,14 +84,19 @@ GET /dashboard/price-trend GET /dashboard/exchange-service-info 文件:交易中心实时服务信息.ms | 前端:ExchangeMonitor.vue -业务:交易中心实时概览——供应/待售/已售头数、剩余车位、今日进场车辆、供应商数。 +业务:交易中心实时概览——供应/待售/已售头数、剩余车位、进场车辆、供应商数。 -表及字段: - yak_trade_ear_tag_inventory — status(计总供应/待售/已售) - yak_car_parking_zone — total_capacity, current_count, status - yak_car_record — plate_no, entry_time, del_flag - yak_trade_entry_record — vehicle_no, entered_at - yak_sn_customer — customer_type='SELLER', del_flag +表:gov_count_real_info +条件:group_item = jygy,source_system = yzt +字段:key, name, value, tag, unit +key 映射: + mngyzl → totalSupply(牦牛供应总量) + dsmn → forSaleYaks(待售牦牛) + ysmn → soldYaks(已售牦牛) + sycw → remainingParking(剩余车位) + jccl → enteringVehicles(进场车辆) + gyssl → supplierCount(供应商数量) +返回:上述 value + Tag + Unit -------------------------------------------------------------------------------- @@ -98,11 +105,12 @@ GET /dashboard/exchange-service-info GET /dashboard/yak-sales-type-stats 文件:牦牛销售类型统计.ms | 前端:YakSalesTypeStats.vue -业务:按订单用途归类为屠宰/养殖/其他,统计头数与占比。 +业务:按 purpose 统计成交头数与占比(一条记录 = 一单)。 -表:yak_sn_order -字段:quantity, purpose, status, del_flag -条件:del_flag='0',status='COMPLETED' +表:gov_count_order_total +字段:purpose, yak_number +口径:GROUP BY purpose,SUM(yak_number);空 purpose 归为「其他」 +返回:name(屠宰/养殖/其他等), value, percent -------------------------------------------------------------------------------- @@ -111,11 +119,12 @@ GET /dashboard/yak-sales-type-stats GET /dashboard/buyer-source-analysis 文件:采购商户来源分析.ms | 前端:PurchaserAnalysis.vue -业务:按地区统计采购商户(BUYER)数量 Top9。 +业务:按 buyer_place 统计采购商户数量 Top9(一条记录 = 一单)。 -表:yak_sn_customer -字段:region_name, customer_type, del_flag -条件:customer_type='BUYER',del_flag='0',region_name 非空 +表:gov_count_order_total +字段:buyer_place, buyer_name, id +口径:GROUP BY buyer_place,COUNT(DISTINCT buyer_name);buyer_name 为空时按 id 计 1 户 +返回:name, value, fullName, description -------------------------------------------------------------------------------- @@ -164,11 +173,21 @@ GET /dashboard/yak-supply-detail GET /dashboard/market-environment 文件:市场环境监控.ms | 前端:MarketEnvironmentMonitor.vue -业务:环境温湿度 + 气象数据各取最新一条。 +业务:环境温湿度 + 气象八项实时指标。 -表及字段: - iot_device_env_data — temperature, humidity, collect_time - iot_device_weather_data — air_pressure, pm25, pm10, uv_index, rainfall, wind_speed, wind_direction, collect_time +表:gov_count_real_info +条件:group_item = env-monitor,source_system = yzt +字段:key, name, value, tag, unit +key 映射: + temperature 温度 + humidity 湿度 + aqi 空气质量 + pressure 大气压强 + uv 紫外线 + rainfall 降雨量 + wind_direction 风向(value=角度,tag=风向名) + wind_power 风力(value=级数) +返回:上述 value + Tag + Unit -------------------------------------------------------------------------------- @@ -177,21 +196,23 @@ GET /dashboard/market-environment GET /dashboard/market-realtime-monitor 文件:市场实时监控.ms | 前端:MarketRealtimeMonitor.vue -业务:视频监控设备列表及播放/预览地址。 +业务:萤石云视频监控设备列表,EZUIKit 播放 ezopen 地址。 表及字段: - iot_device_video — id, name, number, location, address, status, play_url, hd_play_url, preview_img_url, channel_number, index, del_flag, is_show - iot_device_video_data — device_id, stream_url, snapshot_url, online_status, stream_status, fault_code, collect_time + iot_device_video — id, name, serial_number, channel_number, status, play_url, hd_play_url, preview_img_url, video_account_id, index, del_flag, is_show + iot_video_account — id, app_key, token +关联:v.video_account_id = a.id 条件:del_flag='0',is_show=true +返回:ezopenUrl, accessToken, preview 等 -------------------------------------------------------------------------------- 13. 市场实时监控播放配置 -------------------------------------------------------------------------------- GET /dashboard/market-realtime-player-config -文件:市场实时监控播放配置.ms | 前端:MarketRealtimeMonitor.vue(liveStreamPlayer.js) +文件:市场实时监控播放配置.ms | 前端:MarketRealtimeMonitor.vue(ezvizPlayer.js) -业务:直播流协议识别规则与 hls.js / flv.js 播放器参数(静态配置)。 +业务:萤石云 EZUIKit 播放器参数(staticPath、template、scaleMode 等)。 数据表:无 @@ -202,22 +223,25 @@ GET /dashboard/market-realtime-player-config GET /dashboard/map-trading-network 文件:地图迁徙数据.ms | 前端:ChinaMap.vue -业务:中央地图三种模式流向——销售网络(红原→全国)、源地供应(全国→红原)、红原出栏(乡镇→红原)。 +业务:中央地图三种模式流向,头数 SUM(yak_number),一条记录一单。 -表:yak_sn_order;outflow/inflow LEFT JOIN yak_sn_customer -字段: - yak_sn_order — quantity, origin_place, destination_place, buyer_id, seller_id, status, del_flag - yak_sn_customer — id, region_name, del_flag -条件:del_flag='0',status='COMPLETED';local 模式另要求 origin_place 含「红原」 +表:gov_count_order_total +字段:origin_place, destination_place, yak_number +口径: + outflow 销售网络 — origin_place 含「红原」,按 destination_place 聚合,红原→全国 + inflow 源地供应 — destination_place 含「红原」,按 origin_place 聚合,全国→红原 + local 红原出栏 — destination_place 含「红原」且 origin_place 含「红原」,按 origin_place 乡镇聚合,县内乡镇→红原 关联:系统配置 mapHub.name 与脚本 hubName 需一致(默认「红原县」) ================================================================================ 表 → 接口索引 ================================================================================ -yak_sn_order 2, 3, 4, 7, 14 -yak_sn_customer 4, 6, 8, 9, 10, 14 -yak_trade_market_price 5 +gov_count_real_info 6, 11 +gov_count_price 5 +gov_count_order_total 3, 4, 7, 8, 14 +gov_count_item 2 +yak_sn_customer 4, 6, 9, 10 yak_trade_ear_tag_inventory 6, 9, 10 yak_trade_entry_record 6, 9, 10 yak_trade_entry_record_ear_tag 9, 10 @@ -227,8 +251,6 @@ yak_trade_quarantine_certificate 10 yak_car_parking_zone 6 yak_car_record 6, 10 sys_oss 10 -iot_device_env_data 11 -iot_device_weather_data 11 +iot_video_account 12 iot_device_video 12 -iot_device_video_data 12 (无表) 1, 13