Electron for OpenHarmony跨平台开发鸿蒙应用-春节小工具
前言
1.使用MAC 开发Electron鸿蒙跨平台应用-环境搭建及常见问题
2.Electron-Vue-ElementPlus开发鸿蒙跨平台应用-AtomGit 口袋工具
6.【实战复盘】基于 Electron + Vue3 开发 OpenHarmony 应用的阶段性总结
项目起源
不知不觉已经12月了,又是一年年末。年味越来越重了,各大直播间早已带起了年货,今天突然想做一个节日气息浓厚的小玩具,顺便跟大家分享一下,代码简单,情绪价值较高😄。
快速开始
项目的跨平台基础框架,可参照前言的文章使用MAC 开发Electron鸿蒙跨平台应用-环境搭建及常见问题
项目简介
采用vue axios快速构建
html代码如下:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>AI 智能对联生成器</title>
<!-- 引入 Vue 3 CDN -->
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<!-- 引入 Axios CDN -->
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<style>
:root {
--primary-red: #c91919;
--paper-red: #e60000;
--gold: #fcc200;
--bg-color: #fdf6ec;
}
body {
margin: 0;
padding: 0;
font-family: "Kaiti", "STKaiti", "KaiTi_GB2312", serif; /* 使用楷体更有韵味 */
background-color: var(--bg-color);
color: #333;
display: flex;
justify-content: center;
min-height: 100vh;
}
#app {
width: 100%;
max-width: 600px;
padding: 20px;
text-align: center;
}
h1 {
color: var(--primary-red);
font-size: 2.5rem;
margin-bottom: 30px;
text-shadow: 2px 2px 0px rgba(0,0,0,0.1);
}
.input-group {
display: flex;
gap: 10px;
margin-bottom: 30px;
justify-content: center;
}
input {
padding: 12px 20px;
border: 2px solid var(--primary-red);
border-radius: 25px;
font-size: 1.1rem;
width: 60%;
outline: none;
}
button {
padding: 12px 25px;
background-color: var(--primary-red);
color: var(--gold);
border: none;
border-radius: 25px;
font-size: 1.1rem;
cursor: pointer;
font-weight: bold;
transition: transform 0.1s;
}
button:active {
transform: scale(0.95);
}
button:disabled {
background-color: #ccc;
cursor: not-allowed;
}
/* 对联展示区域 */
.couplet-container {
display: flex;
flex-direction: column;
align-items: center;
gap: 20px;
margin-top: 20px;
opacity: 0;
animation: fadeIn 0.8s forwards;
}
.horizontal-scroll {
background-color: var(--paper-red);
color: black;
padding: 10px 30px;
font-size: 1.5rem;
font-weight: bold;
letter-spacing: 5px;
border-radius: 4px;
box-shadow: 0 4px 8px rgba(0,0,0,0.2);
}
.vertical-scrolls {
display: flex;
justify-content: space-between;
width: 80%;
max-width: 400px;
}
.scroll {
background-color: var(--paper-red);
color: black;
padding: 20px 15px;
font-size: 1.8rem;
font-weight: bold;
writing-mode: vertical-rl; /* 文字竖排 */
text-orientation: upright;
border-radius: 4px;
min-height: 200px;
box-shadow: 0 4px 8px rgba(0,0,0,0.2);
letter-spacing: 5px;
}
.loading-text {
color: var(--primary-red);
font-size: 1.2rem;
margin-top: 20px;
}
@keyframes fadeIn {
to { opacity: 1; }
}
.tip {
margin-top: 50px;
font-size: 0.8rem;
color: #999;
font-family: sans-serif;
}
</style>
</head>
<body>
<div id="app">
<h1>🧧 AI 智能对联</h1>
<div class="input-group">
<input
type="text"
v-model="keyword"
@keyup.enter="generateCouplet"
placeholder="输入关键词(如:新婚、春节)..."
>
<button @click="generateCouplet" :disabled="loading">
{{ loading ? '生成中...' : '求对联' }}
</button>
</div>
<!-- 加载状态 -->
<div v-if="loading" class="loading-text">
正在挥毫泼墨,请稍候...
</div>
<!-- 结果展示 -->
<div v-if="result && !loading" class="couplet-container">
<!-- 横批 -->
<div class="horizontal-scroll">
{{ result.horizontal }}
</div>
<!-- 上下联 -->
<div class="vertical-scrolls">
<!-- 右边是上联 (传统习惯) -->
<div class="scroll">
{{ result.upper }}
</div>
<!-- 左边是下联 -->
<div class="scroll">
{{ result.lower }}
</div>
</div>
</div>
<div class="tip">
当前模式: {{ useMock ? 'Mock 模拟数据' : '真实 API 请求' }}
</div>
</div>
<script>
const { createApp, ref, reactive } = Vue;
createApp({
setup() {
// --- 配置区域 ---
const useMock = ref(true); // 【开关】设置为 false 即可发送真实请求
const apiUrl = 'https://api.example.com/v1/couplet'; // 替换为你的后端地址
// ----------------
const keyword = ref('');
const loading = ref(false);
const result = ref(null);
// 1. Mock 模拟函数
const fetchMockData = (kw) => {
return new Promise((resolve) => {
setTimeout(() => {
// 根据简单的关键词返回不同的假数据,增加演示效果
let mockRes = {};
if (kw.includes('婚')) {
mockRes = { upper: '百年恩爱双心结', lower: '千里姻缘一线牵', horizontal: '喜结良缘' };
} else if (kw.includes('春') || kw.includes('年')) {
mockRes = { upper: '春风送暖入屠苏', lower: '瑞气盈门万象新', horizontal: '辞旧迎新' };
} else if (kw.includes('财')) {
mockRes = { upper: '生意兴隆通四海', lower: '财源茂盛达三江', horizontal: '财源广进' };
} else {
mockRes = { upper: '云间瑞气三千丈', lower: '花里春风十二楼', horizontal: '万事如意' };
}
resolve({ data: { code: 200, data: mockRes } });
}, 1000); // 模拟网络延迟 1秒
});
};
// 2. 真实 API 请求函数
const fetchRealApi = (kw) => {
// 这里定义你的真实后端接口格式
return axios.post(apiUrl, {
prompt: kw, // 传递给后端的参数
format: 'json'
}, {
headers: {
'Content-Type': 'application/json',
// 'Authorization': 'Bearer YOUR_TOKEN' // 如果需要 Token
}
});
};
// 3. 核心业务逻辑
const generateCouplet = async () => {
if (!keyword.value.trim()) {
alert('请先输入关键词~');
return;
}
loading.value = true;
result.value = null; // 清空旧结果
try {
let response;
if (useMock.value) {
console.log('正在使用 Mock 数据...');
response = await fetchMockData(keyword.value);
} else {
console.log('正在请求真实 API...');
response = await fetchRealApi(keyword.value);
}
// 假设后端返回结构为: { code: 200, data: { upper: '...', lower: '...', horizontal: '...' } }
const { data } = response.data;
if (data) {
result.value = {
upper: data.upper, // 上联
lower: data.lower, // 下联
horizontal: data.horizontal // 横批
};
} else {
alert('生成失败,后端返回数据格式有误');
}
} catch (error) {
console.error('请求出错:', error);
alert('生成出错了,请检查网络或控制台日志');
} finally {
loading.value = false;
}
};
return {
keyword,
loading,
result,
generateCouplet,
useMock
};
}
}).mount('#app');
</script>
</body>
</html>
对联生成:可对接AI大模型,这边采用servless快速构建,方便好玩的laf云函数快速部署,生成对联的AI接口,laf云函数代码如下:
laf 是开源的云开发平台,提供云函数、云数据库、云存储等开箱即用的应用资源。
让开发者专注于业务开发,无需折腾服务器,快速释放创意。
import cloud from '@lafjs/cloud'; // 引入 @lafjs/cloud,用于云函数开发
const db = cloud.database(); // 获取数据库实例
import axios from 'axios'; // 引入 axios,用于 HTTP 请求
const dayjs = require('dayjs'); // 引入 dayjs,用于时间格式化
const model = "deepseek-chat"
// const modelkey = process.env.DMXAPI_KEY_FAST;
// const modelkey = "sk-3e0900bf1fe14e0ff58ef"
const modelkey = "sk-dpNPBnL0JP3"
export default async function (ctx: FunctionContext) {
// 设置 axios 默认配置
axios.defaults.timeout = 20000; // 设置超时时间为 5000 毫秒 (5 秒)
const { type, prompt } = ctx.request.body || {}; // 从请求体中获取类型 (type) 和提示词 (prompt)
const ip = ctx.headers['x-forwarded-for'] || ctx.headers['x-real-ip']; // 获取客户端 IP 地址
// 检查必要参数是否存在
if (!type || !prompt) {
return {
code: 0,
msg: '缺少必要参数:type 或 prompt',
};
}
console.log(`用户:${ip}, 类型:${type}, 时间:${dayjs().format('YYYY-MM-DD HH:mm:ss')}, 提示词:${prompt}`); // 日志记录
let result;
try {
// 根据类型调用不同的生成功能
switch (type) {
case 'couplets': // 生成春联
result = await handleCoupletsGeneration(ctx, type, prompt, generateCoupletsPrompt());
break;
case 'wish': // 生成新年祝福语
result = await handleDirectGeneration(ctx, type, prompt, generateNewYearBlessingsPrompt());
break;
default:
// 未知类型返回错误
return {
code: 0,
msg: `未知的生成类型: ${type}`,
};
}
return result; // 返回结果
} catch (error) {
console.error('生成失败:', error); // 错误日志记录
return {
code: 0,
msg: '生成失败,请稍后重试',
};
}
}
// 处理对联生成逻辑,解析为 JSON 对象
async function handleCoupletsGeneration(ctx: FunctionContext, type: string, prompt: string, systemPrompt: string) {
const url = "https://www.dmxapi.com/v1/chat/completions";
const payload = JSON.stringify({
model: model,
messages: [
{ role: "system", content: systemPrompt }, // 系统提示,用于指定生成规则
{ role: "user", content: `我的提示是:${prompt}` }, // 用户输入内容
],
});
const headers = {
'Accept': 'application/json',
'Authorization': modelkey, // 从环境变量中读取 API 密钥
'User-Agent': 'mtuopenai/1.0.0 (https://www.dmxapi.com)',
'Content-Type': 'application/json',
};
const res = await fetchData(url, payload, headers, true); // 调用 API 获取结果并解析 JSON
await saveData(ctx, type, prompt, res.data); // 保存生成结果到数据库
return res;
}
// 处理直接生成逻辑,返回字符串内容
async function handleDirectGeneration(ctx: FunctionContext, type: string, prompt: string, systemPrompt: string) {
const url = "https://www.dmxapi.com/v1/chat/completions";
const payload = JSON.stringify({
model: model,
messages: [
{ role: "system", content: systemPrompt },
{ role: "user", content: `我的提示是:${prompt}` },
],
});
const headers = {
'Accept': 'application/json',
'Authorization': modelkey,
'User-Agent': 'mtuopenai/1.0.0 (https://www.dmxapi.com)',
'Content-Type': 'application/json',
};
const res = await fetchData(url, payload, headers, false); // 调用 API 获取原始字符串
await saveData(ctx, type, prompt, res.data); // 保存结果到数据库
return res;
}
// 生成春联的系统提示
function generateCoupletsPrompt(): string {
return `
请根据我的提示生成一组春联,包含上联、下联各一句,每句字数在五到十三字之间,上下联字数必须相同,并附上一个恰当的不超过五个字的横批。
并给出一个字总结。
不要使用生僻字和标点符号。
格式类型:{
"上联": "",
"下联": "",
"横批": "",
"总结": ""
}
直接给出可以被 JSON.parse 解析的字符串,不需要解释内容。
`;
}
// 生成新年祝福语的系统提示
function generateNewYearBlessingsPrompt(): string {
return `
根据我的提示生成一条新年祝福语,语言简洁、温馨、适合家庭、朋友或同事之间的交流。
直接返回字符串内容,无需 JSON 格式。
`;
}
// 生成朋友圈新年文案的系统提示
function generateNewYearPostsPrompt(): string {
return `
根据我的提示生成一条朋友圈新年文案,内容积极向上、幽默或温暖。
直接返回字符串内容,无需 JSON 格式。
`;
}
// 通用的 API 调用函数
async function fetchData(url: string, payload: string, headers: object, parseJson: boolean) {
try {
const response = await axios.post(url, payload, { headers }); // 发起 POST 请求
const msg = response.data.choices[0].message.content; // 获取返回的内容
if (parseJson) {
// 需要解析为 JSON 的情况
const parsedData = JSON.parse(msg.replace(/```json|```/g, "").trim());
return {
code: 1,
data: parsedData, // 返回解析后的数据
msg: '调用成功',
};
} else {
// 不需要解析 JSON,直接返回字符串
return {
code: 1,
data: msg.trim(),
msg: '调用成功',
};
}
} catch (error) {
console.error('API 调用失败:', error); // 错误日志记录
return {
code: 0,
data: null,
msg: '小助手走神了,再来一次吧~',
};
}
}
// 保存生成结果到数据库
async function saveData(ctx: FunctionContext, type: string, prompt: string, data: any) {
const ip = ctx.headers['x-forwarded-for'] || ctx.headers['x-real-ip']; // 获取 IP 地址
await db.collection("ai_spring").add({
type, // 生成类型
prompt, // 用户输入提示词
result: data, // 生成结果
createIp: ip, // 记录请求的 IP 地址
createTime: dayjs().format('YYYY-MM-DD HH:mm:ss'), // 记录生成时间
});
}
Axios 是一个基于 Promise 的 HTTP 客户端,用于浏览器和 Node.js。凭借其优雅的 API 设计、强大的拦截器机制以及自动转换 JSON 数据等特性,它已成为前端领域的“标准配置”。
本文将带你从零开始,掌握 Axios 的核心用法,并学会如何在实际项目中进行二次封装。
为什么选择 Axios?
虽然浏览器原生提供了 fetch API,但 Axios 依然拥有显著优势:
-
支持请求/响应拦截器(核心功能)。
-
自动转换 JSON 数据(省去了 response.json() 的步骤)。
-
客户端支持防御 XSRF。
-
优雅的错误处理。
-
取消请求机制。
axios基础示例:
import axios from 'axios';
// 1. 发送 GET 请求
async function getUser() {
try {
const response = await axios.get('/user', {
params: { id: 123 }
});
console.log(response.data);
} catch (error) {
console.error(error);
}
}
// 2. 发送 POST 请求
async function createUser() {
try {
const response = await axios.post('/user', {
firstName: 'Fred',
lastName: 'Flintstone'
});
console.log(response.data);
} catch (error) {
console.error(error);
}
}
项目预览
输入提示词,点求对联按钮即可生成自己的专属对联


最后
祝大年新年快乐!愿技术突飞猛进,再攀高峰;祝鸿蒙生态繁荣昌盛,越来越好!
欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net
更多推荐
所有评论(0)