WPS加载项·练习项目(1)—时间助手

 最近开始了WPS加载项的研究了,发现WPS加载项是越研究越香,尤其是和“加载项”相比,“WPS加载项”功能更加完善,交互方式也更齐全,比如:自定义功能区、通过功能区跳转出对应页面/窗口等等。两者之间具体的区别可以自行搜索一下。

(一)时间助手

接下来分享我的第一个使用WPS加载项实现的项目——时间助手(在表格窗口加一个显示时间的侧边栏),具体看下方演示效果:

主要的实现步骤如下:

(二)在功能区自定义一个按钮,用于时间助手这个页面的开启和关闭

代码实现:在ribbon.xml中添加一个button,button名称是“时间助手”,绑定了点击事件用于执行OnAction,并通过getImage获取该按钮的图标

<customUI xmlns="http://schemas.microsoft.com/office/2006/01/customui" onLoad="OnAddinLoad">
    <!-- 自定义功能区 -->
        <ribbon startFromScratch="false">
        <tabs>
            <!-- 标签选项卡 -->
            <tab id="wpsAddinTab" label="库存核对">
                <group>
                    <button id="Other" label="其他" onAction="OnAction" getEnabled="OnGetEnabled"  getImage="GetImage" getVisible="OnGetVisible" size="large"/> 
                    <box id="Other" boxStyle="vertical">
                        <!-- 在功能区添加一个按钮,名称是“时间助手” -->
                        <button id="time" label="时间助手" onAction="OnAction" getEnabled="OnGetEnabled"  getImage="GetImage" visible="true" size="large"/>
                        <button id="home" label="工具箱" onAction="OnAction" getEnabled="OnGetEnabled"  getImage="GetImage" visible="true" size="large"/>
                    </box>
                </group>
            </tab>
            
        </tabs>
    </ribbon>

    
    </contextMenus> -->
</customUI>

(三)在ribbon.js中配置相关对应的功能,ribbon.js在WPS加载项创建时会自动生成。

①在OnAction函数中添加侧边栏相关代码,配置路径打开对应的html页面。

function OnAction(control) {
    const eleId = control.Id
    switch (eleId) {
        case "time":
            {
                let tsId1 = wps.PluginStorage.getItem("taskpane_id1")
                if (!tsId1) {
                    let tskpane1 = wps.CreateTaskPane(GetUrlPath() + "/ui/time.html")//这里通过路径打开对应的html页面
                    let id1 = tskpane1.ID
                    wps.PluginStorage.setItem("taskpane_id1", id1)
                    tskpane1.Visible = true
                } else {
                    let tskpane1 = wps.GetTaskPane(tsId1)
                    tskpane1.Visible = !tskpane1.Visible
                }
            }
            break
        default:
            break
    }
    return true
}

② 在GetImage函数中配置button图标的路径。

function GetImage(control) {
    const eleId = control.Id
    switch (eleId) {
        // 其他
        case "Other":
            return "images/QT_logo.png"
        case "time":
            return "images/time.png"
        case "home":
            return "images/home.png" 
        default:
            ;
    }
    return "images/newFromTemp.svg"
}

(四)使用html画出侧边栏页面,比较简单所以直接用了html+css+js实现。

HTML:

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>WPS助手</title>
    <link rel="stylesheet" href="../css/time.css">
</head>
<body>
    <div class="container">
        <div class="info"> <span id="current-time" class="time"></span></div>
        <div class="info"> <span id="current-date" class="highlight"></span></div>
        <div class="info">距离下班: <span id="time-to-off" class="highlight"></span></div>
        <div class="info">下一个周末: <span id="days-to-saturday" class="highlight"></span> 天</div>
        <div class="info">下一个节假日: <span id="days-to-holiday" class="highlight"></span> 天</div>
    </div>
    <div class = 'weather'>
        <div class="tq-1">天气预报</div>
        <div class="tq">今天天气: <span id="today-weather" class="highlight"></span></div>
        <div class="tq">今天温度: <span id="today-temp" class="highlight"></span> °C</div>
        <div class="tq">明天天气: <span id="tomorrow-weather" class="highlight"></span></div>
        <div class="tq">明天温度: <span id="tomorrow-temp" class="highlight"></span> °C</div>
    </div>
    <div class="divItem">
        <div class="div2"><button class="btn" onclick="onbuttonclick('dockLeft')">停靠左边</button></div>
        <div class="div2"><button class="btn" onclick="onbuttonclick('dockRight')">停靠右边</button></div>
        <div class="div2"><button class="btn" onclick="onbuttonclick('hideTaskPane')">隐藏</button></div>
    </div>
    <script src="../js/time.js"></script>
</body>
</html>

CSS:

body, html {
    height: 100%;
    margin: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    background-color: #fffdfd;
    font-family: 'Arial', sans-serif;
}

.container {
    background-color: #fff;
    border: 2px solid #ccc;
    border-radius: 20px;
    padding: 15px;
    width: 180px;
    box-shadow: 0px 4px 8px rgba(0, 0, 0, 0.1);
    text-align: center;
    animation: fadeIn 1s ease-in-out;
    position: absolute;
    top: 10%;
    transform: translateY(-20%);
}

.info {
    margin: 20px 0;
    font-size: 20px;
    color: #333;
}

.time {
    font-size: 30px;
    color: #ff4081;
    font-weight: bold;
    animation: pulse 1.5s infinite;
}

.highlight {
    font-size: 15px;
    color: #ff4081;
    font-weight: bold;
    animation: pulse 1.5s infinite;
}

@keyframes fadeIn {
    from { opacity: 0; }
    to { opacity: 1; }
}

@keyframes pulse {
    0%, 100% { transform: scale(1); }
    50% { transform: scale(1.05); }
}

.weather {
    background-color: #fff;
    border: 2px solid #ccc;
    border-radius: 20px;
    padding: 15px;
    width: 180px;
    box-shadow: 0px 4px 8px rgba(0, 0, 0, 0.1);
    text-align: center;
    animation: fadeIn 1s ease-in-out;
    position: absolute;
    top: 46%;
    transform: translateY(-20%);
}

.tq-1 {
    margin: 20px 0;
    font-size: 20px;
    color: #333;
}

.tq {
    margin: 15px 0;
    font-size: 15px;
    color: #333;
}

.divItem {
    background-color: #fff;
    border: 2px solid #ccc;
    border-radius: 20px;
    padding: 15px;
    box-shadow: 0px 4px 8px rgba(0, 0, 0, 0.1);
    text-align: center;
    width: 180px;
    animation: fadeIn 1s ease-in-out;
    position: absolute;
    top: 77%;
    transform: translateY(-20%);
}

.div2 {
    margin: 10px 0;
    font-size: 15px;
    color: #333;
}

.btn {
    height: 50px;
    width: 100px;
    font-size: 15px;
    color: #080808;
}

.btn:hover {
    background-color: #ff4081;
    font-size: 15px;
    color: #080808;
    animation: pulse 0.5s infinite;
}

JS:

function updateTime() {
    const now = new Date();
    const currentTime = now.toLocaleTimeString();
    const currentDate = now.toLocaleDateString('zh-CN', { year: 'numeric', month: 'long', day: 'numeric', weekday: 'long' });

    document.getElementById('current-time').textContent = currentTime;
    document.getElementById('current-date').textContent = currentDate;

    const offTime = new Date();
    const zhouji = offTime.getDay();
    switch (zhouji) {
        case 3: offTime.setHours(20, 0, 0); // 周三下班时间是20:00
        break  
        case 4: offTime.setHours(20, 0, 0); // 周四下班时间是20:00
        break    
        default : offTime.setHours(18, 0, 0); // 其他下班时间是18:00
        break
    }
    const timeDifference = offTime - now;
    const hours = Math.floor((timeDifference % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
    const minutes = Math.floor((timeDifference % (1000 * 60 * 60)) / (1000 * 60));
    const seconds = Math.floor((timeDifference % (1000 * 60)) / 1000);
    const timeToOff = `${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`;
    document.getElementById('time-to-off').textContent = timeDifference > 0 ? timeToOff : "00:00:00";

    const nextSaturday = new Date(now);
    nextSaturday.setDate(now.getDate() + (6 - now.getDay()));
    const daysToSaturday = Math.ceil((nextSaturday - now) / (1000 * 60 * 60 * 24));
    document.getElementById('days-to-saturday').textContent = daysToSaturday;

    const holidays = [
        new Date(now.getFullYear(), 8, 15), // 例:中秋节9月15日
        new Date(now.getFullYear(), 9, 1), // 例:国庆节10月1日
        new Date(now.getFullYear(), 0, 1), // 例:元旦1月1日
    ];
    let daysToHoliday = Infinity;
    holidays.forEach(holiday => {
        const diff = Math.ceil((holiday - now) / (1000 * 60 * 60 * 24));
        if (diff >= 0 && diff < daysToHoliday) {
            daysToHoliday = diff;
        }
    });
    document.getElementById('days-to-holiday').textContent = daysToHoliday;

    setTimeout(updateTime, 1000);
}

function onbuttonclick(idStr) {
    if (typeof (wps.Enum) != "object") { // 如果没有内置枚举值
        wps.Enum = WPS_Enum
    }
    switch(idStr) {
        case "dockLeft": {
                let tsId = wps.PluginStorage.getItem("taskpane_id1")
                if (tsId){
                    let tskpane = wps.GetTaskPane(tsId)
                    tskpane.DockPosition = wps.Enum.msoCTPDockPositionLeft
                }
                break
            }
        case "dockRight": {
            let tsId = wps.PluginStorage.getItem("taskpane_id1")
                if (tsId){
                    let tskpane = wps.GetTaskPane(tsId)
                    tskpane.DockPosition = wps.Enum.msoCTPDockPositionRight
                }
                break
        }
        case "hideTaskPane": {
            let tsId = wps.PluginStorage.getItem("taskpane_id1")
                if (tsId){
                    let tskpane = wps.GetTaskPane(tsId)
                    tskpane.Visible = false
                }
                break
        }
        case "addString": {
            let curSheet = wps.EtApplication().ActiveSheet;
            if (curSheet){
                curSheet.Cells.Item(1, 1).Formula="Hello, wps加载项!" + curSheet.Cells.Item(1, 1).Formula
            }
            break;
        }
        case "getDocName": {
            let doc = wps.EtApplication().ActiveWorkbook
                let textValue = "";
                if (!doc){
                    textValue = textValue + "当前没有打开任何文档"
                    return
                }
                textValue = textValue + doc.Name
                document.getElementById("text_p").innerHTML = textValue
                break
        }
    }
}

// JavaScript 获取并展示天气信息的部分
const apiKey = '5e19938dc766447fb6552948242106'; // 在这里替换为你自己的 API Key
const city = 'Shanghai'; // 在这里替换为你想要查询天气的城市
function updateWeather() {
    fetch(`https://api.weatherapi.com/v1/forecast.json?key=${apiKey}&q=${city}&days=2&lang=zh`)
        .then(response => response.json())
        .then(data => {
            const todayWeather = data.forecast.forecastday[0].day.condition.text;
            const todayMaxTemp = data.forecast.forecastday[0].day.maxtemp_c;
            const todayMinTemp = data.forecast.forecastday[0].day.mintemp_c;

            const tomorrowWeather = data.forecast.forecastday[1].day.condition.text;
            const tomorrowMaxTemp = data.forecast.forecastday[1].day.maxtemp_c;
            const tomorrowMinTemp = data.forecast.forecastday[1].day.mintemp_c;

            document.getElementById('today-weather').textContent = todayWeather;
            document.getElementById('today-temp').textContent = todayMinTemp + "~" + todayMaxTemp;

            document.getElementById('tomorrow-weather').textContent = tomorrowWeather;
            document.getElementById('tomorrow-temp').textContent = tomorrowMinTemp + "~" + tomorrowMaxTemp;
        })
        .catch(error => console.error('Error fetching weather data:', error));
}

updateTime();
updateWeather();

(五)总结

        截至目前,也做了不少工作相关的WPS加载项(大部分是从之前的加载项代码转置过来的,主要是用于个人工作,定向性比较重所以就不展示分享了)。

关于WPS加载项欢迎留言讨论,或者你想要通过WPS加载项实现某些功能,也欢迎留言or私信,看到了会尽力帮你实现,

        Tip:完全免费(主要想练习)

WPS加载是指在WPS办公软件中增加的一些功能插件或扩展,用于提供更多的功能和便利用户的使用体验。WPS加载的单机发布是指将加载打包成独立的可执行文件,用户可以直接下载、安装和使用,而无需依赖于WPS办公软件的安装。 实现WPS加载的单机发布需要以下步骤: 首先,开发者需要编写好加载的源代码,并将其打包成一个独立的可执行文件。这个可执行文件可以是一个独立的安装程序或者是一个压缩包,其中包含了加载的运行所需的所有文件和依赖。 接着,开发者可使用压缩软件将该可执行文件压缩为一个方便用户下载的安装包。用户可以通过网络下载该安装包,然后解压缩并运行其中的安装程序,完成加载的安装过程。 安装程序在运行时会提供用户界面,指导用户进行加载的安装和配置。用户可以选择安装加载WPS办公软件的插件目录,或者选择安装到其他指定的目录。安装完成后,用户可以在WPS办公软件中找到加载对应的功能模块,并进行相应的操作。 通过将WPS加载进行单机发布,用户可以更方便地获取和使用各种丰富的功能扩展,而无需依赖于WPS办公软件的集成安装。这样既提高了用户的使用便利性,也为开发者提供了更大的灵活性和自由度。同时,开发者还可以通过单机发布的方式进行加载的分发和商业化推广,为自己带来更多的收益和发展机会。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值