PHP对接企业微信
前言
最近在做项目中,要求在后台管理中有企业微信管理的相关功能。相关准备工作,需要准备好企业微信账号,添加自建应用,获得相应功能的权限,以及agentid、secre等。
参考文档:
企业微信开发文档

功能实现
因功能接口比较多,这里以“客户敏感词”为例,以下为“敏感词”管理功能实现。
1 想法思路
企业微信接口有请求次数限制,后台操作频繁,避免多次请求企业微信接口,也为了相应速度考虑,我这里考虑将输入进行入库处理。每次新建敏感词,企业微信“新增敏感词”接口请求成功后,将数据添加到数据库,编辑和删除同理。这样敏感词列表、查看敏感词就可以减少对企业微信接口的请求。
2 注意事项
(1)敏感词这里需要依赖通讯录中的成员和部门,因此需要先开发这两个模块之后,再进行敏感词功能开发(成员和部门也做了入库处理,所以在下面代码中,我也是直接查询数据库的内容);
(2)access_token 有三种:通讯录access_token、联系人access_token以及自建应用 access_token,要根据接口需要,看需要哪一种access_token,否则就会报错。敏感词这里使用的是自建应用 access_token。
(3)要记得添加IP白名单。

3 代码实现
InterceptController.php
<?php
// +-----------------------xiaozhe-----------------------------------------------namespace app\wework\controller;use cmf\controller\AdminBaseController;
use app\wework\service\InterceptService;
use app\wework\service\WechatInterceptApi;
use app\wework\model\InterceptModel;
use app\wework\model\WeUserModel;
use app\admin\model\AdminMenuModel;class InterceptController extends AdminBaseController
{// 敏感词列表public function index(){ // 接口请求敏感词列表// $wxinterceptApi = new WechatInterceptApi();// $list = $wxinterceptApi->getInterceptRuleList();// echo "<pre>";// print_r($list);// exit;$param = $this->request->param();$interceptService = new InterceptService();$data = $interceptService->getList($param);$data->appends($param);$this->assign('keyword', isset($param['keyword']) ? $param['keyword'] : '');$this->assign('lists', $data->items());$this->assign('page', $data->render());return $this->fetch();}// 新增敏感词public function add(){if ($this->request->isPost()) {$data = $this->request->param();$interceptModel = new InterceptModel();$data['create_time'] = time();$data['user_id'] = cmf_get_current_admin_id();$data['group_id'] = 0;if ($data['applicable_type'] == 2) {// 选择员工的话,是员工名$userModel = new WeUserModel();$userList = $userModel->whereIn('userid',$data['applicable_range'])->column("userid","department_id");$group_arr = array_unique(array_keys($userList));$applicable_range['user_list'] = implode(",",$userList);$applicable_range['department_list'] = implode(",",$group_arr);$data['applicable_range'] = json_encode($applicable_range,JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);} else {$userModel = new WeUserModel();$userList = $userModel->whereIn('department_id',$data['applicable_range'])->column("userid");$applicable_range['user_list'] = implode(",",$userList);$applicable_range['department_list'] = $data['applicable_range'];$data['applicable_range'] = json_encode($applicable_range,JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);}if (!empty($data['semantics_list'])) {$data['semantics_list'] = implode(",",$data['semantics_list']);}// 敏感词接口新增$user_list = !empty($applicable_range['user_list']) ? explode(",",$applicable_range['user_list']) : [];$department_list = explode(",",$applicable_range['department_list']);$wx_intercept = array('rule_name' => $data['rule_name'],'word_list' => explode(",",$data['word_list']),'semantics_list' => explode(",",$data['semantics_list']),'intercept_type' => $data['intercept_type'],'applicable_range' => array('user_list' => $user_list,'department_list' => $department_list));$wxinterceptApi = new WechatInterceptApi();$res = $wxinterceptApi->addInterceptRule($wx_intercept);if ($res['errcode'] != 0) {$this->error($res['errmsg'], url("Intercept/index"));}$data['rule_id'] = $res['rule_id'];$result = $interceptModel->save($data);if ($result) {$this->success('添加成功!', url("Intercept/index"));} else {$this->error('添加失败!', url("Intercept/index"));}}return $this->fetch();}// 编辑敏感词public function edit(){if ($this->request->isPost()) {$data = $this->request->param();$id = $data['id'] ?? 0;unset($data['id']);if ($data['applicable_type'] == 2) {// 选择员工的话,是员工名$userModel = new WeUserModel();$userList = $userModel->whereIn('userid',$data['applicable_range'])->column("userid","department_id");$group_arr = array_unique(array_keys($userList));$applicable_range['user_list'] = implode(",",$userList);$applicable_range['department_list'] = implode(",",$group_arr);$data['applicable_range'] = json_encode($applicable_range,JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);} else {$userModel = new WeUserModel();$userList = $userModel->whereIn('department_id',$data['applicable_range'])->column("userid");$applicable_range['user_list'] = implode(",",$userList);$applicable_range['department_list'] = $data['applicable_range'];$data['applicable_range'] = json_encode($applicable_range,JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);}$update_info = $data;$interceptModel = new InterceptModel();// 敏感词接口编辑// 查询原来的数据$rule_info = $interceptModel->field("rule_id,applicable_range")->where("id",$id)->find();$old_add_applicable_range = json_decode($rule_info['applicable_range'],true);$old_user_list = !empty($old_add_applicable_range['user_list']) ? explode(",",$old_add_applicable_range['user_list']) : [];$old_department_list = !empty($old_add_applicable_range['department_list']) ? explode(",",$old_add_applicable_range['department_list']) : [];$user_list = !empty($applicable_range['user_list']) ? explode(",",$applicable_range['user_list']) : [];$department_list = explode(",",$applicable_range['department_list']);$wx_intercept = array('rule_id' => $rule_info['rule_id'],'rule_name' => $update_info['rule_name'],'word_list' => explode(",",$update_info['word_list']),'extra_rule' => array('semantics_list' => $data['semantics_list'],),'intercept_type' => $data['intercept_type'],'add_applicable_range' => array('user_list' => $user_list,'department_list' => $department_list),'remove_applicable_range' => array('user_list' => $old_user_list,'department_list' => $old_department_list));$wxinterceptApi = new WechatInterceptApi();$res = $wxinterceptApi->updateInterceptRule($wx_intercept);if ($res['errcode'] != 0) {$this->error($res['errmsg'], url("Intercept/index"));}if (!empty($update_info['semantics_list'])) {$update_info['semantics_list'] = implode(",",$update_info['semantics_list']);}$result = $interceptModel->where("id",$id)->update($update_info);if ($result) {$this->success('编辑成功!', url("Intercept/index"));} else {$this->error('编辑失败!', url("Intercept/index"));}}$id = $this->request->param('id', 0, 'intval');if (empty($id)) {$this->error('请求参数有误!');}// 查询敏感词信息$interceptService = new InterceptService();$info = $interceptService->getInfo($id);// 接口请求敏感词详情// $wxinterceptApi = new WechatInterceptApi();// $list = $wxinterceptApi->getInterceptRuleInfo(['rule_id'=>$info['rule_id']]);// echo "<pre>";// print_r($list);// exit;$this->assign('info',$info);return $this->fetch();}// 删除敏感词public function delete(){$param = $this->request->param();$interceptModel = new InterceptModel();if (isset($param['id'])) {$id = $this->request->param('id', 0, 'intval');$rule_info = $interceptModel->field("rule_id")->where("id",$id)->find();$wxinterceptApi = new WechatInterceptApi();$wx_res = $wxinterceptApi->deleteInterceptRule(['rule_id'=>$rule_info['rule_id']]);if ($wx_res['errcode'] == 0) {$result = $interceptModel->where('id', $id)->delete();$this->success("删除成功!");} else {$this->error("删除失败!");}}}public function checkWorker(){$param = $this->request->param();$applicable_type = $param['type'] ?? 1;$applicable_range = $param['value'] ?? "";$interceptService = new InterceptService();$result = $interceptService->getWorkerList($param);$this->assign('menus', $result);$this->assign('applicable_range', explode(",",$applicable_range));$this->assign('applicable_type',$applicable_type);return $this->fetch();}}
InterceptService.php
<?php
// +----------------------------------------------------------------------
// xiaozhe
// +----------------------------------------------------------------------
namespace app\wework\service;use app\wework\model\InterceptModel;
use app\wework\model\DepartModel;
use app\wework\model\WeUserModel;
use think\db\Query;class InterceptService
{public function getList($filter){$field = 'a.id,a.rule_name,a.word_list,a.intercept_type,a.applicable_type,a.user_id,a.create_time,a.update_time,u.user_nickname';$interceptModel = new InterceptModel();$result = $interceptModel->alias("a")->leftJoin("user u","a.user_id = u.id")->field($field)->where(function (Query $query) use ($filter) {$keyword = empty($filter['keyword']) ? '' : $filter['keyword'];if (!empty($keyword)) {$query->where('a.title', 'like', "%$keyword%");}})->paginate(15);return $result;}public function getInfo($id){$interceptModel = new InterceptModel();$info = $interceptModel->where("id",$id)->find();if (!empty($info['semantics_list'])) {$info['semantics_list'] = explode(",",$info['semantics_list']);}if (!empty($info['applicable_range'])) {$info['applicable_range'] = json_decode($info['applicable_range'],true);$info['user_count'] = count(explode(",",$info['applicable_range']['user_list']));$info['depart_count'] = count(explode(",",$info['applicable_range']['department_list']));if ($info['applicable_type'] == 1) {// 部门$info['applicable_range_value'] = $info['applicable_range']['department_list'];} else {// 员工$userModel = new WeUserModel();$userIds = $userModel->whereIn("userid",$info['applicable_range']['user_list'])->whereIn("department_id",$info['applicable_range']['department_list'])->column("userid");$info['applicable_range_value'] = implode(",",$userIds);}}return $info;}public function getWorkerList($filter){$type = $filter['type'];switch ($type) {case 1:// 部门$departmentModel = new DepartModel();$newList = $departmentModel->field("department_id as id,name,parentid as parent_id")->select()->toArray();break;case 2:// 员工$userModel = new WeUserModel();$newList = $userModel->field("userid as id,name")->select()->toArray();break;default:// code...break;}return $newList;}}
WechatInterceptApi.php
<?php
// +----------------------------------------------------------------------
// | xiaozhe
// +----------------------------------------------------------------------
namespace app\wework\service;
use app\wework\model\ConfigModel;
use think\Db;
/**
* 企业微信接口
**/
class WechatInterceptApi
{/*** 获取通讯录access_token**/public function getStaffAccessToken(){$cache_key = 'staff_access_token';$res = cache($cache_key);if(empty($res)){// 读取配置$WeworkConfigModel = new ConfigModel();$info = $WeworkConfigModel->where("id",1)->find();$response = cmf_curl_get("https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid={$info['corpid']}&corpsecret={$info['user_secret']}");$arr = json_decode($response, true); if($arr['errcode'] !== 0){return '';}cache($cache_key, $arr['access_token'], 6900);}return $res;}/*** 获取客户联系人access_token**/static public function getCustomerAccessToken(){$cache_key = 'customer_access_token';$res = cache($cache_key);if(empty($res)){$WeworkConfigModel = new ConfigModel();$info = $WeworkConfigModel->where("id",1)->find();$response = cmf_curl_get("https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid={$info['corpid']}&corpsecret={$info['customer_secret']}");$arr = json_decode($response, true); if($arr['errcode'] !== 0){return '';}cache($cache_key, $arr['access_token'], 6900);}return $res;}/*** 获取自建应用 access_token**/public function getSelfappAccessToken(){$cache_key = 'selfapp_access_token';$res = cache($cache_key);if(empty($res)){$WeworkConfigModel = new ConfigModel();$info = $WeworkConfigModel->where("id",1)->find();$response = cmf_curl_get("https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid={$info['corpid']}&corpsecret={$info['corpsecret']}");$arr = json_decode($response, true); if($arr['errcode'] !== 0){return '';}cache($cache_key, $arr['access_token'], 6900);}return $res;}// 获取敏感词列表public function getInterceptRuleList(){$token = self::getSelfappAccessToken();$res = cmf_curl_get("https://qyapi.weixin.qq.com/cgi-bin/externalcontact/get_intercept_rule_list?access_token=".$token,array());$resp_arr = json_decode($res, 1);return $resp_arr;}// 新增敏感词public function addInterceptRule($filter){$token = self::getSelfappAccessToken();$res = self::curl_post("https://qyapi.weixin.qq.com/cgi-bin/externalcontact/add_intercept_rule?access_token=".$token,json_encode($filter));$resp_arr = json_decode($res, 1);return $resp_arr;}// 获取敏感词详情public function getInterceptRuleInfo($filter){$token = self::getSelfappAccessToken();$res = self::curl_post("https://qyapi.weixin.qq.com/cgi-bin/externalcontact/get_intercept_rule?access_token=".$token,json_encode($filter));$resp_arr = json_decode($res, 1);return $resp_arr;}// 修改敏感词规则public function updateInterceptRule($filter){$token = self::getSelfappAccessToken();$res = self::curl_post("https://qyapi.weixin.qq.com/cgi-bin/externalcontact/update_intercept_rule?access_token=".$token,json_encode($filter));$resp_arr = json_decode($res, 1);return $resp_arr;}// 删除敏感词public function deleteInterceptRule($filter){$token = self::getSelfappAccessToken();$res = self::curl_post("https://qyapi.weixin.qq.com/cgi-bin/externalcontact/del_intercept_rule?access_token=".$token,json_encode($filter));$resp_arr = json_decode($res, 1);return $resp_arr;}public function curl_post($url,$data){$curl = curl_init(); // 启动一个CURL会话curl_setopt($curl, CURLOPT_URL, $url); // 要访问的地址curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, 0); // 对认证证书来源的检查curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 0); // 从证书中检查SSL加密算法是否存在curl_setopt($curl, CURLOPT_FOLLOWLOCATION, 1); // 使用自动跳转curl_setopt($curl, CURLOPT_AUTOREFERER, 1); // 自动设置Referercurl_setopt($curl, CURLOPT_POST, 1); // 发送一个常规的Post请求curl_setopt($curl, CURLOPT_POSTFIELDS,$data); // Post提交的数据包curl_setopt($curl, CURLOPT_TIMEOUT, 30); // 设置超时限制防止死循环curl_setopt($curl, CURLOPT_HEADER, 0); // 显示返回的Header区域内容curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); // 获取的信息以文件流的形式返回$result = curl_exec($curl); // 执行操作return $result;}
}
(前端代码我就不放了哈,自行写一哈)

实现效果
敏感词列表

新增敏感词

编辑敏感词

相关文章:
PHP对接企业微信
前言 最近在做项目中,要求在后台管理中有企业微信管理的相关功能。相关准备工作,需要准备好企业微信账号,添加自建应用,获得相应功能的权限,以及agentid、secre等。 参考文档: 企业微信开发文档 功能实现 因…...
【原创】录剪视频的折腾之路
制作视频的起因 本人为IT男,IT发展快,需要学习的东西又多。往往为了一个技术小问题,花好几天时间学习,接下来十来分钟把事情做完。下次遇到这个同样的问题的时候,可能是几个月后,甚至是几年以后了。这些技…...
【BI】FineBI功能学习路径-20231211
FineBI功能学习路径 https://help.fanruan.com/finebi/doc-view-1757.html 编辑数据概述 1.1 调整数据结构 1.2 简化数据 2.1上下合并 2.2其他表添加列 2.3左右合并 新增分析指标 函数参考 https://help.fanruan.com/finereport/doc-view-1897.html 数值函数 日期函数 文…...
pytorch之torch.utils.data学习
1、概述 PyTorch 数据加载利用的核心是torch.utils.data.DataLoader类 。它表示在数据集上 Python 可迭代,支持 map-style and iterable-style datasets(地图样式和可迭代样式数据集), customizing data loading orderÿ…...
Spring Boot 3中一套可以直接用于生产环境的Log4J2日志配置
文章目录 一 Log4J2 相关概念及基本特点二 Spring Boot3 中启用Log4J2的pom.xml配置三 application.properties 的配置四 完整配置 一 Log4J2 相关概念及基本特点 Log4J2是Apache Log4j的升级版,参考了logback的一些优秀的设计,并且修复了一些问题&…...
iOS按钮控件UIButton使用
1.在故事板中添加按钮控件,步聚如下: 同时按钮Shift+Commad+L在出现在控件库中选择Button并拖入View Controller Scene中 将控件与变量btnSelect关联 关联后空心变实心 如何关联?直接到属性窗口拖按钮变量到控件上,出现一条线,然后松开,这样就关联成功了 关联成功后属性窗口…...
小程序开发实战案例之三 | 小程序底部导航栏如何设置
小程序中最常见的功能就是底部导航栏了,今天就来看一下怎么设置一个好看的导航栏~这里我们使用的是支付宝官方小程序 IDE 做示范。 官方提供的底部导航栏 第一步:页面创建 一般的小程序会有四个 tab,我们这次也是配置四个 tab 的…...
Android : 序列化 JSON简单应用
1. JSON介绍 JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,易于阅读和写入,同时也易于机器解析和生成。它基于JavaScript的子集,采用完全独立于语言的文本格式来存储和表示数据。JSON是纯文本&#x…...
Java小案例-RocketMQ的11种消息类型,你知道几种?(普通消息和批量消息)
前言 这篇给大家讲普通消息和批量消息,主要配合代码进行讲解,关于RocketMQ的基础知识已经在上篇给大家讲过需要回顾的点击下面这个链接去看 RocketMQ基础知识 普通消息 普通消息其实就很简单,是Apache RocketMQ中最基础的消息形式&#x…...
前端小技巧: 设计一个简版前端统计 SDK
统计 sdk 如何设计 1 ) 概述 客户端一个sdk ,把数据发送给服务端(第三方统计平台)服务端产生一个统计的报表 2 )需求点 访问量:pv自定义事件:用户的一切行为我们都可以自定义采集性能,错误 3 ) 代码实现 const P…...
DevOps搭建(十一)-Jenkins容器内部使用Docker详解
1、目的 配置的目的是使得Jenkins容器可以直接使用宿主机的Docker,从而可以直接使用Docker命令进行本地打包操作,然后推送到Harbor镜像仓库。 2、修改数据卷 如何在docker中执行宿主机的docker操作,我们管它叫docker in docker。 至于为什么要在docker中操作宿主机的doc…...
用户访问认证
注解 Target(ElementType.METHOD) Retention(RetentionPolicy.RUNTIME) Documented public interface Login { }自定义拦截器 Component public class AuthInterceptor implements HandlerInterceptor {ResourceJwtUtils jwtUtils;Overridepublic boolean preHandle(HttpServ…...
前端知识(七)———HTTPS:保护网络通信安全的关键
当谈到网络通信和数据传输时,安全性是一个至关重要的问题。在互联网上,有许多敏感信息需要通过网络进行传输,例如个人身份信息、银行账户信息和商业机密等。为了保护这些信息不被未经授权的人访问和篡改,HTTPS(超文本传…...
element-ui按钮el-button,点击之后恢复之前的颜色
在开发过程中, 使用el-button 按钮点击之后, 没有恢复到之前的颜色, 还是保持点击之后的颜色,需要解决这个问题, <template><div><el-button size"mini" type"primary" plain click"onClick($event)">按钮</el-button>…...
Excel: Python 如何干掉 VBA 系列 乙
以下内容为本人的学习笔记,如需要转载,请声明原文链接 微信公众号「ENG八戒」https://mp.weixin.qq.com/s/k2XtfXS3GUt4r2QhizMOVg 创建工作表格 创建表格 xlwings 就可以协助创建插入了宏的 excel 表格。 先找到一个心满意足的目录,一般我…...
算法笔记—链表、队列和栈
链表、队列和栈 1. 链表1.1 单链表反转1.2 双链表反转1.3 合并两个有序链表1.4 链表相加1.5 划分链表 2. 队列和栈2.1 循环队列2.2 栈实现队列2.3 队列实现栈2.4 最小栈2.2 双端队列 1. 链表 1.1 单链表反转 力扣 反转链表 // 反转单链表public ListNode reverseList(ListNod…...
MySQL中的时间函数整理汇总
1.获取当前时间 -- 获取当前时间 SELECT NOW(); -- 获取当前日期 SELECT CURDATE(); -- 获取当前时分秒 SELECT CURTIME(); 2.获取对应日期对应的年/月/日/月份名/星期数 -- 返回对应日期对应的年/月/日/月份名/星期数 select year(now())as 年,month(now())as 月,day(now())…...
stu06-VSCode里的常用快捷键
Alt Z:文字自动换行。当一行的文字太长时,可以使用。或者查看→自动换行Alt Shift ↓ :快速复制当前行到下一行Alt Shift ↑ :快速复制当前行到上一行Alt B:在默认浏览器中打开当前.html文件Ctrl Enter…...
Bypass open_basedir
讲解 open_basedir是php.ini中的一个配置选项,可用于将用户访问文件的活动范围限制在指定的区域。 假设open_basedir/var/www/html/web1/:/tmp/,那么通过web1访问服务器的用户就无法获取服务器上除了/var/www/html/web1/和/tmp/这两个目录以外的文件。…...
【数据库设计和SQL基础语法】--查询数据--过滤
一、过滤数据 1.1 WHERE子句 基本条件过滤 使用比较运算符 在SQL中,基本条件过滤是通过使用比较运算符来限定检索的数据。以下是一些常用的比较运算符和它们的用法: 运算符说明示例等于 ()用于检索列中与指定值相等的行。示例:SELECT * FROM…...
脑机新手指南(八):OpenBCI_GUI:从环境搭建到数据可视化(下)
一、数据处理与分析实战 (一)实时滤波与参数调整 基础滤波操作 60Hz 工频滤波:勾选界面右侧 “60Hz” 复选框,可有效抑制电网干扰(适用于北美地区,欧洲用户可调整为 50Hz)。 平滑处理&…...
YSYX学习记录(八)
C语言,练习0: 先创建一个文件夹,我用的是物理机: 安装build-essential 练习1: 我注释掉了 #include <stdio.h> 出现下面错误 在你的文本编辑器中打开ex1文件,随机修改或删除一部分,之后…...
【项目实战】通过多模态+LangGraph实现PPT生成助手
PPT自动生成系统 基于LangGraph的PPT自动生成系统,可以将Markdown文档自动转换为PPT演示文稿。 功能特点 Markdown解析:自动解析Markdown文档结构PPT模板分析:分析PPT模板的布局和风格智能布局决策:匹配内容与合适的PPT布局自动…...
Frozen-Flask :将 Flask 应用“冻结”为静态文件
Frozen-Flask 是一个用于将 Flask 应用“冻结”为静态文件的 Python 扩展。它的核心用途是:将一个 Flask Web 应用生成成纯静态 HTML 文件,从而可以部署到静态网站托管服务上,如 GitHub Pages、Netlify 或任何支持静态文件的网站服务器。 &am…...
新能源汽车智慧充电桩管理方案:新能源充电桩散热问题及消防安全监管方案
随着新能源汽车的快速普及,充电桩作为核心配套设施,其安全性与可靠性备受关注。然而,在高温、高负荷运行环境下,充电桩的散热问题与消防安全隐患日益凸显,成为制约行业发展的关键瓶颈。 如何通过智慧化管理手段优化散…...
QT: `long long` 类型转换为 `QString` 2025.6.5
在 Qt 中,将 long long 类型转换为 QString 可以通过以下两种常用方法实现: 方法 1:使用 QString::number() 直接调用 QString 的静态方法 number(),将数值转换为字符串: long long value 1234567890123456789LL; …...
是否存在路径(FIFOBB算法)
题目描述 一个具有 n 个顶点e条边的无向图,该图顶点的编号依次为0到n-1且不存在顶点与自身相连的边。请使用FIFOBB算法编写程序,确定是否存在从顶点 source到顶点 destination的路径。 输入 第一行两个整数,分别表示n 和 e 的值(1…...
Selenium常用函数介绍
目录 一,元素定位 1.1 cssSeector 1.2 xpath 二,操作测试对象 三,窗口 3.1 案例 3.2 窗口切换 3.3 窗口大小 3.4 屏幕截图 3.5 关闭窗口 四,弹窗 五,等待 六,导航 七,文件上传 …...
MySQL 部分重点知识篇
一、数据库对象 1. 主键 定义 :主键是用于唯一标识表中每一行记录的字段或字段组合。它具有唯一性和非空性特点。 作用 :确保数据的完整性,便于数据的查询和管理。 示例 :在学生信息表中,学号可以作为主键ÿ…...
LOOI机器人的技术实现解析:从手势识别到边缘检测
LOOI机器人作为一款创新的AI硬件产品,通过将智能手机转变为具有情感交互能力的桌面机器人,展示了前沿AI技术与传统硬件设计的完美结合。作为AI与玩具领域的专家,我将全面解析LOOI的技术实现架构,特别是其手势识别、物体识别和环境…...
