mirror of
https://github.com/silenty4ng/k5web
synced 2025-04-01 21:25:02 +00:00
update
This commit is contained in:
parent
48112e0d7e
commit
9c1e9fde65
15 changed files with 1153 additions and 1 deletions
public
src
router/routes/modules
utils
views/guide/f117
BIN
public/LOSEHU117P6.bin
Normal file
BIN
public/LOSEHU117P6.bin
Normal file
Binary file not shown.
BIN
public/LOSEHU117P6K.bin
Normal file
BIN
public/LOSEHU117P6K.bin
Normal file
Binary file not shown.
28
src/router/routes/modules/guide.ts
Normal file
28
src/router/routes/modules/guide.ts
Normal file
|
@ -0,0 +1,28 @@
|
|||
import { DEFAULT_LAYOUT } from '../base';
|
||||
import { AppRouteRecordRaw } from '../types';
|
||||
|
||||
const GUIDE: AppRouteRecordRaw = {
|
||||
path: '/guide',
|
||||
name: 'guide',
|
||||
component: DEFAULT_LAYOUT,
|
||||
meta: {
|
||||
locale: '指南',
|
||||
requiresAuth: true,
|
||||
icon: 'icon-list',
|
||||
order: 3,
|
||||
},
|
||||
children: [
|
||||
{
|
||||
path: 'f117',
|
||||
name: 'f117',
|
||||
component: () => import('@/views/guide/f117/index.vue'),
|
||||
meta: {
|
||||
locale: '使用117P6版',
|
||||
requiresAuth: true,
|
||||
roles: ['*'],
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
export default GUIDE;
|
|
@ -1099,6 +1099,143 @@ function getFontByte(string){
|
|||
return [parseInt(last_byte), parseInt(byte)]
|
||||
}
|
||||
|
||||
function flash_generateCommand(data, address, totalSize) {
|
||||
// the flash command structure is as follows:
|
||||
/* 0x19 0x5 0xc 0x1 0x8a 0x8d 0x9f 0x1d
|
||||
* address_msb address_lsb address_final_msb address_final_lsb length_msb length_lsb 0x0 0x0
|
||||
* [0x100 bytes of data, if length is <0x100 then fill the rest with zeroes] */
|
||||
|
||||
// flash is written in 0x100 blocks, if data is less than 0x100 bytes then it is padded with zeroes
|
||||
if (data.length < 0x100) {
|
||||
const padding = new Uint8Array(0x100 - data.length);
|
||||
data = new Uint8Array([...data, ...padding]);
|
||||
}
|
||||
if (data.length != 0x100) throw new Error('Tell matt that he is an idiot');
|
||||
|
||||
// the address is a 16 bit integer, so we need to split it into two bytes
|
||||
const address_msb = (address & 0xff00) >> 8;
|
||||
const address_lsb = address & 0xff;
|
||||
|
||||
const address_final = (totalSize + 0xff) & ~0xff; // add 0xff to totalSize and then round down to the next multiple of 0x100 by stripping the last byte
|
||||
if (address_final > 0xf000) throw new Error('Total size is too large');
|
||||
const address_final_msb = (address_final & 0xff00) >> 8;
|
||||
const address_final_lsb = 0x0; // since address_final can only be a multiple of 0x100, address_final_lsb is always 0x0
|
||||
|
||||
// the length is fixed to 0x100 bytes
|
||||
const length_msb = 0x01;
|
||||
const length_lsb = 0x00;
|
||||
|
||||
return new Uint8Array([0x19, 0x5, 0xc, 0x1, 0x8a, 0x8d, 0x9f, 0x1d, address_msb, address_lsb, address_final_msb, address_final_lsb, length_msb, length_lsb, 0x0, 0x0, ...data]);
|
||||
}
|
||||
|
||||
async function flash_flashFirmware(port, firmware) {
|
||||
// for loop to flash the firmware in 0x100 byte blocks
|
||||
// this loop is safe as long as the firmware file is smaller than 0xf000 bytes
|
||||
if (firmware.length > 0xefff) throw new Error('Last resort boundary check failed. Whoever touched the code is an idiot.');
|
||||
console.log('Flashing... 0%')
|
||||
|
||||
for (let i = 0; i < firmware.length; i += 0x100) {
|
||||
const data = firmware.slice(i, i + 0x100);
|
||||
const command = flash_generateCommand(data, i, firmware.length);
|
||||
|
||||
try {
|
||||
await sendPacket(port, command);
|
||||
await readPacket(port, 0x1a);
|
||||
} catch (e) {
|
||||
console.log('Flash command rejected. Aborting.');
|
||||
return Promise.reject(e);
|
||||
}
|
||||
|
||||
console.log(`Flashing... ${((i / firmware.length) * 100).toFixed(1)}%`, true);
|
||||
}
|
||||
console.log('Flashing... 100%', true)
|
||||
console.log('Successfully flashed firmware.');
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
const Crc16Tab = [0, 4129, 8258, 12387, 16516, 20645, 24774, 28903, 33032, 37161, 41290, 45419, 49548, 53677, 57806, 61935, 4657, 528, 12915, 8786, 21173, 17044, 29431, 25302, 37689, 33560, 45947, 41818, 54205, 50076, 62463, 58334, 9314, 13379, 1056, 5121, 25830, 29895, 17572, 21637, 42346, 46411, 34088, 38153, 58862, 62927, 50604, 54669, 13907, 9842, 5649, 1584, 30423, 26358, 22165, 18100, 46939, 42874, 38681, 34616, 63455, 59390, 55197, 51132, 18628, 22757, 26758, 30887, 2112, 6241, 10242, 14371, 51660, 55789, 59790, 63919, 35144, 39273, 43274, 47403, 23285, 19156, 31415, 27286, 6769, 2640, 14899, 10770, 56317, 52188, 64447, 60318, 39801, 35672, 47931, 43802, 27814, 31879, 19684, 23749, 11298, 15363, 3168, 7233, 60846, 64911, 52716, 56781, 44330, 48395, 36200, 40265, 32407, 28342, 24277, 20212, 15891, 11826, 7761, 3696, 65439, 61374, 57309, 53244, 48923, 44858, 40793, 36728, 37256, 33193, 45514, 41451, 53516, 49453, 61774, 57711, 4224, 161, 12482, 8419, 20484, 16421, 28742, 24679, 33721, 37784, 41979, 46042, 49981, 54044, 58239, 62302, 689, 4752, 8947, 13010, 16949, 21012, 25207, 29270, 46570, 42443, 38312, 34185, 62830, 58703, 54572, 50445, 13538, 9411, 5280, 1153, 29798, 25671, 21540, 17413, 42971, 47098, 34713, 38840, 59231, 63358, 50973, 55100, 9939, 14066, 1681, 5808, 26199, 30326, 17941, 22068, 55628, 51565, 63758, 59695, 39368, 35305, 47498, 43435, 22596, 18533, 30726, 26663, 6336, 2273, 14466, 10403, 52093, 56156, 60223, 64286, 35833, 39896, 43963, 48026, 19061, 23124, 27191, 31254, 2801, 6864, 10931, 14994, 64814, 60687, 56684, 52557, 48554, 44427, 40424, 36297, 31782, 27655, 23652, 19525, 15522, 11395, 7392, 3265, 61215, 65342, 53085, 57212, 44955, 49082, 36825, 40952, 28183, 32310, 20053, 24180, 11923, 16050, 3793, 7920];
|
||||
|
||||
function crc16_ccitt(data) {
|
||||
var i2, out;
|
||||
i2 = 0;
|
||||
|
||||
for (var i3 = 0, _pj_a = data.length; i3 < _pj_a; i3 += 1) {
|
||||
out = Crc16Tab[(i2 >> 8 ^ data[i3]) & 255];
|
||||
i2 = out ^ i2 << 8;
|
||||
}
|
||||
|
||||
return 65535 & i2;
|
||||
}
|
||||
|
||||
function crc16_ccitt_le(data) {
|
||||
var crc;
|
||||
crc = crc16_ccitt(data);
|
||||
return new Uint8Array([crc & 255, crc >> 8]);
|
||||
}
|
||||
|
||||
function firmware_xor(fwcontent) {
|
||||
const XOR_ARRAY = new Uint8Array([
|
||||
0x47, 0x22, 0xc0, 0x52, 0x5d, 0x57, 0x48, 0x94, 0xb1, 0x60, 0x60, 0xdb, 0x6f, 0xe3, 0x4c, 0x7c,
|
||||
0xd8, 0x4a, 0xd6, 0x8b, 0x30, 0xec, 0x25, 0xe0, 0x4c, 0xd9, 0x00, 0x7f, 0xbf, 0xe3, 0x54, 0x05,
|
||||
0xe9, 0x3a, 0x97, 0x6b, 0xb0, 0x6e, 0x0c, 0xfb, 0xb1, 0x1a, 0xe2, 0xc9, 0xc1, 0x56, 0x47, 0xe9,
|
||||
0xba, 0xf1, 0x42, 0xb6, 0x67, 0x5f, 0x0f, 0x96, 0xf7, 0xc9, 0x3c, 0x84, 0x1b, 0x26, 0xe1, 0x4e,
|
||||
0x3b, 0x6f, 0x66, 0xe6, 0xa0, 0x6a, 0xb0, 0xbf, 0xc6, 0xa5, 0x70, 0x3a, 0xba, 0x18, 0x9e, 0x27,
|
||||
0x1a, 0x53, 0x5b, 0x71, 0xb1, 0x94, 0x1e, 0x18, 0xf2, 0xd6, 0x81, 0x02, 0x22, 0xfd, 0x5a, 0x28,
|
||||
0x91, 0xdb, 0xba, 0x5d, 0x64, 0xc6, 0xfe, 0x86, 0x83, 0x9c, 0x50, 0x1c, 0x73, 0x03, 0x11, 0xd6,
|
||||
0xaf, 0x30, 0xf4, 0x2c, 0x77, 0xb2, 0x7d, 0xbb, 0x3f, 0x29, 0x28, 0x57, 0x22, 0xd6, 0x92, 0x8b
|
||||
]);
|
||||
const XOR_LEN = XOR_ARRAY.length;
|
||||
|
||||
for (let i = 0; i < fwcontent.length; i += 1) {
|
||||
fwcontent[i] ^= XOR_ARRAY[i % XOR_LEN];
|
||||
}
|
||||
|
||||
return fwcontent;
|
||||
}
|
||||
|
||||
|
||||
function unpack(encoded_firmware) {
|
||||
|
||||
if (crc16_ccitt_le(encoded_firmware.slice(0, -2)).toString() === encoded_firmware.slice(-2).toString()) {
|
||||
console.log("CRC check passed...");
|
||||
} else {
|
||||
console.log("WARNING: CRC CHECK FAILED! FIRMWARE NOT VALID!\nMake sure to choose a flashable bin file. ");
|
||||
}
|
||||
|
||||
const decoded_firmware = firmware_xor(encoded_firmware.slice(0, -2));
|
||||
const versionInfoOffset = 0x2000;
|
||||
const versionInfoLength = 16;
|
||||
const resultLength = decoded_firmware.length - versionInfoLength;
|
||||
const result = new Uint8Array(resultLength);
|
||||
|
||||
result.set(decoded_firmware.subarray(0, versionInfoOffset));
|
||||
result.set(decoded_firmware.subarray(versionInfoOffset + versionInfoLength), versionInfoOffset);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
function unpackVersion(encoded_firmware) {
|
||||
|
||||
if (crc16_ccitt_le(encoded_firmware.slice(0, -2)).toString() === encoded_firmware.slice(-2).toString()) {
|
||||
console.log("CRC check passed...");
|
||||
} else {
|
||||
console.log("WARNING: CRC CHECK FAILED! FIRMWARE NOT VALID!\nMake sure to choose a flashable bin file. ");
|
||||
}
|
||||
|
||||
const decoded_firmware = firmware_xor(encoded_firmware.slice(0, -2));
|
||||
const versionInfoOffset = 0x2000;
|
||||
const versionInfoLength = 16;
|
||||
const resultLength = decoded_firmware.length - versionInfoLength;
|
||||
const result = new Uint8Array(resultLength);
|
||||
|
||||
result.set(decoded_firmware.subarray(0, versionInfoOffset));
|
||||
result.set(decoded_firmware.subarray(versionInfoOffset + versionInfoLength), versionInfoOffset);
|
||||
|
||||
const rawVersion = decoded_firmware.subarray(versionInfoOffset, versionInfoOffset + versionInfoLength);
|
||||
|
||||
return rawVersion;
|
||||
}
|
||||
|
||||
export {
|
||||
connect,
|
||||
disconnect,
|
||||
|
@ -1113,5 +1250,8 @@ export {
|
|||
eeprom_read,
|
||||
eeprom_reboot,
|
||||
check_eeprom,
|
||||
eeprom_write
|
||||
eeprom_write,
|
||||
flash_flashFirmware,
|
||||
unpackVersion,
|
||||
unpack
|
||||
}
|
BIN
src/views/guide/f117/assets/cj1.png
Normal file
BIN
src/views/guide/f117/assets/cj1.png
Normal file
Binary file not shown.
After ![]() (image error) Size: 144 KiB |
BIN
src/views/guide/f117/assets/cj2.png
Normal file
BIN
src/views/guide/f117/assets/cj2.png
Normal file
Binary file not shown.
After ![]() (image error) Size: 224 KiB |
BIN
src/views/guide/f117/assets/cj3.png
Normal file
BIN
src/views/guide/f117/assets/cj3.png
Normal file
Binary file not shown.
After ![]() (image error) Size: 188 KiB |
204
src/views/guide/f117/components/card-wrap.vue
Normal file
204
src/views/guide/f117/components/card-wrap.vue
Normal file
|
@ -0,0 +1,204 @@
|
|||
<template>
|
||||
<div class="card-wrap">
|
||||
<a-card v-if="loading" :bordered="false" hoverable>
|
||||
<slot name="skeleton"></slot>
|
||||
</a-card>
|
||||
<a-card v-else :bordered="false" hoverable>
|
||||
<a-space align="start">
|
||||
<a-avatar
|
||||
v-if="icon"
|
||||
:size="24"
|
||||
style="margin-right: 8px; background-color: #626aea"
|
||||
>
|
||||
<icon-filter />
|
||||
</a-avatar>
|
||||
<a-card-meta>
|
||||
<template #title>
|
||||
<a-typography-text style="margin-right: 10px">
|
||||
{{ title }}
|
||||
</a-typography-text>
|
||||
<template v-if="showTag">
|
||||
<a-tag
|
||||
v-if="open && isExpires === false"
|
||||
size="small"
|
||||
color="green"
|
||||
>
|
||||
<template #icon>
|
||||
<icon-check-circle-fill />
|
||||
</template>
|
||||
<span>{{ tagText }}</span>
|
||||
</a-tag>
|
||||
<a-tag v-else-if="isExpires" size="small" color="red">
|
||||
<template #icon>
|
||||
<icon-check-circle-fill />
|
||||
</template>
|
||||
<span>{{ expiresTagText }}</span>
|
||||
</a-tag>
|
||||
</template>
|
||||
</template>
|
||||
<template #description>
|
||||
{{ description }}
|
||||
<slot></slot>
|
||||
</template>
|
||||
</a-card-meta>
|
||||
</a-space>
|
||||
<template #actions>
|
||||
<a-switch v-if="actionType === 'switch'" v-model="open" />
|
||||
<a-space v-else-if="actionType === 'button'">
|
||||
<template v-if="isExpires">
|
||||
<a-button type="outline" @click="renew">
|
||||
{{ expiresText }}
|
||||
</a-button>
|
||||
</template>
|
||||
<template v-else>
|
||||
<a-button v-if="open" @click="handleToggle">
|
||||
{{ closeTxt }}
|
||||
</a-button>
|
||||
<a-button v-else-if="!open" type="outline" @click="handleToggle">
|
||||
{{ openTxt }}
|
||||
</a-button>
|
||||
</template>
|
||||
</a-space>
|
||||
<div v-else>
|
||||
<a-space>
|
||||
<a-button @click="toggle(false)">
|
||||
{{ closeTxt }}
|
||||
</a-button>
|
||||
<a-button type="primary" @click="toggle(true)">
|
||||
{{ openTxt }}
|
||||
</a-button>
|
||||
</a-space>
|
||||
</div>
|
||||
</template>
|
||||
</a-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue';
|
||||
import { useToggle } from '@vueuse/core';
|
||||
|
||||
const props = defineProps({
|
||||
loading: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
title: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
description: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
actionType: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
defaultValue: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
openTxt: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
closeTxt: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
expiresText: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
icon: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
showTag: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
tagText: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
expires: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
expiresTagText: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
});
|
||||
const [open, toggle] = useToggle(props.defaultValue);
|
||||
const handleToggle = () => {
|
||||
toggle();
|
||||
};
|
||||
const isExpires = ref(props.expires);
|
||||
const renew = () => {
|
||||
isExpires.value = false;
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
.card-wrap {
|
||||
height: 100%;
|
||||
transition: all 0.3s;
|
||||
border: 1px solid var(--color-neutral-3);
|
||||
border-radius: 4px;
|
||||
&:hover {
|
||||
transform: translateY(-4px);
|
||||
// box-shadow: 4px 4px 10px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
:deep(.arco-card) {
|
||||
height: 100%;
|
||||
border-radius: 4px;
|
||||
.arco-card-body {
|
||||
height: 100%;
|
||||
.arco-space {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
.arco-space-item {
|
||||
height: 100%;
|
||||
&:last-child {
|
||||
flex: 1;
|
||||
}
|
||||
.arco-card-meta {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
.arco-card-meta-content {
|
||||
flex: 1;
|
||||
.arco-card-meta-description {
|
||||
margin-top: 8px;
|
||||
color: rgb(var(--gray-6));
|
||||
line-height: 20px;
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
.arco-card-meta-footer {
|
||||
margin-top: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
:deep(.arco-card-meta-title) {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
// To prevent the shaking
|
||||
line-height: 28px;
|
||||
}
|
||||
:deep(.arco-skeleton-line) {
|
||||
&:last-child {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
margin-top: 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
115
src/views/guide/f117/components/quality-inspection.vue
Normal file
115
src/views/guide/f117/components/quality-inspection.vue
Normal file
|
@ -0,0 +1,115 @@
|
|||
<template>
|
||||
<div class="list-wrap">
|
||||
<a-typography-title class="block-title" :heading="6">
|
||||
{{ $t('cardList.tab.title.content') }}
|
||||
</a-typography-title>
|
||||
<a-row class="list-row" :gutter="24">
|
||||
<a-col
|
||||
:xs="12"
|
||||
:sm="12"
|
||||
:md="12"
|
||||
:lg="6"
|
||||
:xl="6"
|
||||
:xxl="6"
|
||||
class="list-col"
|
||||
>
|
||||
<div class="card-wrap empty-wrap">
|
||||
<a-card :bordered="false" hoverable>
|
||||
<a-result :status="null" :title="$t('cardList.content.action')">
|
||||
<template #icon>
|
||||
<icon-plus style="font-size: 20px" />
|
||||
</template>
|
||||
</a-result>
|
||||
</a-card>
|
||||
</div>
|
||||
</a-col>
|
||||
<a-col
|
||||
v-for="item in renderData"
|
||||
:key="item.id"
|
||||
class="list-col"
|
||||
:xs="12"
|
||||
:sm="12"
|
||||
:md="12"
|
||||
:lg="6"
|
||||
:xl="6"
|
||||
:xxl="6"
|
||||
>
|
||||
<CardWrap
|
||||
:loading="loading"
|
||||
:title="item.title"
|
||||
:description="item.description"
|
||||
:default-value="item.enable"
|
||||
:action-type="item.actionType"
|
||||
:icon="item.icon"
|
||||
:open-txt="$t('cardList.content.inspection')"
|
||||
:close-txt="$t('cardList.content.delete')"
|
||||
:show-tag="false"
|
||||
>
|
||||
<a-descriptions
|
||||
style="margin-top: 16px"
|
||||
:data="item.data"
|
||||
layout="inline-horizontal"
|
||||
:column="2"
|
||||
/>
|
||||
<template #skeleton>
|
||||
<a-skeleton :animation="true">
|
||||
<a-skeleton-line
|
||||
:widths="['50%', '50%', '100%', '40%']"
|
||||
:rows="4"
|
||||
/>
|
||||
<a-skeleton-line :widths="['40%']" :rows="1" />
|
||||
</a-skeleton>
|
||||
</template>
|
||||
</CardWrap>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { queryInspectionList, ServiceRecord } from '@/api/list';
|
||||
import useRequest from '@/hooks/request';
|
||||
import CardWrap from './card-wrap.vue';
|
||||
|
||||
const defaultValue: ServiceRecord[] = new Array(3).fill({});
|
||||
const { loading, response: renderData } = useRequest<ServiceRecord[]>(
|
||||
queryInspectionList,
|
||||
defaultValue
|
||||
);
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
.card-wrap {
|
||||
height: 100%;
|
||||
transition: all 0.3s;
|
||||
border: 1px solid var(--color-neutral-3);
|
||||
&:hover {
|
||||
transform: translateY(-4px);
|
||||
}
|
||||
:deep(.arco-card-meta-description) {
|
||||
color: rgb(var(--gray-6));
|
||||
.arco-descriptions-item-label-inline {
|
||||
font-weight: normal;
|
||||
font-size: 12px;
|
||||
color: rgb(var(--gray-6));
|
||||
}
|
||||
.arco-descriptions-item-value-inline {
|
||||
color: rgb(var(--gray-8));
|
||||
}
|
||||
}
|
||||
}
|
||||
.empty-wrap {
|
||||
height: 200px;
|
||||
border-radius: 4px;
|
||||
:deep(.arco-card) {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 4px;
|
||||
.arco-result-title {
|
||||
color: rgb(var(--gray-6));
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
51
src/views/guide/f117/components/rules-preset.vue
Normal file
51
src/views/guide/f117/components/rules-preset.vue
Normal file
|
@ -0,0 +1,51 @@
|
|||
<template>
|
||||
<div class="list-wrap">
|
||||
<a-typography-title class="block-title" :heading="6">
|
||||
{{ $t('cardList.tab.title.preset') }}
|
||||
</a-typography-title>
|
||||
<a-row class="list-row" :gutter="24">
|
||||
<a-col
|
||||
v-for="item in renderData"
|
||||
:key="item.id"
|
||||
:xs="12"
|
||||
:sm="12"
|
||||
:md="12"
|
||||
:lg="6"
|
||||
:xl="6"
|
||||
:xxl="6"
|
||||
class="list-col"
|
||||
style="min-height: 140px"
|
||||
>
|
||||
<CardWrap
|
||||
:loading="loading"
|
||||
:title="item.title"
|
||||
:description="item.description"
|
||||
:default-value="item.enable"
|
||||
:action-type="item.actionType"
|
||||
:tag-text="$t('cardList.preset.tag')"
|
||||
>
|
||||
<template #skeleton>
|
||||
<a-skeleton :animation="true">
|
||||
<a-skeleton-line :widths="['100%', '40%']" :rows="2" />
|
||||
<a-skeleton-line :widths="['40%']" :rows="1" />
|
||||
</a-skeleton>
|
||||
</template>
|
||||
</CardWrap>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { queryRulesPresetList, ServiceRecord } from '@/api/list';
|
||||
import useRequest from '@/hooks/request';
|
||||
import CardWrap from './card-wrap.vue';
|
||||
|
||||
const defaultValue: ServiceRecord[] = new Array(6).fill({});
|
||||
const { loading, response: renderData } = useRequest<ServiceRecord[]>(
|
||||
queryRulesPresetList,
|
||||
defaultValue
|
||||
);
|
||||
</script>
|
||||
|
||||
<style scoped lang="less"></style>
|
57
src/views/guide/f117/components/the-service.vue
Normal file
57
src/views/guide/f117/components/the-service.vue
Normal file
|
@ -0,0 +1,57 @@
|
|||
<template>
|
||||
<div class="list-wrap">
|
||||
<a-typography-title class="block-title" :heading="6">
|
||||
{{ $t('cardList.tab.title.service') }}
|
||||
</a-typography-title>
|
||||
<a-row class="list-row" :gutter="24">
|
||||
<a-col
|
||||
v-for="item in renderData"
|
||||
:key="item.id"
|
||||
:xs="12"
|
||||
:sm="12"
|
||||
:md="12"
|
||||
:lg="6"
|
||||
:xl="6"
|
||||
:xxl="6"
|
||||
class="list-col"
|
||||
style="min-height: 162px"
|
||||
>
|
||||
<CardWrap
|
||||
:loading="loading"
|
||||
:title="item.title"
|
||||
:description="item.description"
|
||||
:default-value="item.enable"
|
||||
:action-type="item.actionType"
|
||||
:expires="item.expires"
|
||||
:open-txt="$t('cardList.service.open')"
|
||||
:close-txt="$t('cardList.service.cancel')"
|
||||
:expires-text="$t('cardList.service.renew')"
|
||||
:tag-text="$t('cardList.service.tag')"
|
||||
:expires-tag-text="$t('cardList.service.expiresTag')"
|
||||
:icon="item.icon"
|
||||
>
|
||||
<template #skeleton>
|
||||
<a-skeleton :animation="true">
|
||||
<a-skeleton-line :widths="['100%', '40%', '100%']" :rows="3" />
|
||||
<a-skeleton-line :widths="['40%']" :rows="1" />
|
||||
</a-skeleton>
|
||||
</template>
|
||||
</CardWrap>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { queryTheServiceList, ServiceRecord } from '@/api/list';
|
||||
import useRequest from '@/hooks/request';
|
||||
import CardWrap from './card-wrap.vue';
|
||||
|
||||
const defaultValue: ServiceRecord[] = new Array(4).fill({});
|
||||
const { loading, response: renderData } = useRequest<ServiceRecord[]>(
|
||||
queryTheServiceList,
|
||||
defaultValue
|
||||
);
|
||||
</script>
|
||||
|
||||
<style scoped lang="less"></style>
|
333
src/views/guide/f117/index.vue
Normal file
333
src/views/guide/f117/index.vue
Normal file
|
@ -0,0 +1,333 @@
|
|||
<template>
|
||||
<div class="container">
|
||||
<Breadcrumb :items="['指南', '使用117P6版']" />
|
||||
<a-row :gutter="20" align="stretch">
|
||||
<a-col :span="24">
|
||||
<a-card class="general-card" title="使用117P6版">
|
||||
<a-steps :current="state.step">
|
||||
<a-step>选择固件类型</a-step>
|
||||
<a-step>使用自定义固件</a-step>
|
||||
<a-step>完成</a-step>
|
||||
</a-steps>
|
||||
<a-divider/>
|
||||
<div v-show="state.step == 1" style="min-height: 300px; margin: 50px;">
|
||||
<p style="font-size: 1.2em; font-weight: bold;">你是否想要扩容你的设备以支持中文信道存储:</p>
|
||||
<a-radio-group type="button" v-model="state.kIt">
|
||||
<a-radio value="yes">是的,我想要硬件改造我的设备</a-radio>
|
||||
<a-radio value="no">不,我不需要中文信道</a-radio>
|
||||
</a-radio-group>
|
||||
<br>
|
||||
<div v-show="state.kIt == 'yes'">
|
||||
<p style="color: #ff0000; font-weight: bold;">声明:本方案及相应固件均为技术探索用途。对原机进行改造需要相应专业知识且可能存在安全和法律风险。使用本方案和固件代表您已认可风险并自行承担后果,包括且不限于财产损失、人员伤亡、违法犯罪等。</p>
|
||||
<p style="font-weight: bold; font-size: 1.2em;">一、相关法律</p>
|
||||
<p>
|
||||
自制、改装、拼装的无线电发射设备,应符合国家相关技术标准,并按照工信部官网链接(<a href="http://www.miit.gov.cn/jgsj/wgj/kpzs/art/2022/art_c1ffd3c47e3f455dad38246579092136.html" target="_blank" rel="noopener noreferrer">http://www.miit.gov.cn/jgsj/wgj/kpzs/art/2022/art_c1ffd3c47e3f455dad38246579092136.html</a>,或通过工信部官网-工业和信息化部-机关司局-无管局-科普知识-《关于申请设置、使用业余无线电台所用无线电发射设备相关事宜的说明》)所列情况,提供相应材料。
|
||||
</p>
|
||||
<p style="font-weight: bold; font-size: 1.2em;">二、所需工具</p>
|
||||
<p>
|
||||
写频线、螺丝刀套装、电烙铁、焊锡丝、助焊剂、精密电器清洁剂(可选)、撬棒(可选)、万用表(可选)。
|
||||
</p>
|
||||
<p style="font-weight: bold; font-size: 1.2em;">三、购买扩容芯片</p>
|
||||
<p>芯片型号:<span style="color: #ff0000;">M24M02-DRMN6</span> 或其它 SOP-8 封装 I²C 总线 2Mbit EEPROM 芯片。考虑到芯片质量及操作失误可能导致的损坏,建议多买几片备用。</p>
|
||||
</div>
|
||||
<div v-show="state.kIt == 'no'">
|
||||
<p style="color: #ff0000; font-weight: bold;">声明:本方案及相应固件均为技术探索用途。对原机进行改造需要相应专业知识且可能存在安全和法律风险。使用本方案和固件代表您已认可风险并自行承担后果,包括且不限于财产损失、人员伤亡、违法犯罪等。</p>
|
||||
<p style="font-weight: bold; font-size: 1.2em;">一、所需工具</p>
|
||||
<p>
|
||||
写频线。
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div v-show="state.step == 1" style="text-align: center;">
|
||||
<a-button type="primary" :disabled="!state.kIt" @click="state.step = 2">下一步</a-button>
|
||||
</div>
|
||||
<div v-show="state.step == 2" style="min-height: 300px; text-align: center; color: #C9CDD4; ">
|
||||
<a-spin :loading="state.loading" tip="处理中..." style="width: 100%;">
|
||||
<a-collapse :activeKey="state.flashStep" @change="(e: any)=>{state.flashStep = e; if(e[0] == 'six'){state.finish = true;}}" accordion>
|
||||
<a-collapse-item header="备份原机数据" key="one">
|
||||
<div style="text-align: left;">
|
||||
<p>在对设备进行操作前,应备份原机出厂的配置、校准数据,以保证发射性能符合国家标准。(请妥善保存备份文件)</p>
|
||||
<p>
|
||||
<a-space>
|
||||
<a-button type="primary" :disabled="state.backed" @click="backupIt">备份</a-button><span v-show="state.backed" style="color: #C9CDD4;">已备份✔</span>
|
||||
<a-button type="primary" :disabled="!state.backed" @click="state.flashStep[0] = 'two'">下一步</a-button>
|
||||
</a-space>
|
||||
</p>
|
||||
</div>
|
||||
</a-collapse-item>
|
||||
<a-collapse-item header="拆机" key="two">
|
||||
<div style="text-align: left;">
|
||||
<p>视频教程链接:
|
||||
<a href="https://www.bilibili.com/video/BV1ib4y137Ah" target="_blank" rel="noopener noreferrer">https://www.bilibili.com/video/BV1ib4y137Ah</a>
|
||||
<span style="color: #ff0000;">(硬件拆解及焊接部分可参照本视频,软件刷机部分请务必以本指南为准。)</span>
|
||||
</p>
|
||||
<div>
|
||||
①拆掉电池、天线和旋钮盖。<br>
|
||||
②用撬棒插入主机背面底部正中位置缝隙,向上撬出铝制背板。③向下后方抽出背板。前盖和主板间有扬声器导线连接,此处用力不要过猛,控制幅度,以免拉断导线。<br>
|
||||
④拿掉耳机口挡板。<br>
|
||||
⑤建议将扬声器导线拆焊,以免阻碍后续拆解和焊接,导致拉断导线。最后组装时再对扬声器导线进行焊接。<br>
|
||||
⑥拆卸屏幕(难点,请认真看视频教程!)。在屏幕左下角卡扣位置,用撬棒向内按压同时向上抬起即可拆卸左侧,屏幕左侧松脱后另一侧拆卸相对简单。此处用力不要过猛,控制幅度,屏幕完全拆卸后应妥善固定,以免拉断、折断背面上方排线。<br>
|
||||
⑦拆卸全部 5 颗螺丝并分离背板。
|
||||
</div>
|
||||
<img :src="cj1">
|
||||
<div>
|
||||
需要更换的芯片位于主板背面右下角,型号为 BL24C64A。
|
||||
</div>
|
||||
<img :src="cj2">
|
||||
<div>
|
||||
①拆焊及焊接。有动手能力的朋友自行操作,要求芯片方向正确(以第1 脚圆点为准),焊点饱满,无虚焊、短路,芯片周围的电子元器件保持完好。建议用300℃以上小刀头烙铁配合助焊剂,不建议用热风枪(高手除外)。手残党可以去手机维修店更换,费用5-30 元不等。若周围元件遭到破坏,可按下图参数更换补救。
|
||||
</div>
|
||||
<img :src="cj3">
|
||||
<div>
|
||||
②将主板装回背板。(背板上 3x5mm 导热硅胶垫若脱落,请务必装回对应凸起位置;电池触点部分过背板孔时当心压弯。)<br>
|
||||
③装入电池,按住 PTT 键开机,进入刷机模式(此时手电筒常亮、屏幕无显示)。如无法进入刷机模式,检查电池接触片是否错位、焊点及周边元件是否完好。
|
||||
</div>
|
||||
<div style="color: #ff0000; font-weight: bold;">
|
||||
此时先不要完全组装手台,待后续工作全部完成后再行组装,以便故障返工。此阶段如尝试正常开机后显示异常、电量异常、接收异常等均为正常情况,不用担心。后续操作后会恢复正常。
|
||||
</div>
|
||||
<div>
|
||||
<a-button type="primary" @click="state.flashStep[0] = 'three'">下一步</a-button>
|
||||
</div>
|
||||
</div>
|
||||
</a-collapse-item>
|
||||
<a-collapse-item header="刷入固件" key="three">
|
||||
<div style="text-align: left;">
|
||||
<p>断开写频线,按住 PTT 键开机,进入刷机模式(此时手电筒常亮、屏幕无显示),手电筒常亮后插回写频线。</p>
|
||||
<p>
|
||||
<a-space>
|
||||
<a-button type="primary" :disabled="state.flashIt" @click="iFlashIt">刷入固件</a-button>
|
||||
<a-button type="primary" :disabled="!state.flashIt" @click="state.flashStep[0] = 'four'">下一步</a-button>
|
||||
</a-space>
|
||||
</p>
|
||||
</div>
|
||||
</a-collapse-item>
|
||||
<a-collapse-item header="刷回原机数据" key="four">
|
||||
<div style="text-align: left;">
|
||||
<p>正常开机,使设备处于开机状态,点击刷回备份数据。</p>
|
||||
<p>
|
||||
<a-space>
|
||||
<a-button type="primary" :disabled="state.restoreBackupIt" @click="restoreBackup">刷回备份数据</a-button>
|
||||
<a-button type="primary" :disabled="!state.restoreBackupIt" @click="state.flashStep[0] = 'five'">下一步</a-button>
|
||||
</a-space>
|
||||
</p>
|
||||
</div>
|
||||
</a-collapse-item>
|
||||
<a-collapse-item header="刷入字库" key="five">
|
||||
<div style="text-align: left;">
|
||||
<p>正常开机,使设备处于开机状态,点击刷入字库。</p>
|
||||
<p>
|
||||
<a-space>
|
||||
<a-button type="primary" :disabled="state.flashFontIt" @click="flashFont">刷入字库</a-button>
|
||||
<a-button type="primary" :disabled="!state.flashFontIt" @click="state.flashStep[0] = 'six'">下一步</a-button>
|
||||
</a-space>
|
||||
</p>
|
||||
</div>
|
||||
</a-collapse-item>
|
||||
<a-collapse-item header="完全组装" key="six">
|
||||
<div style="text-align: left;">按拆解顺序进行焊接和组装。</div>
|
||||
</a-collapse-item>
|
||||
</a-collapse>
|
||||
</a-spin>
|
||||
</div>
|
||||
<div v-show="state.step == 2" style="text-align: center;">
|
||||
<a-space>
|
||||
<a-button :disabled="!state.kIt" @click="state.step = 1">上一步</a-button>
|
||||
<a-button type="primary" :disabled="!state.finish" @click="state.step = 3">完成</a-button>
|
||||
</a-space>
|
||||
</div>
|
||||
<div v-show="state.step == 3" style="min-height: 300px; text-align: center; color: #C9CDD4; ">
|
||||
<a-result
|
||||
class="result"
|
||||
status="success"
|
||||
subtitle="刷入成功"
|
||||
/>
|
||||
<a-button type="primary" @click="()=>{router.push('/chirp/base');}">
|
||||
返回首页
|
||||
</a-button>
|
||||
</div>
|
||||
</a-card>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { reactive, nextTick } from 'vue';
|
||||
import { useRouter, useRoute } from 'vue-router';
|
||||
import { useAppStore } from '@/store';
|
||||
import { eeprom_write, eeprom_reboot, eeprom_init, eeprom_read, flash_flashFirmware, connect, disconnect, sendPacket, unpackVersion, readPacket, unpack } from '@/utils/serial.js';
|
||||
import cj1 from './assets/cj1.png'
|
||||
import cj2 from './assets/cj2.png'
|
||||
import cj3 from './assets/cj3.png'
|
||||
|
||||
const appStore = useAppStore();
|
||||
const router = useRouter();
|
||||
|
||||
const state : {
|
||||
step: any,
|
||||
flashStep: any,
|
||||
backed: any,
|
||||
kIt: any,
|
||||
flashIt: any,
|
||||
restoreBackupIt: any,
|
||||
loading: any,
|
||||
flashFontIt: any,
|
||||
finish: any
|
||||
} = reactive({
|
||||
step: 1,
|
||||
flashStep: ['one'],
|
||||
backed: undefined,
|
||||
kIt: undefined,
|
||||
flashIt: false,
|
||||
restoreBackupIt: false,
|
||||
loading: false,
|
||||
flashFontIt: false,
|
||||
finish: false
|
||||
})
|
||||
|
||||
const backupRange = async (start: any, end: any, name: any = new Date() + '_backup.bin') =>{
|
||||
await eeprom_init(appStore.connectPort);
|
||||
let rawEEPROM = new Uint8Array(end - start);
|
||||
for (let i = start; i < end; i += 0x80) {
|
||||
const data = await eeprom_read(appStore.connectPort, i);
|
||||
rawEEPROM.set(data, i - start);
|
||||
}
|
||||
const blob = new Blob([rawEEPROM], { type: 'application/octet-stream' });
|
||||
const url = URL.createObjectURL(blob);
|
||||
const a = document.createElement('a');
|
||||
a.href = url;
|
||||
a.download = name;
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
document.body.removeChild(a);
|
||||
URL.revokeObjectURL(url);
|
||||
return rawEEPROM;
|
||||
}
|
||||
|
||||
const restoreRange = async (start: any = 0, uint8Array: any) => {
|
||||
await eeprom_init(appStore.connectPort);
|
||||
for (let i = start; i < uint8Array.length + start; i += 0x80) {
|
||||
await eeprom_write(appStore.connectPort, i, uint8Array.slice(i - start, i - start + 0x80));
|
||||
}
|
||||
await eeprom_reboot(appStore.connectPort);
|
||||
}
|
||||
|
||||
const backupIt = async () => {
|
||||
if(appStore.connectState != true){alert('点击右上角“连接”按钮连接手台。'); return;};
|
||||
state.loading = true
|
||||
state.backed = await backupRange(0, 0x2000);
|
||||
console.log(state.backed)
|
||||
state.loading = false
|
||||
}
|
||||
|
||||
const iFlashIt = async () => {
|
||||
state.loading = true
|
||||
let fontPacket = undefined
|
||||
if(state.kIt){
|
||||
fontPacket = await fetch('/LOSEHU117P6K.bin')
|
||||
}else{
|
||||
fontPacket = await fetch('/LOSEHU117P6.bin')
|
||||
}
|
||||
const reader = fontPacket.body.getReader();
|
||||
const chunks = [];
|
||||
while(true) {
|
||||
const {done, value} = await reader.read();
|
||||
if (done) {
|
||||
break;
|
||||
}
|
||||
chunks.push(...value)
|
||||
}
|
||||
const binary = new Uint8Array(chunks)
|
||||
if(appStore.connectPort){
|
||||
await disconnect(appStore.connectPort);
|
||||
}
|
||||
let _connect = await connect();
|
||||
await readPacket(_connect, 0x18, 1000);
|
||||
const rawVersion = unpackVersion(binary);
|
||||
const _data = new Uint8Array([0x30, 0x5, rawVersion.length, 0x0, ...rawVersion]);
|
||||
await sendPacket(_connect, _data);
|
||||
await readPacket(_connect, 0x18)
|
||||
await flash_flashFirmware(_connect, unpack(binary))
|
||||
appStore.updateSettings({ connectPort: _connect });
|
||||
state.flashIt = true
|
||||
state.loading = false
|
||||
}
|
||||
|
||||
const restoreBackup = async () => {
|
||||
if(appStore.connectState != true){alert('点击右上角“连接”按钮连接手台。'); return;};
|
||||
state.loading = true
|
||||
await restoreRange(0, state.backed);
|
||||
state.restoreBackupIt = true;
|
||||
state.loading = false
|
||||
}
|
||||
|
||||
const flashFont = async () => {
|
||||
state.loading = true
|
||||
const fontPacket = await fetch('/old_font.bin')
|
||||
const reader = fontPacket.body.getReader();
|
||||
const chunks = [];
|
||||
while(true) {
|
||||
const {done, value} = await reader.read();
|
||||
if (done) {
|
||||
break;
|
||||
}
|
||||
chunks.push(...value)
|
||||
}
|
||||
const binary = new Uint8Array(chunks)
|
||||
await restoreRange(0x02000, binary)
|
||||
state.flashFontIt = true;
|
||||
state.loading = false
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: 'Chi',
|
||||
};
|
||||
</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>
|
19
src/views/guide/f117/locale/en-US.ts
Normal file
19
src/views/guide/f117/locale/en-US.ts
Normal file
|
@ -0,0 +1,19 @@
|
|||
export default {
|
||||
'menu.list.cardList': 'Card List',
|
||||
'cardList.tab.title.all': 'All',
|
||||
'cardList.tab.title.content': 'Quality Inspection',
|
||||
'cardList.tab.title.service': 'The service',
|
||||
'cardList.tab.title.preset': 'Rules Preset',
|
||||
'cardList.searchInput.placeholder': 'Search',
|
||||
'cardList.enable': 'Enable',
|
||||
'cardList.disable': 'Disable',
|
||||
'cardList.content.delete': 'Delete',
|
||||
'cardList.content.inspection': 'Inspection',
|
||||
'cardList.content.action': 'Click Create Qc Content queue',
|
||||
'cardList.service.open': 'Open',
|
||||
'cardList.service.cancel': 'Cancel',
|
||||
'cardList.service.renew': 'Contract of service',
|
||||
'cardList.service.tag': 'Opened',
|
||||
'cardList.service.expiresTag': 'Expired',
|
||||
'cardList.preset.tag': 'Enable',
|
||||
};
|
19
src/views/guide/f117/locale/zh-CN.ts
Normal file
19
src/views/guide/f117/locale/zh-CN.ts
Normal file
|
@ -0,0 +1,19 @@
|
|||
export default {
|
||||
'menu.list.cardList': '卡片列表',
|
||||
'cardList.tab.title.all': '全部',
|
||||
'cardList.tab.title.content': '内容质检',
|
||||
'cardList.tab.title.service': '开通服务',
|
||||
'cardList.tab.title.preset': '规则预置',
|
||||
'cardList.searchInput.placeholder': '搜索',
|
||||
// 'cardList.statistic.enable': '已启用',
|
||||
// 'cardList.statistic.disable': '未启用',
|
||||
'cardList.content.delete': '删除',
|
||||
'cardList.content.inspection': '质检',
|
||||
'cardList.content.action': '点击创建质检内容队列',
|
||||
'cardList.service.open': '开通服务',
|
||||
'cardList.service.cancel': '取消服务',
|
||||
'cardList.service.renew': '续约服务',
|
||||
'cardList.service.tag': '已开通',
|
||||
'cardList.service.expiresTag': '已过期',
|
||||
'cardList.preset.tag': '已启用',
|
||||
};
|
186
src/views/guide/f117/mock.ts
Normal file
186
src/views/guide/f117/mock.ts
Normal file
|
@ -0,0 +1,186 @@
|
|||
import Mock from 'mockjs';
|
||||
import setupMock, { successResponseWrap } from '@/utils/setup-mock';
|
||||
import { ServiceRecord } from '@/api/list';
|
||||
|
||||
const qualityInspectionList: ServiceRecord[] = [
|
||||
{
|
||||
id: 1,
|
||||
name: 'quality',
|
||||
title: '视频类-历史导入',
|
||||
description: '2021-10-12 00:00:00',
|
||||
data: [
|
||||
{
|
||||
label: '待质检数',
|
||||
value: '120',
|
||||
},
|
||||
{
|
||||
label: '积压时长',
|
||||
value: '60s',
|
||||
},
|
||||
{
|
||||
label: '待抽检数',
|
||||
value: '0',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: 'quality',
|
||||
title: '图文类-图片版权',
|
||||
description: '2021-12-11 18:30:00',
|
||||
data: [
|
||||
{
|
||||
label: '待质检数',
|
||||
value: '120',
|
||||
},
|
||||
{
|
||||
label: '积压时长',
|
||||
value: '60s',
|
||||
},
|
||||
{
|
||||
label: '待抽检数',
|
||||
value: '0',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: 'quality',
|
||||
title: '图文类-高清图片',
|
||||
description: '2021-10-15 08:10:00',
|
||||
data: [
|
||||
{
|
||||
label: '待质检数',
|
||||
value: '120',
|
||||
},
|
||||
{
|
||||
label: '积压时长',
|
||||
value: '60s',
|
||||
},
|
||||
{
|
||||
label: '待抽检数',
|
||||
value: '0',
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
const theServiceList: ServiceRecord[] = [
|
||||
{
|
||||
id: 1,
|
||||
icon: 'code',
|
||||
title: '漏斗分析',
|
||||
description:
|
||||
'用户行为分析之漏斗分析模型是企业实现精细化运营、进行用户行为分析的重要数据分析模型。',
|
||||
enable: true,
|
||||
actionType: 'button',
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
icon: 'edit',
|
||||
title: '用户分布',
|
||||
description:
|
||||
'快速诊断用户人群,地域细分情况,了解数据分布的集中度,以及主要的数据分布的区间段是什么。',
|
||||
enable: true,
|
||||
actionType: 'button',
|
||||
expires: true,
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
icon: 'user',
|
||||
title: '资源分发',
|
||||
description:
|
||||
'移动端动态化资源分发解决方案。提供稳定大流量服务支持、灵活定制的分发圈选规则,通过离线化预加载。',
|
||||
enable: false,
|
||||
actionType: 'button',
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
icon: 'user',
|
||||
title: '用户画像分析',
|
||||
description:
|
||||
'用户画像就是将典型用户信息标签化,根据用户特征、业务场景和用户行为等信息,构建一个标签化的用户模型。',
|
||||
enable: true,
|
||||
actionType: 'button',
|
||||
},
|
||||
];
|
||||
const rulesPresetList: ServiceRecord[] = [
|
||||
{
|
||||
id: 1,
|
||||
title: '内容屏蔽规则',
|
||||
description:
|
||||
'用户在执行特定的内容分发任务时,可使用内容屏蔽规则根据特定标签,过滤内容集合。',
|
||||
enable: true,
|
||||
actionType: 'switch',
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
title: '内容置顶规则',
|
||||
description:
|
||||
'该规则支持用户在执行特定内容分发任务时,对固定的几条内容置顶。',
|
||||
enable: true,
|
||||
actionType: 'switch',
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
title: '内容加权规则',
|
||||
description: '选定内容加权规则后可自定义从不同内容集合获取内容的概率。',
|
||||
enable: false,
|
||||
actionType: 'switch',
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
title: '内容分发规则',
|
||||
description: '内容分发时,对某些内容需要固定在C端展示的位置。',
|
||||
enable: true,
|
||||
actionType: 'switch',
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
title: '违禁内容识别',
|
||||
description: '精准识别赌博、刀枪、毒品、造假、贩假等违规物品和违规行为。',
|
||||
enable: false,
|
||||
actionType: 'switch',
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
title: '多语言文字符号识别',
|
||||
description:
|
||||
'精准识别英语、维语、藏语、蒙古语、朝鲜语等多种语言以及emoji表情形态的语义识别。',
|
||||
enable: false,
|
||||
actionType: 'switch',
|
||||
},
|
||||
];
|
||||
|
||||
setupMock({
|
||||
setup() {
|
||||
// Quality Inspection
|
||||
Mock.mock(new RegExp('/api/list/quality-inspection'), () => {
|
||||
return successResponseWrap(
|
||||
qualityInspectionList.map((_, index) => ({
|
||||
...qualityInspectionList[index % qualityInspectionList.length],
|
||||
id: Mock.Random.guid(),
|
||||
}))
|
||||
);
|
||||
});
|
||||
|
||||
// the service
|
||||
Mock.mock(new RegExp('/api/list/the-service'), () => {
|
||||
return successResponseWrap(
|
||||
theServiceList.map((_, index) => ({
|
||||
...theServiceList[index % theServiceList.length],
|
||||
id: Mock.Random.guid(),
|
||||
}))
|
||||
);
|
||||
});
|
||||
|
||||
// rules preset
|
||||
Mock.mock(new RegExp('/api/list/rules-preset'), () => {
|
||||
return successResponseWrap(
|
||||
rulesPresetList.map((_, index) => ({
|
||||
...rulesPresetList[index % rulesPresetList.length],
|
||||
id: Mock.Random.guid(),
|
||||
}))
|
||||
);
|
||||
});
|
||||
},
|
||||
});
|
Loading…
Add table
Reference in a new issue