first commit
This commit is contained in:
commit
03da9d407f
9
app.ux
Normal file
9
app.ux
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
<script>
|
||||||
|
/**
|
||||||
|
* 应用级别的配置,供所有页面公用
|
||||||
|
*/
|
||||||
|
|
||||||
|
export default {
|
||||||
|
onCreate() {}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
BIN
assets/.DS_Store
vendored
Normal file
BIN
assets/.DS_Store
vendored
Normal file
Binary file not shown.
BIN
assets/images/.DS_Store
vendored
Normal file
BIN
assets/images/.DS_Store
vendored
Normal file
Binary file not shown.
BIN
assets/images/logo.png
Normal file
BIN
assets/images/logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.1 KiB |
5
assets/styles/mixins.scss
Normal file
5
assets/styles/mixins.scss
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
@mixin flex-box-mixins($direction: row, $justify: center, $align-items: center) {
|
||||||
|
flex-direction: $direction;
|
||||||
|
justify-content: $justify;
|
||||||
|
align-items: $align-items;
|
||||||
|
}
|
||||||
2
assets/styles/style.scss
Normal file
2
assets/styles/style.scss
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
@import './variables.scss';
|
||||||
|
@import './mixins.scss';
|
||||||
9
assets/styles/variables.scss
Normal file
9
assets/styles/variables.scss
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
$brand: #09ba07;
|
||||||
|
|
||||||
|
$white: #ffffff;
|
||||||
|
$black: #000000;
|
||||||
|
$grey: #9393aa;
|
||||||
|
$red: #fa0101;
|
||||||
|
$green: #ffff00;
|
||||||
|
|
||||||
|
$size-factor: 5px;
|
||||||
46
manifest.json
Normal file
46
manifest.json
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
{
|
||||||
|
"package": "top.chorblack.dictionary",
|
||||||
|
"name": "dictionary",
|
||||||
|
"versionName": "1.0.0",
|
||||||
|
"versionCode": 1,
|
||||||
|
"appCategory": [
|
||||||
|
"other"
|
||||||
|
],
|
||||||
|
"icon": "/assets/images/logo.png",
|
||||||
|
"features": [
|
||||||
|
{
|
||||||
|
"name": "blueos.app.appmanager.router"
|
||||||
|
},
|
||||||
|
{ "name": "blueos.storage.file" },
|
||||||
|
{ "name": "blueos.storage.storage" },
|
||||||
|
{ "name": "blueos.window.prompt" },
|
||||||
|
{ "name": "blueos.network.fetch" }
|
||||||
|
],
|
||||||
|
"deviceTypeList": [
|
||||||
|
"watch",
|
||||||
|
"watch-square"
|
||||||
|
],
|
||||||
|
"config": {
|
||||||
|
"designWidth": 466
|
||||||
|
},
|
||||||
|
"router": {
|
||||||
|
"entry": "pages/index",
|
||||||
|
"pages": {
|
||||||
|
"pages/index": {
|
||||||
|
"component": "index"
|
||||||
|
},
|
||||||
|
"pages/search": {
|
||||||
|
"component": "index"
|
||||||
|
},
|
||||||
|
"pages/mistakes": {
|
||||||
|
"component": "index"
|
||||||
|
},
|
||||||
|
"pages/list": {
|
||||||
|
"component": "index"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"display": {
|
||||||
|
"backgroundColor": "#ffffff"
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
pages/.DS_Store
vendored
Normal file
BIN
pages/.DS_Store
vendored
Normal file
Binary file not shown.
275
pages/index/index.ux
Normal file
275
pages/index/index.ux
Normal file
@ -0,0 +1,275 @@
|
|||||||
|
<template>
|
||||||
|
<div class="wrapper">
|
||||||
|
<text class="title">{{ currentWord.word }}</text>
|
||||||
|
<input
|
||||||
|
class="btn"
|
||||||
|
if="{{!showTranslation}}"
|
||||||
|
type="button"
|
||||||
|
value="我会了"
|
||||||
|
onclick="handleKnow()"
|
||||||
|
/>
|
||||||
|
<input
|
||||||
|
class="btn"
|
||||||
|
type="button"
|
||||||
|
value="不会"
|
||||||
|
onclick="handleNotKnow()"
|
||||||
|
if="{{!showTranslation}}"
|
||||||
|
/>
|
||||||
|
<text if="{{showTranslation}}" class="translation">{{
|
||||||
|
currentWord.translation
|
||||||
|
}}</text>
|
||||||
|
<input
|
||||||
|
class="btn"
|
||||||
|
if="{{showTranslation}}"
|
||||||
|
type="button"
|
||||||
|
onclick="getNextWord()"
|
||||||
|
value="下一个"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<!-- 新增底部按钮 -->
|
||||||
|
<div class="bottom-buttons">
|
||||||
|
<input
|
||||||
|
class="btn error-btn"
|
||||||
|
type="button"
|
||||||
|
value="错题本"
|
||||||
|
onclick="handleErrorBook()"
|
||||||
|
/>
|
||||||
|
<input class="btn circle-btn" type="button" value="去下载" onclick="handleDownload()" if="{{showDownloadBtn}}"/>
|
||||||
|
<input
|
||||||
|
class="btn search-btn"
|
||||||
|
type="button"
|
||||||
|
value="搜索"
|
||||||
|
onclick="handleSearch()"
|
||||||
|
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import router from '@blueos.app.appmanager.router'
|
||||||
|
import storage from '@blueos.storage.storage';
|
||||||
|
import prompt from '@blueos.window.prompt';
|
||||||
|
import file from '@blueos.storage.file'
|
||||||
|
export default {
|
||||||
|
data: {
|
||||||
|
currentWord: {},
|
||||||
|
learnedList: [],
|
||||||
|
noLearnList: [],
|
||||||
|
showDownloadBtn:true,
|
||||||
|
showTranslation: false,
|
||||||
|
chapter: 0,
|
||||||
|
globalIndex: 0, // 全局索引
|
||||||
|
totalCount: 0,
|
||||||
|
jsonDataList: [
|
||||||
|
'output_part_1.json',
|
||||||
|
'output_part_2.json',
|
||||||
|
'output_part_3.json',
|
||||||
|
'output_part_4.json',
|
||||||
|
'output_part_5.json',
|
||||||
|
'output_part_6.json',
|
||||||
|
'output_part_7.json',
|
||||||
|
'output_part_8.json',
|
||||||
|
'output_part_9.json',
|
||||||
|
'output_part_10.json'
|
||||||
|
],
|
||||||
|
idMap: {},
|
||||||
|
wordList: []
|
||||||
|
},
|
||||||
|
onInit() {
|
||||||
|
storage.get({
|
||||||
|
key: 'isFinish',
|
||||||
|
success: (data) => data == '1' ? this.showDownloadBtn = false : 0
|
||||||
|
});
|
||||||
|
storage.get({
|
||||||
|
key: 'chapter',
|
||||||
|
success: (data) => this.chapter = data ? parseInt(data) : 0
|
||||||
|
});
|
||||||
|
storage.get({
|
||||||
|
key: 'globalIndex',
|
||||||
|
success: (data) => this.globalIndex = data ? parseInt(data) : 0
|
||||||
|
});
|
||||||
|
storage.get({
|
||||||
|
key: 'noLearnList',
|
||||||
|
success: (data) => {
|
||||||
|
if (data) {
|
||||||
|
this.noLearnList = JSON.parse(data);
|
||||||
|
// 构建初始id哈希表
|
||||||
|
this.noLearnList.forEach(item => {
|
||||||
|
this.idMap[item.id] = true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.loadCurrentChapter();
|
||||||
|
},
|
||||||
|
handleDownload() {
|
||||||
|
router.push({
|
||||||
|
uri: 'pages/list' // 请确认实际页面路径
|
||||||
|
});
|
||||||
|
},
|
||||||
|
async loadData(chapter) {
|
||||||
|
const num = this.jsonDataList[chapter];
|
||||||
|
|
||||||
|
// 将回调转换为Promise
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
file.readText({
|
||||||
|
uri: `internal://files/${num}`,
|
||||||
|
success: (data) => {
|
||||||
|
try {
|
||||||
|
const parsedData = JSON.parse(data.text);
|
||||||
|
resolve(parsedData); // 正确传递解析后的数据
|
||||||
|
} catch (e) {
|
||||||
|
reject("JSON解析失败");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
fail: (_, code) => {
|
||||||
|
reject(`文件读取失败,错误码:${code}`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
async loadCurrentChapter() {
|
||||||
|
try {
|
||||||
|
this.wordList = await this.loadData(this.chapter);
|
||||||
|
this.totalCount = this.wordList.length;
|
||||||
|
|
||||||
|
// 处理越界情况
|
||||||
|
if (this.globalIndex >= this.totalCount) {
|
||||||
|
this.handleChapterEnd();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.currentWord = this.wordList[this.globalIndex];
|
||||||
|
} catch (e) {
|
||||||
|
prompt.showToast({ message: '请先下载数据' });
|
||||||
|
}
|
||||||
|
},
|
||||||
|
getNextWord() {
|
||||||
|
this.globalIndex++;
|
||||||
|
|
||||||
|
// 章节切换检查
|
||||||
|
if (this.globalIndex >= this.totalCount) {
|
||||||
|
this.handleChapterEnd();
|
||||||
|
} else {
|
||||||
|
this.currentWord = this.wordList[this.globalIndex];
|
||||||
|
}
|
||||||
|
|
||||||
|
this.showTranslation = false;
|
||||||
|
this.saveProgress();
|
||||||
|
},
|
||||||
|
handleChapterEnd() {
|
||||||
|
this.chapter++;
|
||||||
|
this.globalIndex = 0;
|
||||||
|
|
||||||
|
// 所有章节完成处理
|
||||||
|
if (this.chapter >= this.jsonDataList.length) {
|
||||||
|
prompt.showToast({ message: '所有章节已完成!' });
|
||||||
|
this.chapter = 0; // 循环到第一章
|
||||||
|
}
|
||||||
|
|
||||||
|
this.loadCurrentChapter();
|
||||||
|
},
|
||||||
|
|
||||||
|
saveProgress() {
|
||||||
|
storage.set({ key: 'chapter', value: this.chapter.toString() });
|
||||||
|
storage.set({ key: 'globalIndex', value: this.globalIndex.toString() });
|
||||||
|
},
|
||||||
|
|
||||||
|
handleKnow() {
|
||||||
|
this.currentWord.mastered = true;
|
||||||
|
this.getNextWord();
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
handleNotKnow() {
|
||||||
|
this.showTranslation = true;
|
||||||
|
|
||||||
|
if (!this.idMap[this.currentWord.id]) {
|
||||||
|
this.idMap[this.currentWord.id] = true;
|
||||||
|
this.noLearnList.push({ ...this.currentWord });
|
||||||
|
storage.set({ key: 'noLearnList', value: JSON.stringify(this.noLearnList) });
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
handleErrorBook() {
|
||||||
|
router.push({
|
||||||
|
uri: 'pages/mistakes'
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
handleSearch() {
|
||||||
|
router.push({
|
||||||
|
uri: 'pages/search'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
@import './../../assets/styles/style.scss';
|
||||||
|
|
||||||
|
.wrapper {
|
||||||
|
@include flex-box-mixins(column, center, center);
|
||||||
|
position: relative;
|
||||||
|
height: 100%;
|
||||||
|
padding-bottom: 120px;
|
||||||
|
|
||||||
|
.title {
|
||||||
|
font-size: 7 * $size-factor;
|
||||||
|
text-align: center;
|
||||||
|
color: $black;
|
||||||
|
margin-bottom: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn {
|
||||||
|
width: 55 * $size-factor;
|
||||||
|
height: 12 * $size-factor;
|
||||||
|
border-radius: 7 * $size-factor;
|
||||||
|
background-color: $brand;
|
||||||
|
color: $white;
|
||||||
|
font-size: 5 * $size-factor;
|
||||||
|
margin-top: 7 * $size-factor;
|
||||||
|
}
|
||||||
|
|
||||||
|
.translation {
|
||||||
|
text-align: center;
|
||||||
|
margin: 10px 0;
|
||||||
|
font-size: 5 * $size-factor;
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bottom-buttons {
|
||||||
|
position: fixed;
|
||||||
|
bottom: 30px;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 0 20px;
|
||||||
|
|
||||||
|
.btn {
|
||||||
|
width: 35%;
|
||||||
|
height: 14 * $size-factor;
|
||||||
|
border-radius: 10 * $size-factor;
|
||||||
|
font-size: 5 * $size-factor;
|
||||||
|
|
||||||
|
.error-btn {
|
||||||
|
background-color: #ff4d4f;
|
||||||
|
margin-left: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-btn {
|
||||||
|
background-color: #1890ff;
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.circle-btn {
|
||||||
|
width: 25%;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
165
pages/list/index.ux
Normal file
165
pages/list/index.ux
Normal file
@ -0,0 +1,165 @@
|
|||||||
|
<template>
|
||||||
|
<div class="wrapper">
|
||||||
|
<list class="list" bounces="false">
|
||||||
|
<list-item type="ceiling">
|
||||||
|
<input
|
||||||
|
type="button"
|
||||||
|
class="button"
|
||||||
|
value="下载数据{{fileList.length}}"
|
||||||
|
onclick="downloadFile(jsonDataList)"
|
||||||
|
/>
|
||||||
|
</list-item>
|
||||||
|
<list-item type="item" for="{{ fileList }}">
|
||||||
|
<text class="text">{{ $item.uri.split('/').pop() }}</text>
|
||||||
|
</list-item>
|
||||||
|
</list>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import fetch from '@blueos.network.fetch'
|
||||||
|
import prompt from '@blueos.window.prompt'
|
||||||
|
import file from '@blueos.storage.file'
|
||||||
|
import storage from '@blueos.storage.storage'
|
||||||
|
export default {
|
||||||
|
data: {
|
||||||
|
fileList: null,
|
||||||
|
jsonDataList: ['output_part_1.json', 'output_part_10.json', 'output_part_2.json', 'output_part_3.json', 'output_part_4.json', 'output_part_5.json', 'output_part_6.json', 'output_part_7.json', 'output_part_8.json', 'output_part_9.json', 'a.json', 'b.json', 'c.json', 'd.json', 'e.json', 'f.json', 'g.json', 'h.json', 'i.json', 'j.json', 'k.json', 'l.json', 'm.json', 'n.json', 'o.json', 'p.json', 'q.json', 'r.json', 's.json', 't.json', 'u.json', 'v.json', 'w.json', 'x.json', 'y.json', 'z.json'],
|
||||||
|
},
|
||||||
|
onInit() {
|
||||||
|
file.list({
|
||||||
|
uri: 'internal://files/',
|
||||||
|
success: (data) => {
|
||||||
|
this.fileList = data.fileList;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
async fetchPromise(options) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
fetch.fetch({
|
||||||
|
...options,
|
||||||
|
success: resolve,
|
||||||
|
fail: reject,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
async writeTextPromise(options) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
file.writeText({
|
||||||
|
...options,
|
||||||
|
success: resolve,
|
||||||
|
fail: (data, code) => reject({ data, code }),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
async writeArrayBufferPromise(options) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
file.writeArrayBuffer({
|
||||||
|
...options,
|
||||||
|
success: resolve,
|
||||||
|
fail: (data, code) => reject({ data, code }),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
async getFile(fileName) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
file.get({
|
||||||
|
uri: `internal://files/${fileName}`,
|
||||||
|
success: () => {
|
||||||
|
resolve(true);
|
||||||
|
},
|
||||||
|
fail: (_, code) => {
|
||||||
|
reject(`handling fail, code = ${code}`);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
async downloadFile(data) {
|
||||||
|
prompt.showToast({ message: "开始下载" });
|
||||||
|
let totalNum = data.length;
|
||||||
|
let hasDownload = 0;
|
||||||
|
for (let i = 0; i < totalNum; i++) {
|
||||||
|
const fileName = data[i];
|
||||||
|
let isInFile = false;
|
||||||
|
try {
|
||||||
|
isInFile = await this.getFile(fileName);
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
}
|
||||||
|
if (isInFile) hasDownload++;
|
||||||
|
if (!isInFile) {
|
||||||
|
try {
|
||||||
|
let fileUri = `internal://files/${fileName}`;
|
||||||
|
let baseUrl = 'http://download.chorblack.top'
|
||||||
|
const chunkResponse = await this.fetchPromise({
|
||||||
|
url: `${baseUrl}/pd/local/dictionary/${fileName}`,
|
||||||
|
responseType: "arraybuffer",
|
||||||
|
});
|
||||||
|
const textData = chunkResponse.data;
|
||||||
|
/*
|
||||||
|
await this.writeTextPromise({
|
||||||
|
uri: fileUri,
|
||||||
|
text: textData,
|
||||||
|
});
|
||||||
|
*/
|
||||||
|
|
||||||
|
await this.writeArrayBufferPromise({
|
||||||
|
uri: fileUri,
|
||||||
|
buffer: new Uint8Array(textData),
|
||||||
|
});
|
||||||
|
|
||||||
|
prompt.showToast({
|
||||||
|
message: `还剩${data.length - i - 1}`
|
||||||
|
})
|
||||||
|
hasDownload++;
|
||||||
|
} catch (error) {
|
||||||
|
//prompt.showToast({message:`下载失败: ${error}`});
|
||||||
|
console.error(`下载失败: ${fileName}`, error);
|
||||||
|
}
|
||||||
|
file.list({
|
||||||
|
uri: 'internal://files/',
|
||||||
|
success: (data) => {
|
||||||
|
this.fileList = data.fileList;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (hasDownload == totalNum) {
|
||||||
|
prompt.showToast({ message: "下载完成" });
|
||||||
|
storage.set({
|
||||||
|
key: 'isFinish',
|
||||||
|
value: '1',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style>
|
||||||
|
.wrapper {
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
.text {
|
||||||
|
height: 180px;
|
||||||
|
width: 466px;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 40px;
|
||||||
|
background-color: #203a43;
|
||||||
|
color: #ffffff;
|
||||||
|
border-bottom: 1px solid #2c5364;
|
||||||
|
}
|
||||||
|
.title {
|
||||||
|
background-color: #0f2027;
|
||||||
|
}
|
||||||
|
.ceiling {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
|
.button {
|
||||||
|
width: 466px;
|
||||||
|
height: 80px;
|
||||||
|
align-items: center;
|
||||||
|
color: #ffffff;
|
||||||
|
background-color: #1890ff;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
111
pages/mistakes/index.ux
Normal file
111
pages/mistakes/index.ux
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
<template>
|
||||||
|
<div class="wrapper">
|
||||||
|
<vw-list-des-radio-left
|
||||||
|
list-array="{{listArray}}"
|
||||||
|
onwidgetclick="handleWidgetClick"
|
||||||
|
title="错题本"
|
||||||
|
onback="handleBack"
|
||||||
|
onscrollbottom="handleBottom"
|
||||||
|
></vw-list-des-radio-left>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import router from '@blueos.app.appmanager.router'
|
||||||
|
import storage from '@blueos.storage.storage';
|
||||||
|
import prompt from '@blueos.window.prompt';
|
||||||
|
export default {
|
||||||
|
data: {
|
||||||
|
listArray: [] // 初始化为空数组
|
||||||
|
},
|
||||||
|
|
||||||
|
onInit() {
|
||||||
|
try {
|
||||||
|
// 同步获取存储数据
|
||||||
|
const storedData = storage.getSync({ key: 'noLearnList' });
|
||||||
|
if (typeof storedData!="string") return;
|
||||||
|
// 解析数据并转换格式
|
||||||
|
if (storedData) {
|
||||||
|
const noLearnList = JSON.parse(storedData);
|
||||||
|
|
||||||
|
// 过滤无效数据并转换格式
|
||||||
|
this.listArray = noLearnList
|
||||||
|
.map(item => ({
|
||||||
|
id: item.id,
|
||||||
|
title: item.word,
|
||||||
|
des: item.translation,
|
||||||
|
checked: false,
|
||||||
|
// 保留原始数据用于后续操作
|
||||||
|
originData: item
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error('数据加载失败:', e);
|
||||||
|
// 可以添加用户提示
|
||||||
|
prompt.showToast({ message: '加载错题本失败' });
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
handleBack() {
|
||||||
|
router.replace({
|
||||||
|
uri: 'pages/index'
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
handleWidgetClick(data) {
|
||||||
|
const index = data.index;
|
||||||
|
if (index >= 0 && index < this.listArray.length) {
|
||||||
|
const targetId = this.listArray[index].id;
|
||||||
|
|
||||||
|
// 获取最新数据避免脏数据
|
||||||
|
const storedData = storage.getSync({ key: 'noLearnList' });
|
||||||
|
if (!storedData||typeof storedData!="string") return;
|
||||||
|
|
||||||
|
const noLearnList = JSON.parse(storedData);
|
||||||
|
const newList = noLearnList.filter(item => item.id !== targetId);
|
||||||
|
// 双重保障:更新存储和当前数据
|
||||||
|
storage.set({ key: 'noLearnList', value: JSON.stringify(newList) });
|
||||||
|
this.listArray = newList.map(item => ({
|
||||||
|
id: item.id,
|
||||||
|
title: item.word,
|
||||||
|
des: item.translation,
|
||||||
|
originData: item
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// 处理滚动到底部(示例)
|
||||||
|
handleBottom() {
|
||||||
|
// 可以添加加载更多逻辑
|
||||||
|
},
|
||||||
|
loadData() {
|
||||||
|
try {
|
||||||
|
const storedData = storage.getSync({ key: 'noLearnList' });
|
||||||
|
if (storedData && typeof storedData == "string") {
|
||||||
|
const noLearnList = JSON.parse(storedData);
|
||||||
|
this.listArray = noLearnList.map(item => ({
|
||||||
|
id: item.id,
|
||||||
|
title: item.word,
|
||||||
|
des: item.translation,
|
||||||
|
originData: item
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error('加载失败:', e);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.wrapper {
|
||||||
|
background-color: #000000; /* 更友好的背景色 */
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
|
/* 适配列表组件样式 */
|
||||||
|
vw-list-des-radio-left {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
350
pages/search/index.ux
Normal file
350
pages/search/index.ux
Normal file
@ -0,0 +1,350 @@
|
|||||||
|
<template>
|
||||||
|
<div class="container">
|
||||||
|
<text class="words-preview" >{{ words }}</text>
|
||||||
|
<div class="container-row-candidate">
|
||||||
|
<swiper class="wrapper" edit="true" index="{{currentIndexKey}}" id="mySwiper">
|
||||||
|
<div class="swiper-item" for="{{ count }}">
|
||||||
|
<text onclick="displayMean($idx)" class="letter-text">{{ $item }}</text>
|
||||||
|
</div>
|
||||||
|
</swiper>
|
||||||
|
</div>
|
||||||
|
<!-- 滑动键盘区域 -->
|
||||||
|
<!-- 第一行 -->
|
||||||
|
<div class="keyboard-row-scroll" scroll-x="true" if="show">
|
||||||
|
<div class="keyboard-row" for="{{row1Letters}}">
|
||||||
|
<input
|
||||||
|
type="button"
|
||||||
|
class="input-button"
|
||||||
|
value="{{$item}}"
|
||||||
|
onclick="input($item)"
|
||||||
|
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 第二行 -->
|
||||||
|
<div class="keyboard-row-scroll" scroll-x="true" if="show">
|
||||||
|
<div class="keyboard-row" for="{{row2Letters}}">
|
||||||
|
<input
|
||||||
|
type="button"
|
||||||
|
class="input-button"
|
||||||
|
value="{{$item}}"
|
||||||
|
onclick="input($item)"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 第三行 -->
|
||||||
|
<div class="keyboard-row-scroll" scroll-x="true" if="show">
|
||||||
|
<div class="keyboard-row" for="{{row3Letters}}">
|
||||||
|
<input
|
||||||
|
type="button"
|
||||||
|
class="input-button"
|
||||||
|
value="{{$item}}"
|
||||||
|
onclick="input($item)"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="function-row">
|
||||||
|
|
||||||
|
<input type="button" value="空格" class="space-button" onclick="input(' ')"></input>
|
||||||
|
<input type="button" value="←" class="backspace-button" onclick="backspace"></input>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import file from '@blueos.storage.file'
|
||||||
|
import prompt from '@blueos.window.prompt';
|
||||||
|
export default {
|
||||||
|
data: {
|
||||||
|
fromPage: "", //转跳输入法前的页面的Uri
|
||||||
|
fromPageData: null, //转跳输入法前的页面的要保存的数据(转跳页面时传过来一个对象,输入完成后传回去)
|
||||||
|
letters: "", //键盘页输入的拼音
|
||||||
|
words: " ", //键盘页中,提供编辑框后8个字符的预览
|
||||||
|
inputWords: "", //编辑框中的文字,点确定即带上此数据转跳回原页面
|
||||||
|
sindex: 0, //键盘滑动位置,实现从候选页返回时可以返回到原页面
|
||||||
|
mode: "en", //输入模式标记,中文cn,英文en,符号数字标记
|
||||||
|
caps: -1, //大小写标记
|
||||||
|
row1Letters: ["q", "w", "e", "r", "t", "y", "u", "i", "o", "p"],
|
||||||
|
row2Letters: ["a", "s", "d", "f", "g", "h", "j", "k", "l"],
|
||||||
|
row3Letters: ["z", "x", "c", "v", "b", "n", "m"],
|
||||||
|
jsonDataList: ['a.json', 'b.json', 'c.json', 'd.json', 'e.json', 'f.json', 'g.json', 'h.json', 'i.json', 'j.json', 'k.json', 'l.json', 'm.json', 'n.json', 'o.json', 'p.json', 'q.json', 'r.json', 's.json', 't.json', 'u.json', 'v.json', 'w.json', 'x.json', 'y.json', 'z.json'],
|
||||||
|
currentIndex: null,
|
||||||
|
index: -1,
|
||||||
|
count: [],
|
||||||
|
show: true,
|
||||||
|
wordJsonDataList: [
|
||||||
|
'output_part_1.json',
|
||||||
|
'output_part_2.json',
|
||||||
|
'output_part_3.json',
|
||||||
|
'output_part_4.json',
|
||||||
|
'output_part_5.json',
|
||||||
|
'output_part_6.json',
|
||||||
|
'output_part_7.json',
|
||||||
|
'output_part_8.json',
|
||||||
|
'output_part_9.json',
|
||||||
|
'output_part_10.json'
|
||||||
|
],
|
||||||
|
results: {},
|
||||||
|
currentIndexKey:0,
|
||||||
|
},
|
||||||
|
onInit() {
|
||||||
|
|
||||||
|
},
|
||||||
|
async loadWordData(chapter) {
|
||||||
|
const num = this.wordJsonDataList[chapter];
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
file.readText({
|
||||||
|
uri: `internal://files/${num}`,
|
||||||
|
success: (data) => {
|
||||||
|
try {
|
||||||
|
const parsedData = JSON.parse(data.text);
|
||||||
|
resolve(parsedData); // 正确传递解析后的数据
|
||||||
|
} catch (e) {
|
||||||
|
reject("JSON解析失败");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
fail: (_, code) => {
|
||||||
|
reject(`文件读取失败,错误码:${code}`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
async loadCurrentChapter(chapter,id) {
|
||||||
|
try {
|
||||||
|
|
||||||
|
let wordList = await this.loadWordData(chapter);
|
||||||
|
const keys = Object.keys(wordList);
|
||||||
|
const firstValue = wordList[keys[0]].id;
|
||||||
|
let num = id-firstValue;
|
||||||
|
let currentWord = wordList[num];
|
||||||
|
console.log(currentWord);
|
||||||
|
prompt.showToast({message:currentWord.translation});
|
||||||
|
} catch (e) {
|
||||||
|
prompt.showToast({ message: '请先下载数据' });
|
||||||
|
}
|
||||||
|
},
|
||||||
|
displayMean($idx){
|
||||||
|
const keys = Object.keys(this.results);
|
||||||
|
console.log(keys.length);
|
||||||
|
if ($idx >= 0 && $idx < keys.length) {
|
||||||
|
const key = keys[$idx];
|
||||||
|
const value = this.results[key];
|
||||||
|
console.log(`第 ${$idx} 个键:`, key);
|
||||||
|
console.log(`第 ${$idx} 个值:`, value);
|
||||||
|
this.loadCurrentChapter(value.chapter,value.id);
|
||||||
|
} else {
|
||||||
|
console.log("索引超出范围!");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
hideInput(){
|
||||||
|
this.show = !this.show;
|
||||||
|
},
|
||||||
|
async searchWord() {
|
||||||
|
//this.currentIndexKey = 0;
|
||||||
|
const swiper = this.$element('mySwiper');
|
||||||
|
if (swiper && swiper.swipeTo) {
|
||||||
|
swiper.swipeTo({
|
||||||
|
index: 0,
|
||||||
|
behavior: 'smooth' // 添加过渡动画
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (!this.words || this.words.length === 0) {
|
||||||
|
console.log("Error: 'this.words' is empty or undefined.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let searchIndex = this.words[0];
|
||||||
|
if (searchIndex >= 'a' && searchIndex <= 'z') {
|
||||||
|
let fileNameIndex = searchIndex.charCodeAt(0) - 'a'.charCodeAt(0);
|
||||||
|
try {
|
||||||
|
if (this.index !== fileNameIndex) {
|
||||||
|
this.index = fileNameIndex;
|
||||||
|
this.currentIndex = await this.loadData(fileNameIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 保存符合条件的 key 和 value
|
||||||
|
this.results = {};
|
||||||
|
let count = 0;
|
||||||
|
|
||||||
|
for (let key in this.currentIndex) {
|
||||||
|
if (key.startsWith(this.words) && count < 5) {
|
||||||
|
this.results[key] = this.currentIndex[key]; // 保存 key 和 value
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 输出匹配的结果
|
||||||
|
if (Object.keys(this.results).length > 0) {
|
||||||
|
//console.log(`Matched keys and values starting with '${this.words}':`, this.results);
|
||||||
|
this.count = Object.keys(this.results).slice(0, 5);
|
||||||
|
} else {
|
||||||
|
console.log(`No keys starting with '${this.words}' found.`);
|
||||||
|
prompt.showToast({message:`'${this.words}' not found.`});
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`Error loading data from ${fileNameIndex}:`, error);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.error("Error: 'searchIndex' is not a valid lowercase letter.");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async loadData(chapter) {
|
||||||
|
const num = this.jsonDataList[chapter];
|
||||||
|
// 将回调转换为Promise
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
file.readText({
|
||||||
|
uri: `internal://files/${num}`,
|
||||||
|
success: (data) => {
|
||||||
|
try {
|
||||||
|
const parsedData = JSON.parse(data.text);
|
||||||
|
resolve(parsedData); // 正确传递解析后的数据
|
||||||
|
} catch (e) {
|
||||||
|
reject("JSON解析失败");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
fail: (_, code) => {
|
||||||
|
reject(`文件读取失败,错误码:${code}`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
// 修改输入方法
|
||||||
|
input(symbol) {
|
||||||
|
|
||||||
|
this.inputWords += symbol;
|
||||||
|
this.words = this.inputWords.slice(-8);
|
||||||
|
if (this.words.length > 0) {
|
||||||
|
this.searchWord();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
backspace() {
|
||||||
|
|
||||||
|
var that = this;
|
||||||
|
this.wordsBackspace();
|
||||||
|
that.words = that.inputWords.substring(that.inputWords.length - 8)
|
||||||
|
if (this.words.length > 0) {
|
||||||
|
this.searchWord();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
wordsBackspace() {
|
||||||
|
var that = this;
|
||||||
|
if (that.inputWords.length <= 1) {
|
||||||
|
that.inputWords = "";
|
||||||
|
} else {
|
||||||
|
that.inputWords = that.inputWords.substring(0, that.inputWords.length - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.container {
|
||||||
|
flex-direction: column;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
left: 0px;
|
||||||
|
top: 0px;
|
||||||
|
width: 466px;
|
||||||
|
height: 100%;
|
||||||
|
background-color: #000000;
|
||||||
|
}
|
||||||
|
.keyboard-row-scroll {
|
||||||
|
width: 466px;
|
||||||
|
height: 60px;
|
||||||
|
margin: 5px 0;
|
||||||
|
}
|
||||||
|
.keyboard-row {
|
||||||
|
flex-direction: row;
|
||||||
|
height: 60px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-button {
|
||||||
|
width: 70px;
|
||||||
|
height: 60px;
|
||||||
|
min-width: 60px;
|
||||||
|
margin: 0 3px;
|
||||||
|
font-size: 24px;
|
||||||
|
border-radius: 5px;
|
||||||
|
background-color: #444;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
.function-row {
|
||||||
|
position:absolute;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: space-between;
|
||||||
|
width: 466px;
|
||||||
|
margin-top: 10px;
|
||||||
|
top:450px;
|
||||||
|
}
|
||||||
|
.mode-button {
|
||||||
|
width: 150px;
|
||||||
|
height: 60px;
|
||||||
|
background-color: #666;
|
||||||
|
border-radius: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.space-button {
|
||||||
|
margin: 0 5px;
|
||||||
|
height: 60px;
|
||||||
|
color: #f0f8ff;
|
||||||
|
background-color: #9f83fb;
|
||||||
|
width: 50%;
|
||||||
|
border-radius: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.backspace-button {
|
||||||
|
width: 50%;
|
||||||
|
height: 60px;
|
||||||
|
background-color: #f44336;
|
||||||
|
border-radius: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.container-row-candidate {
|
||||||
|
flex-direction: row;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
left: 0px;
|
||||||
|
top: 0px;
|
||||||
|
width: 466px;
|
||||||
|
height: 180px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.words-preview {
|
||||||
|
/* 居中定位方案 */
|
||||||
|
width: 100%;
|
||||||
|
margin: 5px 0;
|
||||||
|
font-size: 40px;
|
||||||
|
height: 60px;
|
||||||
|
|
||||||
|
/* 弹性盒子居中 */
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
/* 文本样式 */
|
||||||
|
color: #f0f8ff;
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
/* 移除冗余属性 */
|
||||||
|
position: absolute;
|
||||||
|
/* margin-left: 50px */
|
||||||
|
}
|
||||||
|
.wrapper {
|
||||||
|
width: 466px;
|
||||||
|
height: 200px;
|
||||||
|
}
|
||||||
|
.swiper-item {
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
.letter-text {
|
||||||
|
font-size: 40px;
|
||||||
|
text-align: center;
|
||||||
|
color: #f0f8ff;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
Loading…
x
Reference in New Issue
Block a user