• 注册
  • 查看作者
  • 宫论项目开发记录

    记录2023年项目进度周期。

    刷新置顶
  • 2
  • 743
  • 0
  • 23.2w
  • 小小乐小可鸭鸭

    请登录之后再进行评论

    登录
  • 0
    小小乐lv.2实名用户
    2025年9月15日
    1、前端新增了一个重要优化功能,即在xinle对象中新增了属性“xinle.shop_details_thumbnail”,用于定义商品默认缩略图样式。后面APP商品详情页中,所有的商品图片将自动应用这一样式,从而有效避免直接输出原图所带来的高流量消耗问题。集成到对象中,可以通过前端进行读取和调用。部分商品数据是通过前端进行旋绕的,因此需要用这个对象属性来添加样式规格。这一改进不仅显著提升了页面加载速度,还能优化用户的浏览体验,同时降低了服务器资源的使用成本,体现了性能优化与用户体验之间的平衡。
    2、在APP项目中,现在将通过handleMessage监听扫一扫请求,如果websocket发送了通讯请求过来,并且对应的扫描请求标识为:QR-Code。那么可以判断本次执行请求的是扫码行为,此时APP会通过uni.requireNativePlugin加载扫码SDK,并将对象保存到mpaasScanModule。在完成SDK的封装处理后,系统会执行mpaasScan来启动扫码组件,进行扫码操作。注:不管什么场景的扫码都是通过这个事件来发起,至于扫码返回的结果,则通过后续的事件进行触发执行。
    3、新增xinle_plus_app事件:该函数用于在网页环境中向APP发送通讯事件,只有在APP环境中才能执行成功。如果当前环境不是APP,则会提示用户该操作仅支持在APP环境中进行,并返回false。若传入的数据为空,则默认发送类型为'test'的事件。参数{Object} data是要发送给APP的数据对象,必须包含事件类型。操作成功时返回true;如果不在APP环境中,则返回false。通讯请求,会使用xinle_is_plus来验证是否完成了plus加载行为。如果加载失败则会直接返回false。注:通过UA来判断容易发生伪装,并不可靠。通过PLUS初始化可以确保APP环境是可靠的。因为绝大部分的事件本身就依赖PLUS来执行。
    4、APP项目中新增了一个内置通讯事件:app_h5,该事件用于将APP中的数据转发给webviews进行处理。主要执行流程如下:首先获取当前页面的AppWebview对象(该操作仅在App端有效),接着获取Webview的第一个子Webview(适用于页面存在多层Webview嵌套的情况)。在Webview中执行一段JavaScript代码,由原生层执行并传递参数。为了防止数据中包含特殊字符导致JavaScript语法错误,需将data对象序列化为字符串,并进行URL编码。在执行通讯请求前,会对需要处理的字符串进行格式化处理,避免因为传递参数过于复杂,导致传参异常。
    5、新增xinle_hook_app_evaljs事件:用于APP与webviews的通讯。当APP需要发送消息给webviews页面中时,会通过app_h5来触发通讯处理,最终消息会转发到这个钩子进行处理。一些底层原生SDK的处理(不支持PLUS)动作,将通过xinle_hook_app_evaljs来进行交互处理。这种交互是实时的,通讯过程中的数据处理,也是通过对象传参。注:这是APP与前端的唯一通讯接口,后续会集成一个token令牌,来确保双方通讯的安全可靠性。APP中转发过来的交互数据,都需要通过内部解码处理再进行对应的业务逻辑。
    6、新增了scan.js脚本,专门用于处理与扫码相关的核心逻辑。该脚本设计旨在实现统一的扫码功能处理,并为后续的功能扩展提供便利。未来将支持多种扫码场景的集成,包括APP扫一扫、微信扫一扫、小程序扫一扫以及PDA设备扫码等,覆盖多个业务需求场景。具体应用包括单据识别、证书识别、发货识别、验收识别等一系列操作。所有与扫码相关的事件均通过该脚本进行集中调用和执行,从而实现统一管理和处理逻辑。该脚本的核心思路是将摄像头扫码识别的结果统一转发到scan.js进行处理,无论来源是APP、微信、小程序或其他设备,都能够通过脚本完成后续的数据解析和业务处理。
    7、新增了一个名为xinle_hook_scan_result的方法,专门用于处理扫码结果的业务逻辑。该方法接收一个包含了多个属性的data对象,其中包括了关键的code属性,代表扫码的结果。方法会通过user.page_name来获取当前页面的名称,并根据这个页面名称以及扫码结果code,来执行相应的业务逻辑处理。这一设计确保了扫码结果能在不同的页面环境下被正确地解析和应用,提升了系统处理扫码事件的灵活性和准确性。
    8、在处理加载请求的过程中,xinle_infinite_hook会对与扫码相关的参数进行精准的校验和处理。首先,系统会检测scan_click对象是否包含自定义属性code。如果该属性被检测到,系统将构建一个名为infinite.scan的参数,用于将扫码结果传递到后端进行进一步处理。与此同时,为了避免在后续搜索操作中出现因残留数据导致的错误或冲突,系统会立即清空scan_click的自定义属性。后端接收到infinite.scan参数后,会使用内置的方法对其进行严格验证,以确保扫码结果符合预定的验证标准。
    9、已修复苹果APP中出现的“初始化PLUS内部钩子失败”这一异常问题。此错误直接影响了几个核心功能的加载,包括一键登录、支付通道和开屏管理机制。在APP启动阶段,通常会在PLUS加载成功后,立即触发xc_hook_app_plus以进行初始化。然而,由于执行优先级的问题,HOOK的回调失败导致无法找到执行方法,从而引发了整个异常。为了彻底解决这一问题,将调整执行优先级,确保钩子能够正确回调,并顺利完成初始化过程,以保障核心功能的正常运行。
    10、苹果APP的底层基座已成功升级至V1.60版本,此次更新涵盖了所有扩展SDK的最新版本,包括微信登录、APP一键登录、分享组件以及相册功能等底层接口的全面更新。此次版本升级的核心亮点在于为iOS设备引入了全新的扫一扫组件。用户现在可以通过页面控件便捷地调用这一功能,享受与安卓设备相同的高效识别和解析机制。这一改进不仅显著提升了用户体验,还确保了跨平台功能的一致性,确保苹果手机用户在使用扫一扫功能时能够获得同样高效和准确的结果。此外,未来扫一扫组件还计划集成小程序扫一扫功能,为用户带来更加丰富的使用场景和便捷的操作体验。
    11、新增字段xinle_user_admin_x_config:该字段用于存储前台管理员名单。通常情况下,前台管理员权限是分配给员工账户,员工可以通过此权限执行一些基础的管理操作。然而,为了确保系统安全性,在员工离职后,必须及时将其账户从配置组中移除,避免可能出现的安全隐患。需要注意的是,前台管理员与超级管理员的权限范围存在显著差异:前台管理员仅限于操作APP页面相关的行为,而无法访问后台管理系统。同时,为了进一步强化资金安全管理,前台管理员的权限也被严格限制,禁止涉及资金处理的相关操作。
  • 0
    小小乐lv.2实名用户
    2025年9月12日
    1、新增的拖拽排序组件:Sortable,通过 wp_enqueue_script 集成到 APP 项目中。该组件支持对列表项的拖拽操作,方便用户进行重新排序。特别是在通过 xinle_upload_image_publish 成功上传图片后,会自动触发 Sortable 组件,使已生成的图片列表变为可拖拽状态。用户可以自由调整图片的顺序。
    2、在上传接口中移除了 ajax_api.php 中的请求拦截器,这是因为上传接口自身已经具备了一套专门的拦截机制,通用的 API 拦截机制并不适用于此类接口。上传接口采用内置的方法来验证请求的安全性和可靠性,以确保上传过程的顺利进行。由于上传操作需要支持并发请求,因此不能对其进行进程锁定,否则可能导致上传行为被不必要地拦截。这一调整能够有效地提升上传接口的效率和稳定性,确保用户上传文件时的流畅体验。
    3、xinle_upload_image_publish 在获取到 blob 对象后,会调用 xinle_upload_blob 来执行上传请求。在上传过程中,系统会实时监控上传的进度和状态变化,并在页面中以进度条的形式展示出来,让用户清晰地看到上传的进展情况。一旦图片上传完成,系统将执行 xinle_delete_blob,以删除本地的 blob 地址,防止内存泄漏,同时将页面中的 blob 地址替换为图片的远程地址。
    4、在执行通用组件的图片上传动作时,处理状态会被同步到 <li> 标签中的 <status></status> 元素,目前有以下几种状态:1、等待上传中:此时已经完成了 blob 的插入,正等待接口进行同步处理。2、正在上传(百分比):上传的百分比会实时更新并显示,帮助用户了解上传进度。3、等待云端同步:即使图片已经上传到服务器,仍需服务器将图片转移到对象存储,此过程在云端进行。4、上传失败:该状态可能由于服务器拒绝请求或云端同步故障而出现。用户可以通过点击上传失败查看具体的错误信息弹出窗口。5、上传成功:表示文件已成功完成同步,状态栏会在500毫秒后自动隐藏。注:每种状态对应不同的背景颜色,以便用户能够轻松区分和处理各个状态。
    5、xinle_upload_image_publish:通用图片上传事件已完成封装处理,整个执行流程如下:1. 用户触发上传 用户点击上传图片按钮,触发 xinle_upload_image_publish(key) 方法。 2. 检查用户登录状态 判断用户是否已登录(xinle.is_login)。 未登录:弹出登录界面(xinle_login()),终止流程。 3. 获取并校验上传配置 通过 key 获取上传配置(xinle_is_config(xinle.upload_image_config, key))。 配置不存在:提示“非法请求-01”,终止流程。 检查当前页面名称与配置页面名称是否一致,不一致则提示“非法请求-02”,终止流程。 4. 获取上传组件区域 根据 key 定位页面中的上传组件容器(如 .xinle_publish_image.key)。 找不到容器:提示“非法请求-03”,终止流程。 5. 检查图片上传数量限制 获取当前已上传图片数量(#xinle_publish_images_list li)。 超出数量限制:提示“图片数量已超过限制”,并隐藏“添加”按钮,终止流程。 计算本次最多可上传的图片数量(upload_number)。 6. 执行图片选择和上传 调用 xinle_upload_image(key, callback, upload_number),弹出图片选择。 用户选择图片后,返回一个 blobs 数组,每个元素包含图片的 blob 数据和类型。 7. 遍历每张图片,逐一处理上传 a. 检查数量限制 每插入一张图片前,再次判断是否已达到最大数量,若达到则隐藏“添加”按钮并跳过后续图片。 b. 页面插入预览 用 URL.createObjectURL(blob) 创建本地图片预览地址。 组装 <li> 结构,包括: <status> 状态标签(显示上传状态) 删除按钮 图片预览(可 fancybox 放大) 将新 <li> 添加到图片列表末尾。 c. 更新数量显示 更新页面的上传数量显示。 d. 设置初始状态 <status> 显示“上传中”,并设置蓝色背景。 8. 上传图片到服务器 调用 xinle_upload_blob(key, blob, onProgress, onComplete) 方法上传图片。 a. 上传进度回调 实时更新 <status>,如“上传中 (20%)”,上传完成时显示“同步云端”。 b. 上传完成回调 上传失败: <status> 显示“上传失败”,背景色变为红色。 预览图禁止点击,点击弹出错误信息。 上传成功: 销毁本地 blob 预览,使用服务器返回的图片地址。 <status> 显示“上传成功”,背景色变为绿色。 0.5 秒后自动淡出隐藏 <status> 提示。 初始化拖拽排序功能(SortableJS),使图片列表可拖拽排序。 9. 拖拽排序支持 每次上传成功后,都会初始化一次 SortableJS 拖拽功能,使图片列表支持顺序调整。
    6、新增了一个图片删除事件:xinle_upload_remove_image。这个函数专门用于删除用户上传的图片,并在图片删除后更新页面上显示的图片数量。如果用户尚未登录,系统会提示用户进行登录操作;如果上传配置或页面名称不匹配,则会显示非法请求的警告。删除图片后,系统会重新计算当前的图片数量,并根据配置进行相应的显示调整。该函数接受两个参数:{string} key,用于标识上传组件的唯一键;{HTMLElement} el,用于触发删除操作的元素。如果删除操作成功,函数将返回 true,否则返回 false。
    7、xinle_upload_remove_image的执行流程如下:1. 检查用户是否登录 如果用户未登录,调用登录弹窗函数 xinle_login(),并终止后续操作。 2. 获取上传图片的配置 通过 xinle_is_config 查找当前 key(如 'shop_image')的上传配置。 如果配置未找到,弹出错误提示“非法请求-01”,终止操作。 3. 校验页面身份 判断当前用户的 page_name 是否和上传配置中的 page_name 匹配。 如果不匹配,弹出错误提示“非法请求-02”,终止操作。 4. 获取上传组件的 DOM 通过类名获取当前页面上的上传区域(如 .xinle_publish_image.shop_image)。 如果没找到,弹出错误提示“非法请求-03”,终止操作。 7. 获取并动画删除当前图片的 <li> 通过 $(el).closest('li') 获取到当前要删除的图片 <li> 元素。 使用 .fadeOut(300, function(){ ... }) 让图片在 300 毫秒内淡出,然后执行回调。 6. 动画结束后更新数量和按钮 在动画回调中,真正移除 <li> 元素。 统计剩余图片数量,并更新显示数量的元素(如 .upload_quantity number)。 如果剩余数量小于上传上限,则显示“添加图片”按钮。
    8、在上传后端接口中新增了一个拦截器,用于处理上传图片的来源校验。如果上传的图片来源标识为 shop_image(即商品包装图),系统将使用 getimagesize 函数来获取该图片的长宽比。一旦检测到图片比例不是1:1(正方形),系统会立即返回错误信息:“商品图比例为1:1(正方形)”。这项措施旨在确保商品包装图在采集和录入时遵循正方形比例,从而避免前端页面展示时出现变形等问题。通过在上传阶段进行拦截处理,从根源上解决潜在的图片展示问题。
    9、在 xinle_upload_remove_image 函数中新增了一个回收机制,以提高系统的内存管理效率。当移除相应的 li 列表时,系统会获取被移除图片的地址。如果该地址是本地的 blob 图片,则会调用 URL.revokeObjectURL 方法来回收该对象。这一机制的实施旨在有效避免内存泄漏风险,确保系统资源的合理利用和稳定运行。通过主动回收不再需要的对象,系统能够更好地维护内存的健康状态,提升整体性能。
    10、在 xinle_page_back(网页后退)监听器中新增了一个重要的处理机制:当用户通过右侧左滑手势返回时,系统会检测 layui-m-layershade 是否存在。如果存在,则表明页面中有 layer 弹出层正在显示,此时系统会触发 layer.closeAll() 来强制关闭所有 layer 弹出层。这样设计的目的是为了避免用户在打开筛选窗口菜单时直接返回上一页,可能导致的异常错误,同时也使得筛选器窗口能够支持左滑手势关闭,提升了用户的操作便利性和界面的稳定性。
    11、当用户加载菜单页面时,会触发 pageBeforeIn 监听动作。首先,系统通过 jQuery 选择器获取两个对象:【page_content:页面内容加载容器、menu:菜单筛选容器区域】。随后,系统会触发一个 AJAX 请求,以请求后端响应对应的初始化页面数据,请求标识为 initialization。需要注意的是,pageBeforeIn 在页面准备加载前就会触发,确保在页面完全呈现给用户之前,所有必要的数据已被加载并准备好,从而保证用户体验的流畅性和数据的完整性。
  • 0
    小小乐lv.2实名用户
    2025年9月11日
    1、xc_upload_image_html组件的封装流程: 1. 获取上传配置 调用 xc_is_config 方法,传入配置名和 key,获取当前上传图片控件的配置信息(比如允许上传的图片数量、图片大小、样式等)。 2. 判断图片列表是否有内容 如果 $image_list 不是空的,进入图片列表处理流程。 如果为空,则只生成一个空的图片上传控件,不显示已上传图片。 3. 规范化图片列表格式 如果图片列表是数组,直接使用。 如果是字符串且包含分号,用分号拆分成数组。 如果是单个图片字符串,则转为数组(数组里只有一个元素)。 4. 生成图片 HTML 遍历图片列表,每个图片生成一个 <li> 标签,里面包含: 隐藏的 <status> 状态提示标签 删除按钮 <i>,绑定 JS 删除方法 图片预览 <a> 包裹 <img>,用于点击放大 所有图片的 <li> 标签拼接起来,形成图片展示区。 5. 统计图片数量 计算图片数组的数量,用于显示当前已上传数量。 6. 生成上传控件整体 HTML 拼接一个大 DIV,包含: 图片列表区域 <ul> “添加图片”按钮(点击触发上传) 数量显示和 loading 动画 7. 返回 HTML 结果 最终返回整个上传图片控件的 HTML 代码字符串。 如果没有配置,直接返回 false。
    2、在前端新增了一个名为 xinle_is_config 的方法,该方法专门用于在配置数组中根据指定的键查找对应的配置项。此函数接收两个参数:$configArray 和 $key。其中,$configArray 是一个配置项数组,数组中的每个元素都是一个包含 'key' 属性的对象;$key 是一个字符串,表示要查找的键。函数的工作机制是遍历 $configArray,查找与 $key 匹配的配置项。如果找到了匹配项,函数将返回该配置项对象;如果没有找到匹配项,则返回 null。这一方法的引入,大大简化了配置项的检索过程,提高了代码的可读性和维护性。
    3、新增了一个前端上传执行请求函数 xinle_upload_image_publish,该方法主要负责通用图片组件的上传工作,充当上传行为的中间层角色。其核心功能是接管上传过程,并对用户的操作进行权限验证,以确保上传操作的合理性和安全性。通过此函数,可以有效地避免未经授权的上传行为,同时确保上传动作的回调能够准确地作用于指定的上传组件中。该方法需要传递一个变量 key,用于标识具体的上传场景。此设计使得图片上传逻辑更加规范化和模块化,不仅提升了功能的灵活性,还增强了系统的安全性和可控性。
    4、xinle_upload_image_publish 的基础拦截逻辑设计如下:
    1. 用户登录状态检查:通过 xinle.is_login 方法验证用户是否已登录。如果检测到用户处于未登录状态,则会强制跳转至登录页面,确保上传操作仅限于已登录用户,提升安全性。
    2. 上传配置读取与校验:利用 xinle_is_config 方法读取上传配置组,并对传入的 key 进行校验。如果 key 存在于配置组中,则将对应的子数组赋值到 config 中,作为后续操作的上传配置依据;若 key 不存在,则直接返回非法请求,杜绝无效或恶意的上传场景。
    3. 页面标识对比:获取当前页面标识,并与上传配置中的标识进行对比。如果标识不一致,则返回对应的错误信息,确保上传行为与当前页面的逻辑绑定一致,避免跨页面执行不合理的请求。
    4. 组件位置获取与交互准备:通过元素选择器锁定上传组件的位置(默认获取最后一个组件)。如果组件位置获取失败,则返回非法请求,阻止后续操作;若获取成功,则创建 page_content 对象,为后续页面交互提供支持。
    5. 图片数量限制检查:读取当前上传组件中已上传图片的数量,并与场景配置中的上传限制进行对比。如果图片数量已达到或超过限制,则直接返回“图片数量已超过限制”的提示,终止上传操作,确保组件的上传行为符合配置规则。
    该逻辑设计旨在对上传行为进行全方位的拦截与验证,保障上传操作的安全性、合理性与规范性,同时确保页面组件交互的正确性与一致性,为通用图片上传功能提供了稳健的底层支持。
    5、xinle_upload_image 方法新增了一个可选变量 number(图片选择数量),以增强对图片上传数量的灵活控制。如果调用时未传递该变量,则默认读取上传配置中的设定数量,确保逻辑上的一致性和默认行为的合理性。由于通用上传场景中存在一个中间层,该中间层的主要职责是对上传行为进行统一管理和校验,包括检查已上传的图片数量。如果已上传的图片数量超过了配置限制,则会直接拦截后续操作。
    在此基础上,为了实现对剩余可上传数量的精准计算,xinle_upload_image 方法需要动态传递当前的剩余可上传数量(由 number 表示)至上传逻辑中。这样可以确保上传组件在执行图片选择操作时,严格遵循剩余可上传数量的限制,从而避免用户选择超过限制数量的图片。
    具体来说,xinle_upload_image 方法的新增逻辑如下:
    1. 变量优先级判断:方法调用时优先检查是否传递了 number 参数。如果传递了,则以该值为准;如果未传递,则自动读取上传配置中的默认设定数量,确保该变量始终有值。
    2. 剩余数量计算:在上传前,中间层会根据当前组件中已上传的图片数量与配置限制进行对比,计算出剩余可上传的图片数量,并将该数量作为参数传递至 xinle_upload_image 方法。
    3. 精准控制图片选择:在最终发起上传时,上传逻辑会根据传入的 number 值限制用户可选择的图片数量,确保用户在上传过程中无法突破配置的数量限制。
    通过新增 number 参数,xinle_upload_image 方法进一步提升了对图片上传数量的动态控制能力,与中间层的逻辑形成了高度协同,有效避免了上传数量超出限制的情况发生。这种设计兼顾了灵活性和严谨性,为通用上传场景的复杂需求提供了强有力的支持。
    6、通用上传图片组件已经完成了集成灯箱响应效果,确保用户无论上传的是本地图片还是远程图片,都可以通过点击图片直接打开灯箱进行预览。这种设计增强了图片浏览的用户体验,使得图片的展示更加直观和友好。同时,为了避免点击事件与 F7 框架的交互逻辑产生冲突,系统为每个 A 标签新增了 link external 类名,使得事件处理更加独立,避免因框架干扰导致点击失败的情况。此外,图片上传功能还预留了一个删除动作事件 xinle_upload_remove_image,以便用户能够对已上传的图片进行移除操作。
    7、通用上传图片组件,在通过xinle_upload_image发起图片选择事件后,会将获取的图片列表转为blob数组,然后执行如下页面交互动作:遍历 blobs 数组: 使用 forEach 方法遍历 blobs 数组。每个元素包含 type 和 blob,其中 blob 是图像文件的 Blob 对象。 获取当前已上传图片数量: 使用 page_content.find('#xinle_publish_images_list li').length 获取当前已经插入的图片列表项数量。 如果列表不存在,默认数量为 0。 检查上传限制: 判断 success_number 是否已经达到或超过 config.number,即上传限制。 如果已达到限制,执行以下操作: 隐藏上传组件(通常是上传按钮),通过 page_content.find('.add').hide()。 使用 return 终止当前循环的后续处理,避免插入更多图片。 增加已上传的数量: 如果未达到限制,增加 success_number 的值。 更新页面上显示的已上传数量: 使用 page_content.find('.upload_quantity number').text(success_number) 更新页面中显示的已上传图片数量。 创建图片的 URL: 使用 URL.createObjectURL(blob) 创建一个 URL,用于预览 Blob 对象(即图像文件)。 构建新的列表项: 使用模板字符串构建新的 <li> 元素,包含以下内容: <status> 标签表示图片状态(例如“等待上传”)。 一个 <i> 标签用于删除图片,绑定 onclick 事件处理器 xinle_upload_remove_image('${key}', this)。 一个 <a> 标签包含图片预览,使用 data-fancybox 属性实现图库功能。 <img> 标签显示图像。 插入图片到列表中: 使用 page_content.find('.images ul').append(add_li) 将新构建的列表项插入到指定的 <ul> 元素中。
    8、在执行 xinle_upload_image_publish 请求时,图片组件会在两个特定场景下自动通过 hide 方法隐藏“添加新图片”模块。首先,在初始化请求阶段,系统会计算当前已生成的 li 元素数量。如果该数量达到或超过配置的上限,组件将拒绝进一步执行上传操作,并同时隐藏上传控件,以防止用户超出限制上传过多图片。其次,在生成 blob 对象并将其构建为 li 元素写入组件容器区域后,系统会再次进行检查。如果此时的图片数量超过了配置的上限,组件将再次自动隐藏上传控件。这种机制确保了用户在使用过程中始终遵循预设的图片数量限制,保持界面的整洁和功能的稳定性,同时避免了因超量上传导致的性能问题或用户体验下降。
    9、新增方法xinle_upload_image_h5 基于 HTML5 的图片上传功能,支持多张图片选择,并通过回调函数返回所选图片的 Blob 对象数组。 limit_image - 限制可上传的图片数量。当值为 1 时,仅允许单张图片上传;当值大于等于 2 时,支持多张图片上传。callback - 图片上传后的回调函数。接收一个参数,为包含图片信息的数组,每个数组元素为一个对象。
    10、xinle_upload_image_h5的执行流程:创建文件选择框 根据limit_image是否大于等于2,决定是否允许多选图片。 创建一个隐藏的<input type="file" accept="image/*">标签,并插入到页面body里。 绑定change事件 给这个input绑定change事件(用户选择文件后触发)。 用户选择图片后,change事件触发,进入回调函数 读取input的files属性,获取用户选中的所有图片文件(FileList对象)。 如果没有选文件: 弹出“未选择任何图片文件”提示。 执行callback([]),回调一个空数组,流程结束。 处理选中的图片文件 声明空数组blobs用于存储所有图片对象。 遍历每一个文件: 如果不是图片类型(type不是image/*),弹出错误提示,不加入数组。 如果是图片类型,压入blobs数组,格式为{type: 文件类型, blob: 文件对象}。 全部处理完成后,回调返回图片数组 如果有有效图片,执行callback(blobs),回调所有图片对象。 如果异常(try-catch捕获),弹出错误提示,并回调空数组callback([])。 清理操作 清空input的值,移除input节点,避免内存泄漏和多次绑定。 自动弹出文件选择框 最后一句fileInput.trigger('click')自动弹出文件选择框,让用户选图片。
    11、xinle_upload_image 方法已完成整体封装,实现了针对不同设备类型的图片上传统一处理逻辑,包括 APP 上传、微信上传以及 H5 上传,确保在多端环境下功能一致性和适配性。该方法包含三个核心变量:1、type - 用于标识上传图片的场景类型,依据该变量匹配对应的配置,从而灵活适应不同场景的需求;2、callback - 上传完成后的回调函数,接收上传后的图片数据,支持后续处理逻辑的自定义扩展,提升功能的灵活性;3、[number] - 可选参数,用于限制上传图片的数量,若未传入则默认采用场景配置中的数量限制,以保证操作的规范性和统一性。这一封装简化了多端图片上传的开发和使用流程,同时提供了高度的可配置性和扩展性,适配不同业务需求。
  • 0
    小小乐lv.2实名用户
    2025年9月10日
    1、新增了 clipboard 脚本,旨在解决跨设备复制文本内容的难题。此前,使用 navigator.clipboard.writeText 方法发起复制请求,但该方法在部分设备上存在兼容性问题,导致复制操作失败或返回空值,尤其是在 webviews 环境下表现不佳。为了克服这些障碍,引入了一个独立的复制脚本,专门负责处理复制操作。这一改进不仅提高了功能的稳定性和适配性,还确保了在不同设备和浏览器环境中顺畅执行复制任务,从而显著提升了用户体验。
    2、新增了“xinle_copy”的方法,专门用于解决跨平台文字复制的挑战。此方法的执行流程设计得更加简洁和高效。首先,它通过 jQuery 创建并插入一个临时按钮,使用 $tempBtn.trigger('click') 来替代传统的 click() 方法进行触发。这种方式不仅提升了操作的流畅性,还确保复制任务完成后自动销毁 ClipboardJS 实例并移除临时按钮,避免了可能出现的内存泄漏问题。此外,为了确保用户体验不受影响,临时按钮的样式设置为 position:fixed;left:-9999px;opacity:0,从而保证按钮完全隐藏,避免页面出现任何闪烁现象。通过增加一个中间层来处理内容复制,这样即使未来需要对复制功能或执行逻辑进行调整,也能够迅速适应变化,确保系统的灵活性和可扩展性。
    3、xinle_copy支持返回 Promise。可以利用 .then() / .catch() 方法链,或采用 async/await 语法来处理复制操作的结果。整个执行流程如下:首先接收要复制的文本 ,并传入想要复制的内容。 判断浏览器环境 首先,函数会判断当前浏览器是否支持最新的剪贴板操作接口(即 navigator.clipboard)。 如果支持,说明是现代浏览器; 如果不支持,说明是较老的浏览器。 现代浏览器的处理方式 如果浏览器支持最新的剪贴板API,函数会用这个接口去复制传入的文本。 复制成功时,函数告诉操作成功; 复制失败时,函数告诉操作失败。 老旧浏览器的兼容处理 如果浏览器不支持最新的API,函数会用一种兼容的方式: 首先,临时创建一个隐藏的输入框,并把要复制的文本填进去; 把这个输入框加到页面里; 选中输入框里的内容; 尝试用浏览器的老式复制命令(execCommand)进行复制; 不管成功还是失败,都把临时输入框移除; 复制成功时,函数告诉操作成功;复制失败时,告诉操作失败。
    4、由于分享组件尚未集成,当前灯箱图片的分享按钮功能被临时设计为直接复制图片地址,而非触发分享行为。复制操作通过 xinle_copy 方法实现。在发起复制之前,系统会通过内置方法动态获取当前4箱图片的地址,并将其传递给 xinle_copy 进行处理。这样的设计不仅确保了功能的可用性,也为未来分享组件的接入预留了灵活的扩展空间,同时利用 xinle_copy 的高兼容性保证了复制操作在各设备和浏览器环境下的稳定性。
    5、在进行图片上传时,xinle_upload_blob会通过xinle_compress_image功能对图片进行压缩处理,并生成相应的blob地址以便后续内部操作。然而,此前在压缩处理完成后,未对这些blob地址进行摧毁,导致存在潜在的内存泄露风险。针对这一问题,进行了优化,确保在图片上传或压缩处理完成后,及时对生成的blob地址进行摧毁。这项改进不仅提升了系统的资源管理效率,还有效降低了内存泄露的可能性,从而提高了整体稳定性。
    6、新增了一项功能:开发了一个名为xinle_delete_blob的方法,用于优化页面中的资源管理。此方法专门针对删除或替换页面中引用的 Blob URL资源。它支持多种HTML标签,包括img、video、audio、source、iframe和a标签,确保广泛的兼容性和应用范围。使用这个方法时,用户可以指定要处理的 Blob URL,通过参数blob_url进行标识。如果提供了new_url参数,系统会自动将原有的 Blob URL替换为新的URL,实现资源的更新和替换。如果没有提供新的URL,系统则仅执行删除操作。此功能在操作完成后会释放相应的 Blob 对象,有效防止内存泄漏,提升页面性能和稳定性。
    6、plus_gallery_photo的相册选择功能现已支持勾选原图选项。此前,该功能曾被禁用,主要原因是安卓10版本对权限体系进行了重新设计,导致APP无法直接访问相册中的原图文件,操作时会提示权限不足。然而,经过此次功能重构,进行了优化处理。现在,在读取原图前,会将其临时移动到APP的临时文件目录中,再进行后续操作。尽管这一流程增加了一个步骤,却有效避免了选择原图失败的问题,提升了用户体验的稳定性和可靠性。
    7、在使用 plus_gallery_photo 功能发送原图时,系统会在用户进入相册后立即触发加载指示,以提醒用户当前正在处理相册图片。这一加载提示在处理完返回结果后会自动消失。由于移动原图过程中通常需要等待大约0.3到0.5秒的响应时间,这段空白期如果没有加载提示,可能会给用户带来不佳的体验。因此,通过这种方式可以有效提升用户的操作体验,让他们在等待过程中感受到更好的反馈。
    8、系统增加了一项安全机制,当相册中的原图被移动到 APP 目录后,系统会在完成 Blob 封装操作后,主动调用 newEntry.remove 方法来删除临时文件。如果移动过程中出现失败,系统同样会触发删除操作。这一机制的引入确保了临时文件能够被及时清理,防止无效文件在 APP 目录中堆积,从而保持系统的整洁和高效运行。
    9、对 xinle_copy 功能进行了全面的重构处理,现已不再依赖 ClipboardJS 方法,而是改为使用原生的 Clipboard API 来实现复制操作。此改进不仅简化了代码逻辑,还提升了兼容性和性能。如果用户浏览器不支持新版 Clipboard API,系统会自动回退到使用 execCommand('copy') 的方式进行处理,以确保复制功能能够在所有平台上正常工作。这种双重处理机制大大增强了功能的稳定性和适配能力,为用户提供了更加可靠的复制体验。
    10、为了改善苹果设备在H5端使用摄像头拍照采集图片时偶尔出现失败的问题,已在h5_upload_image_change功能中加入了日志报错处理机制。此功能通过详尽记录异常情况的日志,能够清晰地跟踪问题发生的具体场景和潜在原因,为后续问题的定位与解决提供了坚实的依据。这一改进不仅有助于确保图片采集功能的稳定性,同时也显著提升了用户体验,使用户在使用过程中更加顺畅无忧。
    11、考虑到未来有很多场景都需要用到图片上传组件,因此封装一个方法来处理上传场景:xinle_upload_image_html。该方法旨在简化图片上传的流程。通过该函数,可以根据特定的配置键和图片列表生成相应的HTML结构。这个结构不仅包括图片的展示和上传按钮,还整合了相关的配置信息,确保组件的功能全面而高效。虽然在集成组件的过程中需要考虑到许多细节和复杂因素,工作量较大,但一旦完成集成,后续在类似场景下的部署将变得非常轻松。这种预先的封装和标准化处理能够显著减少重复性工作,提高开发效率。
  • 0
    小小乐lv.2实名用户
    2025年9月9日
    1、Fancybox初始化流程如下:步骤一:初始化 Fancybox Fancybox.bind('[data-fancybox]', {...}) 这句代码会自动为页面所有带有 data-fancybox 属性的元素(比如图片、a标签等)绑定 Fancybox 弹窗功能。 当用户点击这些元素时,Fancybox 就会弹出灯箱效果。 步骤二:配置参数 Hash: false 禁止弹窗时修改URL hash(即不会出现 #fancybox-xxx 的地址栏变化)。 compact: false 关闭紧凑模式,允许自定义工具栏行为。 contentClick: 'close' 用户点击内容区域时,关闭弹窗。 步骤三:工具栏(Toolbar)配置 Toolbar: { ... } 这里自定义了工具栏内容和布局。 工具栏按钮(items) custom_download tpl: 自定义按钮HTML(SVG图标)。 click: 用户点击按钮时执行函数,获取当前选中的图片地址并调用自定义下载函数 jinsom_download_image(url)。 custom_share tpl: 自定义按钮HTML(font-awesome图标)。 click: 用户点击按钮时,获取当前选中的图片地址,然后用 navigator.clipboard.writeText(url) 复制图片链接到剪贴板,并调用 xinle_msg 显示提示。 工具栏布局(display) left: ['infobar'] 工具栏左侧显示信息栏。 middle: [] 工具栏中间无内容。 right: ['custom_share', 'custom_download', 'thumbs', 'close'] 工具栏右侧依次显示自定义分享按钮、自定义下载按钮、缩略图按钮、关闭按钮。 步骤四:用户交互 用户点击页面上的 [data-fancybox] 元素。 Fancybox 弹窗出现,显示图片或内容。 工具栏展示在弹窗顶部或底部,显示你自定义的按钮。 用户点击工具栏上的按钮: 下载按钮:执行下载逻辑。 分享按钮:复制图片链接,并弹出提示。
    2、新增了方法 xinle_download_image,专用于实现图片的本地下载请求。该方法能够智能识别当前运行环境(如 APP 或其他浏览器环境),并根据环境的不同执行相应的图片处理逻辑,从而确保下载功能的兼容性和稳定性。该方法支持多种格式的图片下载与保存,包括图片的 URL 地址、 blob 数据以及 base64 格式的文件内容。无论用户使用何种格式的图片资源,该方法都能够灵活适配,提供便捷的下载功能,进一步优化了用户在不同环境下的操作体验。
    3、新增方法 xinle_image_url_is_type,用于判断图片链接的类型。该方法需要传递一个 url 变量作为参数,通过对链接内容进行解析和判断来返回对应的图片类型。具体逻辑如下:如果 url 中包含 data:image,则判定为 Base64 格式,并返回 base64;如果通过正则匹配检测到以 http 开头的链接,则判定为普通 URL,并返回 url;如果链接中包含 blob,则判定为 Blob 类型,并返回 blob。如果以上所有条件均不满足,则判定为未知类型,并返回 unknown。该方法的设计便于对图片链接进行分类处理,提升了代码的灵活性和适配能力。
    4、新增图片保存方式:xinle_save_base64_image2gallery:首先,通过 plus.nativeObj.Bitmap() 创建一个 Bitmap 对象,用于处理图片数据。 加载 Base64 图片数据 调用 Bitmap 对象的 loadBase64Data 方法,将传入的 base64Data(Base64 格式的图片数据)加载到 Bitmap 对象中。 成功回调:如果加载成功,进入下一个步骤。 失败回调:如果加载失败,打印错误信息 加载base64图片数据失败,并输出具体的错误原因 e.message。 保存图片到本地路径 调用 Bitmap 对象的 save 方法,将加载的图片数据保存到本地目录 _doc/image 下,保存的图片格式为 png,并设置 overwrite: true 表示允许覆盖同名文件。 成功回调:如果保存成功,返回保存的图片路径信息 i.target,进入下一步。 失败回调:如果保存失败,打印错误信息 保存失败,并输出具体的错误原因 e.message。 保存图片到相册 调用 plus.gallery.save 方法,将保存到本地路径的图片(即 i.target)保存到系统相册中。 成功回调:如果保存成功,调用 xinle_msg 方法提示用户 "图片保存成功"。 失败回调:如果保存到相册失败,打印错误信息 图片保存到相册失败,并输出具体的错误原因 e.message。 执行结束 整个流程完成后,图片会根据逻辑保存在系统相册中,或者输出相应的错误日志,便于排查问题。
    5、新增方法:xinle_blob_to_base64,将图片blob转换base64:函数接受一个 blob 参数,表示需要转换的二进制数据。 创建 Uint8Array 使用 new Uint8Array(blob) 将 blob 转换为一个 Uint8Array(无符号 8 位整型数组)。 这是因为 Uint8Array 提供了对二进制数据的字节级访问,便于逐字节处理。 逐字节遍历并转换为字符串 使用 reduce 方法对 Uint8Array 进行遍历: 初始值为一个空字符串 ''。 每次遍历时,将当前字节 byte 转换为字符(通过 String.fromCharCode(byte)),并与累加字符串 data 拼接,最终形成一个完整的字符串。 将二进制字符串编码为 Base64 使用 btoa() 方法将生成的二进制字符串转换为 Base64 格式。 btoa 是 JavaScript 内置的 Base64 编码函数,可将字符串转换为 Base64 字符串。 返回结果 函数返回最终的 Base64 字符串,表示 blob 数据的 Base64 编码结果。
    6、新增下载文件函数:xinle_download_file该函数用于下载指定的文件。如果当前环境不是小程序(wxapp),则通过浏览器的 fetch API 获取文件并触发下载;如果是在小程序环境中,则提示用户不支持下载,并提供复制链接的功能。
    7、xinle_download_file的执行流程如下:调用 xinle_is_wxapp() 方法判断当前是否处于小程序环境。 非小程序环境(if (!xinle_is_wxapp())):执行文件下载逻辑。 小程序环境:提示用户小程序不支持下载文件,并提供复制链接的功能。 2. 文件下载逻辑(非小程序环境) 发起 fetch 请求 调用 fetch 方法向目标 url 发起 GET 请求,配置参数如下: method: 'GET':设置请求方法为 GET。 mode: 'cors':启用跨域请求模式。 headers: Access-Control-Allow-Origin: '*':设置允许的跨域来源(需根据实际情况调整)。 response-content-type: 'APPLICATION/OCTET-STREAM':设置返回的内容类型为二进制流。 responseType: 'blob':声明返回的响应类型为 blob(二进制文件数据)。 处理响应数据 使用 response.blob() 将返回的数据转换为 blob 对象。 通过 URL.createObjectURL(blob) 创建一个临时的下载链接。 创建下载链接 动态创建一个 <a> 标签,设置其 href 属性为生成的下载链接 downloadUrl。 设置 download 属性为文件名(file_name 参数值,或通过 xinle_get_file_name(url) 自动提取文件名)。 调用 link.click() 模拟用户点击,触发文件下载。 释放资源 调用 URL.revokeObjectURL(downloadUrl) 释放创建的临时 URL,避免内存泄漏。 提示下载成功 在控制台输出下载成功的提示信息。 捕获错误 如果下载过程中发生错误,则进入 catch 块,打印错误信息到控制台(console.log(error))。 3. 小程序环境逻辑 提示不支持下载 如果检测到运行环境是小程序(wxapp),调用 xinle_confirm 弹出提示框,告知用户“小程序不支持下载文件”。 提供复制链接功能 在提示框中提供一个按钮,用户点击后通过 ClipboardJS 实现链接的复制功能。 配置 ClipboardJS 的 text 回调函数,返回需要复制的下载链接 url。 调用 xinle_msg 提示用户“链接已经复制”。
    8新增xinle_get_file_name方法:该函数用于根据提供的 URL 提取文件名。如果 URL 包含查询参数(? 后的内容),会自动忽略这些参数,仅提取路径中的文件名。
    执行流程如下:分割 URL 使用 url.split('?') 将 URL 按照 ? 分割为两个部分: path:URL 的路径部分(? 前的内容)。 params:URL 的查询参数部分(? 后的内容),虽然获取了但没有实际使用。 查找最后一个斜杠的位置 使用 path.lastIndexOf('/') 获取路径中最后一个斜杠(/)的索引位置: 如果返回值为 -1,说明路径中没有斜杠,无法提取文件名。 提取文件名 如果 lastSlashIndex !== -1,使用 path.substring(lastSlashIndex + 1) 提取最后一个斜杠之后的内容,作为文件名返回。 如果 lastSlashIndex === -1,直接返回 null,表示无法从 URL 提取文件名。
    9、为了提升前端对设备环境的处理效率,现封装了一组方法,用于快速判断设备所属环境。这些方法能够帮助开发者更精准地识别用户所处的运行环境,从而实现针对性优化与功能适配。具体方法包括:xinle_is_wechat,用于判断当前设备是否运行在微信环境;xinle_is_wxapp,用于识别是否运行在微信小程序中;xinle_is_qq,用于判断是否运行在QQ环境;xinle_is_qzone,用于判断是否运行在QQ空间;xinle_is_android,用于识别当前设备是否为安卓系统;xinle_is_ios,用于判断是否为iOS系统;xinle_is_app,用于判断是否运行在APP环境。这些方法的封装为前端开发提供了统一的环境检测工具,使得复杂的设备适配工作变得更加高效和便捷。
    10、Fancybox灯箱组件现已实现图片下载功能,该功能在APP和H5环境下均可正常使用。然而,由于微信小程序环境目前尚未进入调试阶段,因此暂时不对该环境进行兼容性处理。在未来的功能规划中,图片展示将支持下载与分享功能,其中,分享功能目前仅在APP环境中提供,后续会进一步优化,直接集成微信分享功能,以提升用户的使用体验和功能完整性。这一改进将为用户在多种设备环境下的操作提供更流畅、更便利的支持。
    11、新增了page:beforeout页面退出监听功能:该功能会主动调用Fancybox.close来关闭所有已打开的灯箱。此外,通过$('.popup').each方法获取所有弹出层,并逐一进行关闭处理,确保页面退出时的整洁和资源释放。同时,还会通过app.fab.close来移除悬浮菜单,进一步优化用户在页面退出时的体验,避免因未关闭的组件而导致的界面混乱或资源浪费。
  • 0
    小小乐lv.2实名用户
    2025年9月8日
    1、为优化用户交互体验,新增了一个核心防抖方法 xinle_debounce(func, wait, immediate)。该方法专门用于场景保护,如搜索、滚动、按钮点击和菜单切换等场景中,用户可能频繁触发操作,导致请求重复执行。通过防抖函数,可以有效拦截多余的操作请求,仅在设定的时间间隔内执行一次,避免资源浪费和系统性能下降。该方法支持设定首次执行禁止防抖,只需要通过第三个变量标记为true即可,系统会自动内部完成处理。
    2、xinle_upload_image接口实现了统一图片上传的功能,并集成了callback回调机制。在H5环境中,回调接口会返回用户选择图片的blob对象地址,并通过该接口完成上传操作。此功能支持多种图片选择方式,包括APP拍摄、APP相册选择、H5页面图片选择以及微信图片选择等,同时进行了全面的兼容性处理,以确保功能在不同环境下的稳定运行
    3、 新增方法plus_camera_photo,支持通过APP调用摄像头直接发起拍照请求。拍摄完成后,系统会将拍摄的图片转换为blob对象并通过回调事件返回给前端,用于后续处理。之前是集合到统一方法中处理,拍摄和相册选择是合并一起的。但是这个方法存在巨大问题,无法支持异步回调的处理,不符合现在的设计要求,因此需要对其进行重构设计,确保后续的集成可以外部接收回调动作。
    4、通过plus_camera_photo发起APP摄像头拍摄请求,会依次执行如下流程:首先判断当前是否运行在H5+(Plus)环境下。如果不是,则提示用户“请在APP中使用”,并终止后续操作。 检查摄像头权限(仅限Android) 如果是在Android系统下,检查应用是否已经获得了摄像头权限。如果没有权限,则弹出提示,通知用户相机权限未开启。 获取相机对象 获取当前设备的相机对象,为后续拍照做准备。 调用相机进行拍照 调用相机让用户拍摄照片。如果拍照成功,进入下一步;如果失败,则根据不同原因进行相应的错误处理。 拍照成功后的处理 关闭之前弹出的权限提示(如果有)。 解析刚拍摄图片的本地路径,获取对应的文件对象。 读取该文件内容,将图片转为base64格式的数据。 将base64数据转换为Blob对象,并通过回调函数返回给调用者。 失败或异常处理 如果解析图片路径失败或获取文件对象失败,则关闭权限提示,并给用户弹出错误提示。 如果拍照失败,且原因是没有权限,则弹出对话框,询问用户是否要前往设置页面开启相机权限。如果用户同意,则跳转到应用设置页面。 这样,整个流程就是: 判断环境 → 检查权限 → 获取相机 → 拍照 → 成功后处理图片 → 失败则提示或引导用户开启权限。
    5、xinle_upload_blob的回调机制进行了重新设计,该函数负责上传Blob文件到服务器,并提供上传进度和结果的回调。在上传前,会检查用户是否已登录,并验证上传配置和页面请求的合法性。有两个回调处理动作:onUploadProgress - 上传进度回调函数,接收一个参数percent表示上传进度百分比。 onUploadResult - 上传结果回调函数,接收一个对象参数,包含上传结果的信息。
    6、xinle_upload_blob重构后的执行流程如下:1. 登录校验 首先判断用户是否已登录。如果未登录,则触发登录流程,并终止后续操作。 2. 上传场景配置校验 根据传入的上传类型,获取对应的上传配置。如果未找到相关配置,则提示“任务场景不存在”,并通过回调返回错误信息,终止操作。 3. 页面场景校验 判断当前页面是否与上传场景配置中的页面一致。如果不一致,则提示“非法请求拦截”,并通过回调返回错误信息,终止操作。 4. 图片压缩处理 对待上传的图片数据进行压缩。如果压缩失败,则通过回调返回错误信息,终止操作。 5. 压缩成功后的处理 创建压缩后的图片对象URL。 如果上传类型为头像,则立即在页面上预览显示该头像图片。 6. Blob对象处理 通过fetch方法,将压缩后的图片URL转为Blob对象,并提取文件类型信息,生成唯一的文件名。 7. 构建上传数据包 组装上传数据,包括上传类型、文件名、媒体类型等。 构建表单数据,将Blob对象和上传数据包一起提交。 8. 发起上传请求 使用Ajax方式向后端接口发起图片上传请求,并设置上传进度监听。 9. 上传进度回调 在上传过程中,实时计算并回调上传进度百分比,供页面显示进度。 10. 上传成功后的处理 销毁压缩后的Blob对象URL,释放内存。 如果上传成功且类型为头像,则更新用户头像地址。 调用成功回调,将后端返回的结果传递出去。 11. 上传失败后的处理 销毁压缩后的Blob对象URL。 调用失败回调,返回详细的错误信息,包括网络错误、服务器返回信息等。 12. 其他异常处理 如果获取Blob数据失败,销毁对象并通过回调返回错误。 如果图片压缩失败,直接通过回调返回错误。 整体流程概括为: 登录校验 → 场景配置校验 → 页面一致性校验 → 图片压缩 → Blob处理 → 构建数据包 → 发起上传请求 → 进度回调 → 成功/失败处理及异常反馈。
    8、xinle_upload_image进行全新重构,现在无论是在H5环境还是APP环境下,图片拍摄或相册选择都不会直接触发上传动作,而是将图片转换为blob对象并返回给前端。支持单图和多图的转换处理,为后续的上传操作提供了更灵活的机制。微信小环境未做兼容处理,现在暂时采用H5方案进行上传处理。
    9、前端统一图片上传逻辑如下:1、登录校验 首先判断用户是否已登录。如果未登录,则触发登录流程,终止后续操作。 2. 上传场景配置校验 根据传入的上传类型,获取对应的场景配置。如果没有找到相关配置,则提示“当前场景配置不存在”,并终止操作。 3. 页面一致性校验 判断当前页面是否与上传场景配置中的页面一致。如果不一致,则提示“非法请求拦截”,终止操作。 4. 上传数量限制处理 根据场景配置,确定本次允许上传的图片数量。如果超过最大限制,则进行限制调整。 5. 根据设备类型发起上传请求 APP端上传 弹出底部操作菜单,提供“拍摄”、“从相册中选择”、“取消”三种选项。 用户选择“拍摄”时,调用拍照功能,拍摄完成后返回图片的Blob数据,并通过回调函数返回。 用户选择“从相册中选择”时,调用相册选择功能,选择完成后返回所有图片的Blob数据,并通过回调函数返回。 用户选择“取消”则关闭菜单,不做任何处理。 微信端上传 根据剩余可上传数量限制,确定本次最多可选图片数量。 调用微信上传图片的相关事件,处理微信环境下的图片上传。 H5网页端上传 创建一个隐藏的文件选择框,根据限制条件决定是否允许多选。 监听文件选择事件,用户选择图片后,将所有文件对象转换为Blob数据,并通过回调函数返回。 文件选择框可多次触发,方便用户反复选择图片。 6. 回调数据处理 无论用户选择哪种上传方式,最终都会将图片的Blob数据(及类型)通过回调函数返回,供后续处理或上传。 整体流程概括为: 登录校验 → 场景配置校验 → 页面一致性校验 → 数量限制 → 根据设备类型弹出上传方式 → 用户选择并返回图片数据。
    10、通过 xinle_query_sql 方法获取媒体库数据表记录时,支持通过远程地址进行查询。方法内部会首先判断当前操作的表是否为媒体上传表(xinle_upload),并校验传入的 $id 是否为非纯数字(即传递的是远程地址,而非主键 ID)。具体流程如下: 1. 拼接 Redis Key:根据传入的远程地址生成一个唯一的 Redis 缓存键名,格式为 wp_xinle_upload_convert:http://xxxx/xxx.jpg,用于在 Redis 中缓存远程地址与 ID 的对应关系。 2. 尝试从 Redis 读取:通过 get_redis_meta() 函数,使用拼接好的 Redis Key 尝试读取缓存中的 ID 值。 3. Redis 命中:如果 Redis 中已缓存该远程地址对应的 ID,则直接将缓存的 ID 赋值给 $id,无需再查询数据库,从而大幅提升查询效率。 4. Redis 未命中:如果 Redis 中未找到对应的 ID,则需要通过 SQL 语句在数据库中查询,具体查询条件为 remote = $id(此时 $id 为远程地址)。 5. 数据库查找结果: * 未查到记录: 如果数据库中没有找到对应的记录,函数直接返回 false,表示该远程地址未入库。 * 查到记录: 如果数据库中找到对应的记录,则取出其 ID,并赋值给 $id。 6. 写入 Redis 缓存:将新查到的 ID 写入 Redis 缓存,并设置有效期为一年(365 天)。下次再查询同样的远程地址时,可直接从缓存中获取 ID,避免重复的数据库查询操作。
    11、全面集成了 Fancybox 灯箱组件,所有图片的展示均通过该灯箱进行统一处理,确保图片查看体验的一致性和视觉效果。此次集成的 Fancybox 组件版本为 5.x,在APP页面初始化的脚本中,系统会自动加载并引入该组件,无需额外手动操作。Fancybox 组件具备自动初始化功能,能够在页面加载完成后自行完成必要的设置,甚至在新内容动态填充到页面后,也无需手动重新初始化操作,组件会自动适配新加载的图片内容。
  • 0
    小小乐lv.2实名用户
    2025年9月5日
    1、xinle_api_post在请求过程中会进行基础的安全校验处理,其中通过自定义请求头X-Requested-With实现初步验证,后端会检查该请求头的内容是否符合预期,若发现不一致,则判定为非法请求。同时,安全令牌X-WP-Nonce的传递也是重要的一环,该令牌由后端在初始化首页时生成,并通过xinle.wpApiSettings进行配置,后端会对传递的令牌进行严格校验与对比,以确保本次请求的合法性和安全性。这一机制有效防止了未经授权的访问,进一步提升了系统的安全防护能力。
    2、xinle_api_post 集成了统一的业务逻辑处理机制:当接口返回的 res 是对象类型且包含 jump 属性时,系统会根据具体的参数内容进行判断和后续操作。如果参数为 captcha,这意味着当前请求需要进行安全校验处理,此时系统会直接调用 xc_hook_captcha 方法,对设备发起人机验证操作,以确保当前行为的可靠性和安全性。而如果参数为其他值,则系统会执行内部 方法,完成相应的页面自动跳转。例如,当后端操作需要用户登录但用户尚未登录时,系统会触发跳转逻辑,将用户引导至登录页面,从而保障操作流程的顺畅性和用户体验的一致性。
    3、新增方法:xinle_hook_jump_page,根据提供的key跳转到相应页面。如果key对应于page_list中的一个条目,则使用该条目的链接进行跳转。如果key不在page_list中,则尝试将key作为URL进行跳转。如果key既不在page_list中,也不是一个有效的URL,则函数会拒绝返回的Promise。该方法需要传递如下变量: key 页面的唯一标识符或要跳转到的URL。[title=''] 跳转前显示的消息标题。如果提供,则显示该消息。[time=2] 延迟跳转的时间(秒)。默认为2秒。返回一个Promise对象。如果跳转成功,Promise将被解决;如果失败,则被拒绝。
    4、xinle_hook_jump_page执行流程如下:参数处理与Promise封装 函数接收三个参数:key(页面标识或URL),title(可选,跳转前消息),time(可选,延迟秒数)。 函数返回一个Promise对象,便于异步处理跳转结果。 延迟时间校正 time参数转为数字,且如果小于0,则默认为1秒。 显示消息(可选) 如果传入了title,则调用xinle_msg(title)显示跳转前的提示消息。 获取页面跳转配置列表 从全局变量xinle.jump_config获取跳转页面列表page_list,如未定义则为[]空数组。 查找匹配页面 在page_list中查找key是否有对应的条目(通过item.key === key判断)。 如果找到,获取该条目的link作为跳转链接。 URL有效性判断 如果没找到匹配条目,则尝试将key作为URL解析: 使用new URL(key)判断其是否为有效URL。 如果解析成功,则认为key本身就是跳转链接。 如果解析失败(抛出异常),说明key既不是配置项也不是有效URL。 失败处理 若key既不是配置页面,也不是有效URL,打印错误信息,并reject(false)拒绝Promise,终止函数执行。 延时跳转 如果得到了有效跳转链接,则使用setTimeout延迟指定秒数后执行跳转: 调用xinle_page_open(linkToJump)进行页面跳转。 跳转完成后resolve(true),标记Promise已解决。
    5、对xc_hook_visibilitychange方法进行了重构与优化。该方法主要用于处理页面可见性变化时的相关事件。此前,无论是否登录,游客访问时也会触发该方法,导致大量无效的API请求被执行,给后端带来了显著的压力指数。经过优化调整,现在该方法仅限登录用户触发,从源头上减少了无意义的请求压力。同时,每次触发时会提取客户端的指纹信息以及当前用户的UID,发送至后端以便进行精准的响应处理。针对这一调整,后端的业务逻辑也进行了相应的优化。由于触发频率较高,该方法不再集成于wp环境中,而是通过Redis来处理相关的来访业务回调动作。这一改动有效降低了对后端服务的压力,提高了系统整体的稳定性与响应效率。
    6、前端新增了一个名为page的脚本,专门负责APP端页面路由的全局监听动作。该脚本通过wp_enqueue_script函数进行加载,并设置其优先级为第一序列,仅次于核心框架framework7,确保其加载顺序与页面逻辑的整体兼容性。在实际执行监听器处理时,脚本采用了document.addEventListener('DOMContentLoaded')事件进行加载,这样能够保证页面框架在完全初始化后再开始监听动作,从而避免由于框架内部变量未完成初始化而导致监听失败的情况发生,为页面路由的全局监听提供了坚实的基础。
    7、宫论APP新增上拉刷新加载监听器,通过JavaScript 和 Framework7 框架的事件执行监听机制,监听 框架内的ptr:refresh 行为:当 .ptr-content 元素触发 ptr:refresh 事件时,回调函数会被执行。回调函数的主要逻辑如下: var ptrContent = $$(this); 通过 $$(this) 获取触发事件的当前元素,并将其赋值给变量 ptrContent,方便后续操作。 let page_name = $$(this).closest('.page').attr('data-name'); 使用 $$(this).closest('.page') 方法找到当前 .ptr-content 元素最近的父级 .page 元素,然后通过 .attr('data-name') 获取该页面元素的 data-name 属性值,并赋值给变量 page_name。这一步主要是为了确定当前所在的页面名称。
    8、新增了一个上拉刷新触发的前端钩子函数:xc_hook_ptr(page_name, Content),当监听器检测到用户进行上拉刷新的操作时,会触发该钩子函数以执行相应的业务逻辑。钩子函数在执行时会接收两个参数:1. page_name,这是页面的唯一标识符,通过该标识符可以明确当前触发操作的页面位置,从而为不同页面实现对应的业务逻辑处理;2. Content,这是一个动画对象的标识符,通过该对象可以对加载动画进行控制,例如关闭、停止或刷新等操作。
    9、xc_hook_ptr根据页面执行不同的加载动作,整个执行流程如下:停止刷新动画 首先调用 app.ptr.done(Content),用于结束当前页面的“下拉刷新”动画效果,保证页面不会一直处于刷新状态。 获取当前页面内容区域 通过 jQuery 选择器 $('.app.' + page_name + '_content:last') 获取当前页面最后一个内容区域 DOM 元素(通常用于多页面或多实例时,确保获取最新的页面内容容器)。 显示加载动画 在页面内容区域的顶部插入 xinle.more_loading,即加载动画或占位元素,提示用户正在加载更多内容。 统一调试日志输出 打印当前页面的刷新动作 console.log('顶部上拉刷新触发[],当前页面:', page_name),便于开发调试和定位问题。
    10、前端新增infinite全局监听动作,用于监听页面底部下拉动作。执行流程如下:通过 $$('.infinite-scroll-content').on('infinite', function() {...}),为页面上所有具有 .infinite-scroll-content 类的元素绑定了“无限滚动”(即到底部自动加载更多内容)的事件监听器。 获取当前内容容器 在事件触发时,var Content = $$(this); 表示获取当前触发事件的内容容器(通常是页面主内容区域),用于后续操作和数据加载。 获取当前页面名称 通过 let page_name = $$(this).closest('.page').attr('data-name');,获取当前内容容器最近的 .page 父级元素的 data-name 属性值,用于区分不同页面(如首页、消息页等)。 执行底部加载处理函数 调用内置方法;,把当前页面名称和内容容器作为参数,执行自定义的底部加载处理逻辑(如请求新数据、渲染更多内容等)。
    11、新增xc_hook_infinite方法,来处理全局页面的滚动监听。首页获取页面内容容器 通过 let page_content = $('.app.' + page_name + '_content:last');,获取当前页面的内容容器元素,用于后续操作(比如插入加载动画、数据渲染等)。 日志打印:触发页面滚动 输出 console.log('触发页面滚动下拉' + page_name);,方便调试,标记已进入下拉加载流程。 首页特殊处理 如果当前页面是首页(page_name == 'xinle_home_index'),直接 return,终止函数,不执行后续加载逻辑。 防止重复触发(无限套娃) 判断 infinite_loading[page_name] 是否为 true,如果是则直接终止,避免重复触发加载事件。 如果未触发,则设置 infinite_loading[page_name] = true;,标记当前页面正在加载,确保本次加载过程中不会再次触发。 插入加载动画 判断当前内容容器中是否已存在 .preloader 元素,如果没有则插入一个加载动画(<div class="preloader ..."></div>)。 输出日志 console.log('插入内容');,用于调试。 显示加载动画 让 .infinite-scroll-preloader 加载动画显示出来,提示用户正在加载。 日志打印:触发底部加载 输出当前正在底部加载的页面名,方便开发调试。 模拟异步加载数据 使用 setTimeout 模拟异步数据加载过程(延迟2秒)。 加载完成后,隐藏加载动画。 在数据加载结束后将 infinite_loading[page_name] = false;,允许后续继续加载;或者如果已到数据末尾,可以调用 app.infiniteScroll.destroy() 停止无限滚动监听器。
  • 0
    小小乐lv.2实名用户
    2025年9月4日
    1、新增 Redis 方法 xinle_redis_get_user_history,用于查询指定用户的历史行为记录。该方法需要传递两个变量:$user_id(用户 ID)和 $action_type(行为类型,例如:visit、favorite、like)。在执行查询时,方法会从 Redis 中检索与指定用户和行为类型相关的历史记录。如果未查询到任何记录,则返回 false;如果查询到记录,则返回一个关联数组,其中包含历史记录的详细信息,并附带每条记录的排名分数。这种设计不仅能快速获取用户的行为历史,还能通过排名分数帮助分析用户的行为偏好和频率。
    2、在 xinle_redis_get_user_history 方法中增加分页功能,通过 page 变量进行控制,该变量默认为 1。系统首先从配置中读取 xinle_app_paging_default_number,以获取后台设定的默认分页返回数量。然后,根据 page 计算出偏移值,用于确定从哪个位置开始检索数据。最后,使用 zRevRangeWithScores 方法从 Redis 中获取指定范围的行为记录及其时间戳。这种分页机制不仅能够有效地管理和展示大量数据,还能提高查询效率,确保用户能够方便地浏览历史记录。
    3、xinle_redis_get_user_history 方法新增了一个可选参数 limit,用于灵活指定每页返回的数据数量。如果未传递该参数,系统会默认采用既定的分页设置。此次优化的核心目的是解决部分页面设计中因返回数据量过大而导致下拉加载无法正常触发的问题。通过允许用户根据需求调整返回数据的数量,进一步提升页面加载的稳定性和交互的可靠性,确保用户体验更加流畅,同时为后续功能扩展提供更灵活的支持。
    4、对xinle_redis_get_user_history函数进行了优化调整:首先,针对zRevRangeWithScores方法可能出现的异常返回问题,进行了深入分析和处理,将其替换为更稳定可靠的zRevRange方法来获取数据,确保了返回结果的准确性和一致性。其次,为了进一步提升用户使用体验,优化了page参数的逻辑处理。当page参数为空或未设置时,系统将智能地返回所有相关历史数据,便于用户快速查看完整记录;而在page参数有值的情况下,系统会根据指定的分页参数精确地对数据进行分割,并返回相应的分页结果,从而兼顾了数据的全面性和灵活性。通过这一系列改进,函数的稳定性、可用性以及用户友好度得到了显著提升。
    5、新增一个方法 xinle_redis_delete_user_history,用于清理指定用户的历史记录,例如删除某条收藏记录或某个商品的点赞记录。该方法需要传递三个参数:$user_id(用户 ID)、$action_type(行为类型,例如:visit、favorite、like),以及 $page_id(页面唯一标识符)。如果 $page_id 为空,则删除该用户和行为类型下的所有记录。通过这种设计,系统能够灵活地管理用户的历史数据,支持单条记录的删除以及批量清理操作,从而帮助维护数据的准确性和完整性。
    6、由于系统设计机制的要求,新增一个 allback 回调脚本,用于集中处理所有的回调动作事件。在主程序初始化阶段,该脚本会自动执行并挂载,从而确保所有回调功能都能够正常运作。大多数回调场景都是通过 Swoole 进行处理,由于其异步执行的特性,必须确保这些方法已成功集成到主程序中,否则可能因未定义的执行函数导致失败。虽然每个 API 接口都有各自的定义脚本,并不需要整合到主程序中,但异步回调必须整合,以确保系统的稳定性和可靠性,避免潜在的执行错误。
    7、后端新增了一个方法xinle_redis_user_is_history,用于判断用户是否对某个页面进行了指定行为(例如收藏或浏览)。该方法通过封装处理用户的历史行为记录来实现。如果用户对页面有相应的行为记录,则返回true,否则返回false。用户的行为记录被存储在Redis中,确保数据读取速度达到毫秒级响应,提供快速高效的查询体验。这一方法不仅提升了系统的性能,还为用户行为分析和个性化推荐奠定了坚实的基础。
    8、宫论用户行为处理方法已完成封装,统一通过redis进行处理。拥有如下特性:高性能:基于Redis的zset数据结构,支持毫秒级读写,适合高并发场景,保证用户体验流畅。灵活性强:所有方法参数灵活,支持分页、limit、批量操作,便于适应不同业务需求和页面设计。数据安全与完整性:支持单条和批量删除,便于数据清理和隐私合规,维护数据库干净、准确。易扩展:方法均为通用封装,后续可随时增加新行为类型(如comment、share等),只需扩展$action_type即可。支持异步回调:通过allback脚本,集中管理所有回调事件,适配Swoole等高性能异步框架,提升系统稳定性。便于分析与推荐:行为数据有时间戳、分数,可用于排序、行为频率统计,为推荐算法和用户画像提供坚实数据支撑。用户行为发生时,调用set_user_history记录数据。需要展示用户历史时,调用get_user_history查询,支持分页和limit。用户主动清理或后台维护时,调用delete_user_history删除指定记录或全部。页面判断用户行为状态时,调用user_is_history,快速判定是否有相应行为。所有行为相关异步处理,均通过allback回调脚本统一管理,确保执行无误。
    9、用户返回页面时,前端预留的【xc_hook_visibilitychange】触发器会被激活,系统会主动调用wp_create_nonce函数来获取最新的_wpnonce。这一过程确保了前端能够及时接收到最新的安全令牌,从而进行相应的处理。_wpnonce作为防止攻击的安全令牌,其有效期有限,因此必须为用户及时更新,以防止因页面停留时间过长而导致令牌过期,进而造成接口响应失败的问题。
    10、xinle_redis进行了重构优化处理,现在通过extension_loaded检测运行环境是否为异步环境。如果检测到运行在 Swoole 环境下,则 Redis 的初始化将采用 pconnect 持久连接方式;若非 Swoole 环境,则使用传统的 connect 普通连接方式。此前在 Swoole 环境中发现 Redis 持久连接存在数小时后自动断开无法响应的问题,此次调整优化了连接机制,以确保该问题得到有效解决。此外,xinle_redis还新增了错误日志记录功能,当出现连接失败或初始化失败时,将通过 xinle_log_error_warn 记录错误信息到 redis_error 中,便于后续问题追踪和快速定位。这一重构不仅提升了系统的稳定性,同时增强了异常处理能力,为应用运行提供了更加可靠的保障。
    11、xinle_api_post已完成封装处理,具体的执行流程如下:传入参数(type, api, data) 组装API请求URL 合并并补全请求数据(type、nonce、referer等) 用serialize方法序列化数据为URL编码格式 用fetch以POST方式发送请求(带请求头、带cookie等) 拿到响应后: 判断响应码 尝试json解析 处理特殊jump场景(如验证码、页面跳转) 返回结果 捕获错误: 判断是否403,弹窗提示 统一返回标准错误对象。核心机制如下:安全性:每次请求都带WordPress nonce和referer,防止CSRF。 兼容性:序列化方法兼容数组/嵌套对象,方便对接复杂后端。 易用性:支持Promise,错误和跳转统一处理,方便前端统一调用和异常捕获。 扩展性:公共参数和数据组装方式灵活,适合多模块、多业务场景。
  • 0
    小小乐lv.2实名用户
    2025年9月3日
    1、在页面路由监听器中(通过 app.on('pageBeforeIn') 事件),新增了一项关键业务处理逻辑:当用户即将进入某个页面时,系统会使用 xinle.tab_config_page.includes(page.name) 方法验证目标页面是否属于首页底部菜单视图。如果验证结果为真,则将 user.is_home 更新为 TRUE;如果结果为假,则更新为 FALSE。这一机制确保了系统能够在用户浏览过程中准确识别当前页面与首页底部菜单的关系,从而为后续的业务逻辑提供可靠的判断依据。注:初始化页面的时候,系统会自动将user标记为true,默认即访问首页,当发行页面变动则根据监听器来进行自动变化处理。
    2、在后退拦截器 xinle_page_back 中,新增了一项突破性的处理逻辑:系统会通过 user.is_home 属性判断用户是否处于首页。如果用户当前位于首页,系统会拦截后退操作,转而通过 plus.runtime.launcher 执行与APP交互的退出逻辑,将用户直接返回手机桌面。主要是解决设备在使用APP时无法通过后退按钮快速退出的问题,特别需要强调的是,由于宫论的APP采用了 WebView 嵌套加载,路由监听处理相对复杂。首页的验证判断需要通过自定义属性方法来进行判断,避免出现后退失败。
    3、经过重构优化,xinle_scrolltop滚动事件的处理方式得到显著提升。此前采用的基于 targetElement.scrollTop 的滚动处理方法在实际使用中存在不稳定性,尤其在复杂页面布局下容易受到窗口尺寸或元素位置变化的影响。现在通过重新设计逻辑,改为动态获取窗口高度与目标元素位置,计算出精确的滚动距离后再执行滚动操作。这种优化有效解决了之前方法的局限性,显著提升了滚动处理的稳定性与精确性,无论用户的设备窗口大小如何变化,页面元素都能准确跳转至指定位置。进一步增强了页面导航的流畅性。
    4、前端新增了名为 xinle_is_sales 的方法,该函数的主要功能是对给定的数字进行格式化,便于以特定的销售额格式进行展示。具体实现逻辑如下:当传入数字的绝对值小于10000时,直接按常规方式显示,整数部分完整呈现,小数部分则保留两位小数;当数字的绝对值处于10000至100000之间时,格式化为以“万”为单位的显示方式,并保留两位小数,从而使数值表达更为直观和简洁。注:涉及到数字格式化的地方,都需要用到这个方法。同样的后端也增加了这个方法,用于数字处理。
    5、前端新增了启动初始化事件:xinle_home_launch_success。当页面完全加载完毕后,该HOOK将会主动触发,这使得一些首页初始化的处理可以通过这个方法来执行。例如,可以用于初始化幻灯片、设置首页菜单监听器、管理下拉ajax监听器等。通过这种机制,页面加载后的动态效果和功能可以得到更好的管理和实现pageBeforeIn监听器新增了处理机制,当用户即将返回首页时,会主动触发xinle_home_launch_success。这一改动将对幻灯片、菜单筛选、下拉滚动等监听器进行重置处理,以防止由于进入三级页面而导致初始化监听失效的问题。通过这种方式,确保了用户在返回首页后,各种动态效果和交互功能能够正常运作,进一步提升了页面的稳定性和用户体验。
    6、APP 路由进行了重构优化,具体实现通过 pageBeforeIn 事件进行监听并动态调整 URL。路径处理分为三种类型:基本路径的情况,对于预定义的特定页面名称(在 case 语句中明确指定),浏览器的 URL 会被设置为根路径 /;动态路径的情况,对于非预定义页面,浏览器的 URL 会根据页面名称动态生成路径并更新;参数化路径的情况,当页面具有 id 参数时,浏览器的 URL 会进一步追加页面名称及 id 参数,从而生成完整的参数化路径。注:本次页面路由的更新主要是为了适配APP分享和小程序分享的跳转处理。
    7、在初始化脚本【start.js】中,新增了一个页面加载完成后的监听事件,用于优化单页应用(SPA)的路由处理逻辑。该事件会在页面加载完毕后,自动检测当前 URL 的哈希值。如果成功获取到哈希值,意味着当前链接中包含路由信息,此时会进一步提取哈希值中的路径参数,并对其进行处理,过滤掉符号“#”。随后,通过调用 window.history.pushState 方法重置浏览器的历史记录,确保页面状态的更新不会触发完整的页面刷新。同时,利用 xinle_page_open 方法发起访问请求,实现路径的跳转和内容加载。不仅能保证单页应用的流畅体验,还适用于网页端和小程序端。
    8、在 xinle_home_launch_success 初始化脚本中新增了一项 DOM 检测机制,旨在提高脚本执行的可靠性与效率。脚本执行前会优先检查页面是否包含自定义属性【launchExecuted】。若该属性已存在,脚本将直接跳过执行,从而避免因重复执行带来的资源浪费与冗余问题。同时,这一机制能够有效防止页面上出现多个重复监听器,避免因重复请求处理导致的性能下降或逻辑混乱,为系统运行提供更稳定的保障。
    9、对 xinle_home_index_infinite 监听器进行了优化升级,重点改善下拉滚动处理的逻辑。在用户触发滚动加载时,系统会首先检测页面是否存在加载动画标志,若检测到加载动画,则表明页面正在进行 AJAX 请求,此时会暂时阻断用户点击加载菜单数据的操作,确保只有在后端数据成功返回后才允许进行菜单切换。该优化机制在极端网络条件下表现尤为突出,有效避免了重复加载或数据冲突的问题,进一步提升了系统的稳定性与用户体验,使操作流程更加顺畅。
    10、在 pageBeforeIn 监听器中新增了一项针对首页的特殊处理逻辑。通过 xinle.tab_config_page.includes(page.name) 方法验证当前页面是否为首页,若判断结果为首页,则会主动重置浏览器的历史记录为空。此举旨在优化导航逻辑:当用户通过链接或 APP 通知事件打开指定页面时,系统会在返回首页时重置链接,而不是继承之前的来访路径。该处理方式能够有效避免因历史记录导致的导航混乱问题,为用户提供更一致且清晰的导航体验,进一步提升系统在复杂导航场景下的适配能力。
    11、新增了 Redis 方法 xinle_redis_set_user_history,用于高效记录用户的历史行为数据,包括浏览记录、收藏记录、点赞记录、搜索记录等。该方法接受三个参数:$user_id(用户 ID)、$action_type(行为类型,例如:visit、favorite、like)、$page_id(页面唯一标识符)。通过将用户行为数据存储至 Redis,不仅能够快速查询和分析用户的行为偏好,还能为后续的推荐策略和系统优化提供强有力的支持。此功能的加入使得用户行为数据的处理更加高效。
  • 0
    小小乐lv.2实名用户
    2025年9月2日
    1、在APP的指纹事件处理中,首先在完成对xinle_is_profile资料的采集动作后,系统会通过array_merge函数将用户对象与现有数据合并,并将合并后的用户对象返回给前端进行响应。在此过程中,系统会将生成的指纹信息写入到客户端的cookie中,方便后续后端在需要时直接通过cookie读取当前客户端的指纹信息。如果对安全性有所顾虑,还可以通过指纹token从Redis中读取数据,这种方式确保了token的参数无法被篡改,从而提升了数据的安全性。
    2、后端的fingerprint完成封装处理,fingerprint是APP首页初始化请求的一个过程,整个流程如下:1. 加载环境 首先,系统会加载WordPress的核心环境和自定义的API接口文件,这样后续的函数和数据操作都可以正常使用。 2. 获取请求类型 系统会接收一个请求类型参数(type),用来判断当前请求属于哪种操作。 3. 判断请求类型 如果请求类型是“fingerprint”,说明这是一次指纹采集和用户环境检测的请求,才会继续执行下面的逻辑。否则会直接返回非法请求提示。 4. 采集并存储指纹 系统会从前端接收到用户的指纹信息,然后结合用户的浏览器信息(UA)和IP地址,生成一个唯一的标识,并把指纹信息存储到Redis缓存中,保存时间为24小时。 5. 采集用户环境信息 接下来,系统会通过一系列自定义函数,检测当前用户的各种环境信息,比如: 是否安全环境 是否在APP里 是否在H5页面 是否在微信环境 是iOS还是安卓 是否在PC端 是否在微信小程序 用户IP和UA 当前设备的类型描述 指纹采集的时间 这些信息会整理成一个用户信息数组。 6. 识别设备类型 系统会根据用户的环境(如是否是APP、H5、微信等),判断用户当前使用的设备类型,并用文字描述(如iPhone APP、安卓APP、微信小程序、PC端等)。 7. 补充用户资料 如果当前用户已登录(有用户ID),还会进一步获取用户的详细资料和权限信息,并补充到用户信息数组中。 8. 返回结果 最后,系统会把整理好的用户信息数组、状态码和提示信息,一起返回给前端,表示本次请求成功。 9. 非法请求处理 如果请求类型不是“fingerprint”,系统会直接返回错误码和“非法请求”的提示信息。
    3、在前端接收到指纹识别响应后,会将现有的user对象与后端返回的user对象进行合并,使用的是Object.assign方法。这是因为在user对象初始化时,某些参数需要系统自动生成,以避免潜在的异常错误。如果这些参数没有被正确生成,可能会导致系统不稳定。一旦后端返回了响应结果,前端会立即进行数据合并,确保数据的一致性和完整性。然而,如果后端返回的数据存在异常,合并过程可能会失败,从而导致整个前端交互系统崩溃。因此,保持后端响应的准确性和完整性至关重要,以确保系统的稳定运行。
    4、如果前端的访问请求携带了link变量参数(微信分享、小程序分享),无论是网页还是APP或者是后续的下程序都是支持内页跳转处理的,但是这个跳转存在一个问题,如果跳转的页面引入了user对象,但是user对象是通过后端异步获取的,如果user对象获取前完成了页面跳转,会导致user对象引入参数显示空白。基于此,调整了请求跳转逻辑,页面跳转的请求必须等待user对象初始化完成才执行。user对象的请求速度是非常快的,基本小于200毫秒,因此不需要担心等待问题。
    5、前后端的指纹初始化动作已完成处理,前端的执行流程如下:1. 页面加载 当页面加载完成(即DOM准备好)时,代码会自动开始执行。 2. 获取设备指纹 调用FingerprintJS库,异步获取当前用户的设备指纹(visitorId),这是一个唯一标识每个设备的字符串。 3. 设置指纹到本地 获取到指纹后,执行以下操作: 把指纹写入浏览器的Cookie,方便后续使用。 在window对象上定义一个不可修改、不可删除的全局变量 fingerprint,用于全局调用。 4. 发送指纹到后端 使用jQuery的Ajax方法,向后端接口(fingerprint.php)发送一个POST请求,内容包括: 请求类型(type: 'fingerprint') 指纹信息(fingerprint) 5. 处理后端返回 后端返回后,执行以下操作: 把后端返回的用户信息合并到前端全局 user 对象(Object.assign)。 打印返回信息到控制台,方便调试。 6. 路由跳转处理 在后端返回成功后,再次触发一个页面路由处理: 读取当前页面的hash(URL锚点),得到要跳转的路径。 使用 pushState 把URL路径重置为根目录 /,保持页面简洁。 调用 xinle_page_open(path) 方法,跳转到指定的内页。 7. Ajax完成回调 Ajax请求完成后(不管成功或失败),可以在 complete 回调里做一些收尾操作
    6、在 pageBeforeIn 监听器中新增了一项处理逻辑:通过 xinle.tab_config_page.includes(page.name) 判断当前页面是否为首页。如果验证结果显示该页面为首页,则会清空浏览器的历史记录。这样设计的目的是,当用户通过链接或 APP 通知事件直接打开某个指定页面时,系统在用户返回首页时会自动重置链接,而不是沿用之前的来访路径。这种处理方式有效避免了因历史记录累积而可能引发的导航混乱,同时确保用户在页面跳转和返回操作中获得更流畅、更一致的使用体验。
    7、在使用 app.views.create 初始化视图时,会触发一系列监听器,这些监听器覆盖了页面生命周期中的多个关键节点,确保开发者可以精准捕获页面状态变化并执行相关逻辑。具体触发时机包括:页面刚插入 DOM 时(mount),此时页面结构完成挂载;页面即将进入时(动画开始前),用于处理页面进入前的准备工作;页面进入完成时(动画结束后),表示页面完全呈现并可供交互;页面即将离开时(动画开始前),适合处理页面离开前的保存或清理操作;页面离开完成时(动画结束后),表示页面已彻底从视图中移除;页面初始化时(仅首次进入页面时触发),通常用于页面的初始数据加载或绑定事件;页面再次激活时(已初始化的页面再次进入时),适合处理已存在页面的重新展示逻辑;页面即将卸载前,提醒开发者进行资源释放或状态保存;页面卸载后,标志页面已完全从内存中清除;页面即将被彻底移除前(如路由返回时,页面彻底销毁)。
    8、页面试图初始化的过程中,首先通过元素选择器定位并获取底部菜单,并将其赋值到 home_toolbar 变量中。接着,通过 pageBeforeIn 事件监听器来判断页面是否即将切换到首页视图,如果条件满足,则显示底部菜单,以确保用户在首页视图中能够正常看到底部导航栏。同时,通过 pageBeforeOut 事件监听器来监测页面即将离开时的状态,一旦页面离开,无论是跳转到其他视图还是关闭当前视图,底部菜单都会被隐藏。这样实现了底部菜单的动态显示与隐藏逻辑,确保其行为与页面切换保持一致。
    9、在视图初始化时,会对页面操作进行加锁保护,以确保用户交互的稳定性和体验流畅性。具体实现方式是通过pageEnterLock机制,为每个页面设置进入锁定状态。当用户尝试进入某个页面时,页面会在加载完成后的700毫秒内保持锁定,期间无法重复进入,从而有效防止快速重复点击导致的页面异常加载或逻辑紊乱。此外,为了进一步提升防护效果,beforeEnter拦截器也集成了防抖机制,在0.7秒内禁止相同页面的重复请求,避免因频繁触发导致的资源浪费或性能问题。这一整套机制既保证了页面加载的稳定性,也提升了用户操作的整体流畅度。
    10、得益于user对象的缓存机制的设计,现在APP首屏加载速度显著提升,在静态资源缓存的情况下,加载时间可以压缩到500毫秒以内,而未启用静态资源缓存时也能控制在1000毫秒以内。当用户核心字段发生变动时,例如 'phone', ‘email’, 'avatar_url', 'weixin_uid' 等,系统会自动通过 xinle_update_user_meta_hook 监听器进行实时缓存刷新,以确保数据的准确性和同步性。此机制通过监听器减少了对SQL的频繁请求。
    11、对整个APP项目的API请求机制进行了重构。原有的请求机制是通过传统的ajax方式实现前后端交互,但这种方式已显得较为落后,且由于缺乏中间层的接管,导致请求过程中的数据监听和异常处理存在一定的困难。为此,单独封装了一个名为“xinle_api_post”的方法,用于统一管理项目中的所有请求逻辑。新方法采用现代化的fetch API来处理请求,支持对复杂数据结构(如数组和嵌套对象)的解析与传递。同时,封装后的方法内置了对fetch的异步处理链路,能够顺畅支持then和catch方法,便于后续对请求响应结果的处理和异常捕获,大幅提升了代码的可维护性和扩展性。
  • 0
    小小乐lv.2实名用户
    2025年9月1日
    1、宫论APP正式集成FingerprintJS浏览器指纹采集,当start.js脚本触发的时候,会加载 FingerprintJS 通过 FingerprintJS.load() 异步加载指纹识别库。这个方法会返回一个 Promise。 获取指纹对象 当库加载完成后,会得到一个指纹对象(fp)。接着,调用 fp.get() 方法,这也是一个异步操作,会继续返回一个 Promise。 得到指纹结果 fp.get() 执行完成后,会返回一个结果对象,其中包含 visitorId,这是根据当前设备和浏览器生成的唯一指纹标识。 存储指纹标识 首先,将 visitorId 赋值给变量 fingerprint。 然后,调用 set_cookie('fingerprint', visitorId),把这个指纹标识存到浏览器的 Cookie 中,方便后端或者其它前端脚本使用。 设置全局不可修改的属性 最后,使用 Object.defineProperty 在 window 对象上定义一个 fingerprint 属性,值为刚才获取到的 visitorId。并且设置为不可修改、不可删除,这样后续任何代码都无法更改这个值,确保指纹标识的唯一性和安全性。
    2、当启动APP成功生成获取到浏览器指纹后,会触发API接口请求,请求后端进行业务响应处理。指纹是通过浏览器的特性来生成的,因此只能通过前端进行处理。然后在通过后端进行业务逻辑的解析处理动作。指纹事件也是宫论APP唯一初始化后,和后端交互的动作,一些参数的交换也是通过指纹事件来完成的。
    3、在后端接收到指纹请求后,系统会通过POST方法提取指纹信息,并结合IP地址、用户代理(ua)以及指纹数据生成一个加密的token令牌。这个令牌有效期为24小时,并将对应的指纹信息写入其中。该token令牌是本次用户会话的安全凭证,后续涉及敏感操作的交互行为将依赖此令牌进行身份验证和安全保障。生成token时,采用MD5加密参数,以确保字符串长度适中,便于处理和传输。
    4、为了确保业务逻辑的一致性和简化开发流程,后端在获取用户设备环境时,采用了一种统一的封装方法来进行读取。这种方法通过一系列精确的判断来识别用户所在的操作环境。具体操作包括:通过xinle_is_app判断用户是否处于APP环境;使用xinle_is_weixin来判断用户是否使用微信环境,这包括微信浏览器和微信小程序;通过xinle_is_miniprogram识别用户是否在小程序中;利用xinle_is_h5判断是否处于H5环境;通过xinle_is_ios和xinle_is_android来分别识别用户设备是否为iOS或安卓系统;使用xinle_is_pc判断用户是否在PC端环境;最后,通过xinle_is_wechat来确认用户是否使用微信浏览器。这些封装方法的运用,使得后端能够更高效地进行环境识别。
    5、除了验证设备环境的相关信息外,系统还专门封装了两个方法,用于便捷地获取设备的具体信息:其一是 xinle_is_ip 方法,该方法用于获取当前客户端的IP地址。由于实际场景中客户端的IP地址可能是IPv4、IPv6,或者经过代理服务器的代理IP,因此需要通过该方法进行统一解析和处理,以确保准确获取和识别。其二是 xinle_is_ua 方法,该方法主要用于获取当前客户端的UA(User Agent)信息。通过解析HTTP请求头中的 HTTP_USER_AGENT 字段,可以提取并返回客户端设备的详细UA信息。
    6、新增一个方法xinle_is_device,检测用户设备的类型并返回对应的设备描述。执行流程:判断是否为应用(App) 首先调用 xinle_is_app() 判断当前环境是否为 App(移动应用)。 如果是 App: 再判断是不是 iOS 设备(xinle_is_ios()),如果是则返回 'iPhone APP'。 否则判断是不是安卓设备(xinle_is_android()),如果是则返回 'Android APP'。 判断是否为微信环境 如果不是 App,继续判断是否为微信环境(xinle_is_weixin())。 如果是微信: 再判断是不是微信小程序(xinle_is_miniprogram()),如果是则返回 '微信小程序'。 否则返回 '微信浏览器'。 判断是否为 H5 移动端 如果不是微信环境,继续判断是否为 H5(移动网页,xinle_is_h5())。 如果是 H5: 判断是不是 iOS 设备(xinle_is_ios()),如果是则返回 'iPhone 移动端'。 否则判断是不是安卓设备(xinle_is_android()),如果是则返回 'Android 移动端'。 如果都不是,返回 'H5 浏览器'。 判断是否为 PC 端 如果不是 H5,继续判断是否为 PC 端(xinle_is_pc())。 如果是,则返回 'PC 电脑端'。 默认返回值 如果以上所有判断都不成立,则返回 '未知设备',作为兜底。
    7、新增xinle_is_security方法,用户验证用户的设备的安全性:基础检查 首先获取当前登录用户ID(xinle_is_login())。 如果用户未登录,或指纹信息(xinle_is_fingerprint())为空或无效,则直接返回 false,表示安全验证不通过。 获取安全信息 通过用户ID,从数据库(xinle_query_sql('xinle_security', $user_id))查询该用户的安全信息。 如果查询不到安全信息,返回 false。 优先检查IP匹配 如果数据库中的安全信息IP($security['ip'])和当前访问IP(xinle_is_ip())完全一致,则直接通过验证,返回 true。 设备类型特定检查 获取当前指纹信息(xinle_is_fingerprint())。 根据不同的设备类型进行对应的指纹比对: App环境 如果是 App,先检查 Cookie 中是否有 uuid 字段,且数据库中的 uuid 是否与其一致。如果不一致,直接返回 false。 如果一致,再比对数据库中的 app_fingerprint 和当前指纹是否一致,返回比对结果。 微信环境 如果是微信,直接比对数据库中的 wx_fingerprint 和当前指纹是否一致,返回比对结果。 H5移动端环境 如果是 H5,直接比对数据库中的 h5_fingerprint 和当前指纹是否一致,返回比对结果。 PC环境 如果是 PC,直接比对数据库中的 pc_fingerprint 和当前指纹是否一致,返回比对结果。 未知设备类型 如果设备类型无法识别,或者以上所有情况都不满足,则返回 false,表示安全验证失败。
    8、后端在处理指纹事件的时候,把当前用户的各种环境信息、设备信息、安全状态等,统一赋值到 $user 数组中。$user['is_security'] 是否通过指纹安全校验(调用 xinle_is_security(),返回布尔值)。 $user['is_app'] 当前是否为 APP 环境(调用 xinle_is_app(),返回布尔值)。 $user['is_h5'] 当前是否为 H5(移动端网页)环境(调用 xinle_is_h5(),返回布尔值)。 $user['is_weiixn'] 当前是否为微信环境(包括微信浏览器和微信小程序,调用 xinle_is_weixin(),返回布尔值)。 注意拼写应为 is_weixin。 $user['is_ios'] 当前是否为 iOS 环境(调用 xinle_is_ios(),返回布尔值,通常包含 iOS APP 和 iOS H5)。 $user['is_android'] 当前是否为安卓环境(调用 xinle_is_android(),返回布尔值,通常包含安卓APP和安卓H5)。 $user['is_pc'] 当前是否为PC端环境(调用 xinle_is_pc(),返回布尔值)。 $user['is_miniprogram'] 当前是否为微信小程序环境(调用 xinle_is_miniprogram(),返回布尔值)。 $user['ip'] 当前客户端IP地址(调用 xinle_is_ip(),返回字符串)。 $user['ua'] 当前客户端的 User-Agent 信息(调用 xinle_is_ua(),返回字符串)。 $user['device'] 当前设备的类型描述(调用 xinle_is_device(),返回字符串,如“iPhone”、“Android”、“PC”等)。 $user['fingerprint_time'] 指纹采集的时间戳(当前服务器时间,格式为“Y-m-d H:i:s”)。
    9、为了提高获取用户资料信息的效率,优化系统性能,减少SQL请求量,新增了一个名为 xinle_is_profile 的方法,用于一次性获取用户的完整资料。该方法需要传递一个固定参数【user_id:指定用户的UID】,如果该参数为空,则方法会直接返回 false,避免无效的处理逻辑。当 user_id 不为空时,方法会初始化一个 profile 数组,并通过一系列内置方法逐步填充用户的详细信息,包括但不限于以下内容:用户ID(user_id)、昵称(nickname)、头像URL(avatar_url)、头像HTML代码(avatar_html)、是否为管理员(is_admin)、是否绑定手机号(is_user_phone)、是否绑定邮箱(is_user_email)、是否绑定微信(is_user_weixin)、用户是否已注册(is_user_registered)、用户是否已登录(is_user_login)、是否通过认证(is_verify)、认证HTML代码(verify_html)、是否获取手机号权限(is_get_phone)、是否获取邮箱权限(is_get_email)等。通过这种方式,能够在单次调用中获取用户的完整信息,减少频繁的SQL查询操作,提升数据获取的整体效率,同时为后续的业务逻辑处理提供更加便捷的支持。
    10、在xinle_is_profile方法中,新增了Redis缓存功能,以提升系统性能。具体实现过程中,首先构建了一个键名【user_profile:' . user_id】,用于标识每个用户的缓存数据。接着,检查uncache参数的状态:如果为true,则禁用缓存功能,直接获取最新的用户资料。如果uncache为false,会调用get_redis_meta方法来检查缓存是否已经存在。如果缓存数据存在,则直接返回缓存结果,避免不必要的重复计算;如果缓存数据不存在,将通过内置方法获取用户资料,并将其结果缓存到Redis中,设置缓存有效期为30天。为了便于区分缓存的数据,每次写入Redis时,会在数据数组中添加一个名为cache的字段,其值为当前的时间日期,这样可以清楚地知道缓存的生成时间。通过这种方式,有效地提高了用户资料的获取效率,同时也为后续的缓存管理提供了便利。
    11、xinle_is_profile 方法默认设置了30天的缓存时间,其缓存的刷新机制是通过 xinle_update_user_meta_hook 钩子来实现的。当用户的以下元字段发生变动时(包括 phone、avatar_url、weixin_uid、email、verify、admin),系统会触发对应的 HOOK 钩子,随后调用 delete_redis_meta 方法来移除与用户相关的 user_profile 缓存数据。这样一来,用户的缓存资料便会被同步清除,确保数据的实时性和准确性。在缓存被移除后,下一次的请求将直接通过 wpdb 数据库查询最新数据,而不是读取此前已缓存的内容
  • 0
    小小乐lv.2实名用户
    2025年8月29日
    1、移动端首页新增自定义meta字段选项:width=device-width:页面宽度与设备屏幕宽度相同,保证自适应。 initial-scale=1:初始缩放比例为1(即页面初始加载时不缩放)。 maximum-scale=1:用户可缩放的最大比例为1(即不能放大)。 minimum-scale=1:用户可缩放的最小比例为1(即不能缩小)。 user-scalable=no:禁止用户缩放页面(双指缩放等无效)。 viewport-fit=cover:针对 iPhone X 及以上带“刘海屏”的设备,页面内容会延伸至屏幕的安全区域,适配全屏显示。viewport-fit:有 auto(默认)、contain(内容不会被安全区遮挡)、cover(内容延伸到整个屏幕)。允许网页以“Web App”模式(即全屏模式)运行,隐藏 Safari 浏览器的工具栏和地址栏。
    2、为了确保移动端的配色一致性,会通过: root进行如下参数的后台接管配置:--xinle_color 主题主色,用于整个网站的主要颜色。 获取方式:xinle_get_option('xinle_mobile_defalut_color') --xinle-navbar-bg 导航栏背景色。 获取方式与主色一致。 --xinle-navbar-text-color 导航栏文字颜色。 获取方式:xinle_get_option('xinle_mobile_defalut_color_text') --f7-tabbar-link-active-color 底部 TabBar 激活时的链接颜色(活跃状态)。 获取方式与主色一致。 --f7-navbar-link-color 导航栏链接文字颜色。 获取方式与导航栏文字颜色一致。 --f7-navbar-font-size 导航栏字体大小,单位为 vw(相对于视口宽度)。 --f7-bars-text-color 所有 bars(导航栏、工具栏等)上的文字颜色。 获取方式与导航栏文字颜色一致。 --f7-toolbar-height 底部菜单栏高度,固定为 49px。 --f7-page-bg-color 页面背景颜色。 获取方式:xinle_get_option('xinle_mobile_defalut_page_bg_color’)。
    3、APP初始化首页的时候,会通过后台获取如下配置:获取当前登录用户的ID,并赋值给 $user_id。 $current_user 通常是通过 wp_get_current_user() 得到的用户对象。通过自定义函数 xinle_get_option 获取 WordPress 后台的“移动端Tab栏配置”选项,赋值给 $tab_config。 这个配置一般是控制移动端底部导航栏(TabBar)的内容和结构。通过 xinle_get_option 获取“页面配置”选项(一般为数组或对象),然后用 json_encode 转换为 JSON 字符串,赋值给 $routesJson。 这个 JSON 数据会传递给前端 JavaScript,用于动态渲染页面或路由。调用自定义函数 xinle_is_chat_list() 获取聊天会话消息列表。通常返回当前用户的聊天会话数据。
    4、APP端的视图窗口现已通过配置项 xinle_mobile_tab_config 进行读取和动态生成,该配置项能够灵活定义视图的相关属性并对其行为进行控制。目前支持的参数包括以下几项:key 用于标识视图的唯一性,以确保不同视图之间的区分;is_login 用于设置视图的访问权限,若该参数为真,则该视图仅对登录用户开放,并会强制要求用户完成登录操作;icon 指定视图的菜单图标,支持自定义图标样式以增强视觉效果;name 为视图的名称,用于显示在菜单或其他位置,帮助用户快速识别视图功能;active 定义视图的类名,主要用于调整样式或交互效果。
    5、视图主容器的处理,读取$tab_config(移动端底部Tab栏的配置数组),每次循环处理一个Tab页面。获取每个Tab的 key 和 page_name。 通过 xinle_is_config 获取该Tab的详细配置。 根据配置的布尔值,生成对应的class类名字符串(如隐藏导航栏、顶部下拉刷新、无限加载、需要登录等)。 只有第一个Tab设置为激活状态(tab-active)。 如果配置了隐藏头部,则加上 hide 类。输出每个Tab的最外层 div,ID为Tab的key,class为 view tab,如果是第一个Tab还会带 tab-active。 里面有页面容器、顶部导航栏。 导航栏左侧、右侧、标题都可以通过后台配置自定义内容(支持WordPress的shortcode)。页面内容区的class会根据配置动态组合,比如支持下拉刷新(ptr-content)、无限加载(infinite-scroll-content)、需要登录(is_login)等。
    6、主视图功能进一步优化,现已支持通过后台灵活设置更多参数,以满足不同场景的需求。具体来说,若当前Tab页配置了顶部下拉刷新功能,则会自动输出下拉刷新动画的HTML结构,提供更直观的交互体验;如果后台已指定该Tab页的具体页面文件地址(例如 /wp-content/themes/你的主题/xxx.php),系统将自动require该文件内容,完成页面内容的集成展示,确保模块加载的便捷性与一致性。而对于未配置具体页面地址的情况,则会智能显示一个加载动画以及提示信息,例如“后台未设定模块地址”,并附带一个跳转链接,方便用户快速定位到后台设置页面进行配置调整。最后,系统会自动关闭HTML标签,并自增变量,顺畅进入下一个Tab页的循环处理,确保每个模块都能按照设定逻辑高效加载与呈现。
    7、当前,APP页面的所有组件均通过后台进行配置管理。在首页初始化时,系统会通过读取xinle_page_config来生成相应的页面。在后台配置页面时,需要设置以下参数:首先是route['key'],即页面组件的唯一标识符;其次是route['componentUrl'],这是页面的读取路径,必须经过标准化的Framework7构建才能被识别。此外,还有route['admin'],此参数用于限定页面访问权限,仅允许管理员访问;最后是route['login'],该参数确保页面仅在用户登录后才能访问。为了确保页面能够正确构建并响应,所有页面组件都必须在后台进行适当配置,否则前端将无法正常访问。
    8、动态生成 Framework7 路由配置的处理逻辑如下:首选通过DOMContentLoaded确保所有 DOM 元素加载完成后再执行代码,避免未加载导致的报错。变量定义visitedPages:用于记录已访问页面(目前没用到,可用于后续功能如页面缓存等)。 app_path:存储移动端页面的基础路径,方便后续拼接组件路径。 routesData:从 PHP 传来的路由 JSON 数据,包含每个页面的配置(如 key、componentUrl、login、admin 等)。遍历每个路由配置,生成 Framework7 的路由对象数组。 path:每个页面的访问路径。 componentUrl:组件页面的实际路径。 beforeEnter:路由进入前的钩子函数,用于权限校验。
    9、Framework7路由配置现在支持权限检测处理,系统会通过beforeEnter来检测当前页面组件访问权限:如果当前路由需要登录(login==true),且用户没登录(!xinle.is_login),则: 调用登录函数 xinle_login()。 阻止跳转,reject()如果页面需要管理员权限,且未登录,先强制登录。如果已登录但不是管理员,则弹窗提示无权访问,并阻止跳转。所有权限校验通过后,允许页面跳转。注:对每个页面实现登录和管理员权限控制,无权限时自动拦截跳转,并弹窗或跳转登录。支持后续扩展页面缓存、跳转方向等功能。
    10、APP端的初始化工作:1. 绑定应用根节点 el: '#app' Framework7 会把页面的主要内容绑定到这个元素( <div id="app"></div>)。 2. 基础配置 name: '奇峰药业' 应用名称。 theme: 'ios' 使用 iOS 风格主题。 infiniteScroll: true 启用无限滚动。 panel: { swipe: true } 允许侧边栏通过滑动打开。 view: { pushState: true, iosSwipeBack: true } pushState: true 启用浏览器历史记录(地址栏变化)。 iosSwipeBack: true 启用 iOS 风格的左滑返回上一页。 3. 路由配置 routes: [ ... ] 路由规则数组,决定页面跳转和内容加载的方式。 3.1. 动态路由(...routes) 由你之前的代码动态生成,每个路由都包含权限校验(登录、管理员)、页面路径和组件路径。 跳转到这些页面时,都会先执行 beforeEnter 权限验证。
    11、在应用实例初始化阶段,当用户通过点击链接或导航菜单跳转页面时,Framework7将按照以下流程进行处理:首先,根据用户跳转的路径匹配对应的路由配置,并执行beforeEnter权限校验(如果设置了相关逻辑),判断用户是否需要登录或具备管理员权限等条件。若权限不满足,系统将弹窗提示或跳转至登录页面,以阻止当前页面跳转操作。权限通过后,系统会加载对应的页面组件。对于未匹配的路径,系统会通过通配符路由进行处理,展示404页面或加载指定的外部页面。此外启用了pushState功能,浏览器地址栏会随着页面跳转动态更新。
  • 0
    小小乐lv.2实名用户
    2025年8月28日
    1、移动端目前实现了对浏览器返回事件(popstate)的监听,利用history.back()、history.pushState()等API对历史记录进行操作时,会触发popstate事件,从而执行绑定的回调函数,最终调用xinle_page_back()方法以完成页面返回的逻辑处理。而在APP环境下(通过检测userAgent中是否包含Html5Plus判断),不会绑定页面上的.back按钮事件,而是通过APP的原生返回事件进行处理,确保在不同环境下都能实现稳定的返回功能。
    2、xinle_page_back负责页面路由后退返回机制,具体的执行流程如下:检查页面上是否存在 layui 的遮罩层(即 .layui-m-layershade)。 如果存在遮罩层,优先关闭所有 layer 弹窗(layer.closeAll()),并终止后续返回操作(return false;)。 这样可以防止用户误操作导致弹窗未关闭直接跳转页面。 首页特殊处理: 如果当前用户处于首页(user.is_home 为 true),可以在这里做特殊处理(如弹窗提示或日志记录)。 获取当前视图对象: 获取框架下当前的视图实例(app.views.current),通常用于 SPA 或前端路由管理框架。 判断参数并返回页面: 如果传入了 url 参数,则直接返回到指定页面,并强制刷新(force: true)。 如果没有传入 url,则默认返回到上一个页面。
    3、安卓返回键处理(plusready 事件) 1. 监听 APP 环境准备就绪 通过 document.addEventListener('plusready', ...),确保代码只在 APP(Html5Plus)环境下运行。 2. 获取当前 Webview 使用 plus.webview.currentWebview() 获取当前页面的 Webview 实例,后续返回操作都基于此 Webview。 3. 监听安卓物理返回键 plus.key.addEventListener('backbutton', ...) 监听安卓设备的物理返回键事件。 4. 判断 Webview 是否可以后退 webview.canBack(function(e){...}) 判断当前 Webview 是否有历史记录可返回。 5. 处理流程如下: a. 如果当前在首页(user.is_home) 直接调用 main.moveTaskToBack(false),把 APP 退到后台(返回桌面),而不是直接退出 APP。 b. 如果有弹窗 检查是否有 .modal-overlay-visible 或 .login-screen.modal-in 元素(即页面有弹窗)。 如果有,优先关闭所有弹窗(myApp.closeModal()),并移除 .popup-overlay 的某些 class(此处建议补全 class 名称)。 c. 如果有 Fancybox 弹窗 检查 .fancybox-is-open,如果有,关闭 Fancybox 弹窗($.fancybox.close())。 d. 否则正常页面后退 如果 Webview 可以后退(e.canBack),执行 webview.back() 返回上一页。 如果不能后退(已到最顶层页面),同样调用 main.moveTaskToBack(false),让 APP 退到后台。
    4、移动端目前在页面初始化时,会执行一系列页面路由监听操作,以确保用户操作和页面状态的实时响应。这些监听事件包括以下几种:pageInit(页面初始化),用于加载页面初始内容及相关逻辑;routeBack(页面行为:后退),当用户执行页面后退操作时触发;routeChange(页面行为:前进),响应用户的页面前进操作;pageBeforeIn(页面即将进入),在页面正式进入前预先处理相关逻辑;pageAfterIn(页面已进入),用于处理页面进入后的状态更新;pageBeforeOut(页面即将离开),在页面离开前执行清理或保存操作;pageAfterOut(页面已离开),确保页面离开后的后续逻辑处理;pageBeforeRemove(页面即将被移除),用于监听页面被移除前的最后处理环节。这些事件的组合使用能够有效提升页面切换的流畅性和用户体验,同时为开发者提供灵活的页面状态管理能力。
    5、移动端在触发(pageBeforeIn:页面即将进入时)会触发以下处理:判断当前页面是不是首页或主Tab页面(通过判断页面名称是在一个预设的数组里)。 如果是首页或Tab页面: 会把浏览器地址栏的路径重置为根路径 /,但不会刷新页面,这样可以避免路由混乱; 同时把一个全局变量(比如 user.is_home)设置为 true,表示当前用户正处于首页; 然后调用一个初始化首页的函数,把首页内容重新渲染出来,确保首页功能正常。 如果不是首页或Tab页面: 只把那个全局变量设置为 false,标记当前页面不是首页。
    6、移动端路由监听:当页面完成切换并“进入”后,会自动触发 pageAfterIn 事件。 2. 获取并保存当前页面内容区域 代码通过 $('.page-content.' + page.name + '_content') 获取当前页面的内容区域,并赋值给全局变量 user.page_content,方便后续操作或渲染。 3. 打印调试信息 在控制台输出:“页面已进入:” 以及页面的名称和路由地址,方便开发时定位和调试当前页面状态。 4. 记录页面历史路由 通过 page.route.url 获取当前页面的路由地址(URL)。 判断该 URL 是否已经存在于 page_history 数组中: 如果不存在,则将当前页面的 URL 添加到 page_history,用于记录用户访问过的页面,方便后续做页面回退、历史导航等操作。
    7、移动端路由监听:当页面即将被销毁、移除(比如返回、跳转到其他页面等)时,自动触发 pageBeforeRemove 事件。 2. 控制台打印调试信息 在控制台输出:“页面即将被移除:” 以及当前页面的名称,方便开发过程中追踪页面的生命周期。 3. 从历史记录中移除当前页面的路由 获取当前页面的路由地址(page.route.url),赋值给变量 pageUrl。 在 page_history 数组中查找该 URL 的位置(indexOf)。 如果找到了(index !== -1),说明历史记录中有这个页面的路由: 通过 splice 方法把这个路由地址从 page_history 数组中删除,保持历史记录的正确性,避免重复和无效数据。
    8、当移动端首页的 DOM 加载完成后(即触发 jQuery 的 $(document).ready() 方法),开始执行预设的函数内容以确保页面功能的正常运行。首先,初始化聊天会话页面,通过调用 xinle_update_view_messages() 方法实现聊天列表的加载与消息内容的显示,同时支持页面的自动刷新,以便用户在进入页面时即可看到最新的聊天信息,优化交互体验。接着,处理 URL 哈希值以实现页面跳转逻辑。具体流程如下:通过 window.location.hash 获取当前窗口的哈希值(如 #chat),然后去掉哈希符号 #,提取实际路径(如 chat)。为了统一页面入口路径并简化后续的页面管理,使用 window.history.pushState(null, null, '/') 将浏览器地址栏的路径设置为根路径 /,这一操作不会触发页面刷新。最后,根据处理后的路径调用 xinle_page_open(path) 方法,加载对应的页面内容或模块。
    9、APP端新增页面路由访问事件 xinle_page_open,负责处理页面访问请求,确保页面切换逻辑高效且流畅。其执行流程如下:首先,函数会获取当前视图对象和路由管理器,这两个核心对象是后续页面操作的基础,确保所有页面操作都基于当前视图和路由进行。随后,函数会检查自定义的历史记录数组 page_history,判断目标页面是否已经打开过。如果发现该页面 URL 已存在于历史记录中,则直接调用 xinle_page_back(url) 返回到之前打开的页面,避免重复打开,并终止函数执行。接着,函数会进一步判断当前页面的 URL 是否与目标页面一致,如果当前页面就是用户要打开的页面,则仅输出一条警告信息,避免页面重复加载,提升性能。
    如果目标页面不在当前页面但已存在于路由的历史记录中,函数会采取三步处理措施:首先,删除页面残留的 DOM 元素,避免内容冲突或重复;其次,从路由历史记录中移除该页面,确保历史记录的准确性;最后,如果该页面是动态注册的路由,则尝试移除相关路由配置(若移除失败会输出警告信息)。在完成上述检查与清理后,函数将通过路由的导航方法 navigate 打开目标页面,并传递相关参数(如动画效果、回调函数等),以实现页面的顺利切换。
    10、APP端新增了一个用于刷新当前页面的路由处理方法(xinle_page_refresh),其执行流程设计如下:首先,通过 app.views.current 获取当前激活的视图对象(View),在 Framework7 框架下,通常只有一个主视图,这一步确保了操作的目标视图是当前正在使用的视图。接着,方法会判断是否传入了 url 参数:如果传入了 url,则将其作为需要刷新的目标页面地址;如果未传入 url,则会自动获取当前路由对象的 URL,将当前页面的地址作为默认刷新目标。随后,方法调用视图对象的路由器(View.router.navigate())来重新加载目标页面,并传递两个关键参数——reloadCurrent: true 和 ignoreCache: true。其中,reloadCurrent: true 强制重新加载当前页面,而非简单地跳转;ignoreCache: true 则确保忽略页面缓存,从服务器端重新获取页面内容,以保证页面内容的最新状态。刷新操作完成后,无论是当前页面还是指定的其他页面,都会根据目标 URL 重新加载,用户看到的始终是最新的页面内容。
    11、宫论APP端的页面路由处理已实现全面监听,对于页面的访问、后退、销毁以及初始化等操作均设置了对应的监听器以执行相应的响应处理。在页面请求阶段,通过xinle_page_open方法接管并执行处理;当用户触发页面后退时,则由xinle_page_back方法负责响应;而页面刷新操作则交由xinle_page_refresh方法进行处理。整个路由的响应逻辑完全依托于Framework7框架进行管理,确保页面切换的流畅性与稳定性。
  • 0
    小小乐lv.2实名用户
    2025年8月27日
    1、在APP端完成了xc_hook_app_plus初始化行为动作后,系统会自动触发【xc_hook_app_webview】监听器。由于当前宫论APP采用了PWA模式运行,webviews对象的行为需要进行全局监听处理,以确保页面事件能够根据实际需求随时进行动态调整。为此,系统专门封装了一个独立的方法,用于统一管理和控制webviews对象的监听逻辑。
    2、当触发 xc_hook_app_webview 时,系统会通过 plus.webview.currentWebview() 获取当前页面的 webviews 对象,并将其赋值到全局变量 webviews 中,方便后续页面直接通过该全局对象进行操作和处理。目前,webviews 已新增对外部链接点击(overrideUrlLoading)的处理逻辑。当用户在 webviews 中点击链接时,系统会监听该链接是否属于宫论内部链接。如果检测到不是宫论链接,则会触发拦截机制,禁止外部跳转,确保所有的跳转操作均通过系统内置方法处理,进一步提升安全性和控制力。此外,系统还对以 "tel:" 开头的 URL 进行专门监听,通过调用 plus.runtime.openURL 实现页面跳转,并强制跳转到手机的拨号界面,便于用户直接进行电话拨打操作。
    3、新增方法plus_open_url,专门用于处理APP端的页面跳转逻辑,主要覆盖了APP启动图跳转以及消息通知跳转的场景。该方法首先会通过xinle_isplus对用户环境进行验证,确认是否处于plus环境,如果验证结果为非plus环境,则直接返回false,避免后续操作。接下来,对传入的type变量进行判断,根据不同类型执行对应的跳转策略:如果type为webviews,则调用plus.runtime.openWeb,通过内置的WebSocket视图窗口实现页面跳转;如果type为web,则使用plus.runtime.openURL直接打开浏览器链接;而当type为page时,则触发内置的页面访问处理器xinle_page_open,完成APP内部页面的跳转。此外,为了优化移动端页面的用户体验,页面跳转过程中还支持通过F7框架实现流畅的移动端页面加载效果。
    4、APP端计划新增支持多种登录方式,包括原生手机一键登录、iOS苹果登录以及微信登录等。这些登录功能均通过对应的SDK进行调用。为提升后续维护效率和统一管理,决定封装一个方法——plus_login_auth,用于处理登录相关的逻辑。该方法不仅包括鉴权、SDK调用,还负责API对象的统一管理。使用时需传递一个type变量,用以标识登录请求的来源,例如weixin表示微信登录,univerify表示一键登录。在具体执行业务逻辑时,会通过xinle_isplus进行校验,判断当前客户端是否处于APP环境。如果校验未通过,则直接返回错误,确保登录流程的安全性和规范性。
    5、新增方法 plus_check_app,用于检测当前设备是否已安装指定的应用程序。此方法需要传递应用的包名或通用名称作为参数,系统将通过内置查询机制进行判断。如果检测到应用已安装,则返回 true;若未安装,则返回 false。此功能尤其适用于某些特定场景,例如调用支付宝进行支付时,若用户设备上未安装支付宝应用,则系统会主动拦截相关请求,并提示用户安装对应的应用程序以解决问题。通过这种方式,能够有效提升用户操作的流畅性,同时避免因缺少必要应用而导致的功能异常或用户体验下降。
    6、plus_login_auth已支持微信APP登录请求,具体执行流程如下:判断当前环境是否支持微信登录 首先判断 type == 'weixin',说明本次请求是微信登录。 使用 plus_check_app(type) 检查当前设备是否安装了微信客户端。 如果未安装,弹出提示“微信客户端未安装,无法使用”,流程终止。 检查微信SDK是否初始化 判断 app_login_auth['weixin'] 是否已初始化。 如果未初始化,弹出提示“未初始化微信SDK,无法发起登录鉴权”,流程终止。 发起微信授权登录 调用 app_login_auth['weixin'].authorize(...) 方法,开始微信授权流程。 授权请求携带参数: scope: 'snsapi_userinfo' state: 'authorize test' appid: xc.wechat_app_id 处理授权结果 授权成功回调(第一个 function 参数): 显示“登录中”加载提示。 输出授权成功的 code 到控制台。 向后端接口 xc.global_url + "/api.php" 发送 POST 请求,携带参数: type: 'xc_app_login_weixin' code: e.code 后端返回结果后,隐藏加载提示,并根据返回内容进行处理: 如果 msg.code == 0(登录成功): 如果返回的 msg.link 存在,说明需要注册账户: 弹出“进入注册流程”提示。 1秒后跳转到 msg.link 注册页面。 如果没有 msg.link,说明登录成功: 执行 xc_login_ok_hook(msg),进行登录成功后的处理(如保存用户信息、跳转主页等)。 输出返回内容到控制台。 如果 msg.code != 0(登录失败): 弹出失败提示,输出返回内容到控制台。 授权失败回调(第二个 function 参数): 输出授权失败信息到控制台。 弹出“授权失败”提示,终止流程。 流程结束。
    7、plus_login_auth已支持univerify(一键登录请求),具体执行流程如下:判断 app_login_auth['univerify'] 是否存在,或者 univerify_login_error 是否被定义。 如果 univerify_login_error 被定义,弹出其内容作为提示。 否则提示“当前设备不支持一键登录”。 以上任一条件满足,流程终止。 用户协议和隐私协议检测 通过 xinle_is_config 方法分别检测用户协议和隐私协议配置,便于后续展示。 控制台输出用户协议的链接。 设置协议默认勾选状态 默认情况下,defaultCheckBoxState 设为 true(已勾选)。 如果设备厂商为“Huawei”,则设为 false(未勾选)。 发起一键登录授权 调用 app_login_auth['univerify'].login 方法,打开一键登录授权界面。 登录成功后回调,拿到授权信息: openid:用户唯一标识 access_token:访问令牌 控制台输出登录成功的 openid 和 access_token。 显示“正在处理登录请求”的等待弹窗。 与后端交互进行登录处理 通过 AJAX POST 请求将 openid 和 access_token 发送到后端 /login.php,请求类型为 xinle_app_login_univerify。 后端返回数据后,关闭等待弹窗,并关闭授权界面。 处理后端返回结果 如果 msg.code == 0(登录或注册成功): 如果 msg.register 存在,说明新账户注册成功,弹窗提示“账户注册成功”,1.5秒后刷新首页。 如果没有 msg.register,说明直接登录成功,弹窗提示“账户登录成功”,1.5秒后刷新首页。
    8、univerify(一键登录)功能现已全面升级,支持通过univerifyStyle直接自定义页面样式。此前,样式调整需要通过APP进行初始化配置,每次修改都需发布新的APP版本才能生效,导致维护和管理流程较为繁琐。而现在,系统引入了内置的PLUS事件机制,配置调整可以实时生效。
    9、集成了plus事件中的plus_camera功能,实现了调用手机系统摄像头进行拍照或录制视频的操作。该方法需要传递两个关键变量:filter和time。其中,filter用于指定操作类型,支持两种模式——“image”和“video”,分别对应拍照图片和录制视频;time为可选参数,用于设置录制视频的时长,最大支持60秒,可根据实际需求进行自定义。在调用摄像头功能前,系统会先通过xinle_isplus验证用户是否处于APP环境中,若用户不在APP环境,则会返回对应的错误提示;若处于APP环境中,则会进一步通过plus_is_permission检测用户是否已授予应用所需权限。如果用户未开放摄像头权限,系统将终止操作并返回相应的错误信息。
    10、通过plus_camera发起的拍照的执行流程如下:用摄像头的 captureImage 方法进行拍照。 如果拍照成功: 关闭之前可能存在的权限提示(Toast)。 控制台打印照片的路径,方便调试。 用 H5+ 的文件系统API解析照片路径,获取文件对象。 读取这个文件内容为base64格式。 将base64数据转成Blob对象,再进行上传操作(通过自定义函数)。 如果解析路径或读取文件失败,会关闭提示,并输出错误信息。 如果拍照失败: 关闭权限提示(Toast)。 输出拍照失败的原因。 如果失败原因是“没有权限”,就弹出一个对话框,询问用户是否前往手机设置页面开启相机权限。 用户同意就跳转到设置页面。 用户取消就不做处理。
    11、APP端新增了一个名为plus_gallery的方法,用于打开系统相册以选择图片或视频。该方法需要传递两个关键变量:filter用于指定选择类型(视频或图片,默认值为图片);number用于指定选择的数量,若选择视频则数量固定为1,若选择图片则可以自由设置,但受系统限制,最多可选择9张图片。此功能首先会通过xinle_isplus方法验证当前环境是否为APP端,若检测到不在APP环境内,则直接返回错误信息,终止操作。随后,系统会通过plus_is_permission方法检测用户是否已授予应用所需权限。如果用户未开启相册权限,操作将无法继续,系统会返回相应的错误提示,确保流程的安全性和用户隐私的保护。
  • 0
    小小乐lv.2实名用户
    2025年8月26日
    1、在用户打开APP时,系统会执行一个名为 plusReady 的初始化动作,其主要功能是定义一个全局变量 app_plus,并将其默认值设置为 false,以此假定当前运行环境不支持 plus(即非APP环境)。当页面加载时,系统会调用 plusReady(callback) 方法进行进一步处理。如果此时 window.plus 已存在,则表明 plus 环境已经准备就绪,系统会立即将 app_plus 设置为 true,并执行传入的回调函数;如果 window.plus 尚未存在,则系统会监听 plusready 事件,当事件触发时,同样将 app_plus 设置为 true,然后执行回调函数。通过 app_plus 变量,后续可以方便地验证用户是否处于 APP 环境:若值为 true,则说明当前为 APP 环境;若值为 false,则表示非APP环境。
    2、一旦APP完成初始化,系统将通过plusReady回调触发一个关键事件:xc_hook_app_plus。此方法主要负责处理APP首次启动时的初始化操作。首先,系统会检测当前用户是否已登录。如果用户已登录,则会通过plus.push.getClientInfo().clientid获取用户的推送标识码,同时利用plus.device.getDeviceId()获取设备的唯一标识码。接下来,系统会发起一个与后端交互的AJAX请求,将上述两个参数传递到xc_hook_app_plus接口进行处理。其中clientid是用户推送唯一标识,触发APP通知消息需要用到这个。getDeviceId则是设备标识,客户端的身份。
    3、后端API接口收到UUID和clientid数据包后,会执行如下处理:首程序会判断当前用户ID是否为空。如果为空,说明没有用户登录或识别,程序会直接结束,不做任何操作。获取客户端标识信息程序会从前端提交的数据中获取clientid和uuid两个值,这两个值通常用于标识设备或客户端。如果这两个值没有传递,则默认为空。处理clientid绑定关系如果获取到clientid,程序会检查是否有其他用户已经绑定了相同的clientid。如果查到有其他用户绑定了这个clientid,而且不是当前用户,则会把这些用户的clientid信息删除,确保这个clientid只属于当前用户。然后,程序会将clientid写入当前用户的资料,并同时更新到浏览器的cookie里,方便前端后续使用。处理uuid绑定关系如果获取到uuid,程序会检查是否有其他用户已经绑定了相同的uuid。如果查到有其他用户绑定了这个uuid,而且不是当前用户,则会把这些用户的uuid信息删除,确保这个uuid只属于当前用户。然后,程序会将uuid写入当前用户的资料,并同时更新到浏览器的cookie里。
    4、新增了xinle_fingerprint_update钩子,专门负责更新用户指纹设备信息。由于宫论业务涉及到第三方交易体系,对用户客户端的管控要求极为严格,因此每个客户端和设备的敏感操作都会被记录其指纹信息,以确保操作的安全性和可追溯性。其中,APP端通过UUID记录设备指纹,而其他客户端则通过浏览器指纹进行追踪。为满足这一需求,封装了一个HOOK用于处理指纹信息的更新动作,该钩子在执行更新时不仅需要确保操作的安全性和可靠性,还需具备一定的灵活性,以应对复杂的使用场景。只有在满足所有安全验证条件的情况下,更新动作才能被成功触发,从而进一步强化对用户敏感操作的防护机制。
    5、新增了数据表 xinle_security,该表用于专门处理设备指纹信息的存储与管理。该表的设计旨在支持多种终端设备的指纹数据记录,便于后续的数据分析和风控处理。其结构及参数设置如下:
    * id:作为表的主键,类型为 BIGINT UNSIGNED,并设置为自动递增,确保每条记录具有唯一性。
    * ip:用于存储用户的 IP 地址,支持 IPv4 和 IPv6 格式,增强了对多种网络环境的兼容性。
    * time:记录每条数据的创建时间,默认值为当前时间,便于追踪数据的生成时刻。
    * update_time:记录每条数据的最后更新时间,默认值为当前时间,并设置为在数据更新时自动刷新,确保记录时间的实时性。
    * h5_fingerprint:可选字段,用于存储 H5 端设备的指纹信息,适配移动端浏览器场景。
    * wx_fingerprint:可选字段,用于存储微信端设备的指纹信息,支持微信小程序或内嵌浏览器的场景。
    * app_fingerprint:可选字段,用于存储独立 APP 的设备指纹信息,覆盖移动应用的场景。
    * pc_fingerprint:可选字段,用于存储 PC 端设备的指纹信息,适配桌面浏览器或客户端应用的场景。
    * uuid:可选字段,存储设备的唯一标识,用于区分不同设备,进一步提升数据的唯一性和可追溯性。
    6、xinle_fingerprint_update已完成封装,当触发客户端指纹更新请求的时候,会执行以下动作:首先,定义数据表名为 xinle_security,初始化一个空数组 $security。 获取当前用户ID,如果没有登录,则返回“用户未登录”提示,并结束流程。 会话与指纹获取 检查PHP会话状态,如果未开启,则自动启动Session。 从Cookie中获取 fingerprint(设备指纹)和 uuid(APP设备指纹),如果指纹不存在,则返回“指纹不存在”,流程结束。 收集安全信息 通过函数获取当前用户的IP地址,存入 $security['ip']。 查询数据库中是否已有该用户的指纹记录。 根据访问环境(微信、APP、H5、PC)将指纹分别存入不同字段: 微信环境:wx_fingerprint APP环境:app_fingerprint(并可处理uuid,uuid为APP端独有) H5环境:h5_fingerprint PC环境:pc_fingerprint 如果环境不匹配,返回“环境异常”,流程结束。 如果Cookie里有 uuid,也一并存入 $security['uuid']。 数据库操作:更新或新增指纹记录 如果数据库已存在该用户的指纹记录: 更新指纹信息和更新时间。 如果更新失败,返回“指纹更新失败”,流程结束。 更新成功,返回“更新指纹成功”。 如果数据库不存在该用户的指纹记录: 写入新的指纹信息。 如果写入失败,返回“指纹写入失败”,流程结束。 写入成功,返回“写入指纹成功”。
    7、APP初始化动作(xc_hook_app_plus)在完成uuid和推送标识处理动作后,还会通过 plus.oauth.getServices执行一键登录SDK的初始动作,具体执行流程如下:调用授权服务列表接口 plus.oauth.getServices(function(services) {...}, function(e){...}) 异步获取可用的第三方登录授权服务列表。 2. 遍历服务列表 对返回的 services 数组进行 forEach 遍历。 每个服务对象 obj 按 id 存入 app_login_auth 对象,方便后续调用。 3. 一键登录服务预处理 如果服务ID为 'univerify'(即一键登录服务): 调用 preLogin 方法进行预登录操作。 预登录成功时: 控制台输出“手机一键登录初始化成功”。 记录当前时间 univerify_login_time。 可以显示一键登录选项给用户。 预登录失败时: 控制台输出“初始化一键登录失败”及错误信息。 记录错误信息到 univerify_login_error。 可以选择不显示一键登录或置灰。
    8、在APP初始化阶段,通过获取当前页面的WebView对象来管理开屏窗口(开屏广告页)。开屏窗口的关闭会触发以下操作:版本更新检查根据配置判断是否需要检查APP版本更新,若需要则弹出更新提示或进入更新流程。开屏广告点击跳转记录用户点击广告的信息(时间、链接、类型等),存储在本地。开屏窗口关闭时,校验点击时间是否在20秒内(防止过期或误跳转)。若通过校验,根据点击类型和目标地址完成跳转。跳转后清除记录,避免重复跳转或误操作。防止误操作限制广告点击生效时间为20秒,并清除记录,防止多次点击或误触导致异常跳转。注:通过统一管理开屏窗口,确保版本更新、广告跳转和用户操作的准确性与可靠性。
    9、为了加快下次 APP 启动速度,后端获取的以下数据会通过 app_plus_storage 方法写入手机设备的本地缓存: 启动图配置信息 系统默认背景颜色 版本配置参数 下次启动时,APP会优先读取本地缓存的数据,而不是等待后端响应。这种机制确保启动过程更快、更流畅,同时后端的数据更新仅用于保证下次启动时数据及时生效,而非当前启动直接使用。
    10、宫论APP现已全面支持原生微信支付和支付宝支付功能。在启动APP时,系统会自动调用 plus.payment.getChannels 方法,以获取设备支持的支付通道列表。该方法能够有效地检测并返回当前设备所支持的支付方式。在获取到支付通道列表后,系统会遍历该列表,并将每个通道对象存储到 app_payment_list 中,确保后续支付操作的便捷性和高效性。接下来,系统会根据具体需求,通过指定支付通道 ID(例如 'desiredChannelId'),进行针对性的初始化操作,从而确保支付功能的正常运行。如果在获取支付通道列表时发生错误,系统会及时捕获并打印日志报错信息。
    11、xc_hook_app_plus完成封装,当APP启动的时候系统会执行以下操作:用户身份验证与设备绑定:确保推送服务和设备信息的唯一性。安全机制强化:通过设备指纹记录和更新,增强风控能力。登录流程优化:集成一键登录服务,简化用户操作。开屏窗口管理:优化广告跳转与版本更新流程,防止误操作。启动性能优化:利用本地缓存加速启动,提升流畅性。支付功能支持:初始化支付通道,满足多样化支付需求。
  • 0
    小小乐lv.2实名用户
    2025年8月25日
    1、服务器的PHP版本已经成功升级至8.4的最高版本,这将为APP端接口的后续优化奠定坚实的基础。未来,计划将所有接口迁移至高性能架构,以显著提升并发请求的处理能力,确保在高负载下系统依然稳定运行。由于此次升级跨度较大,需密切关注现有接口的兼容性问题,特别是涉及第三方SDK扩展的部分,必须确保它们能够顺利适配新版本,以避免在生产环境中出现功能异常或性能下降的情况。通过这种全面升级,提高了系统的灵活性和扩展性。
    2、鉴于当前后端并发性能的瓶颈以及前端组件版本较为老旧的问题,宫论APP端的项目将全面升级并脱离现有框架体系。后端的APP请求接口将完全由新版本的程序进行处理,同时为了保障现有功能的平稳过渡,现有的HOOK钩子功能将继续保留并支持。新版本的后端架构将基于【Swoole、Redis、WebSocket、Workerman、PHP8.4】进行全新构建,通过这些技术的结合,进一步提升系统的并发处理能力、运行效率以及稳定性。注:现有的接口请求仍旧保存,但是会逐步过渡到新架构。
    3、服务器的 wwwroot 文件夹中新增了一个名为 APP 的目录,后续所有的 API 接口和前端组件页面都将通过该目录下的主题架构程序进行统一处理。其中前端APP页面架构将选用了 Framework7(版本号 v8.3.4),Framework7是一个专为构建移动端应用程序(包括 iOS 和 Android)而设计的前端框架。Framework7 提供了丰富的原生应用风格 UI 组件和流畅的交互效果,例如滑动菜单、弹窗、标签页等,能够大幅提升用户体验。此外,它在开发 PWA(渐进式 Web 应用)和 Hybrid App(混合应用)方面也表现出色,既能满足现代化移动端开发的需求,又具备高度的灵活性和扩展性。
    4、新程序架构现已成功集成Codestar Framework配置组件,与之前使用的LightSNS主题采用的是相同的配置框架。这一选择是由于我们需要将大量现有配置平滑过渡到新程序中,因此后台设置仍然沿用原有的配置方式,以便于配置的迁移和管理。值得注意的是,此次集成的Codestar Framework版本为2.3.1,采用了内置hook的方式进行挂载。
    5、程序目录架构设计如下:
    * log:日志存储目录,所有系统运行及调试过程中生成的日志文件都会存放于此,方便后续的排查与分析。
    * configure:项目配置文件目录,通过 Codestar 平台集成的后台配置选项也存储于此,便于管理和修改项目的全局配置。
    * mobile:移动端页面组件目录,主要用于集成移动端相关的页面组件,所有 APP 的前端组件均在此目录中构建与维护。
    * api:统一接口管理目录,负责前后端交互的所有请求,集中处理接口的定义、管理及调试,确保数据交互的高效与安全。
    * functions:全局自定义函数与脚本的存放中心,包括 Redis、Swoole 等多种配置及自定义逻辑,提供系统级别的功能支持。
    * assets:前端资源扩展目录,用于存储 JS 和 CSS 文件,所有前端页面的脚本及样式扩展均在此处集中管理,提升代码可维护性与复用性。
    * sdk:第三方扩展包集合目录,所有外部引入的 SDK、工具包和依赖文件均统一存放于此,方便统一管理和更新。
    * admin:后台配置管理目录,用于集中管理后台的所有配置选项,同时内置的一些原生扩展功能也在此目录集成,支持后台的灵活配置和扩展开发
    6、完成了FontAwesome 7.0图标组件的集成工作,APP端的所有图标资源将统一通过该图标库调用。FontAwesome 7.0 拥有多达数千甚至上万个图标资源,能够全面覆盖页面设计中的图标需求,提供了极大的灵活性与丰富性。为优化页面加载性能,图标组件的加载采用异步方式处理,通过 wp_enqueue_script 实现延迟加载机制,确保在页面其他内容完全加载完毕后再执行图标库的加载,有效避免因资源加载过多导致的页面阻塞问题。
    7、新版本的APP在实现上全面采用HTML5+(plus)技术进行交互处理,页面构建方面选择了Framework7框架,以提升开发效率和用户体验。前后端数据交互模式采用分离式设计,确保数据传输的独立性和安全性。对于需要调用原生SDK的功能模块(如APP内支付、地图分享、硬件功能调用、相册读取等),通过plus事件机制发起操作,并通过回调方法实时监控和处理相关响应。这一套设计防范的优势,可以做到前后端分离、离线支持、页面实时更新、跨平台解决方案。
    8、在APP初始化过程中,系统会自动加载【PLUS】脚本库,该脚本库是整个应用底层交互功能的重要核心。所有涉及APP原生交互的请求都会通过该脚本库进行统一集成处理。脚本库内部封装了多种底层事件处理逻辑,例如【APP统一支付功能、统一分享操作、SDK登录请求的管理、手机摄像头与相册的获取操作、设备权限检测与权限集成处理】等。无论是涉及用户操作还是设备交互的功能请求,均通过这一脚本库进行处理,为APP的功能稳定性和交互一致性提供了强有力的支持。
    9、新增方法【xinle_plus_app:前端向APP发送通讯请求】:该函数用于移动端环境下,向 APP 发送事件或数据。只有在 APP 环境下(由 xinle_isplus() 判断),才允许发送;否则会提示“仅支持APP环境操作”。执行流程如下:环境判断: 首先调用 xinle_isplus() 判断当前是否在 APP 环境。 如果不是 APP 环境,则调用 xinle_msg('仅支持APP环境操作') 给用户提示,并返回 false,函数结束。 数据处理: 如果传入的 data 参数为空,则自动赋值为 { type: 'test' },即默认发送类型为 'test' 的事件。 如果传入的 data 参数是字符串类型,则尝试将其解析为 JSON 对象: 如果解析成功,继续后续处理。 如果解析失败,输出“数据格式错误,无法解析 JSON”,并返回 false,函数结束。 发送消息: 调用 uni.postMessage 方法,向 APP 发送消息,消息内容是 { data: data }。这里 uni 应该是 APP 的 JSBridge(通讯桥),负责前端页面和 APP 之间的数据交互。
    10、新增APP端本地数据缓存管理方法(很多数据需要持久化,并且仅限于当前设备,那么就会用到本地缓存):app_plus_storage,执行流程:判断是否为APP环境 首先,调用 xinle_isplus() 判断当前环境是否为APP(H5+环境)。 如果不是APP环境,函数直接返回 false,后续操作不会执行。 2. 根据操作类型进行分支处理 A. 如果操作类型是 update 使用 plus.storage.setItem(key, value) 方法,将指定的键值对存储到本地。 如果该键已存在,则更新其值。 存储没有明确容量限制,但建议单个键值不要超过10Kb。 存储成功后,返回 true。 B. 如果操作类型是 delete 使用 plus.storage.removeItem(key) 方法,删除指定键名及其对应的值。 删除成功后,返回 true。 C. 如果操作类型是 get 使用 plus.storage.getItem(key) 方法,获取指定键名对应的值。 如果获取到值,则返回该值。 如果没有获取到值(即返回 null),则返回 false。 3. 如果操作类型不是上述三种 如果传入的 type 既不是 update、delete、也不是 get,则直接返回 false。 4. 总结 添加/更新操作(update): 成功返回 true。 删除操作(delete): 成功返回 true。 获取操作(get): 成功返回键值,失败返回 false。 其他情况或不是APP环境: 返回 false。
    11、APP涉及到非常多的权限处理,用户可能允许或者禁用,在执行APP某些操作的时候,需要对其进行权限检查,确保其是否具备操作条件,因此单独封装一个方法:plus_is_permission来检测对应的应用权限。permissions:权限键值。如果权限为未确定状态则返回false,否则返回true。该方法主要是依赖调用 plus.navigator.checkPermission(permissions) 检查该权限的当前状态,返回值可能为 'granted'(已授权)、'denied'(拒绝)、'undetermined'(未确定)等。
  • 0
    小小乐lv.2实名用户
    2025年8月22日
    1、在使用add_post_meta函数创建自定义文章字段时,会自动触发一个名为xc_add_post_meta_callback的回调函数。在这个回调函数内部,会执行update_post_redis动作,将新创建的自定义字段同步写入到Redis缓存中。这一过程确保了系统中的Redis缓存参数与数据库表数据的一致性。该同步操作是通过add_action挂载实现的,以确保在每次字段更新时都能及时反映到缓存中,保持数据的实时同步和一致性。
    2、新增了一个名为xc_update_post_meta_hook的钩子,当用户进行自定义文章字段的更新操作时,无论是使用update、add还是delete方法,该钩子都会被触发。通过挂载这个钩子,可以同步执行一些预设的回调操作,从而实现更灵活的功能扩展。使用这个钩子时,需要传递五个变量:post_id、meta_key、meta_value、type,其中type代表执行的动作类型,可能的值为add、update或delete。这种设计为开发者提供了更高的可控性,能够在文章字段更新时执行特定的逻辑处理,确保数据的一致性和功能的扩展性。
    3、当对WordPress文章自定义字段(meta)操作时,会触发相应的钩子:新增字段时,触发add_post_meta钩子。更新字段时,触发updated_post_meta钩子。删除字段时,触发delete_post_meta钩子。这些钩子触发的时候,系统会自动执行如下操作。缓存同步:每次 meta 字段变动(增/删/改),都会同步到 Redis,保存数据实时更新。 自定义业务逻辑:通过 xc_update_post_meta_hook(),可以实现更多扩展,比如消息推送、数据分析等。 流程自动化:所有操作都是自动响应,不需要手动干预,提高了系统的智能化和可维护性。
    4、在对xc_reids进行重构优化时,发现即使在swoole环境下运行数小时后,系统仍然会出现间歇性崩溃的情况。为了应对这一问题,引入了try-catch机制来捕捉和记录错误。在执行connect、select和ping等操作时,每一步都有可能触发Exception错误,利用xc_log_error_warn将这些错误日志详细记录下来,由于异步redis在整个系统中扮演着至关重要的角色,必须确保其稳定性,否则异步进程的执行将面临诸多潜在问题,影响系统的整体性能和可靠性。
    5、在协程 Redis 模块中,进一步的优化,特别是针对连接不稳定的情况,增加了一个循环重试机制。具体来说,当连接失败时,系统会最多尝试三次重新连接。在每次失败后,程序会暂停 500 毫秒(通过 usleep 函数实现),以便给系统一些恢复时间。这一重试机制仅限于协程 Redis 环境中,每次连接失败后都会详细记录日志,确保问题可追溯。如果经过三次重试依然无法成功连接,系统将记录相应的错误日志,并抛出异常,最终返回 null,以确保调用方能够适当地处理这种异常情况。对于普通的非协程环境,逻辑保持不变,确保稳定性和一致性。
    6、新版xc_redis的处理流程如下:静态变量初始化 声明 static $redis = null;,用于保存 Redis 实例(普通环境下实现复用)。 获取连接参数 通过 xc_get_option() 获取 Redis 的连接参数(IP、端口、数据库编号)。 设置超时时间 $timeout = 5。 判断协程环境 检查是否已加载 swoole 扩展。 判断当前是否为 Swoole 协程环境(Swoole\Coroutine::getCid() > 0)。 尝试连接 Redis(try/catch 保护) 将 $redis = null;,准备开始连接。 4.1 协程环境下(Swoole\Coroutine\Redis) 如果处于 Swoole 协程环境且存在 Swoole\Coroutine\Redis 类: 设置最大重试次数 $maxRetry = 3,初始化 $retry = 0。 进入重试循环 while ($retry < $maxRetry): 检查 Swoole\Coroutine\Redis 是否有 create 方法,有则调用,否则直接 new 一个对象。 尝试连接 Redis,如果连接失败,抛出异常。 尝试选择数据库,如果失败,抛出异常。 尝试 ping 检查连接健康,如果失败,抛出异常。 如果以上步骤全部成功,直接返回 Redis 实例。 如果捕获到异常,记录错误日志,$retry++,并在未到最大次数时等待 300 毫秒(usleep(300000))。 如果三次重试都失败,记录错误日志,并抛出异常。 4.2 非协程环境(普通 Redis) 如果静态变量 $redis 已经是一个 Redis 实例: 检查连接是否有效(isConnected)。 或通过 ping 检查连接健康。 如果连接正常,直接返回 Redis 实例。 如果异常或连接失效,清空 $redis,准备重新连接。 如果 $redis 不是 Redis 实例(或连接失效): 新建 Redis 实例 $redis = new Redis()。 连接 Redis 服务器。 选择数据库。 返回 Redis 实例。 5. 异常处理 如果在任何步骤出现异常: 记录错误日志(包括时间、异常信息)。 返回 null。
    7、为了提升用户行为记录的性能,决定构建一套基于Redis的解决方案,专门用于管理用户的历史行为数据。当用户在进行收藏、点赞、浏览、关注等操作时,这些行为会被Redis实时记录和管理。通过这种方式,能够有效地支持排行榜设计规范,利用分数机制不仅可以调取用户每日的行为记录,还能生成用户行为排行榜。例如,可以快速生成今日点赞排行榜,以及某用户当天的点赞详情列表。由于整个过程都依赖Redis进行数据处理,系统的执行效率得到了显著提升,确保数据管理的流畅和快速响应。
    8、通过 Redis 来记录用户的历史行为:xc_redis_set_user_history。具体的执行流程如下:检查 $user_id、$action_type、$page_id 是否为空。 如果有任何参数为空,则记录错误日志并直接返回,不执行后续逻辑。 构建 Redis 键名 构造哈希表键名:xc_redis:user:{user_id}:{action_type}:hash 构造有序集合键名:xc_redis:user:{user_id}:{action_type}:sorted_set 获取 Redis 实例 调用 xc_redis() 获取 Redis 连接实例。 获取当前时间戳 用 time() 获取当前的 Unix 时间戳,作为记录分数。 判断页面历史记录是否已存在 用 $redis->hExists($hash_key, $page_id) 检查哈希表中是否已存在该页面 ID。 如果存在,只需要更新有序集合(即刷新访问时间):zAdd(sorted_set_key, timestamp, page_id) 如果不存在,先在哈希表中添加该页面 ID,再在有序集合中添加:hSet(hash_key, page_id, 1) 和 zAdd(sorted_set_key, timestamp, page_id) 判断历史记录数量是否超过限制 用 $redis->zCard($sorted_set_key) 获取当前有序集合的数量。 如果数量超过 100: 用 $redis->zRange($sorted_set_key, 0, $count - 101) 获取最早的多余记录(即只保留最新的 100 条)。 遍历这些旧页面 ID,分别从有序集合和哈希表中删除:zRem 和 hDel
    9、新增了查询指定用户历史行为记录的功能,支持分页处理,方法名为 xc_redis_get_user_history,其具体执行流程如下:首先进行参数校验,检查传入的 $user_id 和 $action_type 是否为空,若发现为空,则会记录日志并直接返回 false,避免后续操作。接着构造 Redis 键名,生成对应的有序集合键,格式为:xc_redis:user:{user_id}:{action_type}:sorted_set,确保数据按用户及行为类型进行区分管理。然后,通过调用 xc_redis() 方法获取 Redis 实例以建立连接。根据是否存在分页参数 $page,分为两种处理方式:若未传入分页参数,则使用 zRevRange 方法获取该用户所有的历史记录,按倒序排列并带上分数;若传入分页参数 $page,则进一步判断 $limit 是否为空,若为空则读取系统默认的分页数量,随后根据 $page 和 $limit 计算出偏移量 $offset = ($page - 1) * $limit,通过 zRevRange 按分页读取记录,同样以倒序排列并附带分数。获取到结果后,检查其是否为空,若为空则返回 false。最后,处理后的数据将以 [page_id => 时间戳] 的关联数组格式返回
    10、新增方法:xc_redis_delete_user_history,专门用于删除指定用户的历史行为记录(可选择删除特定页面记录或全部记录)。该方法的执行流程设计如下: 首先,对输入参数进行校验。如果传入的 $user_id 或 $action_type 参数为空,则记录错误日志并直接返回 false,避免无效操作。接着,依据用户 ID 和行为类型,动态生成对应的 Redis 键名,包括哈希表键名和有序集合键名,确保数据定位准确性。然后,通过调用 xc_redis() 方法获取 Redis 实例,为后续操作提供连接支持。为了确保数据一致性与原子性,方法中使用 $redis->multi() 开启 Redis 事务,准备执行批量操作。 在删除逻辑中,根据 $page_id 的值进行分支处理。如果 $page_id 为空,表示需要删除该用户的所有历史记录,此时将清空对应的哈希表和有序集合;如果 $page_id 不为空,则只删除与特定页面相关的历史记录。无论哪种情况,均在事务中操作,以避免中途失败导致数据残留。 最后,提交事务并获取执行结果,判断操作是否成功,并将结果返回。
    11、新增方法:xc_redis_user_is_history,用于判断用户是否对某个页面执行过指定行为(如收藏、浏览)。该方法的执行流程如下:首先进行参数校验,若任意参数为空,则直接返回 false,避免不必要的逻辑执行。接着,按照特定规则构造 Redis 的 hash 键,格式为:xc_redis:user:{user_id}:{action_type}:hash,其中 {user_id} 表示用户 ID,{action_type} 表示行为类型。随后,通过调用 xc_redis() 方法获取 Redis 实例,确保后续操作基于有效的 Redis 连接。在检查指定页面是否存在于 Redis hash 中时,使用 $redis->hExists($hash_key, $page_id) 方法进行判断,若返回 true,表示该页面存在于用户的行为记录中;否则返回 false,表明用户未对该页面执行过指定行为。
  • 0
    小小乐lv.2实名用户
    2025年8月21日
    1、通过 get_post_metadata 注册并接管自定义文章元数据的读取和处理逻辑,目前已通过 xc_get_post_meta_callback 实现对特定元数据键的过滤,以动态决定是否启用 Redis 缓存功能。宫论系统原本预设了多个自定义文章模型,例如用于工单管理、朋友圈动态等内容的封装和处理,这些内容依赖于大量的自定义字段。由于本次对 Redis 缓存系统进行了重构优化,因此在元数据处理逻辑上也同步进行了改进,旨在提高数据读取效率,减少对数据库的直接访问,从而提升整体系统的性能和响应速度。
    2、通过使用 add_filter 注册自定义钩子,可以接管文章自定义元字段的返回值。在这一过程中,需要传递四个关键变量:$metadata(元数据值)、$post_id(文章的 ID)、$meta_key(元数据键)以及 $single(是否返回单个元数据值)。这些参数均由系统方法自动传递并继承而来。在实际的业务逻辑处理中,这四个变量起着至关重要的作用,通过它们可以灵活地实现对元数据的定制化处理,确保数据的正确性和功能的扩展性,从而满足具体的业务需求。
    3、在通过内置方法接管自定义文章元字段的查询时,会对参数 single 进行验证处理。如果该参数值为 false,则表明系统需要返回该文章ID对应的所有自定义元字段,而不是单一字段。然而,由于当前Redis缓存采用的是字典模式,暂时无法支持以列表形式返回全部字段,因此在这种情况下系统将执行一个默认的回调处理逻辑,跳过此次缓存处理,并通过原生方式直接读取数据并响应请求。需要注意的是,跳过处理的实现方式非常简便,只需对元数据(metadata)进行翻译操作即可触发默认回调,从而完成所需的处理逻辑。
    4、针对某些敏感的自定义字段(如商品库存数量、商品出售价格等),为了确保数据的准确性并避免在极端情况下Redis返回的数据与实际情况不符,这类字段的查询必须通过直接调用wpdb进行数据库查询,并禁用缓存机制。为实现这一功能,系统在后台新增了一个字段参数:redis_wp_cache_filter_postmeta(自定义文章过滤缓存字段列表)。该字段支持通过分号(;)分隔多个字段名称。在接管postmeta查询的过程中,系统会自动检查查询字段是否存在于该列表中。如果匹配成功,则会跳过缓存逻辑,直接回源数据库进行查询,确保数据的实时性和准确性。
    5、xc_get_post_meta_callback_cache的接管流程具体如下:首先,系统会优先检测当前的single参数是否为false,如果检测结果为false,则直接跳过缓存逻辑,回源进行处理。接下来,系统会进一步判断本次查询的键值是否属于后台预定义的过滤列表名单。如果键值在名单中,则会通过wpdb直接发起数据库查询操作,并将查询结果返回。在返回结果时,系统会对数据进行检查,如果查询结果存在,则会调用maybe_unserialize函数对数据进行反序列化处理,确保即便存储的是序列化的数组,依然能够正常解析和使用。若上述条件均不满足,则系统会启用edisHASH缓存模式接管该查询请求,通过缓存进行处理并返回结果,从而提高查询效率并减少数据库压力。
    6、新增get_post_redis方法:此方法负责从Redis缓存中优先获取自定义文章元数据,若Redis中尚未缓存相关内容,则自动从数据库中检索并写回Redis,以有效提升后续查询的效率。该方法含有两个主要变量:ppst_id对应的文章ID,meta则用于指定元数据的键名。查询过程中,先尝试从Redis取值,若获取到的信息完整且有效,就会直接返回对应的用户元数据信息;倘若Redis中未查到结果,则改为访问数据库进行检索,并在成功获取后同步将数据写回Redis供后续使用,最终再返回用户元数据。若两处均未能获取到目标信息,将返回false表示查询失败。
    7、get_post_redis的整理处理流程如下:调用 get_post_redis($post_id, $meta),传入文章ID和元数据键名(meta,允许为空)。 2. 连接 Redis 函数内部先通过 xc_redis() 获取 Redis 实例,为后续操作做准备。 3. 判断是否要获取全部元数据 如果 $meta 没传(为 null),说明你想取这个文章的所有元数据: 直接从 Redis 的哈希表 postmeta:$post_id 获取所有字段和值。 把每个值用 maybe_unserialize 处理(这样即使是序列化的数组/对象也能还原)。 关闭 Redis 连接。 返回这个完整的元数据数组。 4. 只获取单个元数据时的流程 如果传了 $meta,表示只想取指定的元数据字段: 先尝试从 Redis 的哈希表里读取 postmeta:$post_id 里的对应键($meta)。 如果 Redis 里有这个值(不为 null 或空字符串): 关闭 Redis。 反序列化并返回该值。 如果 Redis 里该键值是空字符串(''): 关闭 Redis。 返回 false(说明之前已经查过数据库,确实没有这个数据)。 如果 Redis 里没有缓存这个字段(即查出来是 false/null): 用 $wpdb 从 WordPress 数据库的 postmeta 表查询对应的数据。 如果数据库查到了值: 用 update_post_redis 把这个值(序列化处理后)写入 Redis。 关闭 Redis。 反序列化后返回数据。 如果数据库也没有查到值: 用 update_post_redis 把这个字段写入 Redis,值设为空字符串(''),防止下次还要查数据库。 关闭 Redis。 返回 false。 5. 兜底返回 如果所有情况都没命中,最后返回 false。
    8、在符合特定条件时,xc_get_post_meta_callback_cache 会通过 get_post_redis 发起 Redis 的字典查询操作以获取相关数据。如果查询结果存在,该函数会进一步验证返回值的类型:首先通过 is_serialized 和 is_array 检查该值是否为序列化字符串或数组格式。如果验证通过,则会利用 maybe_unserialize 对序列化字符串进行反序列化操作,同时将数据还原为数组形式以确保数据结构的完整性和可用性。若返回的值并非上述类型,则无需额外处理,直接返回从 Redis 中读取到的原始值。
    9、宫论自定义文章元字段的接管业务逻辑封装完毕,执行流程如下:通过 add_filter('get_post_metadata', 'xc_get_post_meta_callback', 10, 4),系统注册了元数据读取钩子,接管所有文章元字段的查询。 每次有文章元数据读取请求时,系统会自动传递四个参数: $metadata:元数据的原始值(一般为空,需返回处理后的值) $post_id:文章ID $meta_key:元数据字段名 $single:是否只获取单个字段值(true/false) 2. 处理参数 single,决定查询模式 如果 $single 为 false,说明要获取该文章的所有自定义元字段(类似于 get_post_meta($post_id) 的场景)。 由于当前 Redis 只支持字典模式缓存单个字段,不支持批量列表查询,所以此时: 直接跳过缓存,交由 WordPress 默认逻辑处理(即数据库查询)。 返回 $metadata,触发原生回调,系统后续自动用数据库结果响应。 3. 判断是否需要跳过缓存(敏感字段过滤) 后台配置有一个过滤字段列表 redis_wp_cache_filter_postmeta,用于指定哪些字段必须直接查数据库,禁止缓存。 在查询时,判断 $meta_key 是否在这个过滤列表中: 如果命中(如库存、价格等敏感字段),直接用 $wpdb 查询数据库,得到值后处理并返回。 若查询结果存在序列化内容,则用 maybe_unserialize 还原为原始结构(如数组)。 如果查询不到,返回 false。 4. 普通字段启用 Redis 缓存查询 如果 $single 为 true 且 $meta_key 不在过滤列表中,则启用 Redis 缓存优化。 此时通过 get_post_redis($post_id, $meta_key) 发起查询,流程如下: 优先从 Redis 哈希表 postmeta:$post_id 读取指定字段的值。 如果 Redis 有值且不为空,直接用 maybe_unserialize 处理后返回。 如果 Redis 有该字段但值为空字符串,说明数据库也没有该数据,直接返回 false。 如果 Redis 没有缓存该字段,则用 $wpdb 查询数据库。 如果数据库查到,写入 Redis 缓存(序列化处理),然后返回数据。 如果数据库查不到,写入 Redis 空值,返回 false。 5. 返回数据类型校验 对于 Redis 返回的数据,如果类型为序列化字符串或数组,使用 maybe_unserialize 还原,确保前端或调用端能正确使用。 非数组/非序列化内容,直接原样返回。
    10、为提升缓存的一致性与可靠性,新增了名为“xc_updated_post_meta_callback”的回调动作过滤钩子。当通过update_post_meta函数更新自定义文章的元字段时,系统将在完成数据表更新后自动触发该回调。该回调会进一步调用update_post_redis更新动作,向Redis发送请求以同步更新对应的字典缓存。这种设计能够确保数据库与缓存之间的数据同步性,避免因数据更新延迟或遗漏导致的缓存不一致问题,从而有效提高系统的稳定性和数据的准确性。
    11、同样地,当通过delete_post_meta函数发起自定义文章元字段的删除请求时,系统在完成清理操作后,会自动触发挂载的过滤钩子xc_delete_post_meta_callback。该钩子负责将删除操作的行为同步到delete_post_redis的清理流程中,并通过Redis对相关字典缓存进行同步移除处理。此机制确保在使用Redis返回查询结果时,缓存中不再包含已删除的元字段数据,避免过时信息的干扰。系统在检测到缓存结果为空时,会自动转向使用wpdb发起实时查询,以确保返回的数据真实、可靠。这种设计不仅提高了数据的一致性,还优化了查询的灵活性与准确性。
  • 0
    小小乐lv.2实名用户
    2025年8月20日
    1、xc_get_user_meta_callback_cache已完成封装处理:获取所有字段时,直接返回原始数据,不做任何处理。 如果 meta_key 在过滤列表里,说明该字段不使用 Redis 缓存,直接查数据库并返回结果。 如果 meta_key 不是 WordPress 内置字段(wp_ 或 session_tokens),则从 Redis 缓存读取数据,并做序列化处理后返回。 其它情况(比如内置字段),直接返回原始数据,交给 WordPress 默认流程处理。这个函数优先用 Redis 缓存获取用户 meta 数据,特殊字段和敏感字段则直接查数据库,内置字段保持 WordPress 默认处理方式。
    2、在系统处理用户自定义元字段更新的过程中,主要涉及到三个核心操作:通过 update_user_meta 更新字段内容,通过 delete_user_meta 删除字段数据,以及通过 add_user_meta 新增字段。当这些操作被触发时,系统会借助 add_action 机制接收对应的回调通知。这些通知会进一步触发与 Redis 相关的处理逻辑,确保用户元字段在底层 SQL 数据库与 Redis 缓存之间保持数据的一致性与同步性,从而提升系统的整体稳定性和性能。
    3、在用户元字段发生更新时,系统会自动触发 xc_update_user_meta_hook 钩子,该钩子会将涉及的用户对象、元字段名称、元字段值以及具体的操作类型(如新增、删除或更新)作为参数传递至钩子中进行集中处理。一旦用户字段发生变动,系统需执行一系列关键任务,包括推送通知、清理缓存、记录日志以及其他与业务逻辑相关的操作。为了确保这些操作的高效性和主流程的流畅性,系统将采用 Swoole 异步任务机制执行相关任务,从而有效减少对主线程的阻塞,并提升整体性能。
    4、当 xc_update_user_meta_hook 钩子被触发时,系统会首先检测元字段的 meta_key 值是否为 chat_list。如果确认 meta_key 为 chat_list,则意味着用户的聊天会话记录表发生了变动。此时,系统会调用 xc_swoole_asyn 执行异步请求,并通过 xc_del_redis 方法清理与用户聊天会话页面相关的 Redis 缓存数据。这一流程的设计,确保了用户聊天页面数据的实时性与准确性,同时降低了同步操作对系统性能的影响。
    5、系统已经实现了对 WordPress 用户元数据(usermeta)读写操作的全面接管,其核心逻辑是:在调用 get_user_metadata 进行数据读取时,对于部分特定字段直接从数据库查询,而其他字段则通过 Redis 缓存获取;在执行 add_user_meta、update_user_meta 和 delete_user_meta 操作时,系统会自动同步更新 Redis 缓存状态。此外,通过 xc_update_user_meta_hook 钩子,系统能够在用户元数据发生变动后实现统一通知与功能扩展,从而为后续业务逻辑的灵活调整提供了强大的支持和保障。
    6、宫论用户自定义字段,目前已完全通过内置redis进行接管处理,整个执行流程如下: 当系统调用 get_user_meta 获取用户元数据时,会先查 Redis 缓存。 如果 Redis 命中,则直接返回,避免数据库查询,提高访问速度。 针对敏感字段(如余额),有后台配置的过滤列表,这些字段强制走数据库查询,确保数据安全和准确性。 2. 读写操作的全面接管 用户元数据的新增、更新、删除操作(add/update/delete),都会同步操作 Redis 缓存和数据库,确保两者数据一致。 所有写操作通过 WordPress 的钩子机制集中处理,方便统一管理和扩展。 3. 钩子机制与异步任务处理 每次用户元数据变动,都会触发 xc_update_user_meta_hook 钩子,把变动的用户、字段名、字段值和操作类型传递给后续处理逻辑。 后续处理包括推送通知、清理缓存、记录日志等。 这些任务通过 Swoole 异步机制执行,避免阻塞主线程,提高系统性能。 4. 聊天会话字段特殊处理 当变动字段是 chat_list 时,系统会自动清理相关的 Redis 聊天缓存,保证聊天页面数据实时更新。 5. 灵活平衡性能与安全 普通自定义字段优先用 Redis 缓存,敏感字段和 WordPress 内置字段则直接查数据库,兼顾性能和数据安全。 整个流程支持后台灵活配置敏感字段列表,业务可扩展性强。 6. 统一扩展与保障 通过自定义钩子和异步任务,所有用户元数据变动都能统一处理,方便后续扩展和维护。 既提升了系统响应速度,也保障了关键数据的一致性和安全性。简要总结: 系统通过 Redis 缓存优化用户元数据读取,敏感字段强制数据库查询,所有写操作同步缓存和数据库,并用钩子与异步任务机制统一处理后续业务,整体实现性能与安全的平衡。
    7、由于宫论的大量字段是通过 option 来读取,而当前的读取方式是直接通过 get_option 方法,这种方式会直接通过 wpdb 执行 SQL 请求,对性能造成了较大的影响。因此,决定引入 Redis 来接管对 option 的处理,从而尽可能减少 SQL 查询的执行。具体实现上,首先通过 pre_option 挂载过滤器来接管 option 的读取流程,然后注册方法 xc_pre_option_callback,用于重写和处理 option 的读取逻辑。这样一来,后续的 get_option 请求将优先通过 Redis 的内置方法进行处理,从而显著优化性能,降低对数据库的直接访问频率。
    8、在使用Redis缓存可能引发一些难以预料的问题,特别是在处理系统级别的参数选项时。因此,在管理get_option的过程中,采取了一些预防措施。首先,对于所有带有wp前缀的参数,选择不进行缓存处理,而是直接通过原生的wpdb进行读取和响应,以确保数据的准确性和一致性。此外,在后台新增了一个可选字段:redis_wp_cache_filter_option,允许用户自行定义哪些字段需要排除在Redis缓存之外。用户可以通过分号分隔多个字段名称,将需要忽略缓存的字段添加到此选项中。这些字段将在读取时直接通过wpdb进行处理,以避免潜在的缓存问题,确保系统的稳定运行。
    9、新增了一个名为 get_option_redis 的 Redis 数据处理方法。该方法的核心功能是通过传递指定的 key 参数,系统自动调用内置的 Redis 方法来读取对应的缓存数据。如果缓存中存在该 key 的数据,系统会进一步对返回值进行检查,分别使用 is_serialized 和 is_array 方法来判断数据是否为数组结构类型。如果检测结果表明数据为数组结构类型,系统将调用 array(maybe_unserialize($redis_meta)) 方法对其进行解析处理,确保数据格式符合 WordPress 的设计规范标准。之所以需要这一解析步骤,是因为在某些情况下,缓存中可能存储的是序列化的数组参数,若不对其进行解序列化和转义处理,可能会导致参数异常或系统错误。
    10、后台新增了一个重要的选项:xc_option_redis_open,用于控制是否启用缓存机制。管理员可以通过这个选项来决定是否使用Redis缓存系统,以优化性能和提升数据处理速度。如果选择不启用,那么系统将会跳过xc_pre_option_callback的正则处理环节,从而减少潜在风险。考虑到option涉及到系统众多敏感参数,未经过适当过滤可能会导致安全隐患,因此这个开关的设计旨在提供一个快速恢复的途径。当系统出现问题时,管理员可以直接在后台关闭此选项,确保系统稳定运行。一旦问题修复完成,可以重新启用该功能,以充分利用Redis的性能优势。
    11、宫论option已完成对redis的缓存的业务处理:拦截get_option调用: 通过pre_option过滤器,挂载自定义回调xc_pre_option_callback,所有的get_option请求都会优先进入此回调。 判断缓存开关: 首先检查后台xc_option_redis_open开关是否启用。未启用时直接返回,走原生数据库查询流程。 2. 敏感字段与缓存排除机制 系统字段排除: 对所有以wp_为前缀的option参数,直接跳过缓存,使用原生wpdb数据库读取,避免缓存系统级参数导致数据混乱。 自定义排除字段: 后台通过redis_wp_cache_filter_option字段,允许管理员自定义需要跳过缓存的option名称(分号分隔)。这些字段在读取时同样直接查数据库。 3. Redis缓存读取逻辑 缓存优先读取: 通过自定义的get_option_redis方法,根据option名称作为key,从Redis读取数据。 数据格式兼容处理: 判断Redis返回值是否序列化(is_serialized),如果是则使用maybe_unserialize进行反序列化,保证与WordPress原生option数据格式兼容。 如果数据为数组,确保返回类型正确,防止类型错乱导致功能异常。 缓存未命中处理: 如果Redis无此数据,则回退到数据库读取,并将结果写入Redis缓存,便于后续请求加速。
  • 0
    小小乐lv.2实名用户
    2025年8月19日
    1、前端新增了基于WebSocket的支付订单付款成功回调通知监听功能。具体实现是,当前端接收到payment_success消息数据包时,会将相关订单数据包转发至【xc_hook_payment_success】钩子进行统一处理,确保所有支付成功的消息均通过该钩子完成后续操作。需要特别注意的是,APP端支付由于采用SDK发起并处理,支持实时的付款成功回调通知,因此无需额外监听处理。而对于H5、公众号以及小程序支付,由于无法直接触发实时回调通知,需要借助WebSocket来监测付款是否成功,从而实现统一的支付结果处理逻辑。这一改动有效提升了支付成功信息的实时性和处理效率,为不同端的支付场景提供了更一致的处理方案。
    2、在xc_hook_payment_success触发时,系统会首先通过xc.is_h5方法来检查用户是否处于H5客户端环境。若用户正处于H5客户端环境,系统会通过layer弹出提示框,简明扼要地告知用户订单付款已成功,并显示支付金额,例如:“订单付款成功,支付金额: ' + payment.pay_amount + '元”。这种提示旨在迅速让用户了解其付款状态。而在非H5环境中,系统则会通过解析payment对象来获取更详细的信息,包括支付环境(如h5、app、微信浏览器、微信小程序)、支付方式(例如微信支付、支付宝、余额支付)、支付凭证、支付用户信息以及支付金额。这些信息对于后续页面的跳转和处理至关重要。
    3、xc_hook_payment_success 在成功获取支付订单数据信息后,会通过 unified_payment_content 元素选择器判断用户当前是否处于统一支付页面。若确认用户正处于统一支付页面,则会立即触发一系列页面交互逻辑:首先,将页面中的支付标识状态更新为“支付成功”,并同步修改对应的文字提示内容,以直观告知用户支付已完成。接着,该逻辑会定位并获取页面的支付定时器,并对其进行移除处理,以避免不必要的计时操作对用户体验造成干扰。随后,系统会对统一支付页面进行“成功”状态标记,明确标识当前付款已完成,防止用户因误操作或系统错误导致重复付款的问题。与此同时,页面还会进一步触发交互提示,包括展示支付完成的相关信息以及播放提示音效。
    4、xc_hook_payment_success目前预留了一个回调事件,当前仅用于处理统一支付订单的回调逻辑,后续将进一步扩展其功能,通过回调事件实现更加复杂的页面交互。未来的应用场景可能包括:在支付完成后跳转到对应的支付订单详情页,同时对路由进行重写,确保用户在返回时能够直接跳过商品详情页,提升使用体验。根据实际付款订单的类型,系统将执行不同的处理逻辑,以满足多样化的业务需求。后续开发中会根据具体情况集成相应的功能模块,确保系统的灵活性和可扩展性。
    5、服务器内置的 Swoole 版本从 4.X 升级至 6.0.2,此次升级的主要目的是更好地支持通过协程机制连接 Redis。在 4.X 版本中,无法使用 Swoole\Coroutine\Redis::create 方法来创建 Redis 的协程连接,限制了协程在 Redis 操作中的优势。而在 6.0.2 版本中,不仅全面支持协程连接 Redis,还能够充分发挥协程的异步非阻塞特性,大幅提升 Redis 操作的效率和性能。通过这一升级,系统在高并发场景下的任务调度和缓存数据处理能力得到了显著增强,同时也为后续的功能扩展和性能优化奠定了更坚实的基础。
    6、对 Swoole 服务器进行重构,加入了协程处理能力。这一改进旨在优化任务转发的效率,使系统能够利用协程机制来处理 Redis 缓存数据的调用。与传统的任务处理方式相比,协程提供了更高效的资源管理和并发处理能力。在传统的 task 模式下,任务执行过程中无法有效调用协程来进行 Redis 的任务调度处理,这可能导致资源的浪费和性能的瓶颈。而通过引入协程,系统能够在任务执行时灵活地进行异步 I/O 操作,显著提升了 Redis 数据处理的速度和效率
    7、对xc_redis() 方法进行了彻底重构,以实现更加灵活和高效的 Redis 连接处理。新版本的 xc_redis() 方法支持两种连接方式:首先,当系统处于 Swoole 协程环境下时,将优先使用 Swoole\Coroutine\Redis 来建立协程连接,以充分发挥协程的异步非阻塞特性,提升 Redis 操作的效率和性能;其次,当处于普通环境时,则采用传统的 Redis 连接方式,并复用已存在的 Redis 实例,以减少资源开销并提高连接的稳定性。此外,为了增强系统的容错能力,如果在 Redis 连接或操作过程中发生异常错误,系统会自动触发日志写入,将异常信息记录下来,以便后续排查问题。
    8、对 xc_swoole_asyn 方法的异步业务逻辑进行了优化,进一步提升了系统的稳定性与执行效率。优化后,方法会通过 extension_loaded('swoole') 函数动态检测当前环境是否加载了 Swoole 扩展。如果检测到 Swoole 已加载,系统会智能切换为同步方式执行业务逻辑,并通过 call_user_func_array 调用目标函数,以确保逻辑执行的快速响应和高效处理。与此同时,当异步请求发生执行失败的情况时,系统将自动捕获异常并触发日志写入机制,错误信息会以【日志标识:swoole_error】记录在日志文件中。
    9、新增了一个处理 Redis 键的清理方法:xc_del_redis($key)。此函数旨在通过提供的键名(支持通配符 :*)批量删除 Redis 中与之匹配的所有键。当成功删除匹配的键时,函数将返回 true;如果 Redis 服务不可用或提供的参数无效,则返回 false。该函数的设计初衷是为了便捷地管理和清理 Redis 数据库中的键,例如可以使用像 "user:*" 这样的通配符模式,快速定位并删除所有相关的用户数据。这种通配符支持不仅提高了操作的灵活性,也在一定程度上简化了对 Redis 数据库的维护工作。
    10、新增了一个名为 xc_user_meta_callback 的 WordPress 接管函数,该函数是一个自定义的回调方法,主要用于拦截并动态调整用户元数据的获取流程。当系统通过 get_user_meta 函数请求用户自定义元字段时,该接管函数会优先检查 Redis 缓存中是否存在相关数据。如果缓存命中,则直接通过 Redis 读取数据,避免传统的 SQL 查询操作,从而显著减少数据库的压力,优化系统的响应性能。这一机制特别适用于高频访问的用户数据场景,能够有效提升整体服务的效率和稳定性。
    11、在接管用户自定义元字段查询的过程中,为了保障数据的准确性和安全性,对于某些敏感字段(如账户余额等),不允许直接通过 Redis 缓存读取,以避免潜在的数据不一致问题。为此,接管函数中新增了一个过滤机制,允许后台管理员自定义配置一个过滤字段组。接管函数会根据该配置自动识别并排除这些敏感字段,对于过滤列表中的字段强制回退到通过 WPDB 查询数据库表的方式读取数据。这种设计既兼顾了性能优化,又确保了核心数据的安全性和一致性,为系统的稳定运行提供了双重保障。
  • 加载更多评论
    单栏布局 侧栏位置: