Commit 3498feca authored by 郭铭瑶's avatar 郭铭瑶 🤘

10/20添加语音输入等暂存

parent 9a1dc521
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -20,6 +20,7 @@
"animate.css": "^4.1.1",
"axios": "^0.21.1",
"countup.js": "^2.0.8",
"crypto-js": "^4.1.1",
"dayjs": "^1.10.6",
"docx": "^6.0.3",
"echarts": "^5.1.2",
......
;(function () {
const self = this
self.onmessage = function (e) {
transAudioData.transcode(e.data)
}
const transAudioData = {
transcode(audioData) {
let output = transAudioData.to16kHz(audioData)
output = transAudioData.to16BitPCM(output)
output = Array.from(new Uint8Array(output.buffer))
self.postMessage(output)
// return output
},
to16kHz(audioData) {
const data = new Float32Array(audioData)
const fitCount = Math.round(data.length * (16000 / 44100))
const newData = new Float32Array(fitCount)
const springFactor = (data.length - 1) / (fitCount - 1)
newData[0] = data[0]
for (let i = 1; i < fitCount - 1; i++) {
const tmp = i * springFactor
const before = Math.floor(tmp).toFixed()
const after = Math.ceil(tmp).toFixed()
const atPoint = tmp - before
newData[i] = data[before] + (data[after] - data[before]) * atPoint
}
newData[fitCount - 1] = data[data.length - 1]
return newData
},
to16BitPCM(input) {
const dataLength = input.length * (16 / 8)
const dataBuffer = new ArrayBuffer(dataLength)
const dataView = new DataView(dataBuffer)
let offset = 0
for (let i = 0; i < input.length; i++, offset += 2) {
const s = Math.max(-1, Math.min(1, input[i]))
dataView.setInt16(offset, s < 0 ? s * 0x8000 : s * 0x7fff, true)
}
return dataView
},
}
})()
......@@ -5,6 +5,7 @@ let MAP_CONFIG: { jsApiUrl: string; cssUrl: string } = {
jsApiUrl: '',
cssUrl: '',
}
let MAP_URL: string = ''
let TOKEN: string = ''
const mdtUser = getCookie('__DM_MDT_USER__')
......@@ -21,14 +22,16 @@ switch (process.env.NODE_ENV) {
cssUrl:
'https://hm.metrodata.cn/cehuiyuan/api418/arcgis_js_api/library/4.18/esri/css/main.css',
}
MAP_URL = 'https://hm.metrodata.cn/cehuiyuan'
break
case 'sit': // 测试环境(暂时部署在测绘院用)
BASE_URL = 'https://survey.maicedata.com/api/data/'
BASE_URL = 'https://www.maicedata.com/collector/data/'
TOKEN = '8d979525-f8ab-4c62-9d6b-a6eeb62c7455'
MAP_CONFIG = {
jsApiUrl: 'http://10.108.3.41/arcgis_js_api/library/4.18/init.js',
cssUrl: 'http://10.108.3.41/arcgis_js_api/library/4.18/esri/css/main.css',
}
MAP_URL = 'http://10.108.3.48'
break
default:
// 本地开发环境
......@@ -38,6 +41,7 @@ switch (process.env.NODE_ENV) {
jsApiUrl: 'http://10.108.3.41/arcgis_js_api/library/4.18/init.js',
cssUrl: 'http://10.108.3.41/arcgis_js_api/library/4.18/esri/css/main.css',
}
MAP_URL = 'http://10.108.3.48'
}
export default {
TOKEN,
......@@ -46,6 +50,7 @@ export default {
imperMdtUser,
BASE_URL,
MAP_CONFIG,
MAP_URL,
ORGANIZATION: '733d0ac0-f67e-4bde-8872-3ca00983f18c',
MEMBER: '6c18d1b6-406e-4961-965c-c4b9cfc14cc4',
ACTIVITY: 'e6659af9-d53c-4b3f-9719-465d02687933',
......
......@@ -11,7 +11,12 @@ import {
import { api } from '@/ajax'
import store from '@/store'
export default async function useInitMap(el: HTMLElement, camera: any) {
export default async function useInitMap(
el: HTMLElement,
camera: any,
showArea: any,
showBuilding: any,
) {
const config = api.MAP_CONFIG
let map: any = null
let sceneView: any = null
......@@ -139,7 +144,7 @@ export default async function useInitMap(el: HTMLElement, camera: any) {
])
const baseLayer = new TileLayer(
'https://hm.metrodata.cn/cehuiyuan/changsanjiao/rest/services/Hosted/Base_Map/MapServer',
api.MAP_URL + '/changsanjiao/rest/services/Hosted/Base_Map/MapServer',
{
id: 'zhengwuBasemap',
visible: true,
......@@ -149,7 +154,7 @@ export default async function useInitMap(el: HTMLElement, camera: any) {
)
const sjgyLayer = new TileLayer(
'https://hm.metrodata.cn/cehuiyuan/changsanjiao/rest/services/sjgy_3857/MapServer',
api.MAP_URL + '/changsanjiao/rest/services/sjgy_3857/MapServer',
{
id: 'sjgy',
visible: true,
......@@ -169,7 +174,9 @@ export default async function useInitMap(el: HTMLElement, camera: any) {
map.layers.add(baseMapGroupLayer)
const sceneLayer0 = new SceneLayer({
url: 'https://hm.metrodata.cn/cehuiyuan/changsanjiao/rest/services/Hosted/HM_BUILDING0826/SceneServer',
url:
api.MAP_URL +
'/changsanjiao/rest/services/Hosted/HM_BUILDING0826/SceneServer',
visible: true,
title: '精模',
id: 'jingmo',
......@@ -186,7 +193,9 @@ export default async function useInitMap(el: HTMLElement, camera: any) {
map.add(graphiclayer)
const sceneLayer3 = new SceneLayer({
url: 'https://hm.metrodata.cn/cehuiyuan/changsanjiao/rest/services/Hosted/HM_ROAD0730/SceneServer',
url:
api.MAP_URL +
'/changsanjiao/rest/services/Hosted/HM_ROAD0730/SceneServer',
visible: true,
title: '全息道路路面',
elevationInfo: {
......@@ -196,7 +205,9 @@ export default async function useInitMap(el: HTMLElement, camera: any) {
})
const sceneLayer4 = new SceneLayer({
url: 'https://hm.metrodata.cn/cehuiyuan/changsanjiao/rest/services/Hosted/HM_BUJIAN0730/SceneServer',
url:
api.MAP_URL +
'/changsanjiao/rest/services/Hosted/HM_BUJIAN0730/SceneServer',
visible: true,
title: '全息道路部件',
elevationInfo: {
......@@ -207,7 +218,9 @@ export default async function useInitMap(el: HTMLElement, camera: any) {
})
const sceneLayer7 = new SceneLayer({
url: 'https://hm.metrodata.cn/cehuiyuan/changsanjiao/rest/services/Hosted/HM_WHITEMODEL_OUTSIDE0320/SceneServer',
url:
api.MAP_URL +
'/changsanjiao/rest/services/Hosted/HM_WHITEMODEL_OUTSIDE0320/SceneServer',
visible: true,
title: '周边白模',
popupEnabled: false,
......@@ -251,104 +264,93 @@ export default async function useInitMap(el: HTMLElement, camera: any) {
window.modelHighlight = null
})
return [map, sceneView, graphiclayer]
}
function addEventListener() {
window.sceneView.on('click', function (event) {
window.sceneView.popup.close()
if (window.modelHighlight) {
window.modelHighlight.remove()
}
window.sceneView.hitTest(event).then(async function (response) {
if (response.results.length > 0) {
const { layer } = response.results[0].graphic
const layername = response.results[0].graphic.layer.id
const objectId = response.results[0].graphic.attributes.OBJECTID
window.sceneView.whenLayerView(layer).then(function (layerView) {
const query = layer.createQuery()
query.outFields = ['*']
query.objectIds = [objectId]
layerView
.queryFeatures(query)
.then(function ({ features }) {
if (!features || features.length === 0) return
let html = ''
const title = ''
let data = features[0]?.attributes
data.json && (data = JSON.parse(data.json))
console.log('click data: ', data)
if (data?.['活动名称']) {
html = transActivityHtml(data)
} else if (data?.['姓名']) {
html = transMemberHtml(data)
} else if (data?.['党组织名称']) {
html = transOrgHtml(data)
if (data?.['类别']?.includes('居民区')) {
const areas =
data?.['管辖范围']?.map(
(item: any) => item?.['范围名称'],
) || []
areas.forEach((area) => showArea(area))
// TODO 待测试
} else if (data?.['类别']?.includes('两新')) {
const buildings =
data?.['管辖楼宇']?.map((item: any) => item?.OBJECTID) ||
[]
buildings.forEach((building) => showBuilding(building))
// TODO 待测试
}
} else if (data?.isList) {
html = transListHtml(data)
} else if (data?.NAME || data?.OBJECTID) {
store.dispatch(
'getBuildingDetail',
data?.NAME || data?.OBJECTID,
)
} else {
if (window.modelHighlight) {
window.modelHighlight.remove()
}
}
if (!html) return
const contentParam = {
dockpoint: response.ground.mapPoint,
title: title,
content: {
type: 'html',
html: html,
},
}
togglePopupTemplate(false)
setPopupContent(contentParam)
function addEventListener() {
window.sceneView.on('click', function (event) {
window.sceneView.popup.close()
if (window.modelHighlight) {
window.modelHighlight.remove()
}
window.sceneView.hitTest(event).then(async function (response) {
if (response.results.length > 0) {
const { layer } = response.results[0].graphic
const layername = response.results[0].graphic.layer.id
const objectId = response.results[0].graphic.attributes.OBJECTID
window.sceneView.whenLayerView(layer).then(function (layerView) {
const query = layer.createQuery()
query.outFields = ['*']
query.objectIds = [objectId]
layerView
.queryFeatures(query)
.then(function ({ features }) {
if (!features || features.length === 0) return
let html = ''
const title = ''
let data = features[0]?.attributes
data.json && (data = JSON.parse(data.json))
console.log('click data: ', data)
if (data?.['活动名称']) {
html = transActivityHtml(data)
} else if (data?.['姓名']) {
html = transMemberHtml(data)
} else if (data?.['党组织名称']) {
html = transOrgHtml(data)
} else if (data?.isList) {
html = transListHtml(data)
} else if (data?.NAME || data?.OBJECTID) {
store.dispatch(
'getBuildingDetail',
data?.NAME || data?.OBJECTID,
)
} else {
if (window.modelHighlight) {
window.modelHighlight.remove()
}
}
if (!html) return
// switch (layername) {
// //可根据图层名称对应不同操作,构造对应的信息面板内容
// case 'jingmo':
// const buildingName = result.features[0].attributes.NAME
// //根据buildingName查询接口,获取信息
// //组装html中的内容
// html = '<div>根据接口获取信息,构造弹出内容' + '</div>'
// title = '获取到的楼名'
// break
// case '党组织撒点图层':
// console.log('click-data: ', result)
// const poiName = result.features[0].attributes['党组织名称']
// //根据poiName查询接口,获取信息
// //组装html中的内容
// html =
// '<div class="pop-container">根据接口获取信息,构造弹出内容' +
// '</div>'
// title = '获取到的poi名称'
// break
// default:
// break
// }
const contentParam = {
dockpoint: response.ground.mapPoint,
title: title,
content: {
type: 'html',
html: html,
},
}
togglePopupTemplate(false)
setPopupContent(contentParam)
if (window.modelHighlight) {
window.modelHighlight.remove()
}
window.modelHighlight = layerView.highlight(objectId)
})
.catch(console.error)
})
}
window.modelHighlight = layerView.highlight(objectId)
})
.catch(console.error)
})
}
})
})
})
}
return [map, sceneView, graphiclayer]
}
function togglePopupTemplate(trueOrFalse: boolean) {
if (trueOrFalse === true) {
window.sceneView.popup.autoOpenEnabled = true
......
import IatRecorder from '@/util/iat-recorder'
import { onBeforeUnmount, ref } from 'vue'
type Status = 'init' | 'ing' | 'end'
export default function useVoiceRecorder() {
const iatRecorder: any = new IatRecorder()
const result = ref('')
const status = ref<Status>('init')
const timer: any = null
iatRecorder.onTextChange = function (txt: string) {
result.value = txt
}
iatRecorder.onWillStatusChange = function (_, curStatus: Status) {
status.value = curStatus
// let seconds = 0
// if (curStatus === 'ing') {
// timer = setInterval(() => {
// seconds += 1
// if (seconds >= 60) {
// iatRecorder.stop()
// clearInterval(timer)
// }
// }, 1000)
// }
}
onBeforeUnmount(() => {
iatRecorder.stop()
timer && clearInterval(timer)
})
function toggleRecorder() {
if (iatRecorder.status === 'ing') {
iatRecorder.stop()
} else {
iatRecorder.start()
}
}
function reset() {
iatRecorder.stop()
iatRecorder.status === 'init'
status.value = 'init'
result.value = ''
}
return { result, toggleRecorder, status, reset }
}
......@@ -51,7 +51,7 @@ export default {
primitive: 'circle',
},
material: {
color: '#dd505e',
color: layerName === '蓝点' ? '#4285F4' : '#dd505e',
},
size: 8,
outline: {
......@@ -90,7 +90,7 @@ export default {
// weight: "bold"
},
haloSize: 2,
haloColor: '#dd505e',
haloColor: layerName === '蓝点' ? '#4285F4' : '#dd505e',
},
labelPlacement: 'above-center',
})
......
import CryptoJS from 'crypto-js'
const transWorker = new Worker('/transcode.worker.js')
const APPID = '4f3360ec'
const API_SECRET = 'ODQ2ZDAyYTg3ZjVhMWQyMWJhYjUxNWQ3'
const API_KEY = '11b7f393e6226ddc575ca155d609cca8'
/**
* 获取websocket url
* 该接口需要后端提供,这里为了方便前端处理
*/
function getWebSocketUrl() {
return new Promise((resolve, reject) => {
// 请求地址根据语种不同变化
let url = 'wss://iat-api.xfyun.cn/v2/iat'
const host = 'iat-api.xfyun.cn'
const apiKey = API_KEY
const apiSecret = API_SECRET
const date = new Date().toGMTString()
const algorithm = 'hmac-sha256'
const headers = 'host date request-line'
const signatureOrigin = `host: ${host}\ndate: ${date}\nGET /v2/iat HTTP/1.1`
const signatureSha = CryptoJS.HmacSHA256(signatureOrigin, apiSecret)
const signature = CryptoJS.enc.Base64.stringify(signatureSha)
const authorizationOrigin = `api_key="${apiKey}", algorithm="${algorithm}", headers="${headers}", signature="${signature}"`
const authorization = btoa(authorizationOrigin)
url = `${url}?authorization=${authorization}&date=${date}&host=${host}`
resolve(url)
})
}
export default class IatRecorder {
constructor({ language, accent, appId } = {}) {
const self = this
this.status = 'null'
this.language = language || 'zh_cn'
this.accent = accent || 'mandarin'
this.appId = appId || APPID
// 记录音频数据
this.audioData = []
// 记录听写结果
this.resultText = ''
// wpgs下的听写结果需要中间状态辅助记录
this.resultTextTemp = ''
transWorker.onmessage = function (event) {
self.audioData.push(...event.data)
}
}
// 修改录音听写状态
setStatus(status) {
this.onWillStatusChange &&
this.status !== status &&
this.onWillStatusChange(this.status, status)
this.status = status
}
setResultText({ resultText, resultTextTemp } = {}) {
this.onTextChange && this.onTextChange(resultTextTemp || resultText || '')
resultText !== undefined && (this.resultText = resultText)
resultTextTemp !== undefined && (this.resultTextTemp = resultTextTemp)
}
// 修改听写参数
setParams({ language, accent } = {}) {
language && (this.language = language)
accent && (this.accent = accent)
}
// 连接websocket
connectWebSocket() {
return getWebSocketUrl().then((url) => {
let iatWS
if ('WebSocket' in window) {
iatWS = new WebSocket(url)
} else if ('MozWebSocket' in window) {
iatWS = new MozWebSocket(url)
} else {
alert('浏览器不支持WebSocket')
return
}
this.webSocket = iatWS
this.setStatus('init')
iatWS.onopen = (e) => {
this.setStatus('ing')
// 重新开始录音
setTimeout(() => {
this.webSocketSend()
}, 500)
}
iatWS.onmessage = (e) => {
this.result(e.data)
}
iatWS.onerror = (e) => {
this.recorderStop()
}
iatWS.onclose = (e) => {
this.recorderStop()
}
})
}
// 初始化浏览器录音
recorderInit() {
navigator.getUserMedia =
navigator.getUserMedia ||
navigator.webkitGetUserMedia ||
navigator.mozGetUserMedia ||
navigator.msGetUserMedia
// 创建音频环境
try {
this.audioContext = new (window.AudioContext ||
window.webkitAudioContext)()
this.audioContext.resume()
if (!this.audioContext) {
alert('浏览器不支持webAudioApi相关接口')
return
}
} catch (e) {
if (!this.audioContext) {
alert('浏览器不支持webAudioApi相关接口')
return
}
}
// 获取浏览器录音权限
if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
navigator.mediaDevices
.getUserMedia({
audio: true,
video: false,
})
.then((stream) => {
getMediaSuccess(stream)
})
.catch((e) => {
getMediaFail(e)
})
} else if (navigator.getUserMedia) {
navigator.getUserMedia(
{
audio: true,
video: false,
},
(stream) => {
getMediaSuccess(stream)
},
function (e) {
getMediaFail(e)
},
)
} else {
if (
navigator.userAgent.toLowerCase().match(/chrome/) &&
location.origin.indexOf('https://') < 0
) {
alert(
'chrome下获取浏览器录音功能,因为安全性问题,需要在localhost或127.0.0.1或https下才能获取权限',
)
} else {
alert('无法获取浏览器录音功能,请升级浏览器或使用chrome')
}
this.audioContext && this.audioContext.close()
return
}
// 获取浏览器录音权限成功的回调
const getMediaSuccess = (stream) => {
console.log('getMediaSuccess')
// 创建一个用于通过JavaScript直接处理音频
this.scriptProcessor = this.audioContext.createScriptProcessor(0, 1, 1)
this.scriptProcessor.onaudioprocess = (e) => {
// 去处理音频数据
if (this.status === 'ing') {
transWorker.postMessage(e.inputBuffer.getChannelData(0))
}
}
// 创建一个新的MediaStreamAudioSourceNode 对象,使来自MediaStream的音频可以被播放和操作
this.mediaSource = this.audioContext.createMediaStreamSource(stream)
// 连接
this.mediaSource.connect(this.scriptProcessor)
this.scriptProcessor.connect(this.audioContext.destination)
this.connectWebSocket()
}
const getMediaFail = (e) => {
alert('请求麦克风失败')
console.log(e)
this.audioContext && this.audioContext.close()
this.audioContext = undefined
// 关闭websocket
if (this.webSocket && this.webSocket.readyState === 1) {
this.webSocket.close()
}
}
}
recorderStart() {
if (!this.audioContext) {
this.recorderInit()
} else {
this.audioContext.resume()
this.connectWebSocket()
}
}
// 暂停录音
recorderStop() {
// safari下suspend后再次resume录音内容将是空白,设置safari下不做suspend
if (
!(
/Safari/.test(navigator.userAgent) && !/Chrome/.test(navigator.userAgen)
)
) {
this.audioContext && this.audioContext.suspend()
}
this.setStatus('end')
}
// 处理音频数据
// transAudioData(audioData) {
// audioData = transAudioData.transaction(audioData)
// this.audioData.push(...audioData)
// }
// 对处理后的音频数据进行base64编码,
toBase64(buffer) {
let binary = ''
const bytes = new Uint8Array(buffer)
const len = bytes.byteLength
for (let i = 0; i < len; i++) {
binary += String.fromCharCode(bytes[i])
}
return window.btoa(binary)
}
// 向webSocket发送数据
webSocketSend() {
if (this.webSocket.readyState !== 1) {
return
}
let audioData = this.audioData.splice(0, 1280)
const params = {
common: {
app_id: this.appId,
},
business: {
language: this.language, //小语种可在控制台--语音听写(流式)--方言/语种处添加试用
domain: 'iat',
accent: this.accent, //中文方言可在控制台--语音听写(流式)--方言/语种处添加试用
vad_eos: 5000,
dwa: 'wpgs', //为使该功能生效,需到控制台开通动态修正功能(该功能免费)
},
data: {
status: 0,
format: 'audio/L16;rate=16000',
encoding: 'raw',
audio: this.toBase64(audioData),
},
}
this.webSocket.send(JSON.stringify(params))
this.handlerInterval = setInterval(() => {
// websocket未连接
if (this.webSocket.readyState !== 1) {
this.audioData = []
clearInterval(this.handlerInterval)
return
}
if (this.audioData.length === 0) {
if (this.status === 'end') {
this.webSocket.send(
JSON.stringify({
data: {
status: 2,
format: 'audio/L16;rate=16000',
encoding: 'raw',
audio: '',
},
}),
)
this.audioData = []
clearInterval(this.handlerInterval)
}
return false
}
audioData = this.audioData.splice(0, 1280)
// 中间帧
this.webSocket.send(
JSON.stringify({
data: {
status: 1,
format: 'audio/L16;rate=16000',
encoding: 'raw',
audio: this.toBase64(audioData),
},
}),
)
}, 40)
}
result(resultData) {
// 识别结束
const jsonData = JSON.parse(resultData)
if (jsonData.data && jsonData.data.result) {
const data = jsonData.data.result
let str = ''
const resultStr = ''
const { ws } = data
for (let i = 0; i < ws.length; i++) {
str = str + ws[i].cw[0].w
}
// 开启wpgs会有此字段(前提:在控制台开通动态修正功能)
// 取值为 "apd"时表示该片结果是追加到前面的最终结果;取值为"rpl" 时表示替换前面的部分结果,替换范围为rg字段
if (data.pgs) {
if (data.pgs === 'apd') {
// 将resultTextTemp同步给resultText
this.setResultText({
resultText: this.resultTextTemp,
})
}
// 将结果存储在resultTextTemp中
this.setResultText({
resultTextTemp: this.resultText + str,
})
} else {
this.setResultText({
resultText: this.resultText + str,
})
}
}
if (jsonData.code === 0 && jsonData.data.status === 2) {
this.webSocket.close()
}
if (jsonData.code !== 0) {
this.webSocket.close()
console.log(`${jsonData.code}:${jsonData.message}`)
}
}
start() {
this.recorderStart()
this.setResultText({ resultText: '', resultTextTemp: '' })
}
stop() {
this.recorderStop()
}
}
......@@ -9,6 +9,7 @@ import useJsApi from '@/hooks/useJsApi'
import clientLayersOperate from '@/util/clientLayersOperate'
import sceneViewPopup from '@/util/sceneViewPopup'
import axios from 'axios'
import { api } from '@/ajax'
const mapRef = ref<HTMLElement | undefined>()
const camera = {
......@@ -24,7 +25,7 @@ onMounted(async () => {
await nextTick()
if (mapRef.value) {
// eslint-disable-next-line
await useInitMap(mapRef.value, camera)
await useInitMap(mapRef.value, camera, showArea, showBuilding)
}
})
......@@ -132,7 +133,7 @@ async function queryBound(layerId: number, name: string) {
'esri/layers/GraphicsLayer',
])
const jdLayerUrl = `https://hm.metrodata.cn/cehuiyuan/changsanjiao/rest/services/HM_BOUND_3857/MapServer/${layerId}`
const jdLayerUrl = `${api.MAP_URL}/changsanjiao/rest/services/HM_BOUND_3857/MapServer/${layerId}`
const queryTask = new QueryTask({
url: jdLayerUrl,
})
......@@ -187,7 +188,7 @@ function showBuilding(name: string) {
const objectId =
(
await axios.get(
`https://hm.metrodata.cn/cehuiyuan/changsanjiao/rest/services/HM_BOUND_3857/MapServer/4/query?where=NAME=%27${name}%27&f=json&outFields=*`,
`${api.MAP_URL}/changsanjiao/rest/services/HM_BOUND_3857/MapServer/4/query?where=NAME=%27${name}%27&f=json&outFields=*`,
)
)?.data?.features?.[0]?.attributes?.id || null
if (!objectId) return
......
......@@ -225,7 +225,7 @@
>
<n-grid :cols="24" :x-gap="12">
<n-form-item-gi
:span="24"
:span="14"
:label="`活动内容描述或描述照片${
mode === 'view' ? '' : '(大小20M以内)'
}`"
......@@ -243,6 +243,19 @@
placeholder="请选择上传类型"
/>
</n-form-item-gi>
<n-form-item-gi
v-if="detailData.describeType === 'text' && mode !== 'view'"
:span="6"
>
<n-button
:type="status === 'ing' ? 'primary' : 'default'"
size="small"
:class="{ recording: status === 'ing' }"
@click="toggleRecorder"
>
{{ status === 'ing' ? '停止输入' : '语音输入' }}
</n-button>
</n-form-item-gi>
<n-form-item-gi
v-if="detailData.describeType === 'text' && mode !== 'view'"
:span="24"
......@@ -316,7 +329,7 @@
<script lang="ts" setup>
import store from '@/store'
import { computed, onMounted, PropType, ref, watch } from 'vue'
import { computed, PropType, ref, watch } from 'vue'
import { FormRules, NForm, useMessage } from 'naive-ui'
import exportIcon from '@images/export.svg'
import { activity } from '@/util/tags'
......@@ -324,7 +337,20 @@ import { useFetchOrg, usePostActivity, usePutActivity } from '@/hooks/useFetch'
import dayjs from '@/util/dayjs'
import useAliOss from '@/hooks/useAliOss'
import useExportDocx from '@/hooks/useExportDocx'
import useVoiceRecorder from '@/hooks/useVoiceRecorder'
const { result, toggleRecorder, status } = useVoiceRecorder()
watch(
() => result.value,
(txt) => {
console.log('txt', txt)
if (!detailData.value.attachment) {
detailData.value.attachment = txt
} else {
detailData.value.attachment += txt
}
},
)
const message = useMessage()
const props = defineProps({
data: {
......@@ -891,6 +917,16 @@ const handleExport = async () => {
font-size .1rem
>span
color $blue
.recording
animation shine .8s ease-in-out infinite alternate
@keyframes shine {
from {
box-shadow 0 0 .01rem 0 $red
}
to {
box-shadow 0 0 .06rem 0.01rem $red
}
}
</style>
<style lang="stylus">
@import '../../components/MyComponent/main.styl'
......
......@@ -35,6 +35,7 @@ const resetMap = () => {
store.commit('SET_MAP_POINTS')
}
const setBoundary = ({ type, name }: { type: string; name: string }) => {
console.log(type, name)
if (!map.value) return
switch (type) {
case 'building':
......@@ -104,7 +105,18 @@ watch(
const data = checkSamePositionPoints(
points.map((point) => JSON.parse(JSON.stringify(point))) || [],
)
map.value.addPoints('撒点', data)
console.log('--', data)
const redPoints: any[] = []
const bluePoints: any[] = []
data.forEach((item) => {
if (item['类别中类'] && item['类别中类'] === '联合支部') {
bluePoints.push(item)
} else {
redPoints.push(item)
}
})
redPoints.length > 0 && map.value.addPoints('红点', redPoints)
bluePoints.length > 0 && map.value.addPoints('蓝点', bluePoints)
},
)
</script>
......
This source diff could not be displayed because it is too large. You can view the blob instead.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment