Compare commits
4 Commits
0ac19eb252
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 4a3b645980 | |||
| 62671bc737 | |||
| a6cd9c42e3 | |||
| c83a5cab26 |
8
ui components/README.MD
Normal file
8
ui components/README.MD
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
## 移动端优先的ui组件示例
|
||||||
|
|
||||||
|
* [Tabris](https://docs.tabris.com/latest/api/ActionSheet.html)
|
||||||
|
|
||||||
|
|
||||||
|
## pc端优先的ui组件示例
|
||||||
|
|
||||||
|
* [PrimeReact - React UI Component Library](https://primereact.org/)
|
||||||
BIN
ui components/action-sheet/android.png
Normal file
BIN
ui components/action-sheet/android.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 24 KiB |
BIN
ui components/action-sheet/ios.png
Normal file
BIN
ui components/action-sheet/ios.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 40 KiB |
|
Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 36 KiB |
75
ui components/sticknav/StickyNavExample.css
Normal file
75
ui components/sticknav/StickyNavExample.css
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
/* 基础样式 */
|
||||||
|
.container {
|
||||||
|
max-width: 800px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 20px;
|
||||||
|
font-family: Arial, sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.subtitle {
|
||||||
|
margin-bottom: 40px;
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 粘性导航样式 */
|
||||||
|
.sticky-nav {
|
||||||
|
position: sticky;
|
||||||
|
top: 0;
|
||||||
|
background-color: white;
|
||||||
|
padding: 15px;
|
||||||
|
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
|
||||||
|
z-index: 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-box {
|
||||||
|
width: 100%;
|
||||||
|
padding: 10px;
|
||||||
|
margin-bottom: 15px;
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.category-tabs {
|
||||||
|
display: flex;
|
||||||
|
gap: 10px;
|
||||||
|
overflow-x: auto;
|
||||||
|
padding-bottom: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.category-tabs button {
|
||||||
|
padding: 8px 16px;
|
||||||
|
border: none;
|
||||||
|
background-color: #f0f0f0;
|
||||||
|
border-radius: 20px;
|
||||||
|
cursor: pointer;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.category-tabs button.active {
|
||||||
|
background-color: #007bff;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 内容区域样式 */
|
||||||
|
.content-section {
|
||||||
|
margin-top: 40px;
|
||||||
|
padding: 20px;
|
||||||
|
border: 1px solid #eee;
|
||||||
|
border-radius: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-section h2 {
|
||||||
|
margin-bottom: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 占位内容,使页面可滚动 */
|
||||||
|
.placeholder {
|
||||||
|
height: 300px;
|
||||||
|
background: linear-gradient(to bottom, #f9f9f9, #e9e9e9);
|
||||||
|
margin-top: 20px;
|
||||||
|
border-radius: 8px;
|
||||||
|
}
|
||||||
128
ui components/sticknav/StickyNavExample.jsx
Normal file
128
ui components/sticknav/StickyNavExample.jsx
Normal file
@@ -0,0 +1,128 @@
|
|||||||
|
import React, { useState, useEffect, useRef } from 'react';
|
||||||
|
import './StickyNavExample.css';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 最小化示例:实现滚动吸顶与分类高亮效果
|
||||||
|
*/
|
||||||
|
const StickyNavExample = () => {
|
||||||
|
// 分类数据
|
||||||
|
const categories = [
|
||||||
|
{ id: 'section1', name: '分类一' },
|
||||||
|
{ id: 'section2', name: '分类二' },
|
||||||
|
{ id: 'section3', name: '分类三' },
|
||||||
|
{ id: 'section4', name: '分类四' },
|
||||||
|
];
|
||||||
|
|
||||||
|
// 状态管理
|
||||||
|
const [activeSection, setActiveSection] = useState(categories[0].id);
|
||||||
|
const isManualScrollRef = useRef(false);
|
||||||
|
const timerRef = useRef(null);
|
||||||
|
|
||||||
|
// 监听滚动事件,更新当前活动分类
|
||||||
|
useEffect(() => {
|
||||||
|
const handleScroll = () => {
|
||||||
|
// 如果是手动点击导致的滚动,则跳过自动检测
|
||||||
|
if (isManualScrollRef.current) return;
|
||||||
|
|
||||||
|
const stickyNav = document.querySelector('.sticky-nav');
|
||||||
|
const stickyHeight = stickyNav?.getBoundingClientRect().height || 0;
|
||||||
|
const triggerOffset = stickyHeight + 20; // 触发点位置
|
||||||
|
|
||||||
|
// 遍历所有分类区块,检查哪个在视口中
|
||||||
|
categories.forEach(category => {
|
||||||
|
const section = document.getElementById(category.id);
|
||||||
|
if (section) {
|
||||||
|
const rect = section.getBoundingClientRect();
|
||||||
|
// 当区块顶部进入触发点时,将其设为当前活动分类
|
||||||
|
if (rect.top <= triggerOffset && rect.bottom >= triggerOffset) {
|
||||||
|
setActiveSection(category.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// 添加滚动事件监听
|
||||||
|
window.addEventListener('scroll', handleScroll);
|
||||||
|
|
||||||
|
// 组件卸载时移除事件监听
|
||||||
|
return () => window.removeEventListener('scroll', handleScroll);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
// 处理分类点击事件
|
||||||
|
const handleCategoryClick = (categoryId) => {
|
||||||
|
// 清除之前的定时器
|
||||||
|
if (timerRef.current) {
|
||||||
|
clearTimeout(timerRef.current);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置为手动滚动,暂时禁用自动检测
|
||||||
|
isManualScrollRef.current = true;
|
||||||
|
setActiveSection(categoryId);
|
||||||
|
|
||||||
|
// 滚动到对应区块
|
||||||
|
const section = document.getElementById(categoryId);
|
||||||
|
const stickyNav = document.querySelector('.sticky-nav');
|
||||||
|
|
||||||
|
if (section && stickyNav) {
|
||||||
|
const stickyHeight = stickyNav.getBoundingClientRect().height;
|
||||||
|
const sectionTop = section.offsetTop - stickyHeight;
|
||||||
|
|
||||||
|
window.scrollTo({
|
||||||
|
top: sectionTop,
|
||||||
|
behavior: 'smooth'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置定时器,1秒后重新启用滚动检测
|
||||||
|
timerRef.current = setTimeout(() => {
|
||||||
|
isManualScrollRef.current = false;
|
||||||
|
}, 1000);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="container">
|
||||||
|
{/* 页面标题 */}
|
||||||
|
<h1 className="title">滚动吸顶示例</h1>
|
||||||
|
<p className="subtitle">向下滚动查看效果</p>
|
||||||
|
|
||||||
|
{/* 粘性导航区域 */}
|
||||||
|
<div className="sticky-nav">
|
||||||
|
{/* 搜索框 */}
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
className="search-box"
|
||||||
|
placeholder="搜索..."
|
||||||
|
/>
|
||||||
|
|
||||||
|
{/* 分类标签 */}
|
||||||
|
<div className="category-tabs">
|
||||||
|
{categories.map(category => (
|
||||||
|
<button
|
||||||
|
key={category.id}
|
||||||
|
className={activeSection === category.id ? 'active' : ''}
|
||||||
|
onClick={() => handleCategoryClick(category.id)}
|
||||||
|
>
|
||||||
|
{category.name}
|
||||||
|
</button>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* 内容区域 */}
|
||||||
|
{categories.map(category => (
|
||||||
|
<div
|
||||||
|
key={category.id}
|
||||||
|
id={category.id}
|
||||||
|
className="content-section"
|
||||||
|
>
|
||||||
|
<h2>{category.name}</h2>
|
||||||
|
<p>这是{category.name}的内容区域。滚动时,当此区域进入视口中间位置,对应的分类标签会自动高亮。</p>
|
||||||
|
{/* 添加一些占位内容使页面可滚动 */}
|
||||||
|
<div className="placeholder"></div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default StickyNavExample;
|
||||||
BIN
ui components/usage/windsurf.png
Normal file
BIN
ui components/usage/windsurf.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 63 KiB |
80
wxwork.robot
Normal file
80
wxwork.robot
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
*** Settings ***
|
||||||
|
Library FlaUILibrary
|
||||||
|
Library OperatingSystem
|
||||||
|
Library Collections
|
||||||
|
Library json
|
||||||
|
|
||||||
|
*** Variables ***
|
||||||
|
${RESULTS_DIR} ${CURDIR}\\results
|
||||||
|
${AVATARS_DIR} ${RESULTS_DIR}\\avatars
|
||||||
|
|
||||||
|
*** Test Cases ***
|
||||||
|
Check If WXWork Is Running
|
||||||
|
${wxwork_running}= Is WXWork Running
|
||||||
|
Log WXWork is running: ${wxwork_running}
|
||||||
|
|
||||||
|
Click Calculator Button
|
||||||
|
# 等待计算器窗口出现
|
||||||
|
Wait Until Element Exist //Window[@Name="计算器" or @Name="Calculator"]
|
||||||
|
# 点击数字按钮
|
||||||
|
Click //Button[@Name="5" or @AutomationId="num5Button"]
|
||||||
|
Click //Button[@Name="+" or @AutomationId="plusButton"]
|
||||||
|
Click //Button[@Name="3" or @AutomationId="num3Button"]
|
||||||
|
Click //Button[@Name="=" or @AutomationId="equalButton"]
|
||||||
|
|
||||||
|
Get WeChat Work Conversation List
|
||||||
|
# 检查企业微信是否运行
|
||||||
|
${wxwork_running}= Is WXWork Running
|
||||||
|
Log WXWork is running: ${wxwork_running}
|
||||||
|
Run Keyword If not ${wxwork_running} Fail 企业微信(WXWork.exe)未运行,请先启动企业微信
|
||||||
|
|
||||||
|
# 创建结果目录
|
||||||
|
Create Directory ${RESULTS_DIR}
|
||||||
|
Create Directory ${AVATARS_DIR}
|
||||||
|
|
||||||
|
# 等待企业微信窗口出现
|
||||||
|
Wait Until Element Exist //Window[contains(@Name, "企业微信")]
|
||||||
|
Wait Until Element Exist //Pane[@Name="TitleBarWindow"]
|
||||||
|
# Wait Until Element Exist //Tree[@Name="clientbg"]
|
||||||
|
# 等待对话列表加载
|
||||||
|
Wait Until Element Exist //Tree[@Name="GeneralConversationItemView"]
|
||||||
|
|
||||||
|
# 创建一个空列表用于存储对话数据
|
||||||
|
@{conversations}= Create List
|
||||||
|
|
||||||
|
# 查找所有对话项
|
||||||
|
${conversation_items}= Find All Elements //Tree[@Name="GeneralConversationItemView"]
|
||||||
|
|
||||||
|
# 遍历每个对话项
|
||||||
|
FOR ${item} IN @{conversation_items}
|
||||||
|
# 获取当前对话项的XPath
|
||||||
|
${item_xpath}= Set Variable ${item.Xpath}
|
||||||
|
|
||||||
|
# 获取头像元素
|
||||||
|
${avatar_elements}= Find All Elements ${item_xpath}//TreeItem[@Name="avataricon"]
|
||||||
|
${avatar_element}= Set Variable ${avatar_elements}[0]
|
||||||
|
|
||||||
|
# 截取头像图片
|
||||||
|
${timestamp}= Evaluate int(round(time.time() * 1000)) time
|
||||||
|
${avatar_path}= Set Variable ${AVATARS_DIR}\\avatar_${timestamp}.png
|
||||||
|
${screenshot}= Take Screenshot ${avatar_element}
|
||||||
|
Copy File ${screenshot} ${avatar_path}
|
||||||
|
|
||||||
|
# 获取用户名元素
|
||||||
|
${username_elements}= Find All Elements ${item_xpath}//TreeItem[@Name="groupbuddyname"]
|
||||||
|
${username}= Get Name From Element ${username_elements}[0]
|
||||||
|
|
||||||
|
# 创建对话数据并添加到列表
|
||||||
|
${conversation}= Create Dictionary name=${username} avatar=file://${avatar_path}
|
||||||
|
Append To List ${conversations} ${conversation}
|
||||||
|
END
|
||||||
|
|
||||||
|
# 将对话列表保存为JSON文件
|
||||||
|
${json_string}= Evaluate json.dumps($conversations, ensure_ascii=False, indent=2) json
|
||||||
|
Create File ${RESULTS_DIR}\\conversations.json ${json_string}
|
||||||
|
|
||||||
|
*** Keywords ***
|
||||||
|
Is WXWork Running
|
||||||
|
${process_output}= Run tasklist /FI "IMAGENAME eq WXWork.exe" /FO CSV /NH
|
||||||
|
${is_running}= Run Keyword And Return Status Should Contain ${process_output} WXWork.exe
|
||||||
|
RETURN ${is_running}
|
||||||
Reference in New Issue
Block a user