提交 a1a33940 authored 作者: 刘旭's avatar 刘旭

完成打印功能测试

上级 470cc522
......@@ -16,11 +16,10 @@
)
</script>
</head>
<body>
<page>
<div id="app"><!--app-html--></div>
<script type="module" src="/src/main.ts"></script>
<script src="./src/static/iconfont/iconfont.js"></script>
</body>
</page>
</html>
<style></style>
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -11,7 +11,6 @@
"build:mp-weixin": "uni build -p mp-weixin"
},
"dependencies": {
"@daadad":"sadsadasdasdasdasdasds",
"@dcloudio/uni-app": "3.0.0-alpha-3061620221230002",
"@dcloudio/uni-app-plus": "3.0.0-alpha-3061620221230002",
"@dcloudio/uni-components": "3.0.0-alpha-3061620221230002",
......@@ -27,6 +26,7 @@
"node-sass": "^7.0.1",
"pinia": "^2.0.21",
"pinia-plugin-persistedstate": "^3.1.0",
"text-encoding": "^0.7.0",
"vk-uview-ui": "^1.4.4",
"vue": "^3.2.45",
"vue-i18n": "^9.1.9"
......
<script setup lang="ts">
import { onLaunch, onShow, onHide } from '@dcloudio/uni-app';
</script>
<style lang="scss" scoped>
@import './static/iconfont/iconfont.css';
@import 'vk-uview-ui/index.scss';
// @import '@/static/iconfont/iconfont.css';
page {
background-color: #f6f6f6;
......
......@@ -7,4 +7,7 @@ export const getMenuList = () => request('/LowCodePlatform/user/getMenuList', 'P
export const getBusinessList = (data: any) => request('/LowCodePlatform/center/business/list', 'GET', data)
export const getMetadataList = () => request('/LowCodePlatform/center/metadata/list', 'GET')
\ No newline at end of file
export const getMetadataList = () => request('/LowCodePlatform/center/metadata/list', 'GET')
// 获取元数据
export const getMetadata = (formId: string) => request('/LowCodePlatform/center/metadata/detail', 'GET', { formId })
\ No newline at end of file
<template>
<u-navbar back-text="" :title="title" :back-icon-name="backIconName" title-color="#000000"
:background="{ background: '#f8f8f8' }">
:background="{ background: '#f8f8f8' }" title-width="400">
<template #right>
<u-icon :name="iconName" :size="44" style="padding: 14rpx 14rpx 14rpx 24rpx;" />
</template>
......@@ -26,10 +26,14 @@ const props = defineProps({
</script>
<style lang = "scss" scoped>
// :deep(.u-line-1) {
// font-weight: normal;
// font-size: 14px;
// }
:deep(.u-line-1) {
font-weight: bold;
font-weight: bold !important;
font-size: 16px !important;
}
// #ifdef APP-PLUS
:deep(.uicon-nav-back:before) {
font-size: 44rpx;
......
import { createSSRApp } from 'vue'
import { broadcastScan } from './utils/scanCode'
import App from './App.vue'
import Model from '@/utils/util'
import uView from 'vk-uview-ui'
import config from '@/utils/config'
import pinia from './store/useStore'
......@@ -10,7 +9,6 @@ import 'virtual:svg-icons-register'
export function createApp() {
const app = createSSRApp(App)
app.config.globalProperties.$baseUrl = config.baseUrl
app.config.globalProperties.$model = Model
app.config.globalProperties.$broadcastScan = broadcastScan
app.use(uView)
app.use(pinia)
......
......@@ -2,7 +2,7 @@
"name" : "pda测试",
"appid" : "__UNI__6D85B85",
"description" : "",
"versionName" : "1.0.0",
"versionName" : "1.0.1",
"versionCode" : "100",
"transformPx" : false,
/* 5+App特有相关 */
......@@ -23,7 +23,8 @@
"modules" : {
"Bluetooth" : {},
"Barcode" : {},
"Geolocation" : {}
"Geolocation" : {},
"Webview-x5" : {}
},
/* 应用发布信息 */
"distribute" : {
......
......@@ -45,6 +45,20 @@
"navigationBarBackgroundColor": "#f6f6f6",
"navigationStyle": "custom"
}
},
{
"path": "pages/blueTooth/index",
"style": {
"navigationBarTitleText": "连接蓝牙",
"navigationBarBackgroundColor": "#f6f6f6"
}
},
{
"path": "pages/blueTooth/printTest",
"style": {
"navigationBarTitleText": "测试标签打印",
"navigationBarBackgroundColor": "#f6f6f6"
}
}
],
"tabBar": {
......
<template>
<view class="card">
<u-row :gutter="12" class="box-list">
<view class="card" v-for="(res, r) in businessList" :key="r">
<block v-for="(item, index) of res" :key="index">
<view style="padding: 10rpx 0; display: flex; flex-direction: row;">
<text style="margin-right: 5rpx; width: 100rpx;">{{ item.label }}</text>
<textl>{{ item.value }}</textl>
</view>
</block>
<!-- <u-row :gutter="12" class="box-list">
<u-col :span="10">
<u-row>
<block v-for="(item, index) in list" :key="index">
<u-col :span="6" class="text-box">
<text class="label">{{ item.label }}</text>
<text class="value">{{ item.value }}</text>
<block v-for="(item, index) of res" :key="index">
<u-col :span="12" class="text-box">
<u-row>
<u-col :span="3" class="label">{{ item.label }}</u-col>
<u-col :span="8" class="value">{{ item.value }}</u-col>
</u-row>
</u-col>
</block>
</u-row>
</u-col>
<u-col :span="1" style="text-align: center;">
<!-- #ifdef APP-PLUS -->
<u-checkbox @change="checkboxChange" v-model="checked" size="17" />
<!-- #endif -->
<!-- #ifdef H5 -->
<u-checkbox @change="checkboxChange" v-model="checked" />
<!-- #endif -->
</u-col>
</u-row>
<u-col :span="1" style="text-align: center;"> -->
<!-- #ifdef APP-PLUS -->
<!-- <u-checkbox @change="checkboxChange" v-model="checked" size="17" /> -->
<!-- #endif -->
<!-- #ifdef H5 -->
<!-- <u-checkbox @change="checkboxChange" v-model="checked" /> -->
<!-- #endif -->
<!-- </u-col>
</u-row> -->
</view>
</template>
<script setup lang='ts'>
import { ref } from 'vue'
let list = [
{ label: '领料单号', value: 'SCLL2023031184' },
{ label: '来源单号', value: '暂无' },
{ label: '备注', value: '林继锋 (样品组)' },
{ label: '创建时间', value: '2023-03-14 13:56:42.797' },
{ label: '创建人', value: '刘国辉' },
{ label: '源单类型', value: '暂无' },
]
const props = defineProps({
businessList: {
type: Array
} as any
})
const checked = ref(false)
......@@ -60,20 +65,20 @@ const checkboxChange = (val: boolean) => {
display: flex;
flex-direction: row;
.text-box {
box-sizing: border-box;
display: flex;
flex-direction: column;
font-size: 14px;
margin-bottom: 10rpx;
// .text-box {
// box-sizing: border-box;
// display: flex;
// flex-direction: row;
// font-size: 14px;
// margin-bottom: 10rpx;
// width: 50%;
.label,
.value {
display: inline-block;
width: 100%;
}
}
// // width: 50%;
// .label,
// .value {
// display: inline-block;
// width: 100%;
// }
// }
}
}
......
<template>
// #ifdef APP-PLUS
<u-form :model="formData" label-width="75" :border-bottom="true">
<!-- <u-form :model="formData" label-width="75" :border-bottom="true">
<u-form-item label="领料单号" prop="oddNumbers">
<u-input v-model="formData.oddNumbers" />
</u-form-item>
......@@ -8,27 +7,24 @@
<u-form-item label="备注" prop="remarks">
<u-input v-model="formData.remarks" />
</u-form-item>
</u-form>
// #endif
// #ifdef H5
<u-form :model="formData" label-width="155" :border-bottom="true">
<u-form-item label="领料单号" prop="oddNumbers">
<u-input v-model="formData.oddNumbers" />
</u-form-item>
<u-line />
<u-form-item label="备注" prop="remarks">
<u-input v-model="formData.remarks" />
</u-form-item>
</u-form>
// #endif
</u-form> -->
<view class="form">
<view v-for="item in metadataList" :key="item.key" class="form-item">
<view class="label">{{ item.label }}</view>
<view class="value">
<input :value="item.options.defaultValue" type="text" :border="false" :placeholder="item.label" />
</view>
</view>
</view>
</template>
<script setup lang='ts'>
import { reactive } from 'vue'
import { ref } from 'vue'
const formData = reactive({
oddNumbers: 'SCLL2023031156',
remarks: ''
const props = defineProps({
metadataList: {
type: Array,
} as any
})
</script>
......@@ -42,4 +38,34 @@ const formData = reactive({
:deep(.u-form-item) {
padding: 0;
}
.form {
width: 100%;
.form-item {
width: 100%;
display: flex;
justify-content: flex-start;
align-items: center;
border-top: 1rpx solid #cccccc61;
padding: 20rpx 0;
margin-left: 16rpx;
font-size: 14px;
white-space: nowrap;
.label {
// margin-left: 30rpx;
width: 25%;
text-align: end;
}
.value {
flex: 1;
.input-placeholder {
font-size: 14px;
}
}
}
}
</style>
\ No newline at end of file
<template>
<input class="inputSty" v-model="wuValue" :focus="focusType" @blur="setfocus" @confirm="searchWu" placeholder="请扫码"
placeholder-style="font-size:12px" />
<!-- :focus="focusType"
@blur="setfocus"
@confirm="searchWu" -->
<input class="inputSty" v-model="props.inputValue" placeholder="请扫码" placeholder-style="font-size:12px" />
</template>
<script setup lang="ts">
import { ref, nextTick } from "vue";
import { onLoad, onUnload, onHide, onBackPress } from "@dcloudio/uni-app";
// import { ref, nextTick } from 'vue';
// import { onLoad, onUnload, onHide, onBackPress } from '@dcloudio/uni-app';
const focusType = ref(true)
// const focusType = ref(false);
const wuValue = ref()
// const wuValue = ref();
//只要操作代码在这里
const keypress = (e: any) => {
console.log(e, "按键码");
// 102 左侧 103 右侧 104 中间按键
if (e.keyCode === 102 || e.keyCode === 103 || e.keyCode === 104) {
//这里按键成功
const props = defineProps({
inputValue: {
type: String,
default: ''
}
})
if (e.keyCode == 66) { //enter按键
//这里input已经拿到数据了,在这里把拿到的数据,通过接口数据联调起来
// const emits = defineEmits(['input-change']);
}
}
// //只要操作代码在这里
// const keypress = async (e: any) => {
// console.log(e, '按键码');
// // focusType.value = true
// nextTick(() => (focusType.value = true));
// // 102 左侧 103 右侧 104 中间按键
// if (e.keyCode === 102 || e.keyCode === 103 || e.keyCode === 104) {
// //这里按键成功
// focusType.value = false;
// }
onLoad((val) => {
// #ifdef APP-PLUS
plus.key.addEventListener("keyup", keypress);
// #endif
// #ifdef H5
document.addEventListener("keyup", keypress);
// #endif
})
// if (e.keyCode == 66) {
// //enter按键
// //这里input已经拿到数据了,在这里把拿到的数据,通过接口数据联调起来
onUnload(() => {
// #ifdef APP-PLUS
plus.key.removeEventListener("keyup", keypress);
// #endif
// #ifdef H5
document.removeEventListener("keyup", keypress);
// #endif
})
// // console.log(wuValue.value, '66');
// nextTick(() => (focusType.value = false));
// }
onHide(() => {
// #ifdef APP-PLUS
plus.key.removeEventListener("keyup", keypress);
// #endif
// #ifdef H5
document.removeEventListener("keyup", keypress);
// #endif
})
onBackPress(() => {
// #ifdef APP-PLUS
plus.key.removeEventListener("keyup", keypress);
// #endif
// #ifdef H5
document.removeEventListener("keyup", keypress);
// #endif
})
// if (e.keyCode == 13) {
// //enter按键
// //这里input已经拿到数据了,在这里把拿到的数据,通过接口数据联调起来
// // emits('input-change', wuValue.value)
// focusType.value = false;
// }
// };
// onLoad(() => {
// // #ifdef APP-PLUS
// plus.key.addEventListener('keyup', keypress);
// // #endif
// // #ifdef H5
// document.addEventListener('keyup', keypress);
// // #endif
// focusType.value = true;
// });
// onUnload(() => {
// // #ifdef APP-PLUS
// plus.key.removeEventListener('keyup', keypress);
// // #endif
// // #ifdef H5
// document.removeEventListener('keyup', keypress);
// // #endif
// });
//解决焦点自动丢失,无法再次自动聚焦
const setfocus = () => {
focusType.value = false
nextTick(() => {
focusType.value = true
})
}
const searchWu = () => {
//这里是调接口,传递数据,等一些列操作
}
// onHide(() => {
// // #ifdef APP-PLUS
// plus.key.removeEventListener('keyup', keypress);
// // #endif
// // #ifdef H5
// document.removeEventListener('keyup', keypress);
// // #endif
// });
// onBackPress(() => {
// // #ifdef APP-PLUS
// plus.key.removeEventListener('keyup', keypress);
// // #endif
// // #ifdef H5
// document.removeEventListener('keyup', keypress);
// // #endif
// });
// //解决焦点自动丢失,无法再次自动聚焦
// const setfocus = () => {
// focusType.value = false;
// nextTick(() => {
// focusType.value = true;
// });
// };
// const searchWu = () => {
// //这里是调接口,传递数据,等一些列操作
// console.log(wuValue.value, 'confirm');
// };
</script>
<style lang = "scss" scoped>
</style>
\ No newline at end of file
<style lang="scss" scoped>
</style>
<template>
<vk-header :title="title" back-icon-name="nav-back" />
<form-list-item @tap="toDetail" />
<form-list-item :business-list="businessList" />
</template>
<script setup lang='ts'>
import { ref } from 'vue'
import { onLoad } from '@dcloudio/uni-app';
import { onLoad, onShow } from '@dcloudio/uni-app';
import { getBusinessList } from '@/api/apply'
import { useFormData } from '@/store/modules/formData';
import { sLoading, hLoading } from '@/utils/util'
import vkHeader from '@/components/header/index.vue'
import FormListItem from './component/FormListItem.vue';
const title = ref('')
const store = useFormData()
const pageData = ref()
const businessList = ref([] as any[])
onLoad(async (options: any) => {
const option = JSON.parse(options.data)
// console.log(option);
const { permTag: formId, subSystem, title: t } = option
title.value = t
onLoad(async () => {
const { subSystem, permTag: formId } = JSON.parse(uni.getStorageSync('pageData'))
const { data: res } = await getBusinessList({ formId, subSystem })
sLoading()
if (res.code === 200) handleLoadData(res.data)
})
const handleLoadData = (data: any) => {
console.log(data);
let list: any[] = []
data.dataList.map((item: any) => {
let arr = [] as any
data.fieldList.map((field: any) => {
let obj = {} as any
for (const d in item) {
if (field.key === d) {
list.push({
})
obj.label = field.fieldName
obj.value = item[d]
arr.push(obj)
}
}
})
businessList.value.push(arr)
})
hLoading()
}
const toDetail = () => {
uni.navigateTo({ url: '/pages/apply/formDetail' })
}
onShow(() => {
pageData.value = JSON.parse(uni.getStorageSync('pageData') as any)
title.value = pageData.value.title
})
</script>
<style lang = "scss" scoped>
......
......@@ -2,7 +2,7 @@
<vk-header :title="title" back-icon-name="nav-back" />
<view class="header">
<view class="scan-input">
<scanInput />
<scanInput :inputValue="inputValue" />
<!-- #ifdef APP-PLUS -->
<u-icon name="scan" size="22" style="padding: 14rpx" />
<!-- #endif -->
......@@ -12,46 +12,35 @@
</view>
<view style="text-align: right;">
<!-- #ifdef APP-PLUS -->
<u-icon name="list" size="22" style="padding: 14rpx" />
<u-icon name="list" size="22" style="padding: 14rpx" @tap="sheetShow = true" />
<!-- #endif -->
<!-- #ifdef H5 -->
<u-icon name="list" size="44" style="padding: 14rpx" />
<u-icon name="list" size="44" style="padding: 14rpx" @tap="sheetShow = true" />
<!-- #endif -->
</view>
</view>
<!-- rgb(218,222,224) -->
<view class="line" />
<view class="detail-content">
<view v-show="show">
<block v-for="item in list">
<view class="detail-content" v-for="(item, i) in list" :key="i">
<view v-show="item.show">
<block v-for="res in item.dataList" :key="res.label">
<view class="list">
<view class="label">{{ item.label }}</view>
<view class="value">{{ item.value }}</view>
<view class="label">{{ res.label }}</view>
<view class="value">{{ res.value }}</view>
</view>
</block>
<view class="label1">规格:</view>
<view class="specifications">
<u-row :gutter="12">
<u-col v-for="item in specList" :span="5.5" style="white-space: nowrap;">
<view class="list">
<view class="label">{{ item.label }}</view>
<view class="value">{{ item.value }}</view>
</view>
</u-col>
</u-row>
</view>
</view>
<view class="footer">
<view>
<view @tap="
() => {
show = !show;
if (show) scanIcon = 'arrow-up-fill';
else scanIcon = 'arrow-down-fill';
item.show = !item.show;
if (item.show) item.scanIcon = 'arrow-up-fill';
else item.scanIcon = 'arrow-down-fill';
}
">
<u-icon :name="scanIcon"></u-icon>
<u-icon :name="item.scanIcon"></u-icon>
关闭扫描详情
</view>
</view>
......@@ -60,37 +49,155 @@
</view>
<view class="footer-form">
<detail-form />
<detail-form :metadataList="metadataList" />
</view>
<!-- 保存 -->
<view class="aside-save">
<!-- #ifdef APP-PLUS -->
<u-icon name="checkmark-circle" size="22" style="padding: 14rpx" @tap="sheetShow = true" />
<!-- #endif -->
<!-- #ifdef H5 -->
<u-icon name="checkmark-circle" size="44" style="padding: 14rpx" color="#2979ff" @tap="modelData.show = true" />
<!-- #endif -->
</view>
<!-- #ifdef APP-PLUS -->
<qs-scanlistener v-if="scanFlag" ref="scanRef" @scan="handleInput"></qs-scanlistener>
<!-- #endif -->
<u-action-sheet :list="sheetList" v-model="sheetShow" @click="sheetClick" />
<u-modal v-model="modelData.show" :content="modelData.content" show-cancel-button @confirm="modelConfirm" />
</template>
<script setup lang="ts">
import { ref, nextTick } from 'vue';
import { nextTick, ref } from 'vue';
import { onShow } from '@dcloudio/uni-app';
import { getMetadata } from '@/api/apply';
import { getBusinessList } from '@/api/apply'
import vkHeader from '@/components/header/index.vue';
import detailForm from './component/detailForm.vue';
import scanInput from './component/scanInput.vue'
const title = ref('业务组');
const show = ref(true);
const scanIcon = ref('arrow-up-fill');
const list = ref([
{ label: '备料单号:', value: 'RQ202303140551' },
{ label: '来源单号:', value: ' Z23027438-1' },
{ label: '物料编码:', value: '21.32092' },
{ label: '助记码:', value: 'RD020V3-201' },
{ label: '物料名称:', value: '镜座' },
{ label: '助记码:', value: 'RQ202303140551' },
]);
const specList = ref([
{ label: '仓库:', value: '装配仓' },
{ label: '储位:', value: '5F-A06-21-1' },
{ label: '需求:', value: '2304' },
{ label: '应发:', value: '2350.08' },
{ label: '数量:', value: '0.000' },
]);
const pageData = ref()
const title = ref();
const scanRef = ref();
const scanFlag = ref(true);
// const show = ref(true);
// const scanIcon = ref('arrow-up-fill');
const inputValue = ref('');
const sheetList = ref([
{ text: '查询' },
{ text: '撤销' },
])
const modelData = ref({
content: '确认提交?',
show: false
})
const sheetShow = ref(false)
const list = ref([] as any);
const handleInput = async (e: any) => {
console.log(e, 'e');
nextTick(() => {
inputValue.value = e
scanFlag.value = false
})
const { subSystem, permTag: formId } = JSON.parse(uni.getStorageSync('pageData'))
const { data: res } = await getBusinessList({ formId, subSystem })
if (res.code === 200) {
const { dataList, fieldList } = res.data
let obj = {
dataList: [],
show: true,
scanIcon: 'arrow-up-fill'
} as any
for (const key in dataList[0]) {
fieldList.map((item: any) => {
if (item.key === key) {
obj.dataList.push({
label: item.fieldName,
value: dataList[0][key],
})
}
})
}
list.value.push(obj)
nextTick(() => {
inputValue.value = ''
scanFlag.value = true
})
}
}
const sheetClick = (index: number) => {
switch (index) {
case 0:
console.log('查询');
uni.navigateTo({ url: '/pages/apply/formDataPage' })
break;
case 1:
console.log('撤销');
break;
}
}
const modelConfirm = () => {
alert('提交成功')
}
onShow(() => {
pageData.value = JSON.parse(uni.getStorageSync('pageData') as any)
title.value = pageData.value.title
init()
})
const metadata = ref()
const metadataList = ref([] as any)
// visibility mobile_list_visible
const init = async () => {
const { data: res } = await getMetadata(pageData.value.permTag)
if (res.code === 200) {
metadata.value = JSON.parse(res.data.formJson)
const list = JSON.parse(JSON.stringify(metadata.value.list))
await filterList(list).forEach((item: any) => {
if (item.columns) metadataList.value = [...metadataList.value, ...item.columns[0].list]
if (item.detailColumns)
item.detailColumns[0].list.forEach((res: any) => {
if (res.columns) metadataList.value = [...metadataList.value, ...res.columns[0].list]
if (res.detailColumns)
item.columns[0].list.forEach((res1: any) => {
if (res1.columns) metadataList.value = [...metadataList.value, ...res1.columns[0].list]
})
})
if (!item.columns && !item.detailColumns) metadataList.value = [...metadataList.value, item]
})
// console.log(metadataList.value);
}
}
const filterList = (list: any[]) => {
let mobileList = [] as any[];
const recursiveFilter = (item: any) => {
if (item.columns)
item.columns[0].list.map((res: any) => {
if (res.options.visibility && res.options.visibility.indexOf("mobile_form_visible") !== -1)
mobileList = [...mobileList, res];
});
if (item.detailColumns)
item.detailColumns[0].list.forEach((res: any) => {
recursiveFilter(res);
});
if (item.options.visibility && item.options.visibility.indexOf("mobile_form_visible") !== -1)
mobileList = [...mobileList, item];
};
list.forEach((item) => recursiveFilter(item))
return mobileList;
};
</script>
<style lang="scss" scoped>
......@@ -101,7 +208,7 @@ const specList = ref([
align-items: center;
.scan-input {
width: 80%;
width: 88%;
box-sizing: border-box;
display: flex;
justify-content: space-between;
......@@ -111,7 +218,7 @@ const specList = ref([
padding: 0 20rpx;
input {
width: 80%;
width: 88%;
}
}
}
......@@ -136,6 +243,7 @@ const specList = ref([
.label {
width: 200rpx;
text-align: right;
margin-right: 20rpx;
}
.value {}
......@@ -179,11 +287,34 @@ const specList = ref([
.footer-form {
box-sizing: border-box;
// position: fixed;
// bottom: 0;
position: fixed;
bottom: 0;
z-index: 999;
width: 100%;
padding: 0 20rpx;
border-top: 1rpx solid #ccc;
border-bottom: 1rpx solid #ccc;
background-color: #ffffff;
}
.aside-save {
position: fixed;
right: 0;
top: 76%;
/* #ifdef APP-PLUS */
width: 100rpx;
height: 120rpx;
line-height: 80rpx;
padding: 6rpx 0 6rpx 6rpx;
border-bottom-left-radius: 30%;
border-top-left-radius: 30%;
/* #endif */
/* #ifdef H5 */
width: 80rpx;
height: 84rpx;
line-height: 80rpx;
padding: 6rpx 0 6rpx 6rpx;
border-bottom-left-radius: 30%;
border-top-left-radius: 30%;
/* #endif */
background-color: #dbf1e1;
box-sizing: border-box;
}
</style>
<template>
<block v-for="res in menuList" :key="res.path">
<view class="card" v-show="res.children?.length">
<h3 class="card-text">{{ res.title }}</h3>
<u-grid :col="4" :border="false">
<u-grid-item v-for="item in res.children" :custom-style="{ 'text-align': 'center' }"
@tap="tapGridItem(item)">
<!-- <svg-icon name="dayin" /> -->
<i class="iconfont icon-dayin" style="color: pink;"></i>
<!-- <svg-icon name="dayin" /> -->
<!-- <i class="iconfont">&#xe609;</i> -->
<view class="grid-text">{{ item.title }}</view>
</u-grid-item>
</u-grid>
</view>
</block>
<block v-for="res in menuList" :key="res.path">
<view class="card" v-show="res.children?.length">
<h3 class="card-text">{{ res.title }}</h3>
<u-grid :col="4" :border="false">
<u-grid-item
v-for="item in res.children"
:custom-style="{ 'text-align': 'center' }"
@tap="tapGridItem(item)"
>
<u-icon
:name="item.icon"
custom-prefix="custom-icon"
size="44"
:color="item.iconStyle"
/>
<view class="grid-text">{{ item.title }}</view>
</u-grid-item>
</u-grid>
</view>
</block>
</template>
<script setup lang='ts'>
import { ref } from 'vue'
import svgIcon from '@/components/svgIcon/index.vue'
<script setup lang="ts">
import { ref } from 'vue';
import { getMenuTree } from '@/api/apply';
const menuList = ref()
const menuList = ref();
const tapGridItem = (row: any) => {
uni.navigateTo({ url: '/pages/apply/formDataPage?data=' + encodeURIComponent(JSON.stringify(row)), })
}
uni.navigateTo({
url: '/pages/apply/formDetail',
success() {
uni.setStorageSync('pageData', JSON.stringify(row));
},
});
};
// 过滤未发布的菜单
const handleMenuTree = (list: any[]) => {
let newList: any[] = []
list.map((item: any) => {
if (item.publish) {
let childCpoy = JSON.parse(JSON.stringify(item.children))
let arr = handleMenuTree(childCpoy)
item.children = [...arr]
newList.push(item)
}
})
return newList
}
let newList: any[] = [];
list.map((item: any) => {
if (item.publish) {
let childCpoy = JSON.parse(JSON.stringify(item.children));
let arr = handleMenuTree(childCpoy);
item.children = [...arr];
newList.push(item);
}
});
return newList;
};
const init = async () => {
const { data: res } = await getMenuTree()
if (res.code === 200) {
menuList.value = handleMenuTree(res.data)
}
}
init()
const { data: res } = await getMenuTree();
if (res.code === 200) {
menuList.value = handleMenuTree(res.data);
}
};
init();
</script>
<style lang = "scss" scoped>
<style lang="scss" scoped>
.card {
box-sizing: border-box;
margin: 16rpx;
border-radius: 8rpx;
border: 1px solid #e4e7ed;
background-color: #ffffff;
overflow: hidden;
color: #303133;
transition: .3s;
box-shadow: 0px 0px 12px rgba(0, 0, 0, .05);
box-sizing: border-box;
margin: 16rpx;
border-radius: 8rpx;
border: 1px solid #e4e7ed;
background-color: #ffffff;
overflow: hidden;
color: #303133;
transition: 0.3s;
box-shadow: 0px 0px 12px rgba(0, 0, 0, 0.05);
.card-text {
padding: 20rpx;
}
.card-text {
padding: 20rpx;
}
.grid-text {
font-size: 28rpx;
margin-top: 4rpx;
color: #303133;
padding: 0 10rpx;
white-space: 'nowrap';
text-overflow: 'ellipsis';
overflow: 'hidden';
}
.grid-text {
font-size: 28rpx;
margin-top: 4rpx;
color: #303133;
padding: 0 10rpx;
white-space: 'nowrap';
text-overflow: 'ellipsis';
overflow: 'hidden';
}
}
</style>
\ No newline at end of file
</style>
<template>
<u-button type="primary" :loading="isSearch" @tap="startSearch">开始搜索</u-button>
<view style="margin: 40rpx 0;"></view>
<u-button type="error" @tap="stopSearch">停止搜索</u-button>
<u-button type="warning">跳转页面</u-button>
<view style="margin: 40rpx 0;"></view>
<u-button type="warning" @tap="openControl">跳转页面</u-button>
<u-cell-group>
<!-- <u-cell-item icon="" v-for="item in list" :data-title="item.deviceId" :title="item.deviceId"
:data-name="item.name" :data-advertisData="item.advertisServiceUUIDs" :key="item.deviceId"
:value="item.name" :arrow="false" @tap="bindViewTap"></u-cell-item> -->
<u-cell-item icon="" data-title="item.deviceId" title="item.deviceId" data-name="name"
data-advertisData="item.advertisServiceUUIDs" value="item.name" :arrow="false" @tap="bindViewTap">
</u-cell-item>
</u-cell-group>
<view v-for="item in list" :data-title="item.deviceId" :data-name="item.name"
:data-advertisData="item.advertisServiceUUIDs" :key="item.deviceId" @tap="bindViewTap">
<view class="item">
......@@ -114,7 +108,6 @@ const getBluetoothDevices = async () => {
// 监听蓝牙设备
plus.bluetooth.onBluetoothDeviceFound((result: any) => {
console.log('onBluetoothDeviceFound:', result);
const arr = list.value
const devices = []
const listArr = result.devices
......@@ -139,7 +132,6 @@ const getBluetoothDevices = async () => {
devices.push(listArr[i]);
}
}
list.value = devices;
console.log('getBluetoothDevices:', res);
resolve();
......@@ -165,15 +157,22 @@ const bindViewTap = (e: any) => {
uni.showLoading({ title: '正在连接' })
console.log('deviceId:', title);
plus.bluetooth.createBLEConnection({
deviceId: title,
success(res: any) {
console.log('createBLEConnection success:', res);
console.log('before', BLEInformation.deviceId);
BLEInformation.deviceId = title;
blueTooth.BLEInformationSet(BLEInformation)
uni.hideLoading();
getSeviceId();
console.log('before', BLEInformation.deviceId);
blueTooth.$patch({
BLEInformation
})
uni.hideLoading()
console.log('纳尼');
('纳尼')
setTimeout(() => {
getSeviceId();
});
},
fail(e) {
errorCodeTip(e.errCode);
......@@ -183,93 +182,95 @@ const bindViewTap = (e: any) => {
}
const getSeviceId = async () => {
try {
const { deviceId } = blueTooth.BLEInformation;
console.log('BLEInformation.deviceId:', deviceId);
const { deviceId } = blueTooth.BLEInformation;
console.log('BLEInformation.deviceId:', deviceId);
// 等待1.5秒后获取蓝牙设备服务信息
await new Promise(resolve => setTimeout(resolve, 1500));
// 等待1.5秒后获取蓝牙设备服务信息
await new Promise(resolve => setTimeout(resolve, 1500));
// 获取蓝牙设备服务信息并更新服务列表
const { services: s } = await new Promise((resolve, reject) => {
plus.bluetooth.getBLEDeviceServices({
deviceId,
success: resolve,
fail: reject,
});
// 获取蓝牙设备服务信息并更新服务列表
const { services: s } = await new Promise((resolve, reject) => {
plus.bluetooth.getBLEDeviceServices({
deviceId,
success: resolve,
fail: reject,
});
console.log('getBLEDeviceServices success:', s);
services.value = s;
getCharacteristics();
} catch (e: any) {
errorCodeTip(e.code);
console.log('getBLEDeviceServices fail:', e);
}
});
services.value = s;
getCharacteristics();
}
const getCharacteristics = async () => {
try {
const num = serviceId.value
const { deviceId } = blueTooth.BLEInformation;
const num = serviceId.value
const { deviceId } = blueTooth.BLEInformation;
// 获取蓝牙设备特征值信息
const { characteristics } = await new Promise((resolve, reject) => {
plus.bluetooth.getBLEDeviceCharacteristics({
deviceId,
serviceId: services.value[num].uuid,
success: resolve,
fail: reject,
});
// 获取蓝牙设备特征值信息
const { characteristics } = await new Promise((resolve, reject) => {
plus.bluetooth.getBLEDeviceCharacteristics({
deviceId,
serviceId: services.value[num].uuid,
success: resolve,
fail: reject,
});
});
console.log('getBLEDeviceCharacteristics success:', characteristics);
console.log('getBLEDeviceCharacteristics success:', JSON.stringify(characteristics));
// 遍历特征值列表,获取写、读、通知特征值ID和服务ID
for (let i = 0; i < characteristics.length; i++) {
const { uuid, properties } = characteristics[i];
if (!notifyCharacter.value && properties.notify) {
blueTooth.BLEInformation.notifyCharaterId = uuid;
blueTooth.BLEInformation.notifyServiceId = services.value[num].uuid;
blueTooth.BLEInformationSet(blueTooth.BLEInformation)
notifyCharacter.value = true;
}
if (!writeCharacter.value && properties.write) {
blueTooth.BLEInformation.writeCharaterId = uuid;
blueTooth.BLEInformation.writeServiceId = services.value[num].uuid;
blueTooth.BLEInformationSet(blueTooth.BLEInformation)
writeCharacter.value = true;
}
if (!readCharacter.value && properties.read) {
blueTooth.BLEInformation.readCharaterId = uuid;
blueTooth.BLEInformation.readServiceId = services.value[num].uuid;
blueTooth.BLEInformationSet(blueTooth.BLEInformation)
readCharacter.value = true;
}
// 遍历特征值列表,获取写、读、通知特征值ID和服务ID
for (let i = 0; i < characteristics.length; i++) {
const { uuid, properties } = characteristics[i];
console.log(uuid, properties, 'characteristics[i]');
if (!notifyCharacter.value && properties.notify) {
blueTooth.BLEInformation.notifyCharaterId = uuid;
blueTooth.BLEInformation.notifyServiceId = services.value[num].uuid;
blueTooth.$patch({
BLEInformation: blueTooth.BLEInformation
})
notifyCharacter.value = true;
console.log('notify');
}
if (!writeCharacter.value && properties.write) {
blueTooth.BLEInformation.writeCharaterId = uuid;
blueTooth.BLEInformation.writeServiceId = services.value[num].uuid;
blueTooth.$patch({
BLEInformation: blueTooth.BLEInformation
})
writeCharacter.value = true;
console.log('write');
}
if (!readCharacter.value && properties.read) {
blueTooth.BLEInformation.readCharaterId = uuid;
blueTooth.BLEInformation.readServiceId = services.value[num].uuid;
blueTooth.$patch({
BLEInformation: blueTooth.BLEInformation
})
readCharacter.value = true;
console.log('read');
}
}
// 如果找不到对应的写、读、通知特征值,则继续查找下一个服务的特征值
if (!writeCharacter.value || !notifyCharacter.value || !readCharacter.value) {
serviceId.value = num + 1;
if (num === services.length - 1) {
uni.showModal({
title: '提示',
content: '找不到该读写的特征值',
});
} else {
await getCharacteristics();
}
// 如果找不到对应的写、读、通知特征值,则继续查找下一个服务的特征值
if (!writeCharacter.value || !notifyCharacter.value || !readCharacter.value) {
serviceId.value = num + 1;
if (num === services.length - 1) {
console.log('找不到该读写的特征值');
uni.showModal({
title: '提示',
content: '找不到该读写的特征值',
});
} else {
openControl();
await getCharacteristics();
}
} catch (e: any) {
console.log('getBLEDeviceCharacteristics fail:', e);
errorCodeTip(e.errCode);
} else {
openControl();
}
}
const openControl = () => {
alert('成功跳转')
console.log('成功跳转');
uni.navigateTo({
url: '/pages/blueTooth/printTest'
})
}
</script>
......
<template>
<view class="content">
<view class="body">
<view>
<textarea class="result" v-model="state.returnResult"></textarea>
</view>
<textarea class="input" @input="inputEvent" />
<view style='margin-top:4%'>
<u-button type='primary' @tap='labelTest' :loading='state.isLabelSend' :disabled='state.isLabelSend'>
标签测试
</u-button>
</view>
<picker style='margin:20px' mode='selector' :range='state.buffSize' :value='state.buffIndex'
@change='buffBindChange'>
当前每次发送字节数为(点击可更换):{{ state.buffSize[state.buffIndex] }}
</picker>
<picker style='margin:20px' mode='selector' :range='state.printNum' :value='state.printNumIndex'
@change='printNumBindChange'>
当前打印份数(点击可更换):{{ state.printNum[state.printNumIndex] }}
</picker>
<view style='margin-top:4%; display: flex; flex-direction: row;'>
<canvas canvas-id='edit_area_canvas'
:style="{ width: state.canvasWidth + 'px', height: state.canvasHeight + 'px' }"></canvas>
</view>
</view>
</view>
</template>
<script setup lang='ts'>
import { reactive, toRefs } from 'vue'
import { useBlueTooth } from '@/store/modules/bluetooth';
import { onLoad, onShow, onReady, onUnload } from '@dcloudio/uni-app';
import { createNew } from '../../utils/ble/tsc'
onLoad(() => {
let { BLEInformation } = blueTooth;
})
onReady(() => {
let list = [] as any[]
let numList = []
let j = 0
for (let i = 20; i < 200; i += 10) {
list[j] = i;
j++
}
for (let i = 1; i < 10; i++) {
numList[i - 1] = i
}
state.buffSize = list;
state.oneTimeData = list[0];
state.printNum = numList;
state.printerNum = numList[0];
})
onShow(() => {
// const ctx = uni.createCanvasContext("edit_area_canvas", state);
// if (app.globalData.platform == "android") {
// ctx.translate(width, height)
// ctx.rotate(180 * Math.PI / 180)
// }
})
onUnload(() => {
// let that = state;
// let {
// BLEInformation
// } = that.Bluetooth;
// uni.closeBLEConnection({
// deviceId: BLEInformation.deviceId,
// success: function(res) {
// console.log("关闭蓝牙成功")
// },
// })
})
const state: any = reactive({
sendContent: "",
looptime: 0,
currentTime: 1,
lastData: 0,
oneTimeData: 0,
returnResult: "",
canvasWidth: 1050,
canvasHeight: 750,
buffSize: [],
buffIndex: 0,
printNum: [],
printNumIndex: 0,
printerNum: 1,
currentPrint: 1,
isReceiptSend: false,
isLabelSend: false
})
const blueTooth = useBlueTooth()
const inputEvent = (e: any) => state.sendContent = e.detail.value;
const labelTest = () => {
let canvasWidth = state.canvasWidth
let canvasHeight = state.canvasHeight
// x 和 y: 文字的起始位置坐标,以毫米为单位。
// font: 字体类型,可以是预装载的或者外部下载的字体。
// x_ 和 y_: 水平和垂直缩放比例,范围为 0 - 10,可调整字体大小。
// str: 要打印的文字内容。
// codetype: 条形码类型,支持 CODE128、CODE39、CODE93 等多种类型。
// height: 条码的高度,以毫米为单位。
// readable: 是否在条形码下方打印可读的文字标签。0 表示不打印,1 表示打印。
// narrow 和 wide: 条形码线条的宽度比例,范围为 1 - 10。
// content: 条形码所表示的内容。
let command = createNew()
command.setSize(70, 52); // 设置页面大小
command.setGap(0); //传感器
command.setCls(); //清除打印机缓存
command.setText(40, 50, 'TSS24.BF2', 1, 1, 'WMS编码号');
command.setBarCode(200, 40, 'EAN8', 64, 1, 3, 3, '1234567');
command.setText(40, 100, 'TSS24.BF2', 1, 1, '佳博智汇');
command.setText(40, 140, 'TSS24.BF2', 1, 1, 'h测试数字12345678');
command.setText(40, 180, 'TSS24.BF2', 1, 1, 'g测试数字12345678');
command.setText(40, 220, 'TSS24.BF2', 1, 1, 'f测试数字12345678');
command.setText(40, 260, 'TSS24.BF2', 1, 1, 'e测试数字12345678');
command.setText(40, 300, 'TSS24.BF2', 1, 1, 'd测试数字12345678');
command.setText(40, 340, 'TSS24.BF2', 1, 1, 'c测试数字12345678');
command.setText(40, 380, 'TSS24.BF2', 1, 1, 'b测试数字12345678');
command.setQR(300, 180, 'L', 8, 'A', 'www.smarnet.cc佳博智汇');
uni.canvasGetImageData({
canvasId: 'edit_area_canvas',
x: 0,
y: 0,
width: canvasWidth,
height: canvasHeight,
success: function (res) {
command.setBitmap(60, 0, 1, res)
},
complete: function () {
command.setPagePrint()
state.isLabelSend = true;
prepareSend(command.getData())
}
})
}
const printNumBindChange = (res: any) => {
let index = res.detail.value
let num = state.printNum[index]
state.printNumIndex = index;
state.printerNum = num;
}
const buffBindChange = (res: any) => {
let index = res.detail.value
let time = state.buffSize[index]
state.buffIndex = index;
state.oneTimeData = time;
}
//准备发送,根据每次发送字节数来处理分包数量
const prepareSend = (buff: any[]) => {
console.log(buff.length, 'buff.length');
let time = state.oneTimeData
let looptime = (Number(buff.length) / Number(time));
let lastData = (Number(buff.length) % Number(time));
console.log(looptime + "---" + lastData)
state.looptime = looptime + 1;
state.lastData = lastData;
state.currentTime = 1;
Send(buff)
}
//分包发送
const Send = (buff: any) => {
let {
currentTime,
looptime: loopTime,
lastData,
oneTimeData: onTimeData,
printerNum: printNum,
currentPrint } = state;
let buf;
let dataView;
if (currentTime < loopTime) {
buf = new ArrayBuffer(onTimeData)
dataView = new DataView(buf)
for (var i = 0; i < onTimeData; ++i) {
dataView.setUint8(i, buff[(currentTime - 1) * onTimeData + i])
}
} else {
buf = new ArrayBuffer(lastData)
dataView = new DataView(buf)
for (var i = 0; i < lastData; ++i) {
dataView.setUint8(i, buff[(currentTime - 1) * onTimeData + i])
}
}
console.log("第" + currentTime + "次发送数据大小为:" + buf.byteLength)
let BLEInformation = blueTooth.BLEInformation
plus.bluetooth.writeBLECharacteristicValue({
deviceId: BLEInformation.deviceId,
serviceId: BLEInformation.writeServiceId,
characteristicId: BLEInformation.writeCharaterId,
value: buf,
success: function (res) {
console.log(res)
},
fail: function (e) {
console.log(e)
},
complete: function () {
currentTime++
if (currentTime <= loopTime) {
state.currentTime = currentTime;
Send(buff)
} else {
uni.showToast({
title: '已打印第' + currentPrint + '张',
})
if (currentPrint == printNum) {
state.looptime = 0;
state.lastData = 0;
state.currentTime = 1;
state.isReceiptSend = false;
state.isLabelSend = false;
state.currentPrint = 1;
} else {
currentPrint++;
state.currentPrint = currentPrint;
state.currentTime = 1;
Send(buff)
}
}
}
})
}
defineExpose({
...toRefs(state)
})
</script>
<style lang = "scss" scoped>
.input {
text-align: top;
width: 90%;
height: 150px;
margin-left: 4%;
margin-right: 4%;
margin-top: 10px;
margin-bottom: 12px;
border: 1px solid slategray;
}
.receiver_info_scroll_view {
width: 90%;
height: 200px;
margin-left: 4%;
margin-right: 4%;
margin-top: 10px;
margin-bottom: 25px;
border: 1px solid black;
}
.result {
width: 90%;
height: 150px;
border: 1px solid black;
margin-left: 4%;
margin-bottom: 4%;
margin-top: 5%;
}
button {
width: 90%;
margin-left: 5%;
margin-right: 5%;
}
.switch {
float: right;
margin-right: 20px;
margin-bottom: 16px;
}
text {
color: #fff;
display: block;
}
input {
color: gainsboro;
float: left;
}
.v_net_ssid {
width: 100%;
background: #fff;
}
.v_net_passw {
width: 100%;
background: antiquewhite;
}
.swiper {
width: 100%;
height: 100%;
}
</style>
\ No newline at end of file
......@@ -2,13 +2,11 @@
<view class="wrap">
<u-swiper :list="list" :height="swiperHeight"></u-swiper>
</view>
<blueTooth />
<u-button type="primary" @tap="toBlueTooth">连接蓝牙</u-button>
</template>
<script setup lang='ts'>
import { ref, onMounted } from 'vue'
import config from '@/utils/config'
import blueTooth from '@/components/blueTooth/index.vue'
const list = [{
image: 'https://cdn.uviewui.com/uview/swiper/1.jpg',
......@@ -23,6 +21,8 @@ const list = [{
title: '谁念西风独自凉,萧萧黄叶闭疏窗,沉思往事立残阳'
}]
const toBlueTooth = () => uni.navigateTo({ url: '/pages/blueTooth/index' })
let swiperHeight = ref('250')
onMounted(() => {
......
{
"id": "3968711",
"name": "wms",
"font_family": "iconfont",
"css_prefix_text": "icon-",
"description": "",
"glyphs": [
{
"icon_id": "2325947",
"name": "移入文件夹",
"font_class": "yiruwenjianjia",
"unicode": "e648",
"unicode_decimal": 58952
},
{
"icon_id": "2325948",
"name": "移出文件夹",
"font_class": "yichuwenjianjia",
"unicode": "e647",
"unicode_decimal": 58951
},
{
"icon_id": "3247660",
"name": "其他出库",
"font_class": "qitachuku",
"unicode": "e613",
"unicode_decimal": 58899
},
{
"icon_id": "3247663",
"name": "其他入库",
"font_class": "qitaruku",
"unicode": "e614",
"unicode_decimal": 58900
},
{
"icon_id": "3703010",
"name": "库存盘点单",
"font_class": "navicon-kcpdd",
"unicode": "e65f",
"unicode_decimal": 58975
},
{
"icon_id": "4178310",
"name": "打印",
"font_class": "dayin",
"unicode": "e609",
"unicode_decimal": 58889
},
{
"icon_id": "4464995",
"name": "出库",
"font_class": "chuku",
"unicode": "e601",
"unicode_decimal": 58881
},
{
"icon_id": "4465007",
"name": "入库",
"font_class": "ruku",
"unicode": "e606",
"unicode_decimal": 58886
},
{
"icon_id": "5044396",
"name": "打印机",
"font_class": "dayinji",
"unicode": "e618",
"unicode_decimal": 58904
},
{
"icon_id": "6941969",
"name": "库存盘点",
"font_class": "kucunpandian-",
"unicode": "e646",
"unicode_decimal": 58950
},
{
"icon_id": "7404458",
"name": "打勾",
"font_class": "dagou",
"unicode": "e782",
"unicode_decimal": 59266
},
{
"icon_id": "11019850",
"name": "出库",
"font_class": "chuku1",
"unicode": "e60a",
"unicode_decimal": 58890
},
{
"icon_id": "11239051",
"name": "退货",
"font_class": "tuihuo",
"unicode": "e649",
"unicode_decimal": 58953
},
{
"icon_id": "11957186",
"name": "星途学堂-打印/打印机",
"font_class": "xingtuxuetang-dayin-",
"unicode": "e605",
"unicode_decimal": 58885
},
{
"icon_id": "12538472",
"name": "打印",
"font_class": "dayin1",
"unicode": "e718",
"unicode_decimal": 59160
},
{
"icon_id": "17121524",
"name": "原材料退料上架",
"font_class": "yuancailiaotuiliaoshangjia",
"unicode": "e600",
"unicode_decimal": 58880
},
{
"icon_id": "17620090",
"name": "销售出库",
"font_class": "tubiaozhizuomoban-01",
"unicode": "e636",
"unicode_decimal": 58934
},
{
"icon_id": "20154005",
"name": "自助打印",
"font_class": "zizhudayindayin",
"unicode": "e607",
"unicode_decimal": 58887
},
{
"icon_id": "20389229",
"name": "生产退料",
"font_class": "shengchantuiliaobeifen2x",
"unicode": "e604",
"unicode_decimal": 58884
},
{
"icon_id": "20671376",
"name": "菜单栏-生产-生产入库",
"font_class": "caidanlan-shengchan-shengchanruku",
"unicode": "e661",
"unicode_decimal": 58977
},
{
"icon_id": "23291105",
"name": "退料记录",
"font_class": "tuiliaojilu",
"unicode": "e651",
"unicode_decimal": 58961
},
{
"icon_id": "23291883",
"name": "生产领料",
"font_class": "shengchanlingliao",
"unicode": "e657",
"unicode_decimal": 58967
},
{
"icon_id": "24272078",
"name": "检验单",
"font_class": "jianyandan",
"unicode": "e68b",
"unicode_decimal": 59019
},
{
"icon_id": "24732473",
"name": "打印",
"font_class": "dayin2",
"unicode": "eca6",
"unicode_decimal": 60582
},
{
"icon_id": "33177972",
"name": "订料入库",
"font_class": "dingliaoruku",
"unicode": "e6f9",
"unicode_decimal": 59129
},
{
"icon_id": "33178017",
"name": "采购入库",
"font_class": "caigouruku",
"unicode": "e6fa",
"unicode_decimal": 59130
},
{
"icon_id": "34263593",
"name": "条码查询",
"font_class": "tiaomachaxun",
"unicode": "e617",
"unicode_decimal": 58903
}
]
}
declare module 'vk-uview-ui'
\ No newline at end of file
declare module 'vk-uview-ui'
declare module 'text-encoding'
\ No newline at end of file
<template>
<view></view>
</template>
<script>
import scaninput from './scanInput.js';
scaninput.initScan();
scaninput.startScan();
export default {
name: 'scan-listener',
created() {
scaninput.install(this.scanHandle);
// uni.$on('scan_handle', this.scanHandle)
},
beforeDestroy() {
scaninput.uninstall(this.scanHandle);
},
methods: {
onEvent(event) {
// console.log(event.key)
if (event.key != 'Enter' && event.key != 'PrintScreen') {
// 拼接输入的值,Enter与PrintScreen是物理按钮要排除
this.inputVal = this.inputVal + event.key;
}
if (event.key == 'Enter') {
let reg = new RegExp('Shift', 'g'); //g代表全部
let reg2 = new RegExp('Unidentified', 'g'); //排除‘Unidentified’字符
let inputVal = this.inputVal;
inputVal = inputVal.replace(reg, '');
inputVal = inputVal.replace(reg2, '');
inputVal = inputVal.replace(/\s/g, '');
inputVal = inputVal.replace(/\r\n/g, '');
inputVal = inputVal.replace(/\n/g, '');
if (this.inputVal) {
// console.log('键盘监听模式')
this.$emit('scan', this.inputVal);
}
this.inputVal = '';
}
},
scanHandle(code) {
// console.log('广播模式')
this.$emit('scan', code);
},
},
data() {
return {
inputVal: '',
};
},
};
</script>
<script module="keyboard" lang="renderjs">
export default {
mounted () {
const onKey = (event) => {
const keys1 = ['type', 'timeStamp']
const keys2 = ['altKey', 'code', 'ctrlKey', 'isComposing', 'key', 'location', 'metaKey', 'repeat', 'shiftKey']
const keys3 = ['char', 'charCode', 'keyCode', 'keyIdentifier', 'keyLocation', 'which']
const data = {}
keys1.concat(keys2, keys3).forEach(key => data[key] = event[key])
this.$ownerInstance.callMethod('onEvent', data)
}
const names = ['keyup'] //'keydown',
names.forEach(name => {
document.addEventListener(name, onKey, false)
})
this.$on('hook:beforeDestroy', () => {
names.forEach(name => {
document.removeEventListener(name, onKey, false)
})
})
}
}
</script>
<style></style>
let main, receiver, filter, _codeQueryTag = false,
temp = [],
init = false,
start = false;
export default {
initScan() {
if (init) return
let _this = this;
main = plus.android.runtimeMainActivity(); //获取activity
var IntentFilter = plus.android.importClass('android.content.IntentFilter');
filter = new IntentFilter();
//android.intent.ACTION_DECODE_DATA
filter.addAction(uni._qs_scanlistener_action || "android.intent.ACTION_DECODE_DATA"); // 换你的广播动作,你的pda设备里面看
receiver = plus.android.implements('io.dcloud.feature.internal.reflect.BroadcastReceiver', {
onReceive: function(context, intent) {
//barcode_string
plus.android.importClass(intent);
let code = intent.getStringExtra(uni._qs_scanlistener_label ||
"barcode_string"); // 换你的广播标签,你的pda设备里面看
_this.queryCode(code);
}
});
init = true
},
startScan() {
if (!start) {
start = true
main.registerReceiver(receiver, filter);
}
},
stopScan() {
if (start) {
start = false
main.unregisterReceiver(receiver);
}
},
install(fn) {
if (typeof fn == 'function' && !~temp.indexOf(fn)) temp.push(fn)
},
uninstall(fn) {
if (typeof fn == 'function') {
const index = temp.find(i => i == fn)
if (~index) temp.splice(index, 1)
}
},
queryCode: function(code) {
//防重复
// if (_codeQueryTag) return false;
// _codeQueryTag = true;
// setTimeout(function() {
// _codeQueryTag = false;
// }, 150);
if (temp && temp.length) {
temp[temp.length - 1](code)
}
uni.vibrateShort()
uni.$emit("qs_scanlistener_handle", code);
}
}
\ No newline at end of file
{
"id": "qs-scanlistener",
"displayName": "qs-scanlistener PDA扫码",
"version": "1.0.0",
"description": "PDA扫码 兼容广播和键盘",
"keywords": [
"pda",
"扫码"
],
"repository": "",
"engines": {
"HBuilderX": "^3.1.0"
},
"dcloudext": {
"type": "component-vue",
"sale": {
"regular": {
"price": "0.00"
},
"sourcecode": {
"price": "0.00"
}
},
"contact": {
"qq": ""
},
"declaration": {
"ads": "无",
"data": "无",
"permissions": "无"
},
"npmurl": ""
},
"uni_modules": {
"dependencies": [],
"encrypt": [],
"platforms": {
"cloud": {
"tcb": "y",
"aliyun": "y"
},
"client": {
"Vue": {
"vue2": "y",
"vue3": "y"
},
"App": {
"app-vue": "y",
"app-nvue": "n"
},
"H5-mobile": {
"Safari": "n",
"Android Browser": "n",
"微信浏览器(Android)": "n",
"QQ浏览器(Android)": "n"
},
"H5-pc": {
"Chrome": "n",
"IE": "n",
"Edge": "n",
"Firefox": "n",
"Safari": "n"
},
"小程序": {
"微信": "n",
"阿里": "n",
"百度": "n",
"字节跳动": "n",
"QQ": "n",
"钉钉": "n",
"快手": "n",
"飞书": "n",
"京东": "n"
},
"快应用": {
"华为": "n",
"联盟": "n"
}
}
}
}
}
\ No newline at end of file
## qs-scanlistener PDA扫码
## 支持广播和键盘
---
### 广播动作可在main.js设置uni._qs_scanlistener_action = 你的广播动作名称, 默认android.intent.ACTION_DECODE_DATA
### 广播标签可在main.js设置uni._qs_scanlistener_label = 你的广播标签名称, 默认barcode_string
---
### 扫码结果也可以uni.$on('qs_scanlistener_handle', code=>{}) 中获取
---
Template
```html
<qs-scanlistener @scan="scan"></qs-scanlistener>
```
js
```javascript
methods: {
scan(code) {
console.log(code)
}
}
```
\ No newline at end of file
// @use "sass:math";
@import '../tools/functions.scss';
@import '../tools/functions.scss';
// 间距基础倍数
$uni-space-root: 2 !default;
// 边框半径默认值
$uni-radius-root:5px !default;
$uni-radius-root: 5px !default;
$uni-radius: () !default;
// 边框半径断点
$uni-radius: map-deep-merge(
(
0: 0,
// TODO 当前版本暂时不支持 sm 属性
// 'sm': math.div($uni-radius-root, 2),
null: $uni-radius-root,
'lg': $uni-radius-root * 2,
'xl': $uni-radius-root * 6,
'pill': 9999px,
'circle': 50%
),
$uni-radius
(
0: 0,
// TODO 当前版本暂时不支持 sm 属性
// 'sm': math.div($uni-radius-root, 2),
null: $uni-radius-root,
'lg': $uni-radius-root * 2,
'xl': $uni-radius-root * 6,
'pill': 9999px,
'circle': 50%,
),
$uni-radius
);
// 字体家族
$body-font-family: 'Roboto', sans-serif !default;
......@@ -26,108 +26,109 @@ $heading-font-family: $body-font-family !default;
$uni-headings: () !default;
$letterSpacing: -0.01562em;
$uni-headings: map-deep-merge(
(
'h1': (
size: 32px,
weight: 300,
line-height: 50px,
// letter-spacing:-0.01562em
),
'h2': (
size: 28px,
weight: 300,
line-height: 40px,
// letter-spacing: -0.00833em
),
'h3': (
size: 24px,
weight: 400,
line-height: 32px,
// letter-spacing: normal
),
'h4': (
size: 20px,
weight: 400,
line-height: 30px,
// letter-spacing: 0.00735em
),
'h5': (
size: 16px,
weight: 400,
line-height: 24px,
// letter-spacing: normal
),
'h6': (
size: 14px,
weight: 500,
line-height: 18px,
// letter-spacing: 0.0125em
),
'subtitle': (
size: 12px,
weight: 400,
line-height: 20px,
// letter-spacing: 0.00937em
),
'body': (
font-size: 14px,
font-weight: 400,
line-height: 22px,
// letter-spacing: 0.03125em
),
'caption': (
'size': 12px,
'weight': 400,
'line-height': 20px,
// 'letter-spacing': 0.03333em,
// 'text-transform': false
)
(
'h1': (
size: 32px,
weight: 300,
line-height: 50px,
// letter-spacing:-0.01562em
),
'h2': (
size: 28px,
weight: 300,
line-height: 40px,
// letter-spacing: -0.00833em
),
'h3': (
size: 24px,
weight: 400,
line-height: 32px,
// letter-spacing: normal
),
'h4': (
size: 20px,
weight: 400,
line-height: 30px,
// letter-spacing: 0.00735em
),
'h5': (
size: 16px,
weight: 400,
line-height: 24px,
// letter-spacing: normal
),
'h6': (
size: 14px,
weight: 500,
line-height: 18px,
// letter-spacing: 0.0125em
),
$uni-headings
'subtitle': (
size: 12px,
weight: 400,
line-height: 20px,
// letter-spacing: 0.00937em
),
'page': (
font-size: 14px,
font-weight: 400,
line-height: 22px,
// letter-spacing: 0.03125em
),
'caption': (
'size': 12px,
'weight': 400,
'line-height': 20px,
// 'letter-spacing': 0.03333em,
// 'text-transform': false,,
),
),
$uni-headings
);
// 主色
$uni-primary: #2979ff !default;
$uni-primary-disable:lighten($uni-primary,20%) !default;
$uni-primary-light: lighten($uni-primary,25%) !default;
$uni-primary-disable: lighten($uni-primary, 20%) !default;
$uni-primary-light: lighten($uni-primary, 25%) !default;
// 辅助色
// 除了主色外的场景色,需要在不同的场景中使用(例如危险色表示危险的操作)。
$uni-success: #18bc37 !default;
$uni-success-disable:lighten($uni-success,20%) !default;
$uni-success-light: lighten($uni-success,25%) !default;
$uni-success-disable: lighten($uni-success, 20%) !default;
$uni-success-light: lighten($uni-success, 25%) !default;
$uni-warning: #f3a73f !default;
$uni-warning-disable:lighten($uni-warning,20%) !default;
$uni-warning-light: lighten($uni-warning,25%) !default;
$uni-warning-disable: lighten($uni-warning, 20%) !default;
$uni-warning-light: lighten($uni-warning, 25%) !default;
$uni-error: #e43d33 !default;
$uni-error-disable:lighten($uni-error,20%) !default;
$uni-error-light: lighten($uni-error,25%) !default;
$uni-error-disable: lighten($uni-error, 20%) !default;
$uni-error-light: lighten($uni-error, 25%) !default;
$uni-info: #8f939c !default;
$uni-info-disable:lighten($uni-info,20%) !default;
$uni-info-light: lighten($uni-info,25%) !default;
$uni-info-disable: lighten($uni-info, 20%) !default;
$uni-info-light: lighten($uni-info, 25%) !default;
// 中性色
// 中性色用于文本、背景和边框颜色。通过运用不同的中性色,来表现层次结构。
$uni-main-color: #3a3a3a !default; // 主要文字
$uni-base-color: #6a6a6a !default; // 常规文字
$uni-secondary-color: #909399 !default; // 次要文字
$uni-extra-color: #c7c7c7 !default; // 辅助说明
$uni-main-color: #3a3a3a !default; // 主要文字
$uni-base-color: #6a6a6a !default; // 常规文字
$uni-secondary-color: #909399 !default; // 次要文字
$uni-extra-color: #c7c7c7 !default; // 辅助说明
// 边框颜色
$uni-border-1: #F0F0F0 !default;
$uni-border-2: #EDEDED !default;
$uni-border-3: #DCDCDC !default;
$uni-border-4: #B9B9B9 !default;
$uni-border-1: #f0f0f0 !default;
$uni-border-2: #ededed !default;
$uni-border-3: #dcdcdc !default;
$uni-border-4: #b9b9b9 !default;
// 常规色
$uni-black: #000000 !default;
$uni-white: #ffffff !default;
$uni-transparent: rgba($color: #000000, $alpha: 0) !default;
$uni-transparent: rgba(
$color: #000000,
$alpha: 0,
) !default;
// 背景色
$uni-bg-color: #f7f7f7 !default;
......@@ -138,9 +139,24 @@ $uni-spacing-base: 15px !default;
$uni-spacing-lg: 30px !default;
// 阴影
$uni-shadow-sm:0 0 5px rgba($color: #d8d8d8, $alpha: 0.5) !default;
$uni-shadow-base:0 1px 8px 1px rgba($color: #a5a5a5, $alpha: 0.2) !default;
$uni-shadow-lg:0px 1px 10px 2px rgba($color: #a5a4a4, $alpha: 0.5) !default;
$uni-shadow-sm: 0 0 5px
rgba(
$color: #d8d8d8,
$alpha: 0.5,
) !default;
$uni-shadow-base: 0 1px 8px 1px
rgba(
$color: #a5a5a5,
$alpha: 0.2,
) !default;
$uni-shadow-lg: 0px 1px 10px 2px
rgba(
$color: #a5a4a4,
$alpha: 0.5,
) !default;
// 蒙版
$uni-mask: rgba($color: #000000, $alpha: 0.4) !default;
$uni-mask: rgba(
$color: #000000,
$alpha: 0.4,
) !default;
import { TextEncoder } from 'text-encoding'
export const createNew = () => {
var jpPrinter = {} as any
var data = ''
var command = [] as any
jpPrinter.name = '蓝牙打印机'
jpPrinter.init = function () { }
jpPrinter.addCommand = function (content: any) {
//将指令转成数组装起
var code = new TextEncoder('gb18030', {
NONSTANDARD_allowLegacyEncoding: true,
}).encode(content)
for (var i = 0; i < code.length; ++i) {
command.push(code[i])
}
}
jpPrinter.setSize = function (pageWidght: any, pageHeight: any) {
//设置页面大小
data =
'SIZE ' +
pageWidght.toString() +
' mm' +
',' +
pageHeight.toString() +
' mm' +
'\r\n'
jpPrinter.addCommand(data)
}
jpPrinter.setSpeed = function (printSpeed: any) {
//设置打印机速度
data = 'SPEED ' + printSpeed.toString() + '\r\n'
jpPrinter.addCommand(data)
}
jpPrinter.setDensity = function (printDensity: any) {
//设置打印机浓度
data = 'DENSITY ' + printDensity.toString() + '\r\n'
jpPrinter.addCommand(data)
}
jpPrinter.setGap = function (printGap: any) {
//传感器
data = 'GAP ' + printGap.toString() + ' mm,0 mm\r\n'
jpPrinter.addCommand(data)
}
jpPrinter.setBline = function (printBline: any) {
//黑标纸
data = 'BLINE ' + printBline.toString() + ' mm,0 mm\r\n'
jpPrinter.addCommand(data)
}
jpPrinter.setCountry = function (country: any) {
//选择国际字符集
/*
001:USA
002:French
003:Latin America
034:Spanish
039:Italian
044:United Kingdom
046:Swedish
047:Norwegian
049:German
*/
data = 'COUNTRY ' + country + '\r\n'
jpPrinter.addCommand(data)
}
jpPrinter.setCodepage = function (codepage: any) {
//选择国际代码页
/*
8-bit codepage 字符集代表
437:United States
850:Multilingual
852:Slavic
860:Portuguese
863:Canadian/French
865:Nordic
Windows code page
1250:Central Europe
1252:Latin I
1253:Greek
1254:Turkish
以下代码页仅限于 12×24 dot 英数字体
WestEurope:WestEurope
Greek:Greek
Hebrew:Hebrew
EastEurope:EastEurope
Iran:Iran
IranII:IranII
Latvian:Latvian
Arabic:Arabic
Vietnam:Vietnam
Uygur:Uygur
Thai:Thai
1252:Latin I
1257:WPC1257
1251:WPC1251
866:Cyrillic
858:PC858
747:PC747
864:PC864
1001:PC100
*/
data = 'CODEPAGE ' + codepage + '\r\n'
jpPrinter.addCommand(data)
}
jpPrinter.setCls = function () {
//清除打印机缓存
data = 'CLS\r\n'
jpPrinter.addCommand(data)
}
jpPrinter.setFeed = function (feed: any) {
//将纸向前推出n
data = 'FEED ' + feed + '\r\n'
jpPrinter.addCommand(data)
}
jpPrinter.setBackFeed = function (backup: any) {
//将纸向后回拉n
data = 'BACKFEED ' + backup + '\r\n'
jpPrinter.addCommand(data)
}
jpPrinter.setDirection = function (direction: any) {
//设置打印方向,参考编程手册
data = 'DIRECTION ' + direction + '\r\n'
jpPrinter.addCommand(data)
}
jpPrinter.setReference = function (x: any, y: any) {
//设置坐标原点,与打印方向有关
data = 'REFERENCE ' + x + ',' + y + '\r\n'
jpPrinter.addCommand(data)
}
jpPrinter.setFromfeed = function () {
//根据Size进一张标签纸
data = 'FORMFEED\r\n'
jpPrinter.addCommand(data)
}
jpPrinter.setHome = function () {
//根据Size找到下一张标签纸的位置
data = 'HOME\r\n'
jpPrinter.addCommand(data)
}
jpPrinter.setSound = function (level: any, interval: any) {
//控制蜂鸣器
data = 'SOUND ' + level + ',' + interval + '\r\n'
jpPrinter.addCommand(data)
}
jpPrinter.setLimitfeed = function (limit: any) {
// 检测垂直间距
data = 'LIMITFEED ' + limit + '\r\n'
jpPrinter.addCommand(data)
}
jpPrinter.setBar = function (x: any, y: any, width: any, height: any) {
//绘制线条
data = 'BAR ' + x + ',' + y + ',' + width + ',' + height + '\r\n'
jpPrinter.addCommand(data)
}
jpPrinter.setBox = function (x_start: any, y_start: any, x_end: any, y_end: any, thickness: any) {
//绘制方框
data =
'BOX ' +
x_start +
',' +
y_start +
',' +
x_end +
',' +
y_end +
',' +
thickness +
'\r\n'
jpPrinter.addCommand(data)
}
jpPrinter.setErase = function (x_start: any, y_start: any, x_width: any, y_height: any) {
//清除指定区域的数据
data =
'ERASE ' + x_start + ',' + y_start + ',' + x_width + ',' + y_height + '\r\n'
jpPrinter.addCommand(data)
}
jpPrinter.setReverse = function (x_start: any, y_start: any, x_width: any, y_height: any) {
//将指定的区域反相打印
data =
'REVERSE ' +
x_start +
',' +
y_start +
',' +
x_width +
',' +
y_height +
'\r\n'
jpPrinter.addCommand(data)
}
jpPrinter.setText = function (x: any, y: any, font: any, x_: any, y_: any, str: any) {
//打印文字
data =
'TEXT ' +
x +
',' +
y +
',"' +
font +
'",' +
0 +
',' +
x_ +
',' +
y_ +
',' +
'"' +
str +
'"\r\n'
jpPrinter.addCommand(data)
}
jpPrinter.setQR = function (x: any, y: any, level: any, width: any, mode: any, content: any) {
//打印二维码
data =
'QRCODE ' +
x +
',' +
y +
',' +
level +
',' +
width +
',' +
mode +
',' +
0 +
',"' +
content +
'"\r\n'
jpPrinter.addCommand(data)
}
jpPrinter.setBarCode = function (
x: any,
y: any,
codetype: any,
height: any,
readable: any,
narrow: any,
wide: any,
content: any
) {
//打印条形码
data =
'BARCODE ' +
x +
',' +
y +
',"' +
codetype +
'",' +
height +
',' +
readable +
',' +
0 +
',' +
narrow +
',' +
wide +
',"' +
content +
'"\r\n'
jpPrinter.addCommand(data)
}
jpPrinter.setBitmap = function (x: any, y: any, mode: any, res: any) {
//添加图片,res为画布参数
// console.log(res)
var width: any = (((Number(res.width) + 7) / 8) * 8) / 8
var height = res.height
var time = 1
var temp = res.data.length - width * 32
var pointList = []
var inverted_Data = []
var correct_Data = []
// console.log(width + '--' + height)
data = 'BITMAP ' + x + ',' + y + ',' + width + ',' + height + ',' + mode + ','
jpPrinter.addCommand(data)
for (var i = 0; i < height; ++i) {
// console.log(temp)
for (var j = 0; j < width; ++j) {
for (var k = 0; k < 32; k += 4) {
if (
res.data[temp] == 0 &&
res.data[temp + 1] == 0 &&
res.data[temp + 2] == 0 &&
res.data[temp + 3] == 0
) {
pointList.push(1)
} else {
pointList.push(0)
}
temp += 4
}
}
time++
temp = res.data.length - width * 32 * time
}
for (let i = 0; i < pointList.length; i += 8) {
var p =
pointList[i] * 128 +
pointList[i + 1] * 64 +
pointList[i + 2] * 32 +
pointList[i + 3] * 16 +
pointList[i + 4] * 8 +
pointList[i + 5] * 4 +
pointList[i + 6] * 2 +
pointList[i + 7]
inverted_Data.push(p)
correct_Data.push(p)
}
for (let i = height; i > 0; i--) {
for (var j = 0; j < width; ++j) {
correct_Data[(height - i - 1) * width + j] = inverted_Data[i * width + j]
}
}
for (let i = 0; i < correct_Data.length; ++i) {
command.push(correct_Data[i])
}
}
jpPrinter.setPagePrint = function () {
//打印页面
data = 'PRINT 1,1\r\n'
jpPrinter.addCommand(data)
}
//获取打印数据
jpPrinter.getData = function () {
return command
}
return jpPrinter
}
//判断两个对象是否相同(包含绝对相等和他们是否有相同的形状)
function looseEqual(a: any, b: any): any {
if (a === b) {
//如果是绝对相等就直接返回true
return true
}
//如果不是绝对相等就哦按的他们是否有相同的形状
var isObjectA = isObject(a)
var isObjectB = isObject(b)
if (isObjectA && isObjectB) {
//两个均是对象
try {
var isArrayA = Array.isArray(a)
var isArrayB = Array.isArray(b)
if (isArrayA && isArrayB) {
//如果都是数组
if (a.length === b.length) {
//如果长度相等
return a.every(function (e: any, i: any) {
//用every和递归来比对a数组和b数组的每个元素,并返回
return looseEqual(e, b[i])
})
}
//长度都不等直接返回false
return false
} else if (a instanceof Date && b instanceof Date) {
//如果是Date 则直接getTime 比较
return a.getTime() === b.getTime()
} else if (!isArrayA && !isArrayB) {
//对象的比较
//拿到两个对象的key
var keysA = Object.keys(a)
var keysB = Object.keys(b)
if (keysA.length === keysB.length) {
//如果keys相等
return keysA.every(function (key: any) {
//用every和递归来比对a对象和b对象的每个元素值,并返回
return looseEqual(a[key], b[key])
})
}
//长度都不等直接返回false
return false
} else {
return false
}
} catch (e) {
return false
}
} else if (!isObjectA && !isObjectB) {
//如果都不是对象则按String来处理
return String(a) === String(b)
} else {
return false
}
}
function isObject(obj: any) {
return obj !== null && typeof obj === 'object'
}
export { looseEqual }
function zconfirm(msg: string, callBackFun?: any) {
export const zconfirm = (msg: string, callBackFun?: any) => {
uni.showModal({
content: msg,
success: function (res) {
success(res) {
if (res.confirm) {
callBackFun(true)
} else if (res.cancel) {
......@@ -10,19 +10,19 @@ function zconfirm(msg: string, callBackFun?: any) {
},
})
}
function zalert(msg: string, callBackFun?: any) {
export const zalert = (msg: string, callBackFun?: any) => {
uni.showModal({
title: '提示',
content: msg,
showCancel: false,
success: function () {
success() {
if (callBackFun) {
callBackFun()
}
},
})
}
function toast(msg: string) {
export const toast = (msg: string) => {
uni.showToast({
title: msg,
duration: 2000,
......@@ -31,22 +31,13 @@ function toast(msg: string) {
})
}
const deepClone = function (origin: any, target: object = {}) {
for (const prop in target) {
if (target[prop] !== null && typeof target[prop] === 'object') {
origin[prop] = Object.prototype.toString.call(target[prop]) === '[object Array]' ? [] : {}
deepClone(origin[prop], target[prop])
} else {
origin[prop] = target[prop]
}
}
}
export default {
zconfirm,
zalert,
toast,
deepClone
export const sLoading = (msg: string = '加载中...') => {
uni.showLoading({
title: msg,
mask: true
})
}
export const hLoading = () => {
uni.hideLoading()
}
\ No newline at end of file
This source diff could not be displayed because it is too large. You can view the blob instead.
差异被折叠。
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论