React antd的datePicker自定义,封装成组件

news2025/5/18 16:34:55
一、antd的datePicker自定义
需求:用户需要为日期选择器的每个日期单元格添加一个Tooltip,当鼠标悬停时显示日期、可兑换流量余额和本公会可兑流量。这些数据需要从接口获取。我需要结合之前的代码,确保Tooltip正确显示,并且数据来自接口。

主要汉化点:

  1. 整个日期选择器面板中文化
  2. 星期显示为中文(周一 到 周日)
  3. 月份显示为中文格式
  4. 操作按钮汉化("确定"、"现在" 等)
  5. 日期格式统一使用中文年月日
  6. 加载提示中文化
  7. Tooltip内容中文化

效果包含:

  • 月份显示为 "2024年5月"
  • 星期列显示为 "一、二、三、四、五、六、日"
  • 今天按钮显示为 "今天"
  • 确定按钮显示为 "确定"
  • 十年范围显示为 "2020-2029"
  • 时间列显示为 "时","分","秒"
  • index.tsx文件
import React, { useState, useEffect } from 'react';
import { DatePicker, Tooltip, Spin, ConfigProvider } from 'antd';
import dayjs, { Dayjs } from 'dayjs';
import isSameOrAfter from 'dayjs/plugin/isSameOrAfter';
import isSameOrBefore from 'dayjs/plugin/isSameOrBefore';
import './custom-datepicker.css';
import 'dayjs/locale/zh-cn';
import zhCN from 'antd/locale/zh_CN';
dayjs.extend(isSameOrAfter);
dayjs.extend(isSameOrBefore);
dayjs.locale('zh-cn'); // 设置dayjs为中文

interface TrafficData {
    date: string;
    personal: string;
    guild: string;
}

const App: React.FC = () => {
  const [selectedDate, setSelectedDate] = useState<Dayjs | null>(null);
  const [trafficData, setTrafficData] = useState<Record<string, TrafficData>>({});
  const [loading, setLoading] = useState(true);

  const today = dayjs().startOf('day');
  const sevenDaysLater = today.add(6, 'day');

  useEffect(() => {
    const mockApi = async () => {
      const data: Record<string, TrafficData> = {};
      Array.from({ length: 7 }).forEach((_, i) => {
        const date = today.add(i, 'day').format('YYYY-MM-DD');
        data[date] = {
          date,
          personal: `${[0, 20, 30, 40, 80, 100, 50][i]}%`,
          guild: `${Math.floor(Math.random() * 100000).toLocaleString()}`,
        };
      });

      await new Promise(resolve => setTimeout(resolve, 500));
      setTrafficData(data);
      setLoading(false);
    };

    mockApi();
  }, []);

  const disabledDate = (current: Dayjs) => current.isBefore(today, 'day') || current.isAfter(sevenDaysLater, 'day');

  if (loading) return <Spin tip="数据加载中..." />;

  return (
    <ConfigProvider locale={zhCN}> {/* 设置Ant Design为中文 */}
      <DatePicker
        value={selectedDate}
        disabledDate={disabledDate}
        onChange={setSelectedDate}
        dropdownClassName="custom-picker-dropdown"
        dateRender={current => {
          const dateStr = current.format('YYYY-MM-DD');
          const data = trafficData[dateStr];
          const isInRange = current.isSameOrAfter(today) && current.isSameOrBefore(sevenDaysLater);
          const isSelected = selectedDate?.isSame(current, 'day');

          return (
            <div className="custom-cell-wrapper">
              <div className="native-cell-content">
                {current.date()}
              </div>
              <Tooltip
                title={data ?
                  `${dayjs(dateStr).format('YYYY年M月D日')}\n可兑流量余额: ${data.personal}\n本公会可兑流量: ${data.guild}`
                  : '无可用数据'}
                overlayStyle={{
                  whiteSpace: 'pre-line',
                  pointerEvents: 'none',
                }}
                placement="bottom"
                mouseEnterDelay={0}
                mouseLeaveDelay={0.1}
                trigger={['hover']}
                getPopupContainer={trigger => trigger.parentElement!}
              >
                <div className={`custom-cell ${isInRange ? 'recent-date' : ''}`}>
                  <div className={`date-number ${isSelected ? 'selected' : ''}`}>
                    {current.date()}
                  </div>
                  {data && (
                    <div className={`availability ${data.personal === '0%' ? 'empty' : ''}`}>
                                            余{data.personal}
                    </div>
                  )}
                </div>
              </Tooltip>
            </div>
          );
        }}
      />
    </ConfigProvider>
  );
};

export default App;
  • custom-datepicker.css文件
/* custom-datepicker.css */
.custom-picker-dropdown {
    z-index: 1001;
}

.custom-cell-wrapper {
    position: relative;
    height: 100%;
    width: 100%;
}

.native-cell-content {
    visibility: hidden;
}

.custom-cell {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    z-index: 2;
    padding: 3px 0;
}

.date-number {
    width: 24px;
    height: 24px;
    line-height: 24px;
    text-align: center;
    color: #000;
    transition: all 0.2s;
    border-radius: 50%;
}

.date-number.selected {
    background: #1890ff;
    color: white !important;
}

.recent-date:hover .date-number:not(.selected) {
    color: #1890ff;
}

.availability {
    font-size: 10px;
    line-height: 14px;
    color: #1890ff;
    margin-top: 2px;
}

.availability.empty {
    color: #ff4d4f !important;
}

.ant-picker-cell-inner {
    padding: 0 !important;
    height: 100% !important;
}

.ant-picker-cell:hover .ant-picker-cell-inner {
    background: transparent !important;
}

/* 添加中文面板样式调整 */
.ant-picker-date-panel {
    font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif;
}

.ant-picker-header-view button {
    font-weight: 500;
}

.ant-picker-cell-inner::before {
    border-radius: 50% !important;
}

二、封装成组件

  • DateSelector.tsx文件
// DateSelector.tsx
import React from 'react';
import {DatePicker, Tooltip, Spin, ConfigProvider} from 'antd';
import dayjs, { Dayjs } from 'dayjs';
import isSameOrAfter from 'dayjs/plugin/isSameOrAfter';
import isSameOrBefore from 'dayjs/plugin/isSameOrBefore';
import 'dayjs/locale/zh-cn';
import './custom-datepicker.css';
import zhCN from 'antd/locale/zh_CN';

dayjs.extend(isSameOrAfter);
dayjs.extend(isSameOrBefore);

export interface TrafficData {
    personal: string;
    guild: string;
}

interface DateSelectorProps {
    value?: Dayjs | null;
    trafficData: Record<string, TrafficData>;
    onChange?: (date: Dayjs | null) => void;
    loading?: boolean;
}

const DateSelector: React.FC<DateSelectorProps> = ({
  value,
  trafficData,
  onChange,
  loading = false,
}) => {
  const today = dayjs().startOf('day');
  const sevenDaysLater = today.add(6, 'day');

  const disabledDate = (current: Dayjs) => current.isBefore(today, 'day') || current.isAfter(sevenDaysLater, 'day');

  const handleChange = (date: Dayjs | null) => {
    onChange?.(date);
  };

  if (loading) {
    return <Spin tip="数据加载中..." style={{ padding: '8px 0' }} />;
  }

  return (
    <ConfigProvider locale={zhCN}> {/* 设置Ant Design为中文 */}
      <DatePicker
        value={value}
        disabledDate={disabledDate}
        onChange={handleChange}
        dropdownClassName="custom-picker-dropdown"
        dateRender={current => {
          const dateStr = current.format('YYYY-MM-DD');
          const data = trafficData[dateStr];
          const isInRange = current.isSameOrAfter(today) && current.isSameOrBefore(sevenDaysLater);
          const isSelected = value?.isSame(current, 'day');

          return (
            <div className="custom-cell-wrapper">
              <div className="native-cell-content">{current.date()}</div>
              <Tooltip
                title={data ?
                  `${dayjs(dateStr).format('YYYY年M月D日')}\n可兑流量余额: ${data.personal}\n本公会可兑流量: ${data.guild}`
                  : '无可用数据'}
                overlayStyle={{
                  whiteSpace: 'pre-line',
                  pointerEvents: 'none',
                }}
                placement="bottom"
                mouseEnterDelay={0}
                mouseLeaveDelay={0.1}
              >
                <div className={`custom-cell ${isInRange ? 'recent-date' : ''}`}>
                  <div className={`date-number ${isSelected ? 'selected' : ''}`}>
                    {current.date()}
                  </div>
                  {data && (
                    <div className={`availability ${data.personal === '0%' ? 'empty' : ''}`}>
                                            余{data.personal}
                    </div>
                  )}
                </div>
              </Tooltip>
            </div>
          );
        }}
      />
    </ConfigProvider>
  );
};

export default DateSelector;
  • custom-datepicker.css
/* custom-datepicker.css */
.custom-picker-dropdown {
    z-index: 1001;
}

.custom-cell-wrapper {
    position: relative;
    height: 100%;
    width: 100%;
}

.native-cell-content {
    visibility: hidden;
}

.custom-cell {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    z-index: 2;
    padding: 3px 0;
}

.date-number {
    width: 24px;
    height: 24px;
    line-height: 24px;
    text-align: center;
    color: #000;
    transition: all 0.2s;
    border-radius: 50%;
}

.date-number.selected {
    background: #1890ff;
    color: white !important;
}

.recent-date:hover .date-number:not(.selected) {
    color: #1890ff;
}

.availability {
    font-size: 10px;
    line-height: 14px;
    color: #1890ff;
    margin-top: 2px;
}

.availability.empty {
    color: #ff4d4f !important;
}

.ant-picker-cell-inner {
    padding: 0 !important;
    height: 100% !important;
}

.ant-picker-cell:hover .ant-picker-cell-inner {
    background: transparent !important;
}

/* 添加中文面板样式调整 */
.ant-picker-date-panel {
    font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif;
}

.ant-picker-header-view button {
    font-weight: 500;
}

.ant-picker-cell-inner::before {
    border-radius: 50% !important;
}
  • index.tsx文件
// 使用示例 ParentComponent.tsx
import React, { useState, useEffect } from 'react';
import DateSelector, { TrafficData } from './DateSelector';
import dayjs from 'dayjs';

const ParentComponent: React.FC = () => {
  const [selectedDate, setSelectedDate] = useState<dayjs.Dayjs | null>(null);
  const [trafficData, setTrafficData] = useState<Record<string, TrafficData>>({});
  const [loading, setLoading] = useState(true);

  const today = dayjs().startOf('day');

  // useEffect(() => {
  //   // 模拟API调用
  //   const mockFetchData = async () => {
  //     const mockData = {
  //       [dayjs().format('YYYY-MM-DD')]: {
  //         personal: '80%',
  //         guild: '100,000',
  //       },
  //       [dayjs().add(1, 'day')
  //         .format('YYYY-MM-DD')]: {
  //         personal: '50%',
  //         guild: '75,000',
  //       },
  //     };
  //
  //     await new Promise(resolve => setTimeout(resolve, 800));
  //     setTrafficData(mockData);
  //     setLoading(false);
  //   };
  //
  //   mockFetchData();
  // }, []);

  useEffect(() => {
    const mockApi = async () => {
      const data: Record<string, TrafficData> = {};
      Array.from({ length: 7 }).forEach((_, i) => {
        const date = today.add(i, 'day').format('YYYY-MM-DD');
        data[date] = {
          personal: `${[0, 20, 30, 40, 80, 100, 50][i]}%`,
          guild: `${Math.floor(Math.random() * 100000).toLocaleString()}`,
        };
      });

      await new Promise(resolve => setTimeout(resolve, 500));
      setTrafficData(data);
      setLoading(false);
    };

    mockApi();
  }, []);

  return (
    <div style={{ padding: 24 }}>
      <h2>日期选择器示例</h2>
      <div style={{ marginBottom: 16 }}>
                当前选择:{selectedDate?.format('YYYY年M月D日') || '未选择'}
      </div>
      <DateSelector
        value={selectedDate}
        trafficData={trafficData}
        onChange={setSelectedDate}
        loading={loading}
      />
    </div>
  );
};

export default ParentComponent;

三、生效时间选择完日期后,还需填入具体时间(或提供一个时间选择器),精确到分,默认为00:00;如选择的日期为今天,则填写的时间不能早于当前时间

// index.tsx
import React, { useState, useEffect } from 'react';
import { Row, Col, TimePicker, Spin, ConfigProvider } from 'antd';
import DateSelector, { TrafficData } from './DateSelector';
import dayjs, { Dayjs } from 'dayjs';
import zhCN from 'antd/locale/zh_CN';

declare module 'dayjs' {
  interface Dayjs {
    isToday(): boolean;
  }
}

dayjs.extend((o, c) => {
  c.prototype.isToday = function () {
    return this.isSame(dayjs(), 'day');
  }
});

const DateTimePicker: React.FC = () => {
  const [selectedDate, setSelectedDate] = useState<Dayjs | null>(null);
  const [selectedTime, setSelectedTime] = useState<Dayjs>(dayjs().startOf('minute'));
  const [trafficData, setTrafficData] = useState<Record<string, TrafficData>>({});
  const [loading, setLoading] = useState(true);
  const today = dayjs().startOf('day');

  const disabledTime = (current: Dayjs | null) => {
    if (!current || !selectedDate?.isToday()) {
      return { disabledHours: () => [], disabledMinutes: () => [] };
    }

    const now = dayjs();
    return {
      disabledHours: () => {
        const currentHour = now.hour();
        return Array.from({ length: currentHour }, (_, i) => i);
      },
      disabledMinutes: (selectedHour: number) => {
        if (selectedHour < now.hour()) return [];
        return Array.from({ length: now.minute() }, (_, i) => i);
      },
    };
  };

  const handleDateChange = (date: Dayjs | null) => {
    setSelectedDate(date);
    setSelectedTime(date?.isToday() ? dayjs().startOf('minute') : dayjs().startOf('day'));
  };

  // useEffect(() => {
  //   // 模拟API请求
  //   const mockData = {
  //     [dayjs().format('YYYY-MM-DD')]: { personal: '80%', guild: '100,000' },
  //     [dayjs().add(1, 'day')
  //       .format('YYYY-MM-DD')]: { personal: '50%', guild: '75,000' },
  //   };
  //
  //   setTimeout(() => {
  //     setTrafficData(mockData);
  //     setLoading(false);
  //   }, 800);
  // }, []);

  useEffect(() => {
    const mockApi = async () => {
      const data: Record<string, TrafficData> = {};
      Array.from({ length: 7 }).forEach((_, i) => {
        const date = today.add(i, 'day').format('YYYY-MM-DD');
        data[date] = {
          personal: `${[0, 20, 30, 40, 80, 100, 50][i]}%`,
          guild: `${Math.floor(Math.random() * 100000).toLocaleString()}`,
        };
      });

      await new Promise(resolve => setTimeout(resolve, 500));
      setTrafficData(data);
      setLoading(false);
    };

    mockApi();
  }, []);

  return (
    <ConfigProvider locale={zhCN}> {/* 设置Ant Design为中文 */}
      <div style={{ padding: 24, maxWidth: 380, margin: '0 auto' }}>
        <h2 style={{ marginBottom: 24 }}>预约时间选择</h2>

        <Row gutter={24} align="middle">
          <Col span={12}>
            {/*<div style={{ marginBottom: 8 }}>选择日期</div>*/}
            <DateSelector
              value={selectedDate}
              trafficData={trafficData}
              onChange={handleDateChange}
              loading={loading}
            />
          </Col>

          <Col span={12}>
            {/*<div style={{ marginBottom: 8 }}>选择时间</div>*/}
            <TimePicker
              value={selectedTime}
              format="HH:mm"
              minuteStep={1}
              disabledTime={disabledTime}
              onChange={time => setSelectedTime(time || dayjs().startOf('minute'))}
              placeholder="请选择时间"
              disabled={!selectedDate}
              allowClear={false}
              showNow={false}
              style={{ width: '100%' }}
            />
          </Col>
        </Row>

        <div style={{ marginTop: 24, padding: 16, background: '#f5f5f5', borderRadius: 4 }}>
          已选择时间: {selectedDate ?
            `${selectedDate.format('YYYY年MM月DD日')} ${selectedTime.format('HH:mm')}`
            : '请先选择日期'}
        </div>
      </div>
    </ConfigProvider>
  );
};

export default DateTimePicker;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2307827.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C++ AVL树详解(含模拟实现)

目录 AVL树的概念 AVL树节点的定义 AVL树的插入 AVL树的旋转&#xff08;难点&#xff09; AVL树的验证 AVL树的删除(本文不做具体的模拟实现) AVL树的性能 AVL树的模拟实现 AVL树的概念 二叉搜索树虽可以缩短查找的效率&#xff0c;但如果数据有序或接近有序二叉搜索…

Spring Boot 3.x 系列【3】Spring Initializr快速创建Spring Boot项目

有道无术&#xff0c;术尚可求&#xff0c;有术无道&#xff0c;止于术。 本系列Spring Boot版本3.0.3 源码地址&#xff1a;https://gitee.com/pearl-organization/study-spring-boot3 文章目录 前言安装JDK 17创建Spring Boot 项目 方式1&#xff1a;网页在线生成方式2&#…

Elasticsearch:过滤 HNSW 搜索,快速模式

作者&#xff1a;来自 Elastic Benjamin Trent 通过我们的 ACORN-1 算法实现&#xff0c;探索我们对 Apache Lucene 中的 HNSW 向量搜索所做的改进。 多年来&#xff0c;Apache Lucene 和 Elasticsearch 一直支持使用 kNN 查询的过滤搜索&#xff0c;允许用户检索符合指定元数据…

【AI测试学习】AnythingLLM+Ollama+DeepSeek部署私人知识库

1.搭建DeepSeek大语言模型 1.1Ollama大预言模型部署 Ollama简化了大型语言模型的运行,让每个人都能在本地轻松体验AI的强大,打开浏览器-下载Ollama-输入命令-搞定,这是本地部署大语言模型的全新方式。 这里我们借助Ollama大预言模型部署工具进行搭建 官网如下:Ollama …

通义灵码插件安装入门教学 - IDEA(安装篇)

在开发过程中&#xff0c;使用合适的工具和插件可以极大地提高我们的工作效率。今天&#xff0c;我们将详细介绍如何在 IntelliJ IDEA 中安装并配置通义灵码插件&#xff0c;这是一款旨在提升开发者效率的实用工具。无论你是新手还是有经验的开发者&#xff0c;本文都将为你提供…

ES、OAS、ERP、电子政务、企业信息化(高软35)

系列文章目录 ES、OAS、ERP、电子政务、企业信息化 文章目录 系列文章目录前言一、专家系统&#xff08;ES&#xff09;二、办公自动化系统&#xff08;OAS&#xff09;三、企业资源规划&#xff08;ERP&#xff09;四、典型信息系统架构模型1.政府信息化和电子政务2.企业信息…

python-leetcode-删除并获得点数

740. 删除并获得点数 - 力扣&#xff08;LeetCode&#xff09; 解法 1&#xff1a;动态规划&#xff08;O(n) 时间&#xff0c;O(n) 空间&#xff09; class Solution:def deleteAndEarn(self, nums: List[int]) -> int:if not nums:return 0# 统计每个数的贡献points Cou…

助力DeepSeek私有化部署服务:让企业AI落地更简单、更安全

在数字化转型的浪潮中&#xff0c;越来越多的企业选择私有化部署AI技术&#xff0c;以保障数据安全、提升业务效率并实现自主可控。DeepSeek作为行业领先的AI开源技术&#xff0c;其技术可以支持企业私有化部署&#xff0c;企业需要一站式服务私有化部署&#xff0c;涵盖硬件采…

【每天认识一个漏洞】url重定向

&#x1f31d;博客主页&#xff1a;菜鸟小羊 &#x1f496;专栏&#xff1a;Linux探索之旅 | 网络安全的神秘世界 | 专接本 | 每天学会一个渗透测试工具 常见应用场景 主要是业务逻辑中需要进行跳转的地方。比如登录处、注册处、访问用户信息、订单信息、加入购物车、分享、收…

纯代码实战--用Deepseek+SQLite+Ollama搭建数据库助手

如何用Python调用本地模型实现DeepSeek提示词模板&#xff1a;一步步教你高效解决13种应用场景 从零到一&#xff1a;纯代码联合PyQt5、Ollama、Deepseek打造简易版智能聊天助手 用外接知识库武装大模型&#xff1a;基于Deepseek、Ollama、LangChain的RAG实战解析 纯代码实战–…

2025 最新版鸿蒙 HarmonyOS 开发工具安装使用指南

为保证 DevEco Studio 正常运行&#xff0c;建议电脑配置满足如下要求&#xff1a; Windows 系统 操作系统&#xff1a;Windows10 64 位、Windows11 64 位内存&#xff1a;16GB 及以上硬盘&#xff1a;100GB 及以上分辨率&#xff1a;1280*800 像素及以上 macOS 系统 操作系统…

AI数字人开发,引领科技新潮流

引言 随着人工智能技术的迅猛发展&#xff0c;AI 数字人在影视娱乐、客户服务、教育及医疗等多个领域展现出巨大的潜力。本文旨在为开发者提供一份详细的 AI 数字人系统开发指南&#xff0c;涵盖从基础架构到实现细节的各个方面&#xff0c;包括人物建模、动作生成、语音交互、…

领域驱动设计:事件溯源架构简介

概述 事件溯源架构通常由3种应用设计模式组成,分别是:事件驱动(Event Driven),事件溯源(Event Source)、CQRS(读写分离)。这三种应用设计模式常见于领域驱动设计(DDD)中,但它们本身是一种应用设计的思想,不仅仅局限于DDD,每一种模式都可以单独拿出来使用。 E…

STM32之影子寄存器

预分频寄存器计数到一半的时候&#xff0c;改变预分频值&#xff0c;此时不会立即生效&#xff0c;会等到计数完成&#xff0c;再从影子寄存器即预分频缓冲器里装载修改的预分频值。 如上图&#xff0c;第一行是内部时钟72M&#xff0c;第二行是时钟使能&#xff0c;高电平启动…

x64汇编下过程参数解析

简介 好久没上博客, 突然发现我的粉丝数变2700了, 真是这几个月涨的粉比我之前好几年的都多, 于是心血来潮来写一篇, 记录一下x64下的调用约定(这里的调用约定只针对windows平台) Windows下的x64程序的调用约定有别于x86下的"stdcall调用约定"以及"cdecl调用约…

Blender调整最佳渲染清晰度

1.渲染采样调高 512 2.根据需要 开启AO ,开启辉光 , 开启 屏幕空间反射 3.调高分辨率 4096x4096 100% 分辨率是清晰度的关键 , 分辨率不高 , 你其他参数调再高都没用 4.世界环境开启体积散射 , 可以增强氛围感 5.三点打光法 放在模型和相机45夹角上 白模 白模带线条 成品

TSMaster【第二十篇:华山论剑——知识图谱全览】

(三维思维导图「独孤九剑总诀式」技能树「经脉贯通」检测系统未来技术「武学秘境」预测) 【武侠场景导入】光明顶秘道惊变 明教光明顶密道中,张无忌面对错综复杂的甬道体系,以乾坤大挪移心法贯通九阳神功与太极拳剑,终成武林至尊。今时今日,三电工程师面对庞杂的TSMaste…

神经性手抖是一种常见的症状

神经性手抖是一种常见的症状&#xff0c;表现为手部无意识或不受控制地颤抖。为了预防神经性手抖&#xff0c;我们可以采取以下几种方法&#xff1a; 1. 放松身心&#xff1a;压力和焦虑是导致神经性手抖的常见原因之一。因此&#xff0c;学会放松身心是预防手抖的关键。可以通…

金融支付行业技术侧重点

1. 合规问题 第三方支付系统的平稳运营&#xff0c;严格遵循《非银行支付机构监督管理条例》的各项条款是基础与前提&#xff0c;其中第十八条的规定堪称重中之重&#xff0c;是支付机构必须牢牢把握的关键准则。 第十八条明确指出&#xff0c;非银行支付机构需构建起必要且独…

支付宝 IoT 设备入门宝典(下)设备经营篇

上篇介绍了支付宝 IoT 设备管理&#xff0c;但除了这些基础功能外&#xff0c;商户还可以利用设备进行一些运营动作&#xff0c;让设备更好的帮助自己&#xff0c;本篇就会以设备经营为中心&#xff0c;介绍常见的设备相关能力和问题解决方案。如果对上篇感兴趣&#xff0c;可以…