mirror of
https://github.com/silenty4ng/k5web
synced 2025-04-01 21:25:02 +00:00
satcom 2.0
This commit is contained in:
parent
e4572fe7c2
commit
69a14d6e32
5 changed files with 580 additions and 0 deletions
|
@ -185,6 +185,7 @@ export default {
|
|||
'chat': 'Radio Chat',
|
||||
'menu.cps.writeNoticeTitle': 'Confirm',
|
||||
'menu.cps.writeNoticeContent': "Confirmation to write the channel shown on the web page to the device? (will override the device's current channel configuration)",
|
||||
'menu.satellite2': 'Satcom 2.0',
|
||||
...localeSettings,
|
||||
...localeMessageBox,
|
||||
...localeLogin,
|
||||
|
|
|
@ -185,6 +185,7 @@ export default {
|
|||
'chat': '无线电聊天',
|
||||
'menu.cps.writeNoticeTitle': '确认',
|
||||
'menu.cps.writeNoticeContent': '确认将网页显示的信道写入设备吗?(将覆盖设备当前信道配置)',
|
||||
'menu.satellite2': '星历写入 2.0',
|
||||
...localeSettings,
|
||||
...localeMessageBox,
|
||||
...localeLogin,
|
||||
|
|
|
@ -62,6 +62,16 @@ const LIST: AppRouteRecordRaw = {
|
|||
roles: ['*'],
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'sat2',
|
||||
name: 'Sat2',
|
||||
component: () => import('@/views/list/sat2/index.vue'),
|
||||
meta: {
|
||||
locale: 'menu.satellite2',
|
||||
requiresAuth: true,
|
||||
roles: ['*'],
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'bl',
|
||||
name: 'BL',
|
||||
|
|
567
src/views/list/sat2/index.vue
Normal file
567
src/views/list/sat2/index.vue
Normal file
|
@ -0,0 +1,567 @@
|
|||
<template>
|
||||
<div class="container">
|
||||
<a-modal width="650px" v-model:visible="state.selfSatModal" @ok="addSelfSat">
|
||||
<template #title>
|
||||
{{ $t("sat.selfSatInfo") }}
|
||||
</template>
|
||||
<div>
|
||||
<a-textarea v-model="state.selfSatInfo" style="height: 120px;" placeholder="ISS (ZARYA)
|
||||
1 25544U 98067A 24320.36274227 .00015569 00000+0 28188-3 0 9999
|
||||
2 25544 51.6413 286.4173 0007936 217.3657 298.3197 15.49809951481990" />
|
||||
</div>
|
||||
</a-modal>
|
||||
<a-modal v-model:visible="state.visible" @ok="handleOk" :ok-text="$t('tool.scaned')">
|
||||
<template #title>
|
||||
{{ $t('tool.scanqr') }}
|
||||
</template>
|
||||
<div style="text-align: center;">
|
||||
<img :src="state.qrcode" /><br>
|
||||
{{ $t('tool.scannotice') }}
|
||||
</div>
|
||||
</a-modal>
|
||||
<Breadcrumb :items="[$t('menu.list'), $t('menu.satellite2')]" />
|
||||
<a-row :gutter="20" align="stretch">
|
||||
<a-col :span="24">
|
||||
<a-card class="general-card" :title="$t('menu.satellite2') + $t('global.onStart')">
|
||||
<a-spin :loading="loading" style="width: 100%;" tip="正在处理 ...">
|
||||
<a-form-item :label-col-style="{ width: '25%' }" field="dt" :label="$t('tool.brtime')"
|
||||
@click="() => { state.showHide += 1 }">
|
||||
{{ state.dt }}
|
||||
</a-form-item>
|
||||
<a-form-item v-show="state.showHide >= 5" :label-col-style="{ width: '25%' }" field="dtCustom"
|
||||
label="自定义时间">
|
||||
<div>
|
||||
<a-date-picker style="width: 220px; margin: 0 24px 24px 0;" show-time
|
||||
:time-picker-props="{ defaultValue: '00:00:00' }" format="YYYY-MM-DD HH:mm:ss"
|
||||
v-model="state.dtCustom" />
|
||||
<t-button size="small" theme="success" @click="writeTime">写入时间到台站</t-button>
|
||||
</div>
|
||||
</a-form-item>
|
||||
<a-form-item :label-col-style="{ width: '25%' }" field="sat" :label="$t('tool.selectSatellite')">
|
||||
<div style="width: 100%;">
|
||||
<a-select v-model="state.sat" @change="changeSat" :placeholder="$t('tool.selectSatellite') + '...'"
|
||||
allow-search allow-clear>
|
||||
<a-option v-for="item in state.satData" :key="item.name" :value="item.name">{{ item.name }}</a-option>
|
||||
</a-select>
|
||||
<a-link @click="() => { state.selfSatModal = true }" style="margin-top: 10px;">{{ $t("sat.addSelfSat")
|
||||
}}</a-link>
|
||||
</div>
|
||||
</a-form-item>
|
||||
<a-form-item :label-col-style="{ width: '25%' }" field="sat" label="">
|
||||
<t-table ref="tableRef" row-key="key" :columns="columns" :data="state.satsData"
|
||||
:editable-cell-state="editableCellState" bordered lazy-load />
|
||||
</a-form-item>
|
||||
<a-form-item :label-col-style="{ width: '25%' }" label="">
|
||||
<a-button type="primary" @click="writeIt">{{ $t('tool.writeData') }}</a-button>
|
||||
</a-form-item>
|
||||
<a-divider />
|
||||
<div id="statusArea"
|
||||
style="height: 20em; background-color: var(--color-bg-3); color: var(--color-text-3); overflow: auto; padding: 20px"
|
||||
v-html="state.status"></div>
|
||||
</a-spin>
|
||||
</a-card>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, reactive, nextTick, onMounted, onUnmounted, computed } from 'vue';
|
||||
import { useAppStore } from '@/store';
|
||||
import { eeprom_write, eeprom_reboot, eeprom_init, hexReverseStringToUint8Array, stringToUint8Array } from '@/utils/serial.js';
|
||||
import useLoading from '@/hooks/loading';
|
||||
import QRCode from 'qrcode';
|
||||
import { Input, Select } from 'tdesign-vue-next';
|
||||
|
||||
const { loading, setLoading } = useLoading(true);
|
||||
|
||||
const appStore = useAppStore();
|
||||
|
||||
const lngRef: any = ref(null)
|
||||
const latRef: any = ref(null)
|
||||
const altRef: any = ref(null)
|
||||
|
||||
const state: {
|
||||
uuid: string,
|
||||
qrcode: string,
|
||||
showHide: number,
|
||||
status: string,
|
||||
sat: string,
|
||||
satData: any[],
|
||||
lng: number,
|
||||
lat: number,
|
||||
alt: number,
|
||||
tx: number,
|
||||
rx: number,
|
||||
txTone: number | undefined,
|
||||
CTCSSOption: any[],
|
||||
pass: any,
|
||||
passOption: any[],
|
||||
rxTone: number | undefined,
|
||||
dt: any,
|
||||
timer: any,
|
||||
passCustom: any,
|
||||
dtCustom: any,
|
||||
freqDb: any,
|
||||
visible: boolean,
|
||||
selfSatModal: boolean,
|
||||
selfSatInfo: string,
|
||||
satsData: any[]
|
||||
} = reactive({
|
||||
uuid: '',
|
||||
qrcode: '',
|
||||
visible: false,
|
||||
showHide: 0,
|
||||
status: "点击写入按钮写入卫星数据到设备<br/><br/>",
|
||||
sat: '',
|
||||
satData: [],
|
||||
lng: 0,
|
||||
lat: 0,
|
||||
alt: 0,
|
||||
tx: 0,
|
||||
rx: 0,
|
||||
txTone: 0,
|
||||
rxTone: 0,
|
||||
CTCSSOption: [0, 67.0, 69.3, 71.9, 74.4, 77.0, 79.7, 82.5, 85.4,
|
||||
88.5, 91.5, 94.8, 97.4, 100.0, 103.5, 107.2, 110.9,
|
||||
114.8, 118.8, 123.0, 127.3, 131.8, 136.5, 141.3, 146.2,
|
||||
151.4, 156.7, 159.8, 162.2, 165.5, 167.9, 171.3, 173.8,
|
||||
177.3, 179.9, 183.5, 186.2, 189.9, 192.8, 196.6, 199.5,
|
||||
203.5, 206.5, 210.7, 218.1, 225.7, 229.1, 233.6, 241.8,
|
||||
250.3, 254.1],
|
||||
pass: undefined,
|
||||
passOption: [],
|
||||
dt: '',
|
||||
timer: undefined,
|
||||
passCustom: undefined,
|
||||
dtCustom: undefined,
|
||||
freqDb: [],
|
||||
selfSatModal: false,
|
||||
selfSatInfo: '',
|
||||
satsData: []
|
||||
})
|
||||
|
||||
const editableCellState = (cellParams) => {
|
||||
// 第一行不允许编辑
|
||||
const { row } = cellParams;
|
||||
return row.status !== 2;
|
||||
};
|
||||
|
||||
const tableRef = ref();
|
||||
|
||||
const columns = computed(() => [
|
||||
{
|
||||
title: '卫星名称',
|
||||
colKey: 'satName',
|
||||
},
|
||||
{
|
||||
title: '上行频率',
|
||||
colKey: 'txFreq',
|
||||
align: 'left',
|
||||
edit: {
|
||||
component: Input,
|
||||
props: {
|
||||
clearable: true,
|
||||
autofocus: true,
|
||||
},
|
||||
// 触发校验的时机(when to validate)
|
||||
validateTrigger: 'change',
|
||||
// 透传给 component: Input 的事件(也可以在 edit.props 中添加)
|
||||
on: (editContext: any) => ({
|
||||
onBlur: () => {
|
||||
console.log('失去焦点', editContext);
|
||||
},
|
||||
onEnter: (ctx: any) => {
|
||||
ctx?.e?.preventDefault();
|
||||
console.log('onEnter', ctx);
|
||||
},
|
||||
}),
|
||||
// 除了点击非自身元素退出编辑态之外,还有哪些事件退出编辑态
|
||||
abortEditOnEvent: ['onEnter'],
|
||||
// 编辑完成,退出编辑态后触发
|
||||
onEdited: (context: any) => {
|
||||
console.log(context);
|
||||
const newData = [...state.satsData];
|
||||
newData.splice(context.rowIndex, 1, context.newRowData);
|
||||
state.satsData = newData;
|
||||
console.log('Edit firstName:', context);
|
||||
},
|
||||
rules: [
|
||||
{ required: true, message: '不能为空' },
|
||||
],
|
||||
defaultEditable: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '上行亚音',
|
||||
colKey: 'txTone',
|
||||
edit: {
|
||||
component: Select,
|
||||
// props, 透传全部属性到 Select 组件
|
||||
props: {
|
||||
clearable: true,
|
||||
options: state.CTCSSOption.map((e:any)=>{return {label: e, value: e}}),
|
||||
},
|
||||
on: (editContext: any) => ({
|
||||
onChange: (params: any) => {
|
||||
console.log('status changed', editContext, params);
|
||||
},
|
||||
}),
|
||||
// 除了点击非自身元素退出编辑态之外,还有哪些事件退出编辑态
|
||||
// abortEditOnEvent: ['onChange'],
|
||||
// 编辑完成,退出编辑态后触发
|
||||
onEdited: (context: any) => {
|
||||
state.satsData.splice(context.rowIndex, 1, context.newRowData);
|
||||
console.log('Edit Framework:', context);
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '下行频率',
|
||||
colKey: 'rxFreq',
|
||||
align: 'left',
|
||||
edit: {
|
||||
component: Input,
|
||||
props: {
|
||||
clearable: true,
|
||||
autofocus: true,
|
||||
},
|
||||
// 触发校验的时机(when to validate)
|
||||
validateTrigger: 'change',
|
||||
// 透传给 component: Input 的事件(也可以在 edit.props 中添加)
|
||||
on: (editContext: any) => ({
|
||||
onBlur: () => {
|
||||
console.log('失去焦点', editContext);
|
||||
},
|
||||
onEnter: (ctx: any) => {
|
||||
ctx?.e?.preventDefault();
|
||||
console.log('onEnter', ctx);
|
||||
},
|
||||
}),
|
||||
// 除了点击非自身元素退出编辑态之外,还有哪些事件退出编辑态
|
||||
abortEditOnEvent: ['onEnter'],
|
||||
// 编辑完成,退出编辑态后触发
|
||||
onEdited: (context: any) => {
|
||||
console.log(context);
|
||||
const newData = [...state.satsData];
|
||||
newData.splice(context.rowIndex, 1, context.newRowData);
|
||||
state.satsData = newData;
|
||||
console.log('Edit firstName:', context);
|
||||
},
|
||||
rules: [
|
||||
{ required: true, message: '不能为空' },
|
||||
],
|
||||
defaultEditable: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '下行亚音',
|
||||
colKey: 'rxTone',
|
||||
edit: {
|
||||
component: Select,
|
||||
// props, 透传全部属性到 Select 组件
|
||||
props: {
|
||||
clearable: true,
|
||||
options: state.CTCSSOption.map((e:any)=>{return {label: e, value: e}}),
|
||||
},
|
||||
on: (editContext: any) => ({
|
||||
onChange: (params: any) => {
|
||||
console.log('status changed', editContext, params);
|
||||
},
|
||||
}),
|
||||
// 除了点击非自身元素退出编辑态之外,还有哪些事件退出编辑态
|
||||
// abortEditOnEvent: ['onChange'],
|
||||
// 编辑完成,退出编辑态后触发
|
||||
onEdited: (context: any) => {
|
||||
state.satsData.splice(context.rowIndex, 1, context.newRowData);
|
||||
console.log('Edit Framework:', context);
|
||||
},
|
||||
},
|
||||
}
|
||||
]);
|
||||
|
||||
onMounted(async () => {
|
||||
try {
|
||||
if (sessionStorage.getItem('satFrequenciesRst')) {
|
||||
state.freqDb = JSON.parse(sessionStorage.getItem('satFrequenciesRst') || "[]")
|
||||
} else {
|
||||
const rst = await (await fetch('https://github.jobcher.com/gh/https://raw.githubusercontent.com/palewire/ham-satellite-database/main/data/amsat-active-frequencies.json')).text()
|
||||
state.freqDb = JSON.parse(rst)
|
||||
sessionStorage.setItem("satFrequenciesRst", rst)
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
|
||||
state.timer = setInterval(() => {
|
||||
state.dt = new Date().toLocaleString()
|
||||
localStorage.setItem('myLng', state.lng.toString());
|
||||
localStorage.setItem('myLat', state.lat.toString());
|
||||
localStorage.setItem('myAlt', state.alt.toString());
|
||||
}, 1000)
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
try {
|
||||
clearInterval(state.timer)
|
||||
} catch { }
|
||||
})
|
||||
|
||||
const writeTime = async () => {
|
||||
if (appStore.connectState != true) { alert(sessionStorage.getItem('noticeConnectK5')); return; };
|
||||
setLoading(true)
|
||||
await eeprom_init(appStore.connectPort);
|
||||
await syncTime();
|
||||
await eeprom_reboot(appStore.connectPort);
|
||||
setLoading(false)
|
||||
}
|
||||
|
||||
const syncTime = async () => {
|
||||
const date = state.dtCustom ? new Date(state.dtCustom) : new Date();
|
||||
const dateArray = [
|
||||
...hexReverseStringToUint8Array(parseInt(date.getUTCFullYear().toString().substring(2, 4)).toString(16)),
|
||||
...hexReverseStringToUint8Array((date.getUTCMonth() + 1).toString(16)),
|
||||
...hexReverseStringToUint8Array(date.getUTCDate().toString(16)),
|
||||
...hexReverseStringToUint8Array(date.getUTCHours().toString(16)),
|
||||
...hexReverseStringToUint8Array(date.getUTCMinutes().toString(16)),
|
||||
...hexReverseStringToUint8Array(date.getUTCSeconds().toString(16))
|
||||
]
|
||||
await eeprom_write(appStore.connectPort, 0x02BA0, new Uint8Array(dateArray), 0x06, appStore.configuration?.uart);
|
||||
}
|
||||
|
||||
const changeSat = async (sat: any) => {
|
||||
const data = state.satData.find(e => e.name == sat);
|
||||
if (data && data.path) {
|
||||
state.status += '<br/>卫星参数:<br/>'
|
||||
data.path.map((e: string) => {
|
||||
state.status += e + '<br/>'
|
||||
})
|
||||
let freqFlag = false
|
||||
state.freqDb.map((e: any) => {
|
||||
if (data.path[1].split(" ")[1] == e.norad_id && e.mode.indexOf('FM') != -1) {
|
||||
console.log(e)
|
||||
freqFlag = true
|
||||
state.tx = e.uplink ? parseFloat(e.uplink.split('/')[0]) : 0
|
||||
state.rx = e.downlink ? parseFloat(e.downlink.split('/')[0]) : 0
|
||||
state.txTone = parseFloat(state.CTCSSOption.reduce((_e: any, _n: any) => {
|
||||
return e.mode.indexOf(_n) != -1 ? _n : _e
|
||||
}))
|
||||
}
|
||||
})
|
||||
if (!freqFlag) {
|
||||
state.tx = 0
|
||||
state.rx = 0
|
||||
state.txTone = 0
|
||||
state.rxTone = 0
|
||||
}
|
||||
state.satsData.push({
|
||||
"satName": sat,
|
||||
"line": data.path,
|
||||
"txFreq": state.tx,
|
||||
"txTone": state.txTone,
|
||||
"rxFreq": state.rx,
|
||||
"rxTone": state.rxTone
|
||||
})
|
||||
console.log(state.satsData)
|
||||
}
|
||||
nextTick(() => {
|
||||
const textarea = document?.getElementById('statusArea');
|
||||
if (textarea) textarea.scrollTop = textarea?.scrollHeight;
|
||||
})
|
||||
}
|
||||
|
||||
const initSat = async () => {
|
||||
setLoading(true)
|
||||
let rst = ''
|
||||
if (sessionStorage.getItem('satRst')) {
|
||||
rst = sessionStorage.getItem('satRst') || ""
|
||||
} else {
|
||||
rst = await (await fetch('https://celestrak.org/NORAD/elements/amateur.txt')).text()
|
||||
sessionStorage.setItem('satRst', rst)
|
||||
}
|
||||
const lines = rst.split(/\r?\n/);
|
||||
const sat = [];
|
||||
let _sat: any = {};
|
||||
for (let i = 0; i < lines.length; i++) {
|
||||
if (Number.isNaN(parseInt(lines[i].substring(0, 1)))) {
|
||||
if (_sat.name && _sat.name != '') {
|
||||
sat.push(_sat)
|
||||
_sat = {}
|
||||
}
|
||||
_sat.name = lines[i]
|
||||
} else {
|
||||
if (!_sat.path) { _sat.path = [] }
|
||||
_sat.path.push(lines[i])
|
||||
}
|
||||
}
|
||||
state.satData = sat
|
||||
setLoading(false)
|
||||
}
|
||||
initSat()
|
||||
|
||||
const handleOk = async () => {
|
||||
const lol = await (await fetch('https://k5.vicicode.cn/api/lol', {
|
||||
method: "POST",
|
||||
mode: "cors",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
func: 1,
|
||||
uuid: state.uuid
|
||||
})
|
||||
})).json();
|
||||
const jsonLol = JSON.parse(lol.cache);
|
||||
if (jsonLol.length >= 3) {
|
||||
state.lng = jsonLol[0],
|
||||
state.lat = jsonLol[1],
|
||||
state.alt = jsonLol[2]
|
||||
}
|
||||
}
|
||||
|
||||
const restoreRange = async (start: any = 0, uint8Array: any) => {
|
||||
await eeprom_init(appStore.connectPort);
|
||||
for (let i = start; i < uint8Array.length + start; i += 0x32) {
|
||||
await eeprom_write(appStore.connectPort, i, uint8Array.slice(i - start, i - start + 0x32), 0x32, appStore.configuration?.uart);
|
||||
state.status = state.status + "写入进度:" + (((i - start) / uint8Array.length) * 100).toFixed(1) + "%<br/>";
|
||||
nextTick(() => {
|
||||
const textarea = document?.getElementById('statusArea');
|
||||
if (textarea) textarea.scrollTop = textarea?.scrollHeight;
|
||||
})
|
||||
}
|
||||
state.status = state.status + "写入进度:100.0%<br/>";
|
||||
}
|
||||
|
||||
const writeIt = async () => {
|
||||
if (appStore.connectState != true) { alert(sessionStorage.getItem('noticeConnectK5')); return; };
|
||||
setLoading(true)
|
||||
await eeprom_init(appStore.connectPort);
|
||||
// console.log(state.satsData)
|
||||
let payload = new Uint8Array(160 * 45)
|
||||
for(let i = 0; i < state.satsData.length; i++){
|
||||
const sat = state.satsData[i]
|
||||
//0x1E200~0x20000每160B是一个卫星的TLE
|
||||
// 9B名称 69B第一行 69B第二行 2B上行亚音 2B下行亚音 4B上行频率 4B下行频率
|
||||
// 卫星名称
|
||||
payload.set(stringToUint8Array(sat.satName).subarray(0,9), i * 160)
|
||||
// 第一行
|
||||
payload.set(stringToUint8Array(sat.line[0]).subarray(0,69), i * 160 + 9)
|
||||
// 第二行
|
||||
payload.set(stringToUint8Array(sat.line[1]).subarray(0,69), i * 160 + 9 + 69)
|
||||
// 上行亚音
|
||||
const _txTone = new Uint8Array(2)
|
||||
if (sat.txTone && sat.txTone > 0) {
|
||||
_txTone.set(hexReverseStringToUint8Array(parseInt((sat.txTone * 10).toFixed(0)).toString(16)).subarray(0, 0x02))
|
||||
}
|
||||
payload.set(_txTone, i * 160 + 9 + 69 + 69)
|
||||
// 下行亚音
|
||||
const _rxTone = new Uint8Array(2)
|
||||
if (sat.rxTone && sat.rxTone > 0) {
|
||||
_rxTone.set(hexReverseStringToUint8Array(parseInt((sat.rxTone * 10).toFixed(0)).toString(16)).subarray(0, 0x02))
|
||||
}
|
||||
payload.set(_rxTone, i * 160 + 9 + 69 + 69 + 2)
|
||||
// 上行频率
|
||||
const _tx = new Uint8Array(4)
|
||||
_tx.set(hexReverseStringToUint8Array(parseInt(((sat.txFreq * 1000000) / 10).toFixed(0)).toString(16)))
|
||||
payload.set(_tx, i * 160 + 9 + 69 + 69 + 2 + 2)
|
||||
// 下行频率
|
||||
const _rx = new Uint8Array(4)
|
||||
_rx.set(hexReverseStringToUint8Array(parseInt(((sat.rxFreq * 1000000) / 10).toFixed(0)).toString(16)))
|
||||
payload.set(_rx, i * 160 + 9 + 69 + 69 + 2 + 2 + 4)
|
||||
}
|
||||
await restoreRange(0x1E200, payload)
|
||||
await syncTime()
|
||||
await eeprom_reboot(appStore.connectPort);
|
||||
setLoading(false)
|
||||
}
|
||||
|
||||
const isValidURL = (url: string) => {
|
||||
const pattern = new RegExp('^(https?:\\/\\/)?' + // 协议 (http 或 https)
|
||||
'((([a-zA-Z\\d]([a-zA-Z\\d-]*[a-zA-Z\\d])*)\\.)+[a-zA-Z]{2,}|' + // 域名
|
||||
'((\\d{1,3}\\.){3}\\d{1,3}))' + // 或者 IP 地址 (IPv4)
|
||||
'(\\:\\d+)?(\\/[-a-zA-Z\\d%_.~+]*)*' + // 端口号和路径
|
||||
'(\\?[;&a-zA-Z\\d%_.~+=-]*)?' + // 查询字符串
|
||||
'(\\#[-a-zA-Z\\d_]*)?$', 'i'); // 锚点
|
||||
return !!pattern.test(url);
|
||||
}
|
||||
|
||||
const addSelfSat = async () => {
|
||||
if (isValidURL(state.selfSatInfo)) {
|
||||
state.selfSatInfo = await (await fetch(state.selfSatInfo)).text()
|
||||
}
|
||||
const lines = (state.selfSatInfo + "\n").split(/\r?\n/);
|
||||
const sat = [];
|
||||
let _sat: any = {};
|
||||
for (let i = 0; i < lines.length; i++) {
|
||||
if (Number.isNaN(parseInt(lines[i].substring(0, 1)))) {
|
||||
if (_sat.name && _sat.name != '') {
|
||||
sat.push(_sat)
|
||||
_sat = {}
|
||||
}
|
||||
_sat.name = lines[i]
|
||||
} else {
|
||||
if (!_sat.path) { _sat.path = [] }
|
||||
_sat.path.push(lines[i])
|
||||
}
|
||||
}
|
||||
state.satData = sat.concat(state.satData)
|
||||
state.selfSatInfo = ''
|
||||
}
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: 'Sat',
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
.container {
|
||||
padding: 0 20px 20px 20px;
|
||||
|
||||
:deep(.arco-list-content) {
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
:deep(.arco-card-meta-title) {
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.arco-list-col) {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
:deep(.arco-list-item) {
|
||||
width: 33%;
|
||||
}
|
||||
|
||||
:deep(.block-title) {
|
||||
margin: 0 0 12px 0;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
:deep(.list-wrap) {
|
||||
|
||||
// min-height: 140px;
|
||||
.list-row {
|
||||
align-items: stretch;
|
||||
|
||||
.list-col {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.arco-space) {
|
||||
width: 100%;
|
||||
|
||||
.arco-space-item {
|
||||
&:last-child {
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -64,6 +64,7 @@ onMounted(() => {
|
|||
{ "name": "BG4IWE", "channel": "QQ", "time": "2024-06-07", "money": "2.00" },
|
||||
{ "name": "BA7IPG", "channel": "QQ", "time": "2024-06-16", "money": "5.00" },
|
||||
{ "name": "BA3QT", "channel": "QQ", "time": "2024-11-18", "money": "6.00" },
|
||||
{ "name": "BI4ACB", "channel": "微信", "time": "2025-01-29", "money": "66.00"}
|
||||
];
|
||||
data.sort((a, b) => {
|
||||
if (parseFloat(b.money) - parseFloat(a.money) === 0){
|
||||
|
|
Loading…
Add table
Reference in a new issue