master
parent
f812ce5d43
commit
139ddd5a67
6
.env
6
.env
|
@ -4,9 +4,9 @@ VITE_APP_NAME=垃圾回收监管平台
|
||||||
# 服务器基础地址
|
# 服务器基础地址
|
||||||
VITE_HTTP_SERVER_BASE_URL=/api
|
VITE_HTTP_SERVER_BASE_URL=/api
|
||||||
VITE_WS_SERVER_BASE_URL=/ws
|
VITE_WS_SERVER_BASE_URL=/ws
|
||||||
VITE_OSS_UPLOAD_BASE_URL=http://218.94.108.114:19000/iot
|
VITE_OSS_UPLOAD_BASE_URL=http://localhost:9000/zsy
|
||||||
VITE_OSS_DOWNLOAD_BASE_URL=/api/file/oss/download
|
VITE_OSS_DOWNLOAD_BASE_URL=/api/oss/download
|
||||||
VITE_OSS_BUCKET_NAME=iot
|
VITE_OSS_BUCKET_NAME=zsy
|
||||||
|
|
||||||
# 接口超时时间
|
# 接口超时时间
|
||||||
VITE_HTTP_SERVER_TIMEOUT=10000
|
VITE_HTTP_SERVER_TIMEOUT=10000
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
"axios": "1.7.4",
|
"axios": "1.7.4",
|
||||||
"decimal.js": "^10.4.3",
|
"decimal.js": "^10.4.3",
|
||||||
"echarts": "^6.0.0",
|
"echarts": "^6.0.0",
|
||||||
|
"flv.js": "^1.6.2",
|
||||||
"gridstack": "^12.0.0",
|
"gridstack": "^12.0.0",
|
||||||
"logan-web": "^1.1.0",
|
"logan-web": "^1.1.0",
|
||||||
"luxon": "^3.4.4",
|
"luxon": "^3.4.4",
|
||||||
|
@ -3267,6 +3268,16 @@
|
||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/flv.js": {
|
||||||
|
"version": "1.6.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/flv.js/-/flv.js-1.6.2.tgz",
|
||||||
|
"integrity": "sha512-xre4gUbX1MPtgQRKj2pxJENp/RnaHaxYvy3YToVVCrSmAWUu85b9mug6pTXF6zakUjNP2lFWZ1rkSX7gxhB/2A==",
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"dependencies": {
|
||||||
|
"es6-promise": "^4.2.8",
|
||||||
|
"webworkify-webpack": "^2.1.5"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/follow-redirects": {
|
"node_modules/follow-redirects": {
|
||||||
"version": "1.15.9",
|
"version": "1.15.9",
|
||||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz",
|
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz",
|
||||||
|
@ -6559,6 +6570,12 @@
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/webworkify-webpack": {
|
||||||
|
"version": "2.1.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/webworkify-webpack/-/webworkify-webpack-2.1.5.tgz",
|
||||||
|
"integrity": "sha512-2akF8FIyUvbiBBdD+RoHpoTbHMQF2HwjcxfDvgztAX5YwbZNyrtfUMgvfgFVsgDhDPVTlkbb5vyasqDHfIDPQw==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/which": {
|
"node_modules/which": {
|
||||||
"version": "2.0.2",
|
"version": "2.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
"axios": "1.7.4",
|
"axios": "1.7.4",
|
||||||
"decimal.js": "^10.4.3",
|
"decimal.js": "^10.4.3",
|
||||||
"echarts": "^6.0.0",
|
"echarts": "^6.0.0",
|
||||||
|
"flv.js": "^1.6.2",
|
||||||
"gridstack": "^12.0.0",
|
"gridstack": "^12.0.0",
|
||||||
"logan-web": "^1.1.0",
|
"logan-web": "^1.1.0",
|
||||||
"luxon": "^3.4.4",
|
"luxon": "^3.4.4",
|
||||||
|
|
|
@ -11,11 +11,12 @@ interface IconfontJson {
|
||||||
}[];
|
}[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function iconfontDts(outFile: string) {
|
export default function iconfontProcess(outPath: string) {
|
||||||
return function (content: string) {
|
return function (content: string) {
|
||||||
const json = JSON.parse(content) as IconfontJson
|
const json = JSON.parse(content) as IconfontJson
|
||||||
const names = json.glyphs.map(glyph => glyph.font_class)
|
const names = json.glyphs.map(glyph => glyph.font_class)
|
||||||
console.log('正在生成文件:', outFile)
|
const dtsFile = outPath + '/iconfont.d.ts'
|
||||||
|
console.log('正在生成文件:', dtsFile)
|
||||||
const dts = `export {}
|
const dts = `export {}
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
|
@ -24,8 +25,13 @@ declare global {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
fs.writeFileSync(outFile, dts, {encoding: 'utf-8'})
|
fs.writeFileSync(dtsFile, dts, {encoding: 'utf-8'})
|
||||||
console.log('文件生成完成')
|
|
||||||
|
|
||||||
|
const tsFile = outPath + '/icons.ts'
|
||||||
|
const ts = `export default reactive([${'\n ' + names.map(name => `{name: '${name}'}`).join(',\n ') + '\n'}])`
|
||||||
|
console.log('正在生成文件:', tsFile)
|
||||||
|
fs.writeFileSync(tsFile, ts, {encoding: 'utf-8'})
|
||||||
|
|
||||||
|
console.log('文件生成完成')
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,5 +1,8 @@
|
||||||
import { get } from '@/common/utils/http-util.ts'
|
import {
|
||||||
import { bucketName } from '@/common'
|
get,
|
||||||
|
getFileUrl
|
||||||
|
} from '@/common/utils/http-util.ts'
|
||||||
|
import { bucketName, } from '@/common'
|
||||||
|
|
||||||
interface PresignedUrl extends Record<string, string | undefined> {
|
interface PresignedUrl extends Record<string, string | undefined> {
|
||||||
bucketName?: string
|
bucketName?: string
|
||||||
|
@ -8,9 +11,12 @@ interface PresignedUrl extends Record<string, string | undefined> {
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
obtainPresignedUrl(filename: string) {
|
obtainPresignedUrl(filename: string) {
|
||||||
return get<PresignedUrl>('/file/oss/obtain_presigned_url', {filename, bucketName})
|
return get<PresignedUrl>('/oss/obtain_presigned_url', {filename, bucketName})
|
||||||
},
|
},
|
||||||
download(objectName: string) {
|
download(objectName: string) {
|
||||||
return get('/file/oss/download/' + objectName)
|
return get('/oss/download/' + objectName)
|
||||||
},
|
},
|
||||||
|
fileUrl(filename: string) {
|
||||||
|
return getFileUrl(filename)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@ export const appName = import.meta.env.VITE_APP_NAME
|
||||||
export const serverBaseUrl = import.meta.env.VITE_HTTP_SERVER_BASE_URL ?? '/'
|
export const serverBaseUrl = import.meta.env.VITE_HTTP_SERVER_BASE_URL ?? '/'
|
||||||
export const uploadBaseUrl = import.meta.env.VITE_OSS_UPLOAD_BASE_URL ?? '/'
|
export const uploadBaseUrl = import.meta.env.VITE_OSS_UPLOAD_BASE_URL ?? '/'
|
||||||
export const downloadBaseUrl = import.meta.env.VITE_OSS_DOWNLOAD_BASE_URL ?? '/'
|
export const downloadBaseUrl = import.meta.env.VITE_OSS_DOWNLOAD_BASE_URL ?? '/'
|
||||||
export const bucketName = import.meta.env.VITE_OSS_BUCKET_NAME ?? 'iot'
|
export const bucketName = import.meta.env.VITE_OSS_BUCKET_NAME ?? 'zsy'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Axios 超时时间
|
* Axios 超时时间
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import {
|
import {
|
||||||
|
downloadBaseUrl,
|
||||||
serverBaseUrl,
|
serverBaseUrl,
|
||||||
serverTimeout
|
serverTimeout
|
||||||
} from '@/common'
|
} from '@/common'
|
||||||
|
@ -6,6 +7,7 @@ import axios, { AxiosRequestConfig } from 'axios'
|
||||||
import * as qs from 'qs'
|
import * as qs from 'qs'
|
||||||
import Toast from '@/components/toast'
|
import Toast from '@/components/toast'
|
||||||
import { useAppUserStore } from '@/common/app/app-user-store.ts'
|
import { useAppUserStore } from '@/common/app/app-user-store.ts'
|
||||||
|
import { throttle } from '@/common/utils/index.ts'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* HTTP 统一响应结构
|
* HTTP 统一响应结构
|
||||||
|
@ -41,24 +43,13 @@ const paramsSerializer = (params: any) => {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 统一错误处理函数
|
* 统一错误处理函数
|
||||||
*
|
|
||||||
* @param code 响应码
|
|
||||||
* @param msg 响应信息
|
|
||||||
* @param message 响应信息(详细)
|
|
||||||
*/
|
*/
|
||||||
function errHandler({code, msg, message}: R) {
|
/* function errHandler(r?: R) {
|
||||||
switch (code) {
|
Toast.error(r?.message ?? '操作失败')
|
||||||
case 450401:
|
} */
|
||||||
console.log(msg, message)
|
const errHandler = throttle(500, (r?: R) => {
|
||||||
break
|
Toast.error(r?.message ?? '操作失败')
|
||||||
case 450403:
|
})
|
||||||
console.log(msg, message)
|
|
||||||
break
|
|
||||||
default:
|
|
||||||
Toast.error(message ?? '操作失败')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* axios 实例
|
* axios 实例
|
||||||
*/
|
*/
|
||||||
|
@ -98,7 +89,7 @@ httpUtil.interceptors.response.use(
|
||||||
return Promise.resolve(response)
|
return Promise.resolve(response)
|
||||||
}
|
}
|
||||||
if (response.data == null) {
|
if (response.data == null) {
|
||||||
response.data = {code: 99999, msg: '无响应内容', message: '无响应内容', data: null, headers: response.headers}
|
response.data = {code: 0, msg: '无响应内容', message: '无响应内容', data: null, headers: response.headers}
|
||||||
}
|
}
|
||||||
response.data.headers = response.headers
|
response.data.headers = response.headers
|
||||||
if (response.data.code === 0) {
|
if (response.data.code === 0) {
|
||||||
|
@ -113,14 +104,14 @@ httpUtil.interceptors.response.use(
|
||||||
error.response.data = {...error.response.data, headers: error.response.headers}
|
error.response.data = {...error.response.data, headers: error.response.headers}
|
||||||
} else if (error.request != null) {
|
} else if (error.request != null) {
|
||||||
error.response = {
|
error.response = {
|
||||||
data: {code: 99999, msg: '服务器未响', message: '服务器未响', data: null},
|
data: {code: 9999, msg: '网络异常', message: '网络异常', data: null},
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
error.response = {
|
error.response = {
|
||||||
data: {code: 55555, msg: '请求发送失败', message: '请求发送失败', data: null},
|
data: {code: 5555, msg: '请求发送失败', message: '请求发送失败', data: null},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return Promise.reject(error)
|
return Promise.reject(error.response.data)
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -132,11 +123,11 @@ httpUtil.interceptors.response.use(
|
||||||
* @param disposeErr 是否处理错误响应,默认-->true
|
* @param disposeErr 是否处理错误响应,默认-->true
|
||||||
*/
|
*/
|
||||||
export function get<T = any>(url: string, params?: any, disposeErr: boolean = true) {
|
export function get<T = any>(url: string, params?: any, disposeErr: boolean = true) {
|
||||||
return httpUtil.get<R<T>>(url, {params, paramsSerializer})
|
return httpUtil.get<R<T>>(url, {params, paramsSerializer, responseType: 'json'})
|
||||||
.then(({data}) => data)
|
.then(({data}) => data)
|
||||||
.catch(res => {
|
.catch(res => {
|
||||||
if (disposeErr) errHandler(res.response.data)
|
if (disposeErr) errHandler(res)
|
||||||
return Promise.reject(res.response.data)
|
return Promise.reject(res)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -149,11 +140,11 @@ export function get<T = any>(url: string, params?: any, disposeErr: boolean = tr
|
||||||
* @param disposeErr 是否处理错误响应,默认-->true
|
* @param disposeErr 是否处理错误响应,默认-->true
|
||||||
*/
|
*/
|
||||||
export function post<T>(url: string, body?: any, config?: AxiosConfig, disposeErr: boolean = true) {
|
export function post<T>(url: string, body?: any, config?: AxiosConfig, disposeErr: boolean = true) {
|
||||||
return httpUtil.post<R<T>>(url, body, config)
|
return httpUtil.post<R<T>>(url, body, {...config, responseType: 'json'})
|
||||||
.then(({data}) => data)
|
.then(({data}) => data)
|
||||||
.catch(res => {
|
.catch(res => {
|
||||||
if (disposeErr) errHandler(res.response.data)
|
if (disposeErr) errHandler(res)
|
||||||
return Promise.reject(res.response.data)
|
return Promise.reject(res)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -173,12 +164,12 @@ export function postForm<T>(url: string, body: any, config?: AxiosConfig, dispos
|
||||||
'Content-Type': ContentType.FORM,
|
'Content-Type': ContentType.FORM,
|
||||||
},
|
},
|
||||||
params: config?.params,
|
params: config?.params,
|
||||||
responseType: config?.responseType,
|
responseType: config?.responseType ?? 'json',
|
||||||
})
|
})
|
||||||
.then(({data}) => data)
|
.then(({data}) => data)
|
||||||
.catch(res => {
|
.catch(res => {
|
||||||
if (disposeErr) errHandler(res.response.data)
|
if (disposeErr) errHandler(res)
|
||||||
return Promise.reject(res.response.data)
|
return Promise.reject(res)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -198,12 +189,12 @@ export function postMltForm<T>(url: string, body: any, config?: AxiosConfig, dis
|
||||||
'Content-Type': ContentType.MLT_FORM,
|
'Content-Type': ContentType.MLT_FORM,
|
||||||
},
|
},
|
||||||
params: config?.params,
|
params: config?.params,
|
||||||
responseType: config?.responseType,
|
responseType: config?.responseType ?? 'json',
|
||||||
})
|
})
|
||||||
.then(({data}) => data)
|
.then(({data}) => data)
|
||||||
.catch(res => {
|
.catch(res => {
|
||||||
if (disposeErr) errHandler(res.response.data)
|
if (disposeErr) errHandler(res)
|
||||||
return Promise.reject(res.response.data)
|
return Promise.reject(res)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -258,14 +249,21 @@ export function download(url: string, params?: any, disposeErr: boolean = true)
|
||||||
window.URL.revokeObjectURL(blobURL)
|
window.URL.revokeObjectURL(blobURL)
|
||||||
})
|
})
|
||||||
.catch(res => {
|
.catch(res => {
|
||||||
if (disposeErr) errHandler(res.response.data)
|
if (disposeErr) errHandler(res)
|
||||||
return Promise.reject(res.response.data)
|
return Promise.reject(res)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getFileUrl(filename: string) {
|
||||||
|
const appUserStore = useAppUserStore()
|
||||||
|
return downloadBaseUrl + filename + '?authorization=' + appUserStore.token
|
||||||
|
}
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
get,
|
get,
|
||||||
post,
|
post,
|
||||||
postForm,
|
postForm,
|
||||||
postMltForm,
|
postMltForm,
|
||||||
|
download,
|
||||||
|
getFileUrl,
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,6 +32,7 @@ declare module 'vue' {
|
||||||
IxFormItem: typeof import('@idux/components/form')['IxFormItem']
|
IxFormItem: typeof import('@idux/components/form')['IxFormItem']
|
||||||
IxFormWrapper: typeof import('@idux/components/form')['IxFormWrapper']
|
IxFormWrapper: typeof import('@idux/components/form')['IxFormWrapper']
|
||||||
IxIcon: typeof import('@idux/components/icon')['IxIcon']
|
IxIcon: typeof import('@idux/components/icon')['IxIcon']
|
||||||
|
IxIconClose: typeof import('@idux/components/icon')['IxIconClose']
|
||||||
IxInput: typeof import('@idux/components/input')['IxInput']
|
IxInput: typeof import('@idux/components/input')['IxInput']
|
||||||
IxInputNumber: typeof import('@idux/components/input-number')['IxInputNumber']
|
IxInputNumber: typeof import('@idux/components/input-number')['IxInputNumber']
|
||||||
IxLayoutSiderTrigger: typeof import('@idux/components/layout')['IxLayoutSiderTrigger']
|
IxLayoutSiderTrigger: typeof import('@idux/components/layout')['IxLayoutSiderTrigger']
|
||||||
|
@ -43,12 +44,14 @@ declare module 'vue' {
|
||||||
IxModal: typeof import('@idux/components/modal')['IxModal']
|
IxModal: typeof import('@idux/components/modal')['IxModal']
|
||||||
IxPagination: typeof import('@idux/components/pagination')['IxPagination']
|
IxPagination: typeof import('@idux/components/pagination')['IxPagination']
|
||||||
IxPopconfirm: typeof import('@idux/components/popconfirm')['IxPopconfirm']
|
IxPopconfirm: typeof import('@idux/components/popconfirm')['IxPopconfirm']
|
||||||
|
IxPopover: typeof import('@idux/components/popover')['IxPopover']
|
||||||
IxProLayout: typeof import('@idux/pro/layout')['IxProLayout']
|
IxProLayout: typeof import('@idux/pro/layout')['IxProLayout']
|
||||||
IxPwdInput: typeof import('./../components/input/IxPwdInput.vue')['default']
|
IxPwdInput: typeof import('./../components/input/IxPwdInput.vue')['default']
|
||||||
IxRadio: typeof import('@idux/components/radio')['IxRadio']
|
IxRadio: typeof import('@idux/components/radio')['IxRadio']
|
||||||
IxRadioGroup: typeof import('@idux/components/radio')['IxRadioGroup']
|
IxRadioGroup: typeof import('@idux/components/radio')['IxRadioGroup']
|
||||||
IxRow: typeof import('@idux/components/grid')['IxRow']
|
IxRow: typeof import('@idux/components/grid')['IxRow']
|
||||||
IxSelect: typeof import('@idux/components/select')['IxSelect']
|
IxSelect: typeof import('@idux/components/select')['IxSelect']
|
||||||
|
IxSelector: typeof import('@idux/components/selector')['IxSelector']
|
||||||
IxSpace: typeof import('@idux/components/space')['IxSpace']
|
IxSpace: typeof import('@idux/components/space')['IxSpace']
|
||||||
IxTable: typeof import('@idux/components/table')['IxTable']
|
IxTable: typeof import('@idux/components/table')['IxTable']
|
||||||
IxTabs: typeof import('@idux/components/tabs')['IxTabs']
|
IxTabs: typeof import('@idux/components/tabs')['IxTabs']
|
||||||
|
|
|
@ -114,21 +114,20 @@ const columns: TableColumn[] = [
|
||||||
|
|
||||||
const pagination = reactive<TablePagination>({
|
const pagination = reactive<TablePagination>({
|
||||||
pageIndex: 1,
|
pageIndex: 1,
|
||||||
pageSize: 10,
|
pageSize: 3,
|
||||||
total: 100,
|
total: 100,
|
||||||
size: 'sm',
|
size: 'sm',
|
||||||
showTotal: true,
|
showTotal: true,
|
||||||
onChange(pageIndex: number, pageSize: number) {
|
onChange(pageIndex: number, pageSize: number) {
|
||||||
console.log('------', pageIndex, pageSize)
|
|
||||||
pagination.pageIndex = pageIndex
|
pagination.pageIndex = pageIndex
|
||||||
pagination.pageSize = pageSize
|
pagination.pageSize = pageSize
|
||||||
|
searchHandler()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
const tableSpin = ref(false)
|
const tableSpin = ref(false)
|
||||||
|
|
||||||
function searchHandler() {
|
function searchHandler() {
|
||||||
console.log('------', formGroup.getValue())
|
|
||||||
tableSpin.value = true
|
tableSpin.value = true
|
||||||
DisposeRecodeApi.paging({
|
DisposeRecodeApi.paging({
|
||||||
...formGroup.getValue(),
|
...formGroup.getValue(),
|
||||||
|
@ -218,7 +217,7 @@ onMounted(() => {
|
||||||
.dispose-recode {
|
.dispose-recode {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
height: 150%;
|
height: 100%;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|
||||||
.title {
|
.title {
|
||||||
|
|
|
@ -20,13 +20,9 @@ const data = reactive<DisposeRecodeTypes.DisposeRecodeData>({
|
||||||
})
|
})
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
console.log(ins)
|
|
||||||
let container = props.container
|
let container = props.container
|
||||||
if (container) {
|
if (container) {
|
||||||
container.style.position = 'relative'
|
container.style.position = 'relative'
|
||||||
for (let child of container.children) {
|
|
||||||
console.log(child)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -37,10 +37,7 @@ import {
|
||||||
type ProLayoutType
|
type ProLayoutType
|
||||||
} from '@idux/pro/layout'
|
} from '@idux/pro/layout'
|
||||||
import Strings from '@/common/utils/strings.ts'
|
import Strings from '@/common/utils/strings.ts'
|
||||||
import {
|
import { appName } from '@/common'
|
||||||
appName,
|
|
||||||
downloadBaseUrl
|
|
||||||
} from '@/common'
|
|
||||||
import { useAppSettingStore } from '@/common/app/app-setting-store.ts'
|
import { useAppSettingStore } from '@/common/app/app-setting-store.ts'
|
||||||
import colls from '@/common/utils/colls.ts'
|
import colls from '@/common/utils/colls.ts'
|
||||||
import {
|
import {
|
||||||
|
@ -49,10 +46,11 @@ import {
|
||||||
} from '@/common/app/contants.ts'
|
} from '@/common/app/contants.ts'
|
||||||
import Nav from '@/common/router/nav.ts'
|
import Nav from '@/common/router/nav.ts'
|
||||||
import Iconfont from '@/components/iconfont/Iconfont.vue'
|
import Iconfont from '@/components/iconfont/Iconfont.vue'
|
||||||
|
import AppApi from '@/common/app/app-api.ts'
|
||||||
|
|
||||||
const appSettingStore = useAppSettingStore()
|
const appSettingStore = useAppSettingStore()
|
||||||
const logoImage = computed(() => {
|
const logoImage = computed(() => {
|
||||||
return Strings.isBlank(appSettingStore.logo) ? defaultLogo : downloadBaseUrl + appSettingStore.logo!
|
return Strings.isBlank(appSettingStore.logo) ? defaultLogo : AppApi.fileUrl(appSettingStore.logo!)
|
||||||
})
|
})
|
||||||
const logo = {
|
const logo = {
|
||||||
image: logoImage.value,
|
image: logoImage.value,
|
||||||
|
@ -131,7 +129,7 @@ function openPageHandler(options: MenuClickOptions) {
|
||||||
|
|
||||||
.page-change-enter-active,
|
.page-change-enter-active,
|
||||||
.page-change-leave-active {
|
.page-change-leave-active {
|
||||||
transition: all .3s ease-in;
|
transition: opacity .3s ease-in, transform .3s ease-in;
|
||||||
}
|
}
|
||||||
|
|
||||||
.page-change-enter-from {
|
.page-change-enter-from {
|
||||||
|
|
|
@ -33,11 +33,11 @@ import TabList from '@/pages/main-zone/tab-list/TabList.vue'
|
||||||
import Strings from '@/common/utils/strings.ts'
|
import Strings from '@/common/utils/strings.ts'
|
||||||
import { useAppSettingStore } from '@/common/app/app-setting-store.ts'
|
import { useAppSettingStore } from '@/common/app/app-setting-store.ts'
|
||||||
import UserPanel from '@/pages/main-zone/header-bar/UserPanel.vue'
|
import UserPanel from '@/pages/main-zone/header-bar/UserPanel.vue'
|
||||||
import { downloadBaseUrl } from '@/common'
|
import AppApi from '@/common/app/app-api.ts'
|
||||||
|
|
||||||
const appSettingStore = useAppSettingStore()
|
const appSettingStore = useAppSettingStore()
|
||||||
const logo = computed(() => {
|
const logo = computed(() => {
|
||||||
return Strings.isBlank(appSettingStore.logo) ? defaultLogo : downloadBaseUrl + appSettingStore.logo!
|
return Strings.isBlank(appSettingStore.logo) ? defaultLogo : AppApi.fileUrl(appSettingStore.logo!)
|
||||||
})
|
})
|
||||||
|
|
||||||
const menuPanel = ref<InstanceType<typeof MenuPanel>>()
|
const menuPanel = ref<InstanceType<typeof MenuPanel>>()
|
||||||
|
|
|
@ -48,10 +48,10 @@ import ModifyPwdForm from '@/pages/main-zone/header-bar/ModifyPwdForm.vue'
|
||||||
import UserInfo from '@/pages/main-zone/header-bar/UserInfo.vue'
|
import UserInfo from '@/pages/main-zone/header-bar/UserInfo.vue'
|
||||||
import { VKey } from '@idux/cdk'
|
import { VKey } from '@idux/cdk'
|
||||||
import Nav from '@/common/router/nav.ts'
|
import Nav from '@/common/router/nav.ts'
|
||||||
import { downloadBaseUrl } from '@/common'
|
|
||||||
import MenuPanelApi from '@/pages/main-zone/menu-panel/menu-panel-api.ts'
|
import MenuPanelApi from '@/pages/main-zone/menu-panel/menu-panel-api.ts'
|
||||||
import Toast from '@/components/toast'
|
import Toast from '@/components/toast'
|
||||||
import { reloadUserInfo } from '@/common/app'
|
import { reloadUserInfo } from '@/common/app'
|
||||||
|
import AppApi from '@/common/app/app-api.ts'
|
||||||
|
|
||||||
const appSettingStore = useAppSettingStore()
|
const appSettingStore = useAppSettingStore()
|
||||||
const appUserStore = useAppUserStore()
|
const appUserStore = useAppUserStore()
|
||||||
|
@ -66,7 +66,7 @@ const tabsDtaSource = [
|
||||||
]
|
]
|
||||||
|
|
||||||
const avatar = computed(() => {
|
const avatar = computed(() => {
|
||||||
return Strings.isBlank(appUserStore.avatar) ? defaultAvatar : downloadBaseUrl + appUserStore.avatar!
|
return Strings.isBlank(appUserStore.avatar) ? defaultAvatar : AppApi.fileUrl(appUserStore.avatar!)
|
||||||
})
|
})
|
||||||
const tenantName = computed(() => {
|
const tenantName = computed(() => {
|
||||||
return appUserStore.tenantName
|
return appUserStore.tenantName
|
||||||
|
|
|
@ -35,7 +35,7 @@ const leftFuns = computed<PageTypes.Fun[]>(() => {
|
||||||
menuForm.value!.reset()
|
menuForm.value!.reset()
|
||||||
})
|
})
|
||||||
.catch(_ => {
|
.catch(_ => {
|
||||||
Toast.success('添加失败')
|
Toast.error('添加失败')
|
||||||
})
|
})
|
||||||
.finally(() => {
|
.finally(() => {
|
||||||
Toast.close(toastId)
|
Toast.close(toastId)
|
||||||
|
|
|
@ -58,6 +58,20 @@
|
||||||
</IxFormItem>
|
</IxFormItem>
|
||||||
</IxCol>
|
</IxCol>
|
||||||
</IxRow>
|
</IxRow>
|
||||||
|
<IxRow>
|
||||||
|
<IxCol :span="6">
|
||||||
|
<IxFormItem
|
||||||
|
:gutter="[0, 10]"
|
||||||
|
label="图标">
|
||||||
|
<IxPopover closable header="图标列表" placement="bottom" trigger="click">
|
||||||
|
<IxInput control="icon"/>
|
||||||
|
<template #content>
|
||||||
|
<IxTable v-model:selectedRowKeys="selectedRowKeys" :columns="columns" :dataSource="iconTableDataSource" :pagination="pagination" get-key="name"/>
|
||||||
|
</template>
|
||||||
|
</IxPopover>
|
||||||
|
</IxFormItem>
|
||||||
|
</IxCol>
|
||||||
|
</IxRow>
|
||||||
</IxForm>
|
</IxForm>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -75,7 +89,61 @@ import { TreeSelectNode } from '@idux/components/tree-select/src/types'
|
||||||
import { SelectData } from '@idux/components/select/src/types'
|
import { SelectData } from '@idux/components/select/src/types'
|
||||||
import MenuApi from '@/pages/sys/menus/menu-api.ts'
|
import MenuApi from '@/pages/sys/menus/menu-api.ts'
|
||||||
import Colls from '@/common/utils/colls.ts'
|
import Colls from '@/common/utils/colls.ts'
|
||||||
|
import icons from '@/components/iconfont/icons.ts'
|
||||||
|
import {
|
||||||
|
TableColumn,
|
||||||
|
TableColumnSelectable
|
||||||
|
} from '@idux/components/table'
|
||||||
|
import Iconfont from '@/components/iconfont/Iconfont.vue'
|
||||||
|
import { TablePagination } from '@idux/components/table/src/types'
|
||||||
|
|
||||||
|
interface IconData {
|
||||||
|
name: string
|
||||||
|
}
|
||||||
|
|
||||||
|
const selectedRowKeys = ref<string[]>([])
|
||||||
|
|
||||||
|
const iconTableDataSource = ref<IconData[]>(icons.filter((_, i) => {
|
||||||
|
return i >= 0 && i < 5
|
||||||
|
}))
|
||||||
|
const selectableColumn = reactive<TableColumnSelectable<IconData>>({
|
||||||
|
type: 'selectable',
|
||||||
|
align: 'center',
|
||||||
|
multiple: false,
|
||||||
|
showIndex: false,
|
||||||
|
trigger: 'click',
|
||||||
|
onChange: (selectedKeys) => {
|
||||||
|
menuForm.get('icon')?.setValue(selectedKeys[0] as string)
|
||||||
|
},
|
||||||
|
})
|
||||||
|
const columns: TableColumn<IconData>[] = [
|
||||||
|
selectableColumn,
|
||||||
|
{
|
||||||
|
title: '图标',
|
||||||
|
dataKey: 'name',
|
||||||
|
customCell: ({record}: { record: IconData }) => {
|
||||||
|
return h(Iconfont, {name: record.name})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '名称',
|
||||||
|
dataKey: 'name',
|
||||||
|
},
|
||||||
|
]
|
||||||
|
const pagination = reactive<TablePagination>({
|
||||||
|
pageIndex: 1,
|
||||||
|
pageSize: 5,
|
||||||
|
total: icons.length,
|
||||||
|
size: 'sm',
|
||||||
|
showTotal: true,
|
||||||
|
onChange(pageIndex: number, pageSize: number) {
|
||||||
|
pagination.pageIndex = pageIndex
|
||||||
|
pagination.pageSize = pageSize
|
||||||
|
iconTableDataSource.value = icons.filter((_, i) => {
|
||||||
|
return i >= (pageIndex - 1) * pageSize && i < pageIndex * pageSize
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
const props = withDefaults(defineProps<{ status?: 'create' | 'view' | 'edit' }>(),
|
const props = withDefaults(defineProps<{ status?: 'create' | 'view' | 'edit' }>(),
|
||||||
{
|
{
|
||||||
status: 'create',
|
status: 'create',
|
||||||
|
@ -89,6 +157,7 @@ const menuForm = useFormGroup<MenuTypes.MenuForm>({
|
||||||
sort: [ 0 ],
|
sort: [ 0 ],
|
||||||
routeName: [ '' ],
|
routeName: [ '' ],
|
||||||
sn: [ undefined ],
|
sn: [ undefined ],
|
||||||
|
icon: [ undefined ],
|
||||||
})
|
})
|
||||||
const menuCategoryCtrl = menuForm.get('menuCategory')
|
const menuCategoryCtrl = menuForm.get('menuCategory')
|
||||||
const routeNameCtrl = menuForm.get('routeName')
|
const routeNameCtrl = menuForm.get('routeName')
|
||||||
|
@ -140,6 +209,9 @@ defineExpose({
|
||||||
},
|
},
|
||||||
setValue(data: MenuTypes.MenuForm) {
|
setValue(data: MenuTypes.MenuForm) {
|
||||||
menuForm.setValue(data)
|
menuForm.setValue(data)
|
||||||
|
if (data.icon != null) {
|
||||||
|
selectedRowKeys.value = [ data.icon ]
|
||||||
|
}
|
||||||
},
|
},
|
||||||
reset() {
|
reset() {
|
||||||
menuForm.reset()
|
menuForm.reset()
|
||||||
|
|
|
@ -14,7 +14,7 @@ declare global {
|
||||||
// 菜单名称
|
// 菜单名称
|
||||||
title: string
|
title: string
|
||||||
// 图标
|
// 图标
|
||||||
icon: string
|
icon?: string
|
||||||
// 层级; >= 1
|
// 层级; >= 1
|
||||||
tier: number
|
tier: number
|
||||||
// 排序
|
// 排序
|
||||||
|
@ -28,7 +28,7 @@ declare global {
|
||||||
}
|
}
|
||||||
|
|
||||||
type SearchForm = Partial<Pick<SysMenu, 'title' | 'routeName'>>
|
type SearchForm = Partial<Pick<SysMenu, 'title' | 'routeName'>>
|
||||||
type MenuForm = Pick<SysMenu, 'pid' | 'menuCategory' | 'title' | 'sort' | 'routeName' | 'sn'>
|
type MenuForm = Pick<SysMenu, 'pid' | 'menuCategory' | 'title' | 'sort' | 'routeName' | 'sn' | 'icon'>
|
||||||
type AddForm = Pick<SysMenu, 'pid' | 'menuCategory' | 'title' | 'sort' | 'routeName' | 'sn'>
|
type AddForm = Pick<SysMenu, 'pid' | 'menuCategory' | 'title' | 'sort' | 'routeName' | 'sn'>
|
||||||
type ModifyForm = Pick<SysMenu, 'id' | 'pid' | 'menuCategory' | 'title' | 'sort' | 'routeName'>
|
type ModifyForm = Pick<SysMenu, 'id' | 'pid' | 'menuCategory' | 'title' | 'sort' | 'routeName'>
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<IxInput control="nickname" placeholder="请输入用户昵称"></IxInput>
|
<IxInput control="nickname" placeholder="请输入用户昵称"></IxInput>
|
||||||
</IxFormItem>
|
</IxFormItem>
|
||||||
<IxFormItem :gutter="[0, 10]" label="账号">
|
<IxFormItem :gutter="[0, 10]" label="账号">
|
||||||
<IxInput control="routeName" placeholder="请输入账号"></IxInput>
|
<IxInput control="username" placeholder="请输入账号"></IxInput>
|
||||||
</IxFormItem>
|
</IxFormItem>
|
||||||
<button style="display: none" type="submit"/>
|
<button style="display: none" type="submit"/>
|
||||||
</IxForm>
|
</IxForm>
|
||||||
|
@ -28,7 +28,7 @@
|
||||||
</template>
|
</template>
|
||||||
<template #avatar="{record}">
|
<template #avatar="{record}">
|
||||||
<img v-if="!record.avatar" :src="defaultAvatar" alt="头像" style="width: 2rem">
|
<img v-if="!record.avatar" :src="defaultAvatar" alt="头像" style="width: 2rem">
|
||||||
<img v-else :src="record.avatar" alt="头像" style="width: 2rem">
|
<img v-else :src="AppApi.fileUrl(record.avatar)" alt="头像" style="width: 2rem">
|
||||||
</template>
|
</template>
|
||||||
</IxTable>
|
</IxTable>
|
||||||
<IxRow justify="end">
|
<IxRow justify="end">
|
||||||
|
@ -56,6 +56,7 @@ import Toast from '@/components/toast'
|
||||||
import UserApi from '@/pages/sys/user/user-api.ts'
|
import UserApi from '@/pages/sys/user/user-api.ts'
|
||||||
import defaultAvatar from '@/assets/images/avatar.png'
|
import defaultAvatar from '@/assets/images/avatar.png'
|
||||||
import { useUserDetailStore } from '@/pages/sys/user/user-detail/user-detail-store.ts'
|
import { useUserDetailStore } from '@/pages/sys/user/user-detail/user-detail-store.ts'
|
||||||
|
import AppApi from '@/common/app/app-api.ts'
|
||||||
|
|
||||||
const searchForm = useFormGroup<UserTypes.SearchForm>({
|
const searchForm = useFormGroup<UserTypes.SearchForm>({
|
||||||
nickname: [ undefined ],
|
nickname: [ undefined ],
|
||||||
|
|
|
@ -84,7 +84,7 @@
|
||||||
<IxForm :control="searchForm" :control-col="{span:18}" :label-col="{span:6}"
|
<IxForm :control="searchForm" :control-col="{span:18}" :label-col="{span:6}"
|
||||||
label-align="end"
|
label-align="end"
|
||||||
layout="horizontal"
|
layout="horizontal"
|
||||||
@submit="searchHandler">
|
@submit.prevent="searchHandler">
|
||||||
<IxRow>
|
<IxRow>
|
||||||
<IxCol :span="6">
|
<IxCol :span="6">
|
||||||
<IxFormItem :gutter="[0, 10]" align="center" label="角色编码">
|
<IxFormItem :gutter="[0, 10]" align="center" label="角色编码">
|
||||||
|
@ -161,6 +161,7 @@ const pagination = reactive<G.Pagination>({
|
||||||
size: 100,
|
size: 100,
|
||||||
total: 0,
|
total: 0,
|
||||||
})
|
})
|
||||||
|
|
||||||
const searchForm = useFormGroup<RoleTypes.SearchForm>({
|
const searchForm = useFormGroup<RoleTypes.SearchForm>({
|
||||||
roleCode: [ undefined ],
|
roleCode: [ undefined ],
|
||||||
roleName: [ undefined ]
|
roleName: [ undefined ]
|
||||||
|
@ -243,7 +244,7 @@ const columns = computed<TableColumn<RoleTypes.SysRole>[]>(() => ([
|
||||||
|
|
||||||
const genderDataSource = computed<SelectData[]>(() => Object.entries(Gender).map(([ key, label ]) => ({key, label})))
|
const genderDataSource = computed<SelectData[]>(() => Object.entries(Gender).map(([ key, label ]) => ({key, label})))
|
||||||
|
|
||||||
const files = ref()
|
const files = ref<UploadFile []>()
|
||||||
|
|
||||||
|
|
||||||
function updateFormStatus() {
|
function updateFormStatus() {
|
||||||
|
@ -262,6 +263,13 @@ defineExpose({
|
||||||
},
|
},
|
||||||
setValue(data: UserTypes.SysUser) {
|
setValue(data: UserTypes.SysUser) {
|
||||||
formGroup.setValue(data)
|
formGroup.setValue(data)
|
||||||
|
if (data.avatar != null) {
|
||||||
|
files.value = [ {
|
||||||
|
key: data.avatar,
|
||||||
|
name: data.avatar,
|
||||||
|
thumbUrl: AppApi.fileUrl(data.avatar),
|
||||||
|
} ]
|
||||||
|
}
|
||||||
if (data.roles != null) {
|
if (data.roles != null) {
|
||||||
selectedRowKeys.value = data.roles.map(it => it.id as string)
|
selectedRowKeys.value = data.roles.map(it => it.id as string)
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,10 +6,13 @@ import { TablePagination } from '@idux/components/table/src/types'
|
||||||
import CreateTsp from '@/pages/tsp/create-tsp.vue'
|
import CreateTsp from '@/pages/tsp/create-tsp.vue'
|
||||||
import TspApi from '@/pages/tsp/tsp-api.ts'
|
import TspApi from '@/pages/tsp/tsp-api.ts'
|
||||||
import { ref } from 'vue'
|
import { ref } from 'vue'
|
||||||
|
import VideoPanel from '@/pages/tsp/VideoPanel.vue'
|
||||||
|
import Toast from '@/components/toast'
|
||||||
|
|
||||||
const createTsp = ref<InstanceType<typeof CreateTsp> | null>(null)
|
const createTsp = ref<InstanceType<typeof CreateTsp> | null>(null)
|
||||||
|
const videoPanel = ref<InstanceType<typeof VideoPanel> | null>(null)
|
||||||
const dataSource: SelectData[] = [
|
const dataSource: SelectData[] = [
|
||||||
{key: '', label: '所有'},
|
{key: '', label: '全部状态'},
|
||||||
{key: 'ZhengChang', label: '正常运营'},
|
{key: 'ZhengChang', label: '正常运营'},
|
||||||
{key: 'FenZhengChang', label: '非正常运营'},
|
{key: 'FenZhengChang', label: '非正常运营'},
|
||||||
]
|
]
|
||||||
|
@ -21,9 +24,9 @@ const pagination = reactive<TablePagination>({
|
||||||
size: 'sm',
|
size: 'sm',
|
||||||
showTotal: true,
|
showTotal: true,
|
||||||
onChange(pageIndex: number, pageSize: number) {
|
onChange(pageIndex: number, pageSize: number) {
|
||||||
console.log('------', pageIndex, pageSize)
|
|
||||||
pagination.pageIndex = pageIndex
|
pagination.pageIndex = pageIndex
|
||||||
pagination.pageSize = pageSize
|
pagination.pageSize = pageSize
|
||||||
|
searchHandler()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -89,6 +92,14 @@ function searchHandler() {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function playVideo(record: TspTypes.TspData) {
|
||||||
|
if (record.videoUrl == null) {
|
||||||
|
Toast.error('该收纳点未配置视频监控')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
videoPanel.value?.open(record.videoUrl, record.pointName)
|
||||||
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
searchHandler()
|
searchHandler()
|
||||||
TspApi.statistics()
|
TspApi.statistics()
|
||||||
|
@ -154,8 +165,8 @@ onMounted(() => {
|
||||||
<Iconfont name="mapmarker" wrapper/>
|
<Iconfont name="mapmarker" wrapper/>
|
||||||
<span>{{ record.pointName }}</span>
|
<span>{{ record.pointName }}</span>
|
||||||
</template>
|
</template>
|
||||||
<template #action>
|
<template #action="{record}">
|
||||||
<IxButton class="video-btn" icon="eye" mode="text">查看监控</IxButton>
|
<IxButton class="video-btn" icon="eye" mode="text" @click="playVideo(record)">查看监控</IxButton>
|
||||||
</template>
|
</template>
|
||||||
<template #status="{record}">
|
<template #status="{record}">
|
||||||
<IxTag v-if="record.status === 'ZhengChang'" status="success">{{ record.statusTxt }}</IxTag>
|
<IxTag v-if="record.status === 'ZhengChang'" status="success">{{ record.statusTxt }}</IxTag>
|
||||||
|
@ -164,11 +175,13 @@ onMounted(() => {
|
||||||
</IxTable>
|
</IxTable>
|
||||||
</IxCard>
|
</IxCard>
|
||||||
<CreateTsp ref="createTsp"/>
|
<CreateTsp ref="createTsp"/>
|
||||||
|
<VideoPanel ref="videoPanel"/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang="stylus" scoped>
|
<style lang="stylus" scoped>
|
||||||
.tsp {
|
.tsp {
|
||||||
|
position relative
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
|
|
@ -0,0 +1,224 @@
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import FlvJs from 'flv.js'
|
||||||
|
import { nanoid } from 'nanoid'
|
||||||
|
import Toast from '@/components/toast'
|
||||||
|
|
||||||
|
const show = ref(false)
|
||||||
|
const fullscreen = ref(false)
|
||||||
|
// 0-->未初始化、1-->播放中、2-->暂停
|
||||||
|
const status = ref(0)
|
||||||
|
const video = ref<HTMLVideoElement | null>(null)
|
||||||
|
const containerElement = ref<HTMLElement | null>(null)
|
||||||
|
let videoUrl: string = ''
|
||||||
|
const header = ref<string>('视频监控')
|
||||||
|
// http://localhost:8888/live?port=1935&app=live&stream=stream1
|
||||||
|
// ffmpeg -re -i "C:\Users\24955\Downloads\1.mp4" -c:v libx264 -c:a aac -f flv rtmp://localhost:1935/live/stream1
|
||||||
|
const id = nanoid()
|
||||||
|
let flvPlayer: FlvJs.Player | null = null
|
||||||
|
|
||||||
|
/* const logListener = (type: any, str: any) => {
|
||||||
|
console.log(type, str)
|
||||||
|
} */
|
||||||
|
|
||||||
|
function toggleScreen() {
|
||||||
|
if (fullscreen.value) {
|
||||||
|
fullscreen.value = false
|
||||||
|
document.exitFullscreen()
|
||||||
|
} else {
|
||||||
|
fullscreen.value = true
|
||||||
|
containerElement.value!.requestFullscreen()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function flvErrorHandler(type: string, message: string) {
|
||||||
|
switch (type) {
|
||||||
|
case FlvJs.ErrorTypes.NETWORK_ERROR:
|
||||||
|
console.log(message)
|
||||||
|
Toast.error('网络异常,播放失败')
|
||||||
|
break
|
||||||
|
case FlvJs.ErrorTypes.MEDIA_ERROR:
|
||||||
|
console.log(message)
|
||||||
|
Toast.error('视频格式错误,播放失败')
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
console.log(message)
|
||||||
|
Toast.error('视频播放失败')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function createPlayer() {
|
||||||
|
if (FlvJs.isSupported()) {
|
||||||
|
flvPlayer = FlvJs.createPlayer({
|
||||||
|
type: 'flv',
|
||||||
|
url: videoUrl
|
||||||
|
})
|
||||||
|
|
||||||
|
flvPlayer.on(FlvJs.Events.ERROR, flvErrorHandler)
|
||||||
|
flvPlayer.attachMediaElement(video.value!)
|
||||||
|
|
||||||
|
flvPlayer?.load()
|
||||||
|
play()
|
||||||
|
} else {
|
||||||
|
Toast.error('当前浏览器不支持视频播放')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function play() {
|
||||||
|
flvPlayer?.play()
|
||||||
|
status.value = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
function destroy() {
|
||||||
|
// FlvJs.LoggingControl.removeLogListener(logListener)
|
||||||
|
flvPlayer?.off(FlvJs.Events.ERROR, flvErrorHandler)
|
||||||
|
flvPlayer?.pause()
|
||||||
|
flvPlayer?.unload()
|
||||||
|
flvPlayer?.detachMediaElement()
|
||||||
|
flvPlayer?.destroy()
|
||||||
|
flvPlayer = null
|
||||||
|
status.value = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
function reload() {
|
||||||
|
destroy()
|
||||||
|
createPlayer()
|
||||||
|
play()
|
||||||
|
}
|
||||||
|
|
||||||
|
function pauseOrPlay() {
|
||||||
|
if (status.value === 1) {
|
||||||
|
flvPlayer?.pause()
|
||||||
|
status.value = 2
|
||||||
|
} else {
|
||||||
|
play()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function closeHandler() {
|
||||||
|
destroy()
|
||||||
|
containerElement.value!.style!.width = '0'
|
||||||
|
containerElement.value!.style!.height = '0'
|
||||||
|
videoUrl = ''
|
||||||
|
if (fullscreen.value) toggleScreen()
|
||||||
|
show.value = false
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleFullscreenChange() {
|
||||||
|
fullscreen.value = document.fullscreenElement === containerElement.value
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
document.addEventListener('fullscreenchange', handleFullscreenChange)
|
||||||
|
})
|
||||||
|
|
||||||
|
onBeforeUnmount(() => {
|
||||||
|
document.removeEventListener('fullscreenchange', handleFullscreenChange)
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
defineExpose({
|
||||||
|
open(url: string, title?: string) {
|
||||||
|
status.value = 0
|
||||||
|
videoUrl = url
|
||||||
|
header.value = title ?? '视频监控'
|
||||||
|
show.value = true
|
||||||
|
containerElement.value!.style!.width = '100%'
|
||||||
|
containerElement.value!.style!.height = '100%'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div :id="id" ref="containerElement" class="ix_modal-container">
|
||||||
|
<IxModal v-model:visible="show" :container="containerElement!"
|
||||||
|
:header="header" :mask="false"
|
||||||
|
:on-after-open="createPlayer"
|
||||||
|
:on-before-close="closeHandler"
|
||||||
|
type="default" width="100%">
|
||||||
|
<video ref="video" class="video-element" controls></video>
|
||||||
|
|
||||||
|
<template #footer>
|
||||||
|
<IxTooltip placement="top" title="刷新">
|
||||||
|
<IxButton icon="sync" @click="reload"/>
|
||||||
|
</IxTooltip>
|
||||||
|
<IxTooltip :title="status === 1?'暂停':'播放'" placement="top">
|
||||||
|
<IxButton :icon="status === 1?'pause':'play'" mode="primary" @click="pauseOrPlay"/>
|
||||||
|
</IxTooltip>
|
||||||
|
<IxTooltip :title="fullscreen?'退出全屏':'全屏'" placement="top">
|
||||||
|
<IxButton :icon="fullscreen?'fullscreen-exit':'fullscreen'" @click="toggleScreen"/>
|
||||||
|
</IxTooltip>
|
||||||
|
</template>
|
||||||
|
</IxModal>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="stylus" scoped>
|
||||||
|
.ix_modal-container {
|
||||||
|
position absolute
|
||||||
|
top 0
|
||||||
|
left 0
|
||||||
|
|
||||||
|
:deep(.ix-modal) {
|
||||||
|
width 100%
|
||||||
|
height 100%
|
||||||
|
|
||||||
|
.ix-modal-body {
|
||||||
|
width 100%
|
||||||
|
overflow hidden
|
||||||
|
border-top: 1px dashed #E1E5EB;
|
||||||
|
border-bottom: 1px dashed #E1E5EB;
|
||||||
|
|
||||||
|
.video-element {
|
||||||
|
width 100%
|
||||||
|
height 100%
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.ix-modal-footer {
|
||||||
|
justify-content center
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 隐藏全屏按钮 */
|
||||||
|
video::-webkit-media-controls-fullscreen-button {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 隐藏播放按钮 */
|
||||||
|
video::-webkit-media-controls-play-button {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 隐藏进度条 */
|
||||||
|
video::-webkit-media-controls-timeline {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 隐藏当前时间显示 */
|
||||||
|
video::-webkit-media-controls-current-time-display {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 隐藏剩余时间显示 */
|
||||||
|
video::-webkit-media-controls-time-remaining-display {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 隐藏音量按钮 */
|
||||||
|
video::-webkit-media-controls-mute-button {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 隐藏音量控制条 */
|
||||||
|
video::-webkit-media-controls-volume-slider {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 隐藏所有控件 */
|
||||||
|
video::-webkit-media-controls-enclosure {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -8,6 +8,7 @@ declare global {
|
||||||
microdistrict: string
|
microdistrict: string
|
||||||
propertyManagement: string
|
propertyManagement: string
|
||||||
status: 'ZhengChang' | 'FenZhengChang'
|
status: 'ZhengChang' | 'FenZhengChang'
|
||||||
|
videoUrl?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
interface AddParam {
|
interface AddParam {
|
||||||
|
|
|
@ -16,7 +16,7 @@ import processHtml from './plugin/html-process'
|
||||||
import zipDist from './plugin/zip-dist'
|
import zipDist from './plugin/zip-dist'
|
||||||
import { viteStaticCopy } from 'vite-plugin-static-copy'
|
import { viteStaticCopy } from 'vite-plugin-static-copy'
|
||||||
import { fileWatcher } from './plugin/file-watcher'
|
import { fileWatcher } from './plugin/file-watcher'
|
||||||
import iconfontDts from './plugin/iconfont-dts'
|
import iconfontProcess from './plugin/iconfont-process'
|
||||||
|
|
||||||
let viteConfig: UserConfigFnObject = configEnv => {
|
let viteConfig: UserConfigFnObject = configEnv => {
|
||||||
const env = loadEnv(configEnv.mode, process.cwd(), '')
|
const env = loadEnv(configEnv.mode, process.cwd(), '')
|
||||||
|
@ -51,7 +51,7 @@ let viteConfig: UserConfigFnObject = configEnv => {
|
||||||
Icons(),
|
Icons(),
|
||||||
fileWatcher({
|
fileWatcher({
|
||||||
file: './public/iconfont/ali/iconfont.json',
|
file: './public/iconfont/ali/iconfont.json',
|
||||||
fn: iconfontDts('./src/components/iconfont/iconfont.d.ts'),
|
fn: iconfontProcess('./src/components/iconfont'),
|
||||||
}),
|
}),
|
||||||
viteStaticCopy({
|
viteStaticCopy({
|
||||||
targets: [
|
targets: [
|
||||||
|
@ -91,6 +91,11 @@ let viteConfig: UserConfigFnObject = configEnv => {
|
||||||
target: env.VITE_HTTP_PROXY_TARGET,
|
target: env.VITE_HTTP_PROXY_TARGET,
|
||||||
rewrite: path => env.VITE_HTTP_SERVER_BASE_URL == null || env.VITE_HTTP_SERVER_BASE_URL == '/' ? path : path.replace(new RegExp(env.VITE_HTTP_SERVER_BASE_URL), ''),
|
rewrite: path => env.VITE_HTTP_SERVER_BASE_URL == null || env.VITE_HTTP_SERVER_BASE_URL == '/' ? path : path.replace(new RegExp(env.VITE_HTTP_SERVER_BASE_URL), ''),
|
||||||
} as ProxyOptions,
|
} as ProxyOptions,
|
||||||
|
[env.VITE_OSS_UPLOAD_BASE_URL]: {
|
||||||
|
proxyTimeout: 10000,
|
||||||
|
target: 'http://localhost:9000',
|
||||||
|
rewrite: path => env.VITE_OSS_UPLOAD_BASE_URL == null || env.VITE_OSS_UPLOAD_BASE_URL == '/' ? path : path.replace(new RegExp(env.VITE_OSS_UPLOAD_BASE_URL), ''),
|
||||||
|
} as ProxyOptions,
|
||||||
[env.VITE_WS_SERVER_BASE_URL]: {
|
[env.VITE_WS_SERVER_BASE_URL]: {
|
||||||
ws: true,
|
ws: true,
|
||||||
target: env.VITE_WS_PROXY_TARGET,
|
target: env.VITE_WS_PROXY_TARGET,
|
||||||
|
|
Loading…
Reference in New Issue