1、添加数学公式渲染功能;2、增加数学公式渲染自定义指令(只适用h5);3、修改package.json

master
chris 2 months ago
parent 32ddbd1316
commit 9d073a9d06

@ -65,3 +65,7 @@ body {
margin: 0;
font-size: $uni-font-size-base;
}
uni-page {
background-color: #efeff4;
}

@ -0,0 +1,6 @@
import mathJax from './mathJax'
export default function registerDirectives (app) {
// 注册全局指令
app.directive(mathJax.name, mathJax.inserted)
}

@ -0,0 +1,13 @@
// 该指令只支持H5
import renderMath from '@/utils/mathJax/renderMath.js'
export default {
name: 'math',
inserted (el, binding) {
if (!binding.value) return;
// console.log(binding.value)
// console.log(Reflect.ownKeys(el.__vnode.el))
// console.log(el.__vnode)
el.__vnode.el.innerHTML = renderMath(binding.value)
}
}

@ -0,0 +1,14 @@
declare namespace UniCrazyGlobalTypes {
interface UniCrazyRouterParams {
passedParams?: object | null;
routeParams?: object | null;
}
}
declare namespace UniApp {
interface RedirectToOptions extends UniCrazyGlobalTypes.UniCrazyRouterParams {}
interface ReLaunchOptions extends UniCrazyGlobalTypes.UniCrazyRouterParams {}
interface SwitchTabOptions extends UniCrazyGlobalTypes.UniCrazyRouterParams {}
interface NavigateBackOptions extends UniCrazyGlobalTypes.UniCrazyRouterParams {}
interface NavigateToOptions extends UniCrazyGlobalTypes.UniCrazyRouterParams {}
}

@ -0,0 +1,49 @@
/// <reference path="./global.d.ts" />
type to = {
url: string;
query?: object | null;
jumpType: string;
search?: string;
} & UniCrazyGlobalTypes.UniCrazyRouterParams;
type from = ({
url: string;
query?: object | null;
search?: string;
} & UniCrazyGlobalTypes.UniCrazyRouterParams) | null | undefined;
interface callWithNext {
(hook: (to: to, from: from, next: Function) => void) : Function;
}
interface callWithoutNext {
(hook: (to: to, from: from) => void): Function;
}
interface normalCall {
(call: Function): void;
}
export const beforeEach: callWithNext;
export const afterEach: callWithoutNext;
export const onError: callWithoutNext;
export const afterNotNext: normalCall;
interface uniCrazyRouter {
beforeEach: callWithNext;
afterEach: callWithoutNext;
onError: callWithoutNext;
afterNotNext: normalCall;
install: any;
}
declare const uniCrazyRouter: uniCrazyRouter;
export default uniCrazyRouter;
// for Vue2
declare module "vue/types/vue" {
interface Vue {
$routeParams?: object | null;
$passedParams?: object | null;
}
}
// for Vue3
declare module '@vue/runtime-core' {
interface ComponentCustomProperties {
$routeParams?: object | null;
$passedParams?: object | null;
}
}

File diff suppressed because one or more lines are too long

@ -0,0 +1,16 @@
{
"id": "crazy-router",
"name": "一个更贴合uni-app的router路由拦截插件",
"version": "1.1.1",
"description": "一个更贴合uni-app的router插件一切都使用uni-app原生钩子实现和方法实现抛弃了v",
"keywords": [
"router",
"路由"
],
"dcloudext": {
"category": [
"JS SDK",
"通用 SDK"
]
}
}

@ -0,0 +1,49 @@
/// <reference path="./global.d.ts" />
type to = {
url: string;
query?: object | null;
jumpType: string;
search?: string;
} & UniCrazyGlobalTypes.UniCrazyRouterParams;
type from = ({
url: string;
query?: object | null;
search?: string;
} & UniCrazyGlobalTypes.UniCrazyRouterParams) | null | undefined;
interface callWithNext {
(hook: (to: to, from: from, next: Function) => void) : Function;
}
interface callWithoutNext {
(hook: (to: to, from: from) => void): Function;
}
interface normalCall {
(call: Function): void;
}
export const beforeEach: callWithNext;
export const afterEach: callWithoutNext;
export const onError: callWithoutNext;
export const afterNotNext: normalCall;
interface uniCrazyRouter {
beforeEach: callWithNext;
afterEach: callWithoutNext;
onError: callWithoutNext;
afterNotNext: normalCall;
install: any;
}
declare const uniCrazyRouter: uniCrazyRouter;
export default uniCrazyRouter;
// for Vue2
declare module "vue/types/vue" {
interface Vue {
$routeParams?: object | null;
$passedParams?: object | null;
}
}
// for Vue3
declare module '@vue/runtime-core' {
interface ComponentCustomProperties {
$routeParams?: object | null;
$passedParams?: object | null;
}
}

File diff suppressed because one or more lines are too long

@ -1,6 +1,7 @@
import App from './App'
import '@/assets/styles/main.scss'
import '@/uni_modules/uni-scss/theme-custom.scss'
import 'katex/dist/katex.min.css';
// #ifdef APP-VUE
plus.screen.lockOrientation('landscape-primary');
@ -21,12 +22,14 @@ app.$mount()
import { createSSRApp } from 'vue';
import * as Pinia from 'pinia';
import registerComponents from '@/components/components.js';
import registerDirectives from '@/directive';
import { setupRouter } from './router'
export function createApp() {
const app = createSSRApp(App)
app.use(Pinia.createPinia())
setupRouter(app)
registerComponents(app);
registerDirectives(app);
return {
app,
Pinia

4100
package-lock.json generated

File diff suppressed because it is too large Load Diff

@ -1,20 +1,20 @@
{
"id": "wangqingzhou311-bleBlueTooth",
"name": "Android、ios、小程序等ble蓝牙小票、标签、面单打印插件",
"displayName": "Android、ios、小程序等ble蓝牙小票、标签、面单打印插件",
"version": "1.02",
"description": "蓝牙打印参考示例支持vue3小程序、APP安卓ios可以对不同型号打印机的指令发送即可打印理论上任何打印机的指令都可以在例子中运行demo附含指令文档手册自行查询。",
"keywords": [
"蓝牙打印",
"二维码打印",
"小票打印",
"标签打印",
"打印指令"
],
"dcloudext": {
"category": [
"前端组件",
"通用组件"
]
"id": "smart_campus",
"name": "学情监测仪",
"displayName": "学情监测仪",
"version": "0.0.0.9",
"description": "",
"dependencies": {
"html2canvas": "^1.4.1",
"js-cookie": "^3.0.5",
"katex": "^0.16.11",
"postcss-pxtorpx-pro": "^2.0.0",
"uni-crazy-router": "^1.1.3",
"uni-vite-plugin-h5-prod-effect": "^1.0.1",
"vite-plugin-vue-setup-extend": "^0.4.0"
},
"devDependencies": {
"vite-plugin-commonjs": "^0.10.1",
"vite-plugin-require": "^1.2.14"
}
}

@ -156,6 +156,26 @@
"titleNView": false
}
}
},
{
"path" : "pages/testPage/testPage",
"style" :
{
"navigationStyle": "custom",
"app-plus": {
"titleNView": false
}
}
},
{
"path" : "pages/printNew/printNew",
"style" :
{
"navigationStyle": "custom",
"app-plus": {
"titleNView": false
}
}
}
],
"globalStyle": {

@ -0,0 +1,14 @@
.search-btn {
// margin-top: 15px;
// margin-left: 20px;
// margin-bottom: 15px;
// margin-left: 50%;
// transform: translateX(-50%);
}
// canvas
uni-canvas {
// position: absolute;
// top: -1000px;
// left: -1000px;
}

@ -0,0 +1,181 @@
<template>
<view class="print-page">
<ch-nav-bar :height="66" title="选择打印机" :rightWidth="140">
<block v-slot:right>
<ch-nav-btn icon="paperplane-filled" iconSize="28" color="#fff" @click="print">
打印
</ch-nav-btn>
</block>
</ch-nav-bar>
<uni-section title="附近打印机" type="line">
<block v-slot:right>
<button type="primary" size="mini" class="search-btn" :loading="searching" :disabled="searching" @tap="searchDevices">{{ searching ? '...' : '' }}</button>
</block>
<uni-list>
<block v-for="item in devices" :key="item.deviceId">
<uni-list-item
showArrow
showExtraIcon
:extraIcon="extraIcon"
:clickable="true"
:title="item.name || item.deviceId"
@click="connectBLE(item.deviceId)">
<block v-slot:footer>
<text>{{ item.deviceId == connectId ? '已连接' : ''}}</text>
</block>
</uni-list-item>
</block>
</uni-list>
</uni-section>
<sp-html2canvas-render domId="render-dom" ref="renderRef" @renderOver="renderOver"></sp-html2canvas-render>
<view id="render-dom" style="">
<view>测试 htmltoCanvas</view>
<!-- <view>测试 htmltoCanvas</view>
<view>测试 htmltoCanvas</view>
<view>测试 htmltoCanvas</view>
<view>测试 htmltoCanvas</view>
<view>测试 htmltoCanvas</view>
<view>测试 htmltoCanvas</view>
<view>测试 htmltoCanvas</view> -->
<view>
<image src="../../static/logo.png" style="height: 50px;width: 50px;"></image>
</view>
</view>
<canvas id="myCanvas" canvas-id="myCanvas" style="width: 800px; height: 800px;"></canvas>
</view>
</template>
<script setup>
import { onBeforeUnmount, onMounted, reactive, toRefs, ref, nextTick } from 'vue';
import { getImgData } from '@/api/common.js';
import ble from './util/bluetooth.js';
const CPCL = require('./util/CPCL.min.js');
const HEX = require('./util/HEX.min.js');
// #ifdef APP-PLUS
// const bluetooth = new Bluetooth();
// #endif
const renderRef = ref(null)
const data = reactive({
searching: false,
printer: null,
connectId: '',
devices: [],
currentDevices: [],
writeId: '',
extraIcon: {
type: 'smallcircle',
color: '#4cd964',
size: '32'
},
questions: [],
imgPixData: null
});
const { devices, currentDevices, writeId, searching, connectId, extraIcon, questions, imgPixData, printer } = toRefs(data);
onMounted(() => {
uni.getStorage({
key: 'questions',
success: (res) => {
questions.value = JSON.parse(res.data)
console.log(questions.value)
// getImg();
}
})
})
onBeforeUnmount(() => {
// #ifdef APP-PLUS
// bluetooth.closeBluetoothAdapter() //
// #endif
})
//
function searchDevices () {
closeConnection()
searching.value = true;
devices.value = []
ble.find(res => {
console.log(res.devices)
const newDevices = res.devices;
newDevices.forEach(newItem => {
const isExist = devices.value.some(item => item.deviceId == newItem.deviceId);
if (!newItem.name || isExist) return false;
devices.value.push(newItem)
})
});
setTimeout(() => {
ble.stopFind();
searching.value = false;
}, 10000)
}
//
async function connectBLE (deviceId) {
ble.stopFind();
searching.value = false;
closeConnection()
printer.value = await ble.connect({
deviceId,
onBLEConnectionStateChange,
onBLECharacteristicValueChange,
fail() {
uni.showToast({
icon: 'none',
title: '连接失败'
})
}
})
}
async function print() {
console.log(CPCL)
// renderRef.value.h2cRenderDom();
const imgData = await generateCanvasImageData()
renderOver({ base64: '', imgData })
}
function renderOver({ base64, imgData }) {
console.log('imgData', imgData)
// CPCL
let cpcl = CPCL.Builder.createArea(0, 2376, 1)
// ID
.taskId('1')
//
.pageWidth(1680)
// CanvasImageData x y
.imageGG(imgData, 10, 10) //
.formPrint()
.build();
//
console.log(imgData)
printer.value.write(cpcl);
}
//
function onBLEConnectionStateChange ({ deviceId, connected }) {
connectId.value = connected ? deviceId : ''
}
//
function onBLECharacteristicValueChange (res) {
}
//
function closeConnection () {
if (!printer.value || !printer.connected) return;
printer.value.close().then(() => {
connectId.value = ''
}).catch(error => {
console.error('断开连接失败', error)
})
}
</script>
<style lang="scss" scoped>
@import './print.scss';
</style>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -0,0 +1,445 @@
/*!
* Create by Winford
*/
// var HEX = require('./HEX.min.js');
// 初始化蓝牙
const _openBluetoothAdapter = () => {
return new Promise(function(resolve, reject) {
uni.closeBluetoothAdapter({
fail: reject,
success () {
// 初始化蓝牙
console.log('初始化蓝牙')
uni.openBluetoothAdapter({
success: resolve,
fail: reject
})
}
})
});
}
// 蓝牙建立连接
const _createBLEConnection = (deviceId) => {
// 连接BLE
return new Promise(function(resolve, reject) {
uni.createBLEConnection({
deviceId,
success: resolve,
fail: reject
})
});
}
const _getBLEDeviceServices = (deviceId) => {
// 获取服务
return new Promise(function(resolve, reject) {
uni.getBLEDeviceServices({
deviceId,
success: (res) => {
for (let i = 0; i < res.services.length; i++) {
let service = res.services[i];
if (service.uuid.startsWith('0000FF00')) {
resolve(service);
return;
}
}
resolve();
//resolve(await _getBLEDeviceServices(deviceId))
},
fail: reject
// fail: function(e) {
// console.log(e);
// }
})
});
}
const _getBLEDeviceCharacteristics = (deviceId, serviceId) => {
// 获取读写特征值
return new Promise(function(resolve, reject) {
uni.getBLEDeviceCharacteristics({
deviceId,
serviceId,
success: (res) => {
let characteristics = {};
for (let i = 0; i < res.characteristics.length; i++) {
let item = res.characteristics[i];
// console.log(item);
if (item.properties.notify) {
characteristics.notify = characteristics.notify || item;
}
if (item.properties.write) {
characteristics.write = characteristics.write || item;
}
if (item.uuid.startsWith('0000FF03')) {
characteristics.dataFC = characteristics.dataFC || item;
}
}
resolve(characteristics);
},
fail: reject
});
});
}
// 写数据
const _wxWriteBLECharacteristicValue = ({
deviceId,
serviceId,
characteristicId,
value
}) => {
return new Promise(function(resolve, reject) {
uni.writeBLECharacteristicValue({
deviceId,
serviceId,
characteristicId,
value,
writeType: 'writeNoResponse',
//writeType: 'write',
success: function() {
resolve(true);
},
fail: function(e) {
console.log(e);
if (e.code == 10007) {
// uniapp bug, retry.
resolve(false);
} else {
reject(e)
}
}
});
});
}
const sleep = (time) => new Promise((resolve, reject) => setTimeout(resolve, time));
// 写数据
const _writeBLECharacteristicValue = async (deviceId, serviceId, characteristicId, value, mtu = 20) => {
const total = value.byteLength;
console.log("================mtu=" + mtu, new Date())
let num = 0;
let count = 0;
while (count < total) {
const element = value.slice(count, count + mtu); // 取出MTU个数据
if (element.byteLength === 0) break; // 表示已经发送完毕
// #ifdef APP-PLUS
// await sleep(50);
let writeResult = await _wxWriteBLECharacteristicValue({
deviceId,
serviceId,
characteristicId,
value: element
});
if (writeResult) {
count = count + element.byteLength;
num++;
}
// #endif
// #ifdef MP-WEIXIN
// num % 100 == 0 && await sleep(100);
_wxWriteBLECharacteristicValue({
deviceId,
serviceId,
characteristicId,
value: element
});
count = count + element.byteLength;
num++;
// #endif
// console.log("================count=" + count)
// console.log("================num=" + num)
}
console.log("================num=" + num, new Date())
}
// 写数据
const _writeBLECharacteristicValueWithDataFC = async (device, value) => {
// const data = value.slice(); // copy一份浅拷贝
const total = value.byteLength;
console.log('total--->', total);
let num = 0;
let count = 0;
const dataFC = device.dataFC;
while (count < total) {
if (dataFC.mtu > 0 && dataFC.credit > 0) {
const subData = value.slice(count, count + dataFC.mtu - 3); // 取出MTU-3个数据
if (subData.byteLength === 0) break; // 表示已经发送完毕
count = count + subData.byteLength;
dataFC.credit--;
// #ifdef APP-PLUS
while (!(await _wxWriteBLECharacteristicValue({
deviceId: device.deviceId,
serviceId: device.serviceId,
characteristicId: device.writeCharacteristicId,
value: subData,
}))) {
await sleep(100); // I don't know why, but uni-app is shit, okay
console.log('写入失败,正在重新写入。。。');
}
// #endif
// #ifndef APP-PLUS
_wxWriteBLECharacteristicValue({
deviceId: device.deviceId,
serviceId: device.serviceId,
characteristicId: device.writeCharacteristicId,
value: subData,
});
// #endif
num++;
} else {
// 令牌用尽,等待令牌
await sleep(0);
// console.log('令牌用尽,等待令牌');
}
}
console.log('num--->', num);
}
// 发现设备
const find = (onBluetoothDeviceFound) => {
_openBluetoothAdapter().then(function(res) {
// 添加监听
uni.onBluetoothDeviceFound(function(res) {
if (onBluetoothDeviceFound) {
onBluetoothDeviceFound(res);
}
});
uni.startBluetoothDevicesDiscovery({
interval: 1000
});
}).catch(function(res) {
uni.showToast({
title: '请打开蓝牙',
icon: 'none'
})
});
}
// 停止发现设备
const stopFind = () => {
uni.stopBluetoothDevicesDiscovery();
}
// 连接
const connect = async ({
deviceId,
onBLEConnectionStateChange,
onBLECharacteristicValueChange,
onDataFCValueChange,
fail,
}) => {
let device = {
connected: false,
deviceId: deviceId,
serviceId: '',
notifyCharacteristicId: '',
writeCharacteristicId: '',
dataFCCharacteristicId: '',
onBLEConnectionStateChange,
onBLECharacteristicValueChange,
onDataFCValueChange,
dataFC: {
mtu: 0,
credit: 0,
},
};
// 请求蓝牙权限
await _openBluetoothAdapter().then(function(res) {
return new Promise((resolve, reject) => {
// 添加监听
uni.onBLEConnectionStateChange(function(res) {
// 该方法回调中可以用于处理连接意外断开等异常情况
device.connected = res.connected;
if (device.onBLEConnectionStateChange) {
device.onBLEConnectionStateChange(res);
}
if (res.connected) {
resolve(res);
} else {
reject(res);
}
});
// 连接BLE
_createBLEConnection(deviceId);
});
// 添加监听
// uni.onBLEConnectionStateChange(function(res) {
// // 该方法回调中可以用于处理连接意外断开等异常情况
// device.connected = res.connected;
// if (device.onBLEConnectionStateChange) {
// device.onBLEConnectionStateChange(res);
// }
// });
// // 连接BLE
// return _createBLEConnection(deviceId);
})
.then(async function(res) {
// 获取服务
await sleep(1000);
let service = await _getBLEDeviceServices(deviceId);
if (!service) {
// 有时候获取不到,尝试重新获取
await sleep(2000);
service = await _getBLEDeviceServices(deviceId);
}
if (!service) {
Promise.reject('获取service失败');
} else {
return service;
}
})
.then(function(service) {
// 获取读写特征值
console.log('获取读写特征值')
device.serviceId = service.uuid;
return _getBLEDeviceCharacteristics(device.deviceId, device.serviceId);
})
.then(function(characteristics) {
// 读
device.notifyCharacteristicId = characteristics.notify ? characteristics.notify.uuid : '';
// 写
device.writeCharacteristicId = characteristics.write ? characteristics.write.uuid : '';
// 流控
device.dataFCCharacteristicId = characteristics.dataFC ? characteristics.dataFC.uuid : '';
})
.catch(function(err) {
console.log(err);
fail(err)
});
device.mtu = 20;
if (uni.getSystemInfoSync().platform === 'android') {
await new Promise(function(resolve, reject) {
uni.setBLEMTU({
deviceId: deviceId,
mtu: 512,
success(res) {
//device.mtu = res.mtu;
console.log('setBLEMTU success', res);
resolve(res);
},
fail(res) {
console.log('setBLEMTU fail', res);
reject(res);
},
});
});
// #ifdef APP-PLUS
await sleep(500); // I don't know why, but uni-app is shit, okay
// #endif
}
console.log('onBLECharacteristicValueChange')
// 监听
uni.onBLECharacteristicValueChange(function(res) {
// 读监听
if (res.characteristicId === device.notifyCharacteristicId) {
device.onBLECharacteristicValueChange && device.onBLECharacteristicValueChange(res);
}
// 流控监听
if (res.characteristicId === device.dataFCCharacteristicId) {
const data = new Uint8Array(res.value);
const flag = data[0];
if (flag === 1) {
device.dataFC.credit += data[1];
// console.log('===流控更新credit', data[1]);
} else if (flag === 2) {
device.dataFC.mtu = (data[2] << 8) + data[1]; // 低位在前,高位在后
// console.log('===流控更新mtu', device.dataFC.mtu);
}
device.onDataFCValueChange && device.onDataFCValueChange(res);
}
});
// 读监听
if (device.notifyCharacteristicId) {
console.log('notifyBLECharacteristicValueChange: ' + device.notifyCharacteristicId)
await new Promise(function(resolve, reject) {
uni.notifyBLECharacteristicValueChange({
state: true, // 启用 notify 功能
// 这里的 deviceId 需要已经通过 createBLEConnection 与对应设备建立链接
deviceId: device.deviceId,
// 这里的 serviceId 需要在 getBLEDeviceServices 接口中获取
serviceId: device.serviceId,
// 这里的 characteristicId 需要在 getBLEDeviceCharacteristics 接口中获取
characteristicId: device.notifyCharacteristicId,
success: resolve,
fail: reject
});
});
}
// 流控监听
if (device.dataFCCharacteristicId) {
// #ifdef APP-PLUS
await sleep(500); // I don't know why, but uni-app is shit, okay
// #endif
console.log('notifyBLECharacteristicValueChange: ' + device.dataFCCharacteristicId)
await new Promise(function(resolve, reject) {
uni.notifyBLECharacteristicValueChange({
state: true, // 启用 notify 功能
// 这里的 deviceId 需要已经通过 createBLEConnection 与对应设备建立链接
deviceId: device.deviceId,
// 这里的 serviceId 需要在 getBLEDeviceServices 接口中获取
serviceId: device.serviceId,
// 这里的 characteristicId 需要在 getBLEDeviceCharacteristics 接口中获取
characteristicId: device.dataFCCharacteristicId,
success: resolve,
fail: reject
});
});
}
// 写方法
// device.write = async (value, {
// mtu = 20
// }) => {
// // console.log(device.deviceId, 'write', HEX.ab2hex(value));
// if (device.writeCharacteristicId) {
// await _writeBLECharacteristicValue(device.deviceId, device.serviceId, device
// .writeCharacteristicId, value, mtu);
// }
// };
// 流控写方法(传输速度提升6倍)
device.write = async (value) => {
// console.log(device.deviceId, 'writeWithDataFC', HEX.ab2hex(value));
if (device.writeCharacteristicId && device.dataFCCharacteristicId) {
await _writeBLECharacteristicValueWithDataFC(device, value);
}
};
// 断开连接
device.close = () => {
return new Promise((resolve, reject) => {
uni.closeBLEConnection({
deviceId: device.deviceId,
success: resolve,
fail: reject
})
})
};
console.log(device);
return device;
}
export default {
find,
stopFind,
connect
}

@ -1,3 +1,7 @@
::v-deep uni-page-wrapper {
overflow: hidden;
}
.ques-details-page {
height: 100vh;
overflow: hidden;

@ -7,7 +7,7 @@
</ch-nav-btn>
</block>
</ch-nav-bar>
<ch-flex items="center">
<ch-flex items="center" v-show="isExit">
<button class="toggle-btn" type="warn" :disabled="questionId == quesIds[0]" @click="toggleQues(-1)">
<uni-icons type="arrow-left" size="28" color="#fff"></uni-icons>
</button>
@ -37,9 +37,10 @@
<script setup>
import ChFlex from '@/components/ch-flex/ch-flex.vue';
import ChNavBtn from '@/components/ch-nav-btn/ch-nav-btn.vue'
import { onBeforeUnmount, onMounted, reactive, toRefs } from 'vue';
import { onBeforeUnmount, onMounted, reactive, toRefs, computed } from 'vue';
import { onLoad } from '@dcloudio/uni-app';
import { getQuestionInfo } from '@/api/question.js';
import renderMath from '@/utils/mathJax/renderMath';
const data = reactive({
question: {},
@ -49,6 +50,10 @@ const data = reactive({
const { question, questionId, quesIds } = toRefs(data)
const isExit = computed(() => {
return question.value && JSON.stringify(question.value) !== '{}'
})
onLoad(option => {
console.log(option)
questionId.value = option.id;
@ -58,8 +63,8 @@ onMounted(() => {
const params = {
questionid: questionId.value
}
getQuestionInfo(params).then(info => {
question.value = info;
getQuestionInfo(params, { loading: true }).then(info => {
question.value = detailQues(info);
})
uni.getStorage({
@ -82,8 +87,8 @@ function toggleQues(step) {
console.log(cIndex)
if (cIndex == -1) return;
const id = quesIds.value[cIndex + step]
getQuestionInfo({ questionid: id }).then(info => {
question.value = info;
getQuestionInfo({ questionid: id }, { loading: true }).then(info => {
question.value = detailQues(info);
questionId.value = id;
})
}
@ -97,6 +102,21 @@ function print () {
url: '/pages/print/print'
})
}
function detailQues (question) {
question.questionanswer = detailMath(question.questionanswer)
question.questionexplain = detailMath(question.questionexplain)
question.questioncontent = detailMath(question.questioncontent)
question.option = question.option.map(item => {
item.optioncontent = detailMath(item.optioncontent)
return item
})
return question
}
function detailMath(text) {
return renderMath(text)
}
</script>
<style lang="scss" scoped>

@ -39,6 +39,7 @@
import { onMounted, reactive, toRefs, ref, nextTick, watch } from 'vue';
import { onLoad } from '@dcloudio/uni-app'
import { getQuestionList } from '@/api/question.js';
import renderMath from '@/utils/mathJax/renderMath.js';
const defaultParams = {
gradeid: 0,
@ -69,7 +70,10 @@ onLoad((option) => {
onMounted(() => {
getQuestionList(queryParams.value, { loading: true }).then(list => {
questionList.value = list;
questionList.value = list.map(item => {
item.questioncontent = detailMath(item.questioncontent);
return item;
});
})
})
@ -88,21 +92,30 @@ function createQuesIdList (list) {
function scrollBottom () {
console.log('到底了')
if (isNoMore.value) return;
if (isNoMore.value || (scrollStatus.value === 'loading')) return;
scrollStatus.value = 'loading';
queryParams.value.pageindex++;
console.log(queryParams.value)
getQuestionList(queryParams.value).then(list => {
if (!list.length) {
scrollStatus.value = 'no-more'
isNoMore.value = true;
return;
}
list = list.map(item => {
item.questioncontent = detailMath(item.questioncontent);
return item;
});
questionList.value = [...questionList.value, ...list]
}).finally(() => {
scrollStatus.value = 'more';
})
}
function detailMath(text) {
return renderMath(text);
}
function edit () {
isEdit.value = true;
}

@ -0,0 +1,88 @@
<template>
<view>
<button type="primary" @tap="connect"></button>
<!-- <button type="warn" @tap="print"></button> -->
</view>
</template>
<script setup>
import { onMounted } from 'vue';
onMounted(() => {
uni.onSocketOpen((res) => {
console.log('连接成功', res)
print()
uni.showToast({
title: '连接成功',
icon: 'none'
})
})
uni.onSocketError((error) => {
console.log('连接错误', error)
uni.showToast({
title: '连接错误',
icon: 'none'
})
})
uni.onSocketClose((res) => {
console.log('连接关闭', res)
uni.showToast({
title: '连接关闭',
icon: 'none'
})
})
uni.onSocketMessage((res) => {
console.log('收到消息', res)
uni.showToast({
title: '收到消息',
icon: 'none'
})
})
})
function connect() {
uni.connectSocket({
url: 'ws://192.168.1.200:9100',
success() {
uni.showToast({
title: '连接成功',
icon: 'none'
})
},
fail(error) {
console.log(error)
uni.showToast({
title: '连接失败',
icon: 'none'
})
}
})
}
function print () {
uni.sendSocketMessage({
// data: '<html><body><div></div></body></html>',
data: '我就打印下,莫慌。。。。',
success() {
uni.showToast({
title: '发送成功',
icon: 'none'
})
},
fail(error) {
console.log(error)
uni.showToast({
title: '发送失败',
icon: 'none'
})
}
})
}
</script>
<style lang="scss">
</style>

@ -0,0 +1,90 @@
import katex from "katex";
import splitAtDelimiters from "./splitAtDelimiters";
const renderMathInText = function(text, optionsCopy) {
const data = splitAtDelimiters(text, optionsCopy.delimiters);
if (data.length === 1 && data[0].type === 'text') {
// There is no formula in the text.
// Let's return null which means there is no need to replace
// the current text node with a new one.
return data[0].data;
}
let html = ''
for (let i = 0; i < data.length; i++) {
if (data[i].type === "text") {
html += data[i].data;
} else {
let math = data[i].data;
// Override any display mode defined in the settings with that
// defined by the text itself
optionsCopy.displayMode = data[i].display;
try {
if (optionsCopy.preProcess) {
math = optionsCopy.preProcess(math);
}
html += katex.renderToString(math, optionsCopy);
} catch (e) {
if (!(e instanceof katex.ParseError)) {
throw e;
}
optionsCopy.errorCallback(
"KaTeX auto-render: Failed to parse `" + data[i].data +
"` with ",
e
);
html += data[i].rawData;
continue;
}
}
}
return html;
};
const renderMath = function(text, options) {
if (!text) {
throw new Error("No text provided to render");
}
const optionsCopy = {};
// Object.assign(optionsCopy, option)
for (const option in options) {
if (options.hasOwnProperty(option)) {
optionsCopy[option] = options[option];
}
}
// default options
optionsCopy.delimiters = optionsCopy.delimiters || [
{left: "$$", right: "$$", display: true},
{left: "\\(", right: "\\)", display: false},
// LaTeX uses $…$, but it ruins the display of normal `$` in text:
{left: "$", right: "$", display: false},
// $ must come after $$
// Render AMS environments even if outside $$…$$ delimiters.
{left: "\\begin{equation}", right: "\\end{equation}", display: true},
{left: "\\begin{align}", right: "\\end{align}", display: true},
{left: "\\begin{alignat}", right: "\\end{alignat}", display: true},
{left: "\\begin{gather}", right: "\\end{gather}", display: true},
{left: "\\begin{CD}", right: "\\end{CD}", display: true},
{left: "\\[", right: "\\]", display: true},
];
optionsCopy.ignoredTags = optionsCopy.ignoredTags || [
"script", "noscript", "style", "textarea", "pre", "code", "option",
];
optionsCopy.ignoredClasses = optionsCopy.ignoredClasses || [];
optionsCopy.errorCallback = optionsCopy.errorCallback || console.error;
// Enable sharing of global macros defined via `\gdef` between different
// math elements within a single call to `renderMathInElement`.
optionsCopy.macros = optionsCopy.macros || {};
return renderMathInText(text, optionsCopy);
};
export default renderMath;

@ -0,0 +1,85 @@
/* eslint no-constant-condition:0 */
const findEndOfMath = function(delimiter, text, startIndex) {
// Adapted from
// https://github.com/Khan/perseus/blob/master/src/perseus-markdown.jsx
let index = startIndex;
let braceLevel = 0;
const delimLength = delimiter.length;
while (index < text.length) {
const character = text[index];
if (braceLevel <= 0 &&
text.slice(index, index + delimLength) === delimiter) {
return index;
} else if (character === "\\") {
index++;
} else if (character === "{") {
braceLevel++;
} else if (character === "}") {
braceLevel--;
}
index++;
}
return -1;
};
const escapeRegex = function(string) {
return string.replace(/[-/\\^$*+?.()|[\]{}]/g, "\\$&");
};
const amsRegex = /^\\begin{/;
const splitAtDelimiters = function(text, delimiters) {
let index;
const data = [];
const regexLeft = new RegExp(
"(" + delimiters.map((x) => escapeRegex(x.left)).join("|") + ")"
);
while (true) {
index = text.search(regexLeft);
if (index === -1) {
break;
}
if (index > 0) {
data.push({
type: "text",
data: text.slice(0, index),
});
text = text.slice(index); // now text starts with delimiter
}
// ... so this always succeeds:
const i = delimiters.findIndex((delim) => text.startsWith(delim.left));
index = findEndOfMath(delimiters[i].right, text, delimiters[i].left.length);
if (index === -1) {
break;
}
const rawData = text.slice(0, index + delimiters[i].right.length);
const math = amsRegex.test(rawData)
? rawData
: text.slice(delimiters[i].left.length, index);
data.push({
type: "math",
data: math,
rawData,
display: delimiters[i].display,
});
text = text.slice(index + delimiters[i].right.length);
}
if (text !== "") {
data.push({
type: "text",
data: text,
});
}
return data;
};
export default splitAtDelimiters;

@ -85,7 +85,7 @@ function requestFun ({ url, method, data = {} }, config = { loading: true }) {
resolve(data)
},
fail: (error) => {
console.log('Request Error', new Error(error));
console.log('Request Error', error);
uni.showToast({
icon: 'error',
title: '请求失败'

@ -0,0 +1,9 @@
export function createScript(src) {
return new Promise((resolve, reject) => {
const script = document.createElement('script');
script.src = src;
script.onload = () => resolve(script);
script.onerror = () => reject(new Error(`Script load error for ${src}`));
document.head.append(script);
});
}

@ -3,9 +3,11 @@ import uni from '@dcloudio/vite-plugin-uni';
import postcssCfg from './postcss.config.js'
import VueSetupExtend from 'vite-plugin-vue-setup-extend';
import h5ProdEffectPlugin from 'uni-vite-plugin-h5-prod-effect';
// import commonjs from 'vite-plugin-commonjs'
// import vitePluginRequire from "vite-plugin-require";
export default defineConfig({
plugins: [uni(), VueSetupExtend(), h5ProdEffectPlugin()],
plugins: [ uni(), VueSetupExtend(), h5ProdEffectPlugin()],
css: {
preprocessorOptions: {
scss: {

Loading…
Cancel
Save