本文档面向已经了解 面板小程序开发 的开发者,您需要充分的了解什么是面板小程序,什么是 DP 功能。
在某些设备的面板中需要提供给 C 端用户查看设备数据的能力,并需要导出数据使用户能够进一步分析。这里一般会导出如:温度、湿度、PM2.5 等的数据,涂鸦提供了相关的接口,可以按小时、天、月等粒度导出数据,把数据生成 Excel 文件,并通过邮件的方式发送给用户。
| 参数名称 | 参数类型 | 是否必选 | 默认值 | 描述 | 
| string | 是 | 无 | 接收导出文件的邮箱地址 | |
| devId | string | 是 | 无 | 待操作的设备 ID | 
| dpExcelQuery | string | 是 | 无 | 具体 DP 点的查询条件 | 
| date | string | 是 | 无 | 待导出数据的日期,格式:20230901 | 
| type | string | 是 | 无 | DP 点的统计类型,支持:sum/avg/minux/min/max/count 等 | 
| auto | number | 否 | 0 | 补数据的类型, 0:代表无数据补 0,1:代表无数据时会拿上一个时间点的数据补到当前时间点,2:代表无数据时补# | 
| keepScalaPoint | boolean | 否 | false | 是否按照 dp 点上报扩大倍数保留小数点 | 
| lang | string | 否 | 无 | 多语言 code | 
| title | string | 否 | 无 | 邮件标题 | 
| 参数名称 | 参数类型 | 是否必选 | 默认值 | 描述 | 
| string | 是 | 无 | 接收导出文件的邮箱地址 | |
| devId | string | 是 | 无 | 待操作的设备 ID | 
| dpExcelQuery | string | 是 | 无 | 具体 DP 点的查询条件 | 
| startDay | string | 是 | 无 | 待导出数据的开始日期,格式:20230901 | 
| endDay | string | 是 | 无 | 待导出数据的结束日期,格式:20230930 | 
| type | string | 是 | 无 | DP 点的统计类型,支持:sum/avg/minux/min/max/count 等 | 
| keepScalaPoint | boolean | 否 | false | 是否按照 dp 点上报扩大倍数保留小数点 | 
| lang | string | 否 | 无 | 多语言 code | 
| title | string | 否 | 无 | 邮件标题 | 
| 参数名称 | 参数类型 | 是否必选 | 默认值 | 描述 | 
| string | 是 | 无 | 接收导出文件的邮箱地址 | |
| devId | string | 是 | 无 | 待操作的设备 ID | 
| dpExcelQuery | string | 是 | 无 | 具体 DP 点的查询条件 | 
| startMonth | string | 是 | 无 | 待导出数据的开始年月,格式:202309 | 
| endMonth | string | 是 | 无 | 待导出数据的结束年月,格式:202309 | 
| type | string | 是 | 无 | DP 点的统计类型,支持:sum/avg/minux/min/max/count 等 | 
| keepScalaPoint | boolean | 否 | false | 是否按照 dp 点上报扩大倍数保留小数点 | 
| lang | string | 否 | 无 | 多语言 code | 
| title | string | 否 | 无 | 邮件标题 | 
此值为一个数组结构的 JSON 字符串,数组元素的结构为:
| 属性名称 | 类型 | 是否必须 | 描述 | 
| dpId | Number | 是 | DP 功能的 ID | 
| name | String | 是 | DP 功能名称 | 
| handler | String | 否 | 可支持温度的转换,值可为 temperatureF2C 或 temperatureC2F | 
示例
[{"dpId":"101","name":"华氏度转摄氏度","handler":"temperatureF2C"}]
示例为:需要导出设备的温度 (101)、湿度 (102)两个 DP 的数据,并且需要支持将温度的单位转为华氏度。

import React, { FC, useState, useCallback, useRef } from "react";
import { View, Text, Button, Checkbox, showToast } from "@ray-js/ray";
import SwitchButton from "@ray-js/components-ty-switch";
import ActionSheet from "@ray-js/components-ty-actionsheet";
import List from "@ray-js/components-ty-cell";
import DatePicker from "@ray/components-ty-datetime-picker";
import Input from "@ray-js/components-ty-input";
import { hooks } from "@ray-js/panel-sdk";
import * as api from "./api";
const langs = {
	hour: "时",
	day: "天",
	month: "月",
};
const exportFn = {
	hour: api.exportHour,
	day: api.exportDay,
	month: api.exportMonth,
};
const formDate = (date, format = "YYYYMMDD") => {
	const year = date.getFullYear();
	const month = date.getMonth() + 1;
	const day = date.getDate();
	return format
		.replace("YYYY", year)
		.replace("MM", month.toString().padStart(2, "0"))
		.replace("DD", day.toString().padStart(2, "0"));
};
const Page: FC = () => {
	const devInfo = hooks.useDevInfo();
	const [unit, setUnit] = useState(false);
	const [type, setType] = useState("hour");
	const [email, setEmail] = useState("");
	const isEnd = useRef(false);
	const [showList, setShowList] = useState(false);
	const [showTime, setShowTime] = useState(false);
	const [startTime, setStartTime] = useState(new Date());
	const [endTime, setEndTime] = useState(new Date());
	const handleShowEnd = useCallback(() => {
		isEnd.current = true;
		setShowTime(true);
	}, []);
	const handleShowStart = useCallback(() => {
		isEnd.current = false;
		setShowTime(true);
	}, []);
	const handleSelectTime = useCallback((v) => {
		if (isEnd.current) {
			setEndTime(v);
		} else {
			setStartTime(v);
		}
	}, []);
	const handleExport = useCallback(() => {
		if (!email) {
			showToast({
				title: "请输入邮箱",
				icon: "error",
			});
			return;
		}
		const format = type === "month" ? "YYYYMM" : "YYYYMMDD";
		let start = formDate(startTime, format);
		let end = formDate(startTime, format);
		const data = {
			title: "温湿度数据表",
			devId: devInfo.devId,
			email,
			dpExcelQuery: [
				{
					dpId: "101",
					name: "室内温度",
					handler: unit ? "temperatureC2F" : undefined,
				},
				{ dpId: "102", name: "室内湿度" },
			],
		};
		switch (type) {
			case "hour":
				data.date = start;
				break;
			case "day":
				data.startDay = start;
				data.endDay = end;
				break;
			case "month":
				data.startMonth = start;
				data.endMonth = end;
				break;
		}
		exportFn[type](data);
	}, [type, email, unit, startTime, endTime, devInfo?.devId]);
	return (
		<View>
			<List>
				<List.Item
					title="使用华氏度"
					content={<SwitchButton checked={unit} onChange={(v) => setUnit(v)} />}
				/>
				<List.Item
					title="粒度"
					onClick={() => setShowList(true)}
					content={<Text>{langs[type]}</Text>}
				/>
				<List.Item
					title={type === "hour" ? "时间" : "开始时间"}
					onClick={handleShowStart}
					content={
						<Text>
							{formDate(startTime, type === "month" ? "YYYYMM" : "YYYYMMDD")}
						</Text>
					}
				/>
				{type !== "hour" && (
					<List.Item
						title="结束时间"
						onClick={handleShowEnd}
						content={
							<Text>
								{formDate(endTime, type === "month" ? "YYYYMM" : "YYYYMMDD")}
							</Text>
						}
					/>
				)}
				<List.Item
					title="邮箱"
					content={
						<Input
							placeholder="请输入"
							value={email}
							onInput={(e) => setEmail(e.value)}
						/>
					}
				/>
			</List>
			<ActionSheet
				show={showList}
				header="选择粒度"
				onCancel={() => setShowList(false)}
				okText=""
			>
				<List.Row
					dataSource={Object.keys(langs).map((key) => {
						return {
							title: langs[key],
							content: type === key ? <Checkbox checked /> : null,
							onClick: () => {
								setType(key);
								setShowList(false);
							},
						};
					})}
				/>
			</ActionSheet>
			<ActionSheet
				show={showTime}
				header="选择时间"
				onCancel={() => setShowTime(false)}
				onOk={() => setShowTime(false)}
			>
				<DatePicker
					onChange={handleSelectTime}
					type={type === "month" ? "year-month" : "date"}
				/>
			</ActionSheet>
			<Button onClick={handleExport}>导出</Button>
		</View>
	);
};
export default Page;
api.js 文件内容
import {
	exportStatisticsDay,
	exportStatisticsHour,
	exportStatisticsMonth,
} from "@ray-js/ray";
// 导出小时数据
export const exportHour = async (params) => {
	try {
		await exportStatisticsHour({
			email: params.email,
			devId: params.devId,
			dpExcelQuery: JSON.stringify(params.dpExcelQuery),
			date: params.date,
			type: "avg",
			auto: 2,
			keepScalaPoint: true,
			lang: "cn",
		});
		// 导出成功
	} catch {
		// 导出失败
	}
};
// 导出天数据
export const exportDay = async (params) => {
	try {
		await exportStatisticsDay({
			email: params.email,
			devId: params.devId,
			dpExcelQuery: JSON.stringify(params.dpExcelQuery),
			startDay: params.startDay,
			endDay: params.endDay,
			type: "avg",
			keepScalaPoint: true,
			lang: "cn",
		});
		// 导出成功
	} catch {
		// 导出失败
	}
};
// 导出月数据
export const exportMonth = async (params) => {
	try {
		await exportStatisticsMonth({
			email: params.email,
			devId: params.devId,
			dpExcelQuery: JSON.stringify(params.dpExcelQuery),
			startMonth: params.startMonth,
			endMonth: params.endMonth,
			type: "avg",
			keepScalaPoint: true,
			lang: "cn",
		});
		// 导出成功
	} catch {
		// 导出失败
	}
};