🐛 修复代码检查提示的缺陷

This commit is contained in:
my_ong 2024-12-10 11:01:23 +08:00
parent a7172a2d8b
commit 58cd837553
23 changed files with 34 additions and 2471 deletions

View File

@ -3,7 +3,8 @@
*/
class PontCoreManager {
static singleInstance = null as PontCoreManager;
// static singleInstance = undefined as PontCoreManager;
private static singleInstance: PontCoreManager | null = null;
static getSignleInstance() {
if (!PontCoreManager.singleInstance) {
@ -36,12 +37,12 @@ class PontCoreManager {
this.fetch = fetch;
}
getUrl(path: string, queryParams: any, method: string) {
getUrl(path: string, queryParams: any) {
const params = {
...(queryParams || ({} as any)),
};
const url = path.replace(/\{([^\\}]*(?:\\.[^\\}]*)*)\}/gm, (match, key) => {
const url = path.replace(/\{([^\\}]*(?:\\.[^\\}]*)*)\}/gm, ( key) => {
// eslint-disable-next-line no-param-reassign
key = key.trim();

6
src/components.d.ts vendored
View File

@ -7,6 +7,7 @@ export {}
/* prettier-ignore */
declare module 'vue' {
export interface GlobalComponents {
AAlert: typeof import('ant-design-vue/es')['Alert']
AAvatar: typeof import('ant-design-vue/es')['Avatar']
AButton: typeof import('ant-design-vue/es')['Button']
ACard: typeof import('ant-design-vue/es')['Card']
@ -21,6 +22,7 @@ declare module 'vue' {
AFormItem: typeof import('ant-design-vue/es')['FormItem']
AImage: typeof import('ant-design-vue/es')['Image']
AInput: typeof import('ant-design-vue/es')['Input']
AInputPassword: typeof import('ant-design-vue/es')['InputPassword']
AInputSearch: typeof import('ant-design-vue/es')['InputSearch']
ALayout: typeof import('ant-design-vue/es')['Layout']
ALayoutContent: typeof import('ant-design-vue/es')['LayoutContent']
@ -48,9 +50,11 @@ declare module 'vue' {
ATabPane: typeof import('ant-design-vue/es')['TabPane']
ATabs: typeof import('ant-design-vue/es')['Tabs']
ATag: typeof import('ant-design-vue/es')['Tag']
ATextarea: typeof import('ant-design-vue/es')['Textarea']
ATooltip: typeof import('ant-design-vue/es')['Tooltip']
ATransfer: typeof import('ant-design-vue/es')['Transfer']
ATree: typeof import('ant-design-vue/es')['Tree']
ATypographyLink: typeof import('ant-design-vue/es')['TypographyLink']
ATypographyParagraph: typeof import('ant-design-vue/es')['TypographyParagraph']
ATypographyTitle: typeof import('ant-design-vue/es')['TypographyTitle']
AuxiliaryItemRender: typeof import('./components/form-render/auxiliary-item-render.vue')['default']
AWatermark: typeof import('ant-design-vue/es')['Watermark']

View File

@ -48,7 +48,7 @@ export const routes = [
path: '/stock/inbound', //入库
name: 'Inbound',
meta: {title: 'menus.stock.inbound',icon: 'icon-permission'},
component: ()=> import('../views/stock/inboud/inboud-page.vue'),
component: ()=> import('../views/stock/inboud/inboud-page.vue'),
},
{
path: '/stock/outbound', //出库
@ -107,11 +107,6 @@ export default createRouter({
name: 'Index',
redirect: '/login',
},
{
path: '/dashboard',
name: 'Dashboard',
component: () => import('../views/dashboard/dashboard-page.vue'),
},
{
path: '/login',
name: 'Login',

View File

@ -1,383 +0,0 @@
<template>
<page-container>
<a-row :gutter="[16, 16]">
<a-col :span="8">
<a-card title="XXX项目档案目录">
<template #extra>
<a-select ref="select" v-model:value="value1" style="width: 120px" :options="options1"></a-select>
</template>
<a-directory-tree
v-model:expanded-keys="expandedKeys"
v-model:selected-keys="selectedKeys"
:tree-data="treeData"
></a-directory-tree>
</a-card>
</a-col>
<a-col :span="16">
<a-card title="XXX项目 一、勘测定界图或拟征地红线图 电子档案">
<a-row :gutter="[16, 16]">
<a-col v-for="item in 32" :key="item" span="3">
<a-card hoverable>
<template #cover>
<img alt="example" :src="pics[Math.floor(Math.random() * 10) % 4]" />
</template>
<a-card-meta>
<template #title>
<span style="font-size: 12px">xxx 公告第{{ Math.floor(Math.random() * 10) }}</span>
</template>
</a-card-meta>
</a-card>
</a-col>
</a-row>
</a-card>
</a-col>
</a-row>
</page-container>
</template>
<script setup lang="ts">
import { SelectProps, TreeProps } from 'ant-design-vue'
import excel from '@/assets/excel.png'
import word from '@/assets/WORD.png'
import pdf from '@/assets/PDF.png'
import image from '@/assets/image.png'
const pics = ref<string[]>([excel, word, pdf, image])
const value1 = ref('lucy')
const options1 = ref<SelectProps['options']>([
{
value: 'jack',
label: '项目一',
},
{
value: 'lucy',
label: '项目二',
},
{
value: 'yiminghe',
label: '项目三',
},
])
const expandedKeys = ref<string[]>(['0-0', '0-1'])
const selectedKeys = ref<string[]>([])
const treeData: TreeProps['treeData'] = [
{
title: '征地档案',
key: '0-0',
children: [
{
title: '一、勘测定界图或拟征地红线图',
key: '0-0-0',
isLeaf: true,
},
{
title: '二、关于征收土地预公告(附件1)',
key: '0-0-1',
isLeaf: true,
},
{
title: '三、征地动员和政策宣传影像资料和相关文字记录',
key: '0-0-2',
isLeaf: true,
},
{
title: '四、拟征收土地现状调查',
key: '0-0-3',
isLeaf: false,
children: [
{
title: '凤凰镇双凤村1社',
key: '3-0-0',
isLeaf: false,
children: [
{ title: '四(一)、人口调查表(附件2-1)', key: '3-1-0', isLeaf: true },
{ title: '四(二)、拟征收土地分户调查表(附件2-2)', key: '3-1-1', isLeaf: true },
{ title: '四(三)、其他地上附着物和青苗分户现状调查表(附件2-3)', key: '3-1-2', isLeaf: true },
{
title: '张三(例)',
key: '3-1-3',
isLeaf: false,
children: [
{ title: '四(四)、构筑物分户调查表(附件2-4)', key: '3-1-3-0', isLeaf: true },
{ title: '四(五)、农村房屋分户现状调查表(附件2-5)', key: '3-1-3-1', isLeaf: true },
{ title: '四(六)、生产经营活动现状调查表(附件2-6)', key: '3-1-3-2', isLeaf: true },
{ title: '四(七)、未取得不动产权证书房屋产权面积认定表(附件9-2)', key: '3-1-3-3', isLeaf: true },
],
},
{ title: '李四(例)', key: '3-1-4', isLeaf: false },
],
},
{ title: '凤凰镇双凤村2社', key: '3-0-1', isLeaf: false },
],
},
{
title: '五、征地社会稳定风险评估报告及县信访办备案文书',
key: '0-0-4',
isLeaf: true,
},
{
title: '六、征地补偿安置方案',
key: '0-0-5',
isLeaf: false,
children: [
{
title: '六(一)、征地补偿安置方案公告(附件3)',
key: '5-0-1',
isLeaf: true,
},
{
title: '六(二)、提出异议的书面材料或听证申请书',
key: '5-0-2',
isLeaf: true,
},
{
title: '六(三)、异议答复材料或召开听证会相关材料',
key: '5-0-3',
isLeaf: true,
},
],
},
{
title: '七、补偿登记',
key: '0-0-6',
isLeaf: false,
children: [
{
title: '凤凰镇双凤村1社',
key: '6-0-0',
isLeaf: false,
children: [
{ title: '七(一)、被征收土地及土地补偿费补偿登记表(附件5-1)', key: '6-1-0', isLeaf: true },
{ title: '七(二)、其他地上附着物和青苗补偿登记表(附件5-2)', key: '6-1-1', isLeaf: true },
{ title: '七(三)、农村房屋补偿登记表(附件5-3)', key: '6-1-2', isLeaf: true },
{
title: '七(四)、林地上的林木及附着物分户现状调查和补偿登记表(附件9-1)',
key: '6-1-3',
isLeaf: false,
children: [
{
title: '张三(例)',
key: '6-1-3-1',
isLeaf: false,
children: [
{ title: '1.住房安置特殊对象调查表(附件9-3)', key: '6-1-3-1-0', isLeaf: true },
{ title: '2.增加安置住房申请书', key: '6-1-3-1-1', isLeaf: true },
{ title: '3.准生证', key: '6-1-3-1-2', isLeaf: true },
{ title: '4.结婚证', key: '6-1-3-1-3', isLeaf: true },
{ title: '5.无房申明和家庭成员住房查询记录', key: '6-1-3-1-4', isLeaf: true },
{ title: '6.集体经济组织出具的长期居住证明', key: '6-1-3-1-5', isLeaf: true },
{
title: '7.户籍所在地集体经济组织出具的不享有宅基地权利的证明',
key: '6-1-3-1-6',
isLeaf: true,
},
],
},
{ title: '李四(例)', key: '6-1-3-2', isLeaf: false },
],
},
{ title: '七(五)、住房安置特殊对象资料', key: '6-1-4', isLeaf: true },
{ title: '七(六)、征地集体资产汇总公示表(附件9-4)', key: '6-1-5', isLeaf: true },
{ title: '七(七)、对补偿登记情况提出异议的书面材料', key: '6-1-6', isLeaf: true },
{ title: '七(八)、对异议的核实、决议及公布材料', key: '6-1-7', isLeaf: true },
{
title: '七(九)、土地承包经营权证、房屋不动产权证',
key: '6-1-8',
isLeaf: false,
children: [
{ title: '张三(例)', key: '6-1-8-1', isLeaf: true },
{ title: '李四(例)', key: '6-1-8-2', isLeaf: true },
],
},
{
title: '七(十)、被征地农户的身份证、户口簿及银行卡',
key: '6-1-9',
isLeaf: false,
children: [
{ title: '张三(例)', key: '6-1-9-1', isLeaf: true },
{ title: '李四(例)', key: '6-1-9-2', isLeaf: true },
],
},
],
},
{ title: '凤凰镇双凤村2社', key: '6-0-1', isLeaf: false },
],
},
{
title: '八、确定征地补偿安置方案公告(附件4)',
key: '0-0-7',
isLeaf: true,
},
{
title: '九、补偿安置协议',
key: '0-0-8',
isLeaf: false,
children: [
{
title: '凤凰镇双凤村1社',
key: '8-0-0',
isLeaf: false,
children: [
{ title: '九(一)、征地补偿安置协议书', key: '8-1-0', isLeaf: true },
{
title: '九(二)、被征地农户签订的土地、青苗及附着物分户补偿协议书',
key: '8-1-1',
isLeaf: false,
children: [
{ title: '张三(例)', key: '8-1-8-1', isLeaf: true },
{ title: '李四(例)', key: '8-1-8-2', isLeaf: true },
],
},
{
title: '九(三)、同被征地农户签订的住房补偿安置协议书',
key: '8-1-2',
isLeaf: false,
children: [
{ title: '张三(例)', key: '8-1-9-1', isLeaf: true },
{ title: '李四(例)', key: '8-1-9-2', isLeaf: true },
],
},
],
},
{ title: '凤凰镇双凤村2社', key: '6-0-1', isLeaf: false },
],
},
{
title: '十、确定具体人员安置对象',
key: '0-0-9',
isLeaf: false,
children: [
{
title: '凤凰镇双凤村1社',
key: '9-0-0',
isLeaf: false,
children: [
{
title: '十(一)、召开村民大会确定具体安置人员安置对象的会议记录及影像资料',
key: '9-1-0',
isLeaf: true,
},
{
title: '十(二)、征地人员安置对象名单及公示照片',
key: '9-1-1',
isLeaf: true,
},
{
title: '十(三)、征地人员安置对象核准表(附件6)',
key: '9-1-2',
isLeaf: true,
},
],
},
{ title: '凤凰镇双凤村2社', key: '6-0-1', isLeaf: false },
],
},
{
title: '十一、市人民政府关于农用地转用和土地征收的批复',
key: '0-1-0',
isLeaf: true,
},
{
title: '十二、征收土地的公告(附件7)',
key: '0-1-1',
isLeaf: true,
},
{
title: '十三、支付补偿安置费用',
key: '0-1-2',
isLeaf: false,
children: [
{
title: '凤凰镇双凤村1社',
key: '9-0-0',
isLeaf: false,
children: [
{
title: '十三(一)、领取征地补偿安置费通知书及送达登记表',
key: '12-1-0',
isLeaf: true,
},
{
title: '十三(二)、安置补助费发放表(附件8-2)',
key: '12-1-1',
isLeaf: true,
},
{
title: '十三(三)、集体对公账户详细信息',
key: '12-1-2',
isLeaf: true,
},
{
title: '十三(四)、征地补偿安置费用发放记录',
key: '12-1-3',
isLeaf: true,
},
],
},
{ title: '凤凰镇双凤村2社', key: '6-0-1', isLeaf: false },
],
},
{
title: '十四、作出征地补偿安置决定资料',
key: '0-1-3',
isLeaf: false,
children: [
{
title: '十四(一)、征地补偿安置决定书',
key: '13-1-0',
isLeaf: true,
},
{
title: '十四(二)、被征收人申请行政复议或提起行政诉讼有关资料',
key: '13-1-1',
isLeaf: true,
},
{
title: '十四(三)、行政复议或行政诉讼判决书',
key: '13-1-2',
isLeaf: true,
},
{
title: '十四(四)、申请强制执行资料',
key: '13-1-3',
isLeaf: true,
},
],
},
{
title: '十五、基本养老保险缴费补贴对象及补贴年限确认表(附件8-1)',
key: '0-1-4',
isLeaf: false,
children: [
{ title: '凤凰镇双凤村1社', key: '14-0-0', isLeaf: true },
{ title: '凤凰镇双凤村2社', key: '14-0-1', isLeaf: true },
],
},
{
title: '十六、其他资料',
key: '0-1-5',
isLeaf: true,
},
],
},
{
title: '项目建设档案',
key: '0-1',
disabled: true,
children: [
{
title: 'leaf 1-0',
key: '0-1-0',
isLeaf: true,
disabled: true,
},
{
title: 'leaf 1-1',
key: '0-1-1',
isLeaf: true,
disabled: true,
},
],
},
]
</script>

View File

@ -1,73 +0,0 @@
import { FormItem, FormConfig } from '@/components/form-render/form-render-types'
export const config: FormConfig = {
layout: 'horizontal',
colon: true,
hideRequiredMark: false,
labelAlign: 'right',
scrollToFirstError: false,
validateOnRuleChange: true,
labelCol: {
span: 4,
offset: 0,
},
}
export const formItems: FormItem[] = [
{
group: 'form',
type: 'input',
config: {
autoLink: true,
hasFeedback: false,
label: '设备编号',
name: 'key',
required: true,
},
properties: {
size: 'default',
type: 'text',
allowClear: false,
bordered: true,
showCount: false,
placeholder: '请输入设备编号',
},
rules: [],
},
{
group: 'form',
type: 'input',
config: {
autoLink: true,
hasFeedback: false,
label: '设备名称',
name: 'name',
},
properties: {
size: 'default',
type: 'text',
allowClear: false,
bordered: true,
showCount: false,
placeholder: '请输入设备名称',
},
rules: [],
},
{
type: 'input-number',
group: 'form',
config: {
autoLink: true,
hasFeedback: false,
label: '设备通道数',
name: 'channels',
required: true,
},
properties: {
size: 'default',
controls: true,
placeholder: '请填写设备通道数',
},
rules: [],
},
]

View File

@ -1,95 +0,0 @@
<template>
<a-card size="small" :title="`通道 ${item.key} 数据情况`">
<template #extra>
<a-badge v-if="station" status="success" :text="station?.name" :style="{ cursor: 'pointer' }" @click="toDetail" />
<a-badge v-else status="default" text="未绑定工位" />
</template>
<v-chart class="chart" :option="option" autoresize />
</a-card>
</template>
<script setup lang="ts">
const props = defineProps({
item: {
type: Object as PropType<{ key: number; value: sensor.SensorLog[] }>,
required: true,
},
station: {
type: Object as PropType<sensor.Station>,
required: false,
default: () => null,
},
})
const { item, station } = toRefs(props)
const option = computed(() => {
return {
// grid: { top: '10px', left: '10px', right: '10px', bottom: '20px', containLable: true },
grid: { top: '35px', left: '55px', right: '35px', bottom: '35px', containLable: true },
tooltip: {
trigger: 'axis',
formatter: '{b0}<br> 电流: {c0} A<br /> 电压: {c1} V<br /> 温度: {c2} ℃',
},
xAxis: {
type: 'category',
data: item.value.value.map((l) => l.createdTime?.split(' ')[1]),
},
yAxis: [
{
position: 'left',
type: 'value',
nameLocation: 'start',
offset: 25,
name: '电流(A)',
// show: false,
// min: 5,
// max: 15,
},
{
position: 'left',
type: 'value',
name: '电压(V)',
// show: false,
min: 0,
max: 400,
},
{
position: 'right',
type: 'value',
name: '温度(℃)',
// show: false,
min: -10,
max: 60,
},
],
series: [
{
data: item.value.value.map((l) => l.ampere),
type: 'line',
smooth: true,
yAxisIndex: 0,
},
{
data: item.value.value.map((l) => l.voltage),
type: 'line',
smooth: true,
yAxisIndex: 1,
},
{
data: item.value.value.map((l) => l.temperature),
type: 'line',
smooth: true,
yAxisIndex: 2,
},
],
}
})
const router = useRouter()
const toDetail = () => {
router.push({ name: 'station-detail', params: { key: station.value.uid } })
}
</script>
<style scoped>
.chart {
height: 230px;
}
</style>

View File

@ -1,84 +0,0 @@
<template>
<a-drawer v-model:open="open" title="设备详情" placement="right" width="45%" :body-style="{ padding: '6px 12px' }">
<template #extra>
已持续工作
<a-badge status="success" color="cyan" :count="info.value" :overflow-count="9999999"></a-badge>
{{ info.unit === 'day' ? '天' : '小时' }}
</template>
<a-row v-if="detailGroup.length" :gutter="[16, 4]">
<a-col v-for="item in detailGroup" :key="item.key" :span="24">
<sensor-channel
:item="item"
:station="detail?.stations.filter((s) => s.channel === item.key)[0]"
></sensor-channel>
</a-col>
</a-row>
<a-flex v-else :style="{ height: 'calc( 100vh - 80px )' }" justify="center" align="center">
<a-spin tip="数据加载中..."></a-spin>
</a-flex>
</a-drawer>
</template>
<script setup lang="ts">
import SensorChannel from './sensor-channel.vue'
import api from '@/api'
import dayjs from 'dayjs'
import { PropType } from 'vue'
const props = defineProps({
show: {
type: Boolean,
default: () => false,
},
sensor: {
type: Object as PropType<sensor.Sensor>,
default: () => null,
},
})
const emit = defineEmits<{
'update:show': [value: boolean]
}>()
const { show, sensor } = toRefs(props)
const open = computed({
get: () => show.value,
set: (val) => emit('update:show', val),
})
const info = computed(() => {
const days = dayjs().diff(dayjs(sensor.value.createdTime), 'day')
if (days > 0) {
return { value: days, unit: 'day' }
}
return { value: dayjs().diff(dayjs(sensor.value.createdTime), 'hour'), unit: 'hour' }
})
const detail = ref<sensor.SensorDetail>()
const detailGroup = computed(() => {
const items = detail.value?.logs || []
return Object.values({
...Array.from(new Set(items.map((item) => item.channel))),
})
.sort((a, b) => Number(a) - Number(b))
.map((channel) => ({
key: Number(channel),
value: items
.filter(({ channel: c }) => channel === c)
.sort((a, b) => String(a.createdTime)?.localeCompare(String(b.createdTime))),
}))
})
const timer = ref()
watch(
sensor,
(val) => {
if (val && show.value) {
clearInterval(timer.value)
timer.value = setInterval(() => {
loadData(Number(val.id))
}, 5000)
}
},
{ immediate: false, deep: true },
)
const loadData = async (_id: number) => {
api.sensorApi.sensor.detail(Number(_id), (data) => {
detail.value = data
})
}
</script>

View File

@ -1,187 +0,0 @@
<template>
<page-container>
<template #ops>
<a-row>
<a-col :span="18">
<a-input-search
v-model:value="searchKey"
:placeholder="`请输入设备号/名称`"
allow-clear
enter-button
@search="loadData()"
></a-input-search>
</a-col>
<a-col :span="6">
<a-button type="primary" style="margin-left: 10px" @click="addOrEdit()">
<template #icon>
<icon-font type="icon-plus" />
</template>
添加
</a-button>
</a-col>
</a-row>
</template>
<div style="min-height: calc(100vh - 305px)">
<a-table
:columns="columns"
:data-source="sensorPage?.records"
bordered
:pagination="pagination"
:loading="loading"
row-key="key"
>
<template #bodyCell="{ column, record }">
<template v-if="column.dataIndex === 'key'">
<a-typography-link
href="javascript:;"
:style="{ color: token.colorPrimary }"
@click="showDetail(record as sensor.Sensor)"
>
{{ record.key }}
</a-typography-link>
</template>
<template v-if="column.dataIndex === 'operation'">
<a-button type="link" :style="{ color: token.colorPrimary }" @click="addOrEdit(record)">
<template #icon>
<icon-font type="icon-edit" />
</template>
编辑
</a-button>
<a-popconfirm :title="`确定需要删除设备 ${record.name}(${record.key}) 吗?`" @confirm="remove(record.id)">
<a-button type="link" danger style="margin-left: 10px">
<template #icon>
<icon-font type="icon-delete" />
</template>
删除
</a-button>
</a-popconfirm>
</template>
</template>
</a-table>
</div>
</page-container>
<form-drawer
ref="formDrawer"
v-model="sensor"
:form-items="items"
:config="formConfig"
:title="modalTitle"
@ok="doSave"
/>
<sensor-detail-drawer ref="sensorDetailDrawer" v-model:show="show" :sensor="currentSensor" />
</template>
<script setup lang="ts">
import FormDrawer from '@/components/form-render/form-drawer.vue'
import SensorDetailDrawer from './sensor-detail-drawer.vue'
import api from '@/api'
import { IPage } from '@/api/api'
import { notification, theme } from 'ant-design-vue'
import { config, formItems } from './form'
import { FormDataType } from '@/components/form-render/form-render-types'
const { useToken } = theme
const { token } = useToken()
const searchKey = ref('')
const sensorPage = ref<IPage<sensor.Sensor>>()
const loading = ref(false)
const loadData = async (page = 1, size = 10) => {
loading.value = true
api.sensorApi.sensor.sensors(
{ page: page || sensorPage.value?.current, size: size || sensorPage.value?.size, key: searchKey.value },
(data) => {
loading.value = false
sensorPage.value = data
},
)
}
loadData()
//
const columns = [
{
title: '设备编号',
dataIndex: 'key',
},
{
title: '设备名称',
dataIndex: 'name',
},
{
title: '设备通道数',
dataIndex: 'channels',
},
{
title: '操作',
dataIndex: 'operation',
width: 400,
},
]
//
const pagination = computed(() => {
return {
current: sensorPage.value?.current,
pageSize: sensorPage.value?.size,
total: sensorPage.value?.total,
onChange: (page: number, pageSize: number) => {
loadData(page, pageSize)
},
}
})
const sensor = ref<Partial<sensor.Sensor>>({})
//
const formDrawer = ref<typeof FormDrawer>()
const formConfig = computed(() => {
return config
})
//
const items = computed(() => {
return formItems
})
//
const modalTitle = computed(() => {
return sensor.value.id ? '编辑设备' : '添加设备'
})
const addOrEdit = (u?: Record<string, unknown>) => {
sensor.value = { ...(u ?? { channels: 3 }) }
formDrawer.value?.show()
}
const doSave = (_data: FormDataType) => {
const f = sensor.value.id ? api.sensorApi.sensor.update : api.sensorApi.sensor.add
f(_data as unknown as sensor.Sensor, (data) => {
console.log(data)
formDrawer.value?.close()
notification.success({
message: '操作成功',
description: '设备信息保存成功,页面将自动刷新!',
onClose: () => {
loadData(1)
},
})
})
}
const remove = (id: number) => {
api.sensorApi.sensor.deleteSensor(id, () => {
notification.success({
message: '操作成功',
description: '设备信息删除成功,页面将自动刷新!',
onClose: () => {
loadData(1)
},
})
})
}
const currentSensor = ref<sensor.Sensor>()
const show = ref(false)
const showDetail = (_s: sensor.Sensor) => {
currentSensor.value = _s
show.value = true
}
</script>

View File

@ -1,119 +0,0 @@
import { FormItem, FormConfig } from '@/components/form-render/form-render-types'
export const config: FormConfig = {
layout: 'horizontal',
colon: true,
hideRequiredMark: false,
labelAlign: 'right',
scrollToFirstError: false,
validateOnRuleChange: true,
labelCol: {
span: 4,
offset: 0,
},
}
export const formItems: FormItem[] = [
{
type: 'divider',
group: 'auxiliary',
properties: {
showText: true,
type: 'horizontal',
orientation: 'left',
text: '工位信息',
},
},
{
group: 'form',
type: 'input',
config: {
autoLink: true,
hasFeedback: false,
label: '工位名称',
name: 'name',
required: true,
},
properties: {
size: 'default',
type: 'text',
allowClear: true,
bordered: true,
showCount: true,
placeholder: '请输入工位名称',
},
rules: [],
},
{
type: 'divider',
group: 'auxiliary',
properties: {
showText: true,
type: 'horizontal',
orientation: 'left',
text: '工位参数',
},
},
{
type: 'input-number',
group: 'form',
config: {
autoLink: true,
hasFeedback: false,
label: '待机电流',
name: 'standby',
required: true,
},
properties: {
size: 'default',
controls: true,
placeholder: '请输入待机电流',
precision: 2,
step: 0.01,
addonAfter: 'A',
decimalSeparator: '',
},
rules: [],
},
{
type: 'input-number',
group: 'form',
config: {
autoLink: true,
hasFeedback: false,
label: '工作电流',
name: 'working',
required: true,
},
properties: {
size: 'default',
controls: true,
placeholder: '请输入工作电流',
precision: 2,
step: 0.01,
addonAfter: 'A',
},
rules: [],
},
{
type: 'input-number',
group: 'form',
config: {
autoLink: true,
hasFeedback: false,
label: '工作间歇',
name: 'maxGap',
required: true,
},
properties: {
size: 'default',
controls: true,
placeholder: '请输入最大工作间隙时长',
min: 15,
step: 1,
prefix: '',
addonAfter: '秒',
},
rules: [],
},
]

View File

@ -1,255 +0,0 @@
<template>
<a-row :gutter="[16, 16]">
<a-col :span="12">
<v-chart :loading="monthStatistics.length == 0" class="chart" :option="monthOption" autoresize />
</a-col>
<a-col :span="12">
<v-chart :loading="yearStatistics.length == 0" class="chart" :option="yearOption" autoresize />
</a-col>
<a-col :span="24">
<v-chart :loading="sensorLogs.length == 0" class="chart" :option="sensorOption" autoresize />
</a-col>
</a-row>
</template>
<script setup lang="ts">
import api from '@/api'
const props = defineProps({
stationId: {
type: Number,
required: false,
default: () => 0,
},
teamId: {
type: Number,
required: false,
default: () => 0,
},
})
const { stationId, teamId } = toRefs(props)
const monthStatistics = ref<station.Statistic[]>([])
const monthOption = computed(() => {
return {
title: {
text: '月开机/工作',
},
tooltip: {
trigger: 'axis',
},
legend: {
data: ['开机', '工作'],
},
grid: {
left: '3%',
right: '4%',
bottom: '3%',
containLabel: true,
},
toolbox: {
feature: {
saveAsImage: { title: '保存为图片' },
dataView: { title: '数据视图' },
magicType: {
type: ['line', 'bar'],
title: {
line: '切换为折线图',
bar: '切换为柱状图',
},
},
},
},
xAxis: {
type: 'category',
boundaryGap: false,
data: monthStatistics.value.map((s) => s.scale),
},
yAxis: {
type: 'value',
},
series: [
{
name: '开机',
type: 'line',
smooth: true,
data: monthStatistics.value.map((s) => s.powerHours),
},
{
name: '工作',
type: 'line',
smooth: true,
data: monthStatistics.value.map((s) => s.workingHours),
},
],
}
})
const yearStatistics = ref<station.Statistic[]>([])
const yearOption = computed(() => {
return {
title: {
text: '年开机/工作',
},
tooltip: {
trigger: 'axis',
},
legend: {
data: ['开机', '工作'],
},
grid: {
left: '3%',
right: '4%',
bottom: '3%',
containLabel: true,
},
toolbox: {
feature: {
saveAsImage: { title: '保存为图片' },
dataView: { title: '数据视图' },
magicType: {
type: ['line', 'bar'],
title: {
line: '切换为折线图',
bar: '切换为柱状图',
},
},
},
},
xAxis: {
type: 'category',
boundaryGap: false,
data: yearStatistics.value.map((s) => s.scale),
},
yAxis: {
type: 'value',
},
series: [
{
name: '开机',
type: 'line',
smooth: true,
data: yearStatistics.value.map((s) => s.powerHours),
},
{
name: '工作',
type: 'line',
smooth: true,
data: yearStatistics.value.map((s) => s.workingHours),
},
],
}
})
const sensorLogs = ref<station.SensorLog[]>([])
const timer = setInterval(() => {
api.stationApi.station.sensorLogs(stationId.value, (data) => {
sensorLogs.value = data.sort((a, b) => String(a.createdTime)?.localeCompare(String(b.createdTime)))
})
}, 5000)
watch(
teamId,
(val) => {
api.stationApi.station.monthStatistics(stationId.value, { teamId: val }, (data) => {
monthStatistics.value = data.sort((a, b) => String(a.scale).localeCompare(String(b.scale)))
})
api.stationApi.station.yearStatistics(stationId.value, { teamId: val }, (data) => {
yearStatistics.value = data.sort((a, b) => String(a.scale).localeCompare(String(b.scale)))
})
},
{ immediate: true },
)
const sensorOption = computed(() => {
return {
title: {
text: '设备原始采样',
},
legend: {
data: ['电流', '电压', '温度'],
},
grid: {
left: '3%',
right: '4%',
bottom: '3%',
containLabel: true,
},
tooltip: {
trigger: 'axis',
formatter: '{b0}<br> 电流: {c0} A<br /> 电压: {c1} V<br /> 温度: {c2} ℃',
},
toolbox: {
feature: {
saveAsImage: { title: '保存为图片' },
dataView: { title: '数据视图' },
},
},
xAxis: {
type: 'category',
boundaryGap: false,
data: sensorLogs.value.map((l) => l.createdTime?.split(' ')[1]),
},
yAxis: [
{
position: 'left',
type: 'value',
nameLocation: 'start',
offset: 60,
name: '电流(A)',
// show: false,
// min: 5,
// max: 15,
},
{
position: 'left',
type: 'value',
name: '电压(V)',
// show: false,
min: 0,
max: 400,
},
{
position: 'right',
type: 'value',
name: '温度(℃)',
// show: false,
min: -10,
max: 60,
},
],
series: [
{
name: '电流',
data: sensorLogs.value.map((l) => l.ampere),
type: 'line',
smooth: true,
yAxisIndex: 0,
},
{
name: '电压',
data: sensorLogs.value.map((l) => l.voltage),
type: 'line',
smooth: true,
yAxisIndex: 1,
},
{
name: '温度',
data: sensorLogs.value.map((l) => l.temperature),
type: 'line',
smooth: true,
yAxisIndex: 2,
},
],
}
})
onBeforeUnmount(() => {
clearInterval(timer)
})
</script>
<style scoped>
.chart {
height: 300px;
}
</style>

View File

@ -1,98 +0,0 @@
<template>
<page-container
:tabs="tabs"
:current-tab="currentTab"
:sub-title="`${station?.name} (传感器:${station?.key} 通道:${station?.channel})`"
@tab-changed="tabChanged"
>
<template #tags>
<a-tag :color="status?.powered ? 'processing' : 'warning'">{{ status?.powered ? '已开机' : '未开机' }}</a-tag>
<a-tag :color="status?.working ? 'processing' : 'warning'">{{ status?.working ? '焊接中' : '未焊接' }}</a-tag>
</template>
<template #ops>
<a-select
v-model:value="team"
style="width: 150px"
placeholder="请选择班组"
:options="options"
allow-clear
></a-select>
</template>
<station-charts
v-if="station && currentTab === 'charts'"
:station-id="station?.id"
:team-id="team"
></station-charts>
<station-power-log
v-if="station && currentTab === 'power'"
:station-id="station?.id"
:team-id="team"
></station-power-log>
<station-working-log
v-if="station && currentTab === 'working'"
:station-id="station?.id"
:team-id="team"
></station-working-log>
</page-container>
</template>
<script setup lang="ts">
import api from '@/api'
import { Key } from 'ant-design-vue/es/_util/type'
import StationCharts from './station-charts.vue'
import StationPowerLog from './station-power-log.vue'
import StationWorkingLog from './station-working-log.vue'
const teams = ref<station.Team[]>([])
api.stationApi.team.teams({}, (data) => {
teams.value = data.records ?? []
})
const options = computed(() => {
return teams.value.map((team) => ({
label: team.name,
value: team.id,
}))
})
const team = ref<number>()
const route = useRoute()
const key = computed(() => route.params.key)
const station = ref<station.Station>()
const status = ref<station.StationStatus>()
watch(
key,
(val) => {
api.stationApi.station.detail(String(val), (data) => {
station.value = data
})
},
{ immediate: true },
)
watch(
station,
(val) => {
if (val?.id) {
api.stationApi.stationStatus.detail(val.id, (data) => {
status.value = data
})
}
},
{ immediate: false, deep: true },
)
const tabs = ref([
{
key: 'charts',
title: '工位数据图表',
},
{
key: 'working',
title: '焊接记录',
},
{
key: 'power',
title: '开机记录',
},
])
const currentTab = ref('charts')
const tabChanged = (key: Key) => {
currentTab.value = key as string
}
</script>

View File

@ -1,314 +0,0 @@
<template>
<page-container>
<template #ops>
<a-row>
<a-col :span="18">
<a-input-search
v-model:value="searchKey"
:placeholder="`请输入设备号/工位名称`"
allow-clear
enter-button
@search="loadData()"
></a-input-search>
</a-col>
<a-col :span="6">
<a-button type="primary" style="margin-left: 10px" @click="addOrEdit()">
<template #icon>
<icon-font type="icon-plus" />
</template>
添加
</a-button>
</a-col>
</a-row>
</template>
<div style="min-height: calc(100vh - 305px)">
<a-table
:columns="columns"
:data-source="stationPage?.records"
bordered
:pagination="pagination"
:loading="loading"
row-key="id"
>
<template #bodyCell="{ column, record }">
<template v-if="column.dataIndex === 'key'">
<a-typography-link
href="javascript:;"
:style="{ color: token.colorPrimary }"
@click="showDetail(record as station.Station)"
>
{{ record.key }}
</a-typography-link>
</template>
<template v-if="column.dataIndex === 'channel'">通道 #{{ record.channel }}</template>
<template v-if="column.dataIndex === 'operation'">
<a-button type="link" :style="{ color: token.colorPrimary }" @click="addOrEdit(record)">
<template #icon>
<icon-font type="icon-edit" />
</template>
编辑
</a-button>
<a-popconfirm :title="`确定需要删除设备 ${record.name}(${record.key}) 吗?`" @confirm="remove(record.id)">
<a-button type="link" danger style="margin-left: 10px">
<template #icon>
<icon-font type="icon-delete" />
</template>
删除
</a-button>
</a-popconfirm>
</template>
</template>
</a-table>
</div>
</page-container>
<form-drawer
ref="formDrawer"
v-model="station"
:form-items="items"
:config="formConfig"
:title="modalTitle"
@ok="doSave"
>
<template #after-name>
<a-row>
<a-col :span="12">
<a-form-item
label="设备绑定"
name="key"
:rules="[{ required: true, message: '请选择设备' }]"
:label-col="{ span: 8 }"
>
<a-select
v-model:value="station.key"
show-search
placeholder="请输入设备名称/编码"
:default-active-first-option="false"
:show-arrow="false"
:filter-option="false"
not-found-content="没有找到设备"
:field-names="{ label: 'name', value: 'key' }"
allow-clear
:options="sensors"
@search="handleSearch"
></a-select>
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item
label="设备通道"
name="channel"
:rules="[{ required: true, message: '请选择通道' }]"
:label-col="{ span: 8 }"
>
<a-select
v-model:value="station.channel"
allow-clear
placeholder="请选择设备通道"
:options="channels"
></a-select>
</a-form-item>
</a-col>
</a-row>
</template>
<template #after-maxGap>
<a-slider
v-model:value="range"
:tip-formatter="formatter"
dots
range
:marks="marks"
:max="station.working ? station.working * 1.1 : 100"
:step="station.working ? Math.floor((station.working < 20 ? 20 : station.working) / 20) : 100 / 20"
/>
</template>
</form-drawer>
</template>
<script setup lang="ts">
import FormDrawer from '@/components/form-render/form-drawer.vue'
import api from '@/api'
import { IPage } from '@/api/api'
import { notification, SelectProps, theme } from 'ant-design-vue/es'
import { config, formItems } from './form'
import { FormDataType } from '@/components/form-render/form-render-types'
import { SliderMarks } from 'ant-design-vue/es/slider'
const { useToken } = theme
const { token } = useToken()
const searchKey = ref('')
const stationPage = ref<IPage<station.Station>>()
const loading = ref(false)
const loadData = async (page = 1, size = 10) => {
loading.value = true
api.stationApi.station.stations(
{ page: page || stationPage.value?.current, size: size || stationPage.value?.size, key: searchKey.value },
(data) => {
loading.value = false
stationPage.value = data
},
)
}
loadData()
//
const columns = [
{
title: '设备编号',
dataIndex: 'key',
},
{
title: '设备通道',
dataIndex: 'channel',
},
{
title: '工位名称',
dataIndex: 'name',
},
{
title: '待机电流(安培)',
dataIndex: 'standby',
},
{
title: '工作电流(安培)',
dataIndex: 'working',
},
{
title: '最大工作间歇(秒)',
dataIndex: 'maxGap',
},
{
title: '操作',
dataIndex: 'operation',
width: 400,
},
]
//
const pagination = computed(() => {
return {
current: stationPage.value?.current,
pageSize: stationPage.value?.size,
total: stationPage.value?.total,
onChange: (page: number, pageSize: number) => {
loadData(page, pageSize)
},
}
})
const router = useRouter()
const showDetail = (_station: station.Station) => {
router.push({ name: 'station-detail', params: { key: _station.uid } })
}
const station = ref<Partial<station.Station>>({})
const range = computed({
get: () => {
return [station.value.standby ?? 10, station.value.working ?? 100] as [number, number]
},
set: (val) => {
station.value.standby = val[0]
station.value.working = val[1]
},
})
const marks = computed(() => {
const standby = station.value.standby ?? 10
const working = station.value.working ?? 100
const a: SliderMarks = {}
a[standby] = `${standby} A`
a[working] = `${working} A`
return a as SliderMarks
})
const formatter = (value?: number) => {
if (value === station.value.standby) {
return `待机电流: ${value} A`
}
if (value === station.value.working) {
return `工作触发电流: ${value} A`
}
return `${value}`
}
//
const formDrawer = ref<typeof FormDrawer>()
const formConfig = computed(() => {
return config
})
//
const items = computed(() => {
return formItems
})
//
const modalTitle = computed(() => {
return station.value.id ? '编辑工位' : '添加工位'
})
const addOrEdit = (u?: Record<string, unknown>) => {
station.value = { ...u }
formDrawer.value?.show()
}
const doSave = (_data: FormDataType) => {
const f = station.value.id ? api.stationApi.station.update : api.stationApi.station.add
f(_data as unknown as station.Station, (data) => {
console.log(data)
formDrawer.value?.close()
notification.success({
message: '操作成功',
description: '工位信息保存成功,页面将自动刷新!',
onClose: () => {
loadData(1)
},
})
})
}
const remove = (id: number) => {
api.stationApi.station.deleteStation(id, () => {
notification.success({
message: '操作成功',
description: '工位信息删除成功,页面将自动刷新!',
onClose: () => {
loadData(1)
},
})
})
}
const sensors = ref<Array<sensor.Sensor>>([])
const handleSearch = (val: string) => {
api.sensorApi.sensor.sensors({ key: val }, (data) => {
sensors.value = data.records ?? []
})
}
const channels = ref<SelectProps['options']>([])
watch(
() => {
return station.value.key
},
(val) => {
if (val)
api.sensorApi.sensor.channels(val, (data) => {
channels.value = data.map((item) => {
return {
label: item.label,
value: Number(item.value),
disabled: item.disabled,
}
})
})
},
{ immediate: true, deep: true },
)
watch(
() => {
return station.value.key
},
(val) => {
if (val) handleSearch(val)
},
{ immediate: true },
)
</script>

View File

@ -1,103 +0,0 @@
<template>
<a-table
:columns="columns"
:data-source="powerLogPage?.records"
bordered
:pagination="pagination"
:loading="loading"
row-key="id"
>
<template #bodyCell="{ column, record }">
<template v-if="column.dataIndex === 'teamId'">
{{ teams.filter((t) => t.id === record.teamId)[0]?.name }}
</template>
</template>
</a-table>
</template>
<script setup lang="ts">
import api from '@/api'
import { IPage } from '@/api/api'
const props = defineProps({
stationId: {
type: Number,
required: false,
default: () => 0,
},
teamId: {
type: Number,
required: false,
default: () => 0,
},
})
const { stationId, teamId } = toRefs(props)
const powerLogPage = ref<IPage<station.PowerLog>>()
const loading = ref(false)
const loadData = async (page = 1, size = 10) => {
loading.value = true
api.stationApi.powerLog.powerLogs(
{
stationId: stationId.value,
teamId: teamId?.value,
page: page || powerLogPage.value?.current,
size: size || powerLogPage.value?.size,
},
(data) => {
powerLogPage.value = data
loading.value = false
},
)
}
watch(
teamId,
() => {
loadData()
},
{ immediate: true },
)
const pagination = computed(() => {
return {
current: powerLogPage.value?.current,
pageSize: powerLogPage.value?.size,
total: powerLogPage.value?.total,
onChange: (page: number, pageSize: number) => {
loadData(page, pageSize)
},
}
})
//
const columns = [
{
title: '班组',
dataIndex: 'teamId',
},
{
title: '日期',
dataIndex: 'date',
},
{
title: '开机时间',
dataIndex: 'powerOn',
},
{
title: '开机类型',
dataIndex: ['powerOnTypeInfo', 'description'],
},
{
title: '关机时间',
dataIndex: 'powerOff',
},
{
title: '关机类型',
dataIndex: ['powerOffTypeInfo', 'description'],
},
]
const teams = ref<station.Team[]>([])
api.stationApi.team.teams({}, (data) => {
teams.value = data.records ?? []
})
</script>

View File

@ -1,110 +0,0 @@
<template>
<a-table
:columns="columns"
:data-source="workingLogPage?.records"
bordered
:pagination="pagination"
:loading="loading"
row-key="id"
>
<template #bodyCell="{ column, record }">
<template v-if="column.dataIndex === 'teamId'">
{{ teams.filter((t) => t.id === record.teamId)[0]?.name }}
</template>
<template v-if="column.dataIndex === 'duration'">
{{ dayjs(record.end).diff(record.start, 'seconds') + ' 秒' }}
</template>
</template>
</a-table>
</template>
<script setup lang="ts">
import api from '@/api'
import { IPage } from '@/api/api'
import dayjs from 'dayjs'
const props = defineProps({
stationId: {
type: Number,
required: false,
default: () => 0,
},
teamId: {
type: Number,
required: false,
default: () => 0,
},
})
const { stationId, teamId } = toRefs(props)
const workingLogPage = ref<IPage<station.WorkingLog>>()
const loading = ref(false)
const loadData = async (page = 1, size = 10) => {
loading.value = true
api.stationApi.workingLog.workingLogs(
{
stationId: stationId.value,
teamId: teamId?.value,
page: page || workingLogPage.value?.current,
size: size || workingLogPage.value?.size,
},
(data) => {
workingLogPage.value = data
loading.value = false
},
)
}
watch(
teamId,
() => {
loadData()
},
{ immediate: true },
)
const pagination = computed(() => {
return {
current: workingLogPage.value?.current,
pageSize: workingLogPage.value?.size,
total: workingLogPage.value?.total,
onChange: (page: number, pageSize: number) => {
loadData(page, pageSize)
},
}
})
//
const columns = [
{
title: '班组',
dataIndex: 'teamId',
},
{
title: '日期',
dataIndex: 'date',
},
{
title: '开始时间',
dataIndex: 'start',
},
{
title: '开始类型',
dataIndex: ['startTypeInfo', 'description'],
},
{
title: '结束时间',
dataIndex: 'end',
},
{
title: '结束类型',
dataIndex: ['endTypeInfo', 'description'],
},
{
title: '持续时间',
dataIndex: 'duration',
},
]
const teams = ref<station.Team[]>([])
api.stationApi.team.teams({}, (data) => {
teams.value = data.records ?? []
})
</script>

View File

@ -1,70 +0,0 @@
import { FormItem, FormConfig } from '@/components/form-render/form-render-types'
export const config: FormConfig = {
layout: 'horizontal',
colon: true,
hideRequiredMark: false,
labelAlign: 'right',
scrollToFirstError: false,
validateOnRuleChange: true,
labelCol: {
span: 4,
offset: 0,
},
}
export const formItems: FormItem[] = [
{
group: 'form',
type: 'input',
config: {
autoLink: true,
hasFeedback: false,
label: '班组名称',
name: 'name',
required: true,
},
properties: {
size: 'default',
type: 'text',
allowClear: false,
bordered: true,
showCount: false,
placeholder: '请填写班组名称',
},
rules: [],
},
{
type: 'time-picker',
group: 'form',
config: {
autoLink: true,
hasFeedback: false,
label: '开始时间',
name: 'start',
required: true,
help: '',
},
properties: {
size: 'default',
valueFormat: 'HH:mm:ss',
},
rules: [],
},
{
type: 'time-picker',
group: 'form',
config: {
autoLink: true,
hasFeedback: false,
label: '结束时间',
name: 'end',
required: true,
},
properties: {
size: 'default',
valueFormat: 'HH:mm:ss',
},
rules: [],
},
]

View File

@ -1,172 +0,0 @@
<template>
<page-container>
<template #ops>
<a-row>
<a-col :span="18">
<a-input-search
v-model:value="searchKey"
:placeholder="`请输入班组名称`"
allow-clear
enter-button
@search="loadData()"
></a-input-search>
</a-col>
<a-col :span="6">
<a-button type="primary" style="margin-left: 10px" @click="addOrEdit()">
<template #icon>
<icon-font type="icon-plus" />
</template>
添加
</a-button>
</a-col>
</a-row>
</template>
<div style="min-height: calc(100vh - 305px)">
<a-table
:columns="columns"
:data-source="teamPage?.records"
bordered
:pagination="pagination"
:loading="loading"
row-key="id"
>
<template #bodyCell="{ column, record }">
<template v-if="column.dataIndex === 'operation'">
<a-button type="link" :style="{ color: token.colorPrimary }" @click="addOrEdit(record)">
<template #icon>
<icon-font type="icon-edit" />
</template>
编辑
</a-button>
<a-popconfirm :title="`确定需要删除设备 ${record.name} 吗?`" @confirm="remove(record.id)">
<a-button type="link" danger style="margin-left: 10px">
<template #icon>
<icon-font type="icon-delete" />
</template>
删除
</a-button>
</a-popconfirm>
</template>
</template>
</a-table>
</div>
</page-container>
<form-drawer
ref="formDrawer"
v-model="team"
:form-items="items"
:config="formConfig"
:title="modalTitle"
@ok="doSave"
/>
</template>
<script setup lang="ts">
import FormDrawer from '@/components/form-render/form-drawer.vue'
import api from '@/api'
import { IPage } from '@/api/api'
import { config, formItems } from './form'
import { FormDataType } from '@/components/form-render/form-render-types'
import { notification, theme } from 'ant-design-vue/es'
const { useToken } = theme
const { token } = useToken()
const searchKey = ref('')
const teamPage = ref<IPage<station.Team>>()
const loading = ref(false)
const loadData = async (page = 1, size = 10) => {
loading.value = true
api.stationApi.team.teams(
{ page: page || teamPage.value?.current, size: size || teamPage.value?.size, key: searchKey.value },
(data) => {
loading.value = false
teamPage.value = data
},
)
}
loadData()
//
const columns = [
{
title: '班组名称',
dataIndex: 'name',
},
{
title: '开始时间',
dataIndex: 'start',
},
{
title: '结束时间',
dataIndex: 'end',
},
{
title: '操作',
dataIndex: 'operation',
width: 400,
},
]
//
const pagination = computed(() => {
return {
current: teamPage.value?.current,
pageSize: teamPage.value?.size,
total: teamPage.value?.total,
onChange: (page: number, pageSize: number) => {
loadData(page, pageSize)
},
}
})
const team = ref<Partial<station.Team>>({})
//
const formDrawer = ref<typeof FormDrawer>()
const formConfig = computed(() => {
return config
})
//
const items = computed(() => {
return formItems
})
//
const modalTitle = computed(() => {
return team.value.id ? '编辑班组' : '添加班组'
})
const addOrEdit = (u?: Record<string, unknown>) => {
team.value = { ...u }
formDrawer.value?.show()
}
const doSave = (_data: FormDataType) => {
const f = team.value.id ? api.stationApi.team.update : api.stationApi.team.add
f(_data as unknown as station.Team, () => {
formDrawer.value?.close()
notification.success({
message: '操作成功',
description: '班组信息保存成功,页面将自动刷新!',
onClose: () => {
loadData(1)
},
})
})
}
const remove = (id: number) => {
api.stationApi.team.deleteTeam(id, () => {
notification.success({
message: '操作成功',
description: '班组信息删除成功,页面将自动刷新!',
onClose: () => {
loadData(1)
},
})
})
}
</script>

View File

@ -1,223 +0,0 @@
<template>
<a-card ref="dashboard" :body-style="{ ...style, minHeight: isFullscreen ? '100vh' : '100px' }" :bordered="false">
<a-row :gutter="[16, 16]">
<a-col :span="4"></a-col>
<a-col :span="16" style="text-align: center">
<a-typography-title>
<span :style="style">{{ currentTeam?.name }}班组数据采集</span>
</a-typography-title>
</a-col>
<a-col :span="4">
<a-radio-group v-model:value="team" button-style="solid" size="large">
<a-radio-button v-for="t in teams" :key="t.id" :value="t.id">{{ t.name }}</a-radio-button>
</a-radio-group>
</a-col>
<a-col :span="24">
<a-card :body-style="cardStyle" :bordered="false">
<a-row justify="center">
<a-col :span="4" style="text-align: center">
<a-statistic
:value="stationStatusStatistic?.powered ?? 0"
style="margin-right: 50px"
:value-style="{ fontFamily: 'digii', fontSize: '40px', fontWeight: 700, ...cardStyle }"
>
<template #title>
<span style="font-size: 20px" :style="cardStyle">开机工位</span>
</template>
<template #suffix>
<span>/ {{ stations.length }}</span>
</template>
</a-statistic>
</a-col>
<a-col :span="4" style="text-align: center">
<a-statistic
:value="stationStatusStatistic?.working ?? 0"
style="margin-right: 50px"
:value-style="{ fontFamily: 'digii', fontSize: '40px', fontWeight: 700, ...cardStyle }"
>
<template #title>
<span style="font-size: 20px" :style="cardStyle">有效工作</span>
</template>
<template #suffix>
<span>/ {{ stations.length }}</span>
</template>
</a-statistic>
</a-col>
<a-col :span="4" style="text-align: center">
<a-statistic
:value="XEUtils.commafy(dayStatistic?.powerHours ?? 0, { digits: 3 })"
style="margin-right: 50px"
:value-style="{ fontFamily: 'digii', fontSize: '40px', fontWeight: 700, ...cardStyle }"
>
<template #title>
<span style="font-size: 20px" :style="cardStyle">当日开机时长</span>
</template>
<template #suffix>
<span>H</span>
</template>
</a-statistic>
</a-col>
<a-col :span="4" style="text-align: center">
<a-statistic
:value="XEUtils.commafy(dayStatistic?.workingHours ?? 0, { digits: 3 })"
style="margin-right: 50px"
:value-style="{ fontFamily: 'digii', fontSize: '40px', fontWeight: 700, ...cardStyle }"
>
<template #title>
<span style="font-size: 20px" :style="cardStyle">当日焊接时长</span>
</template>
<template #suffix>
<span>H</span>
</template>
</a-statistic>
</a-col>
<a-col :span="4" style="text-align: center">
<a-statistic
:value="XEUtils.commafy(monthStatistic?.powerHours ?? 0, { digits: 3 })"
style="margin-right: 50px"
:value-style="{ fontFamily: 'digii', fontSize: '40px', fontWeight: 700, ...cardStyle }"
>
<template #title>
<span style="font-size: 20px" :style="cardStyle">当月开机时长</span>
</template>
<template #suffix>
<span>H</span>
</template>
</a-statistic>
</a-col>
<a-col :span="4" style="text-align: center">
<a-statistic
:value="XEUtils.commafy(monthStatistic?.workingHours ?? 0, { digits: 3 })"
style="margin-right: 50px"
:value-style="{ fontFamily: 'digii', fontSize: '40px', fontWeight: 700, ...cardStyle }"
>
<template #title>
<span style="font-size: 20px" :style="cardStyle">当月焊接时长</span>
</template>
<template #suffix>
<span>H</span>
</template>
</a-statistic>
</a-col>
</a-row>
</a-card>
</a-col>
<a-col :span="24">
<a-card :body-style="cardStyle" :bordered="false">
<a-card-grid
v-for="(station, index) in stations"
:key="index"
:style="{
width: '13.8%',
marginTop: isFullscreen ? '55px' : '20px',
marginBottom: isFullscreen ? '55px' : '20px',
marginRight: index % 7 === 6 ? '0.08%' : '0.54%',
marginLeft: index % 7 === 0 ? '0.08%' : '0',
paddingRight: 0,
paddingBottom: 0,
paddingTop: '4px',
boxShadow:
'1px 0 0 0 #1362e5,0 1px 0 0 #1362e5,1px 1px 0 0 #1362e5,1px 0 0 0 #1362e5 inset,0 1px 0 0 #1362e5 inset',
...style,
}"
:bordered="false"
>
<station-card v-if="team && station" :station="station" :team-id="team"></station-card>
</a-card-grid>
</a-card>
</a-col>
</a-row>
</a-card>
</template>
<script setup lang="ts">
import api from '@/api'
import StationCard from './station-card.vue'
import dayjs from 'dayjs'
import XEUtils from 'xe-utils'
const stations = ref<station.Station[]>([])
// api.stationApi.station.stations({ page: 1, size: 100 }, (data) => {
// stations.value = data.records ?? []
// })
stations.value = Array.from({ length: 14 }).map((_, index) => ({
id: index + 1,
name: `工位${index + 1}`,
channel: 1,
standby: 69.2,
working: 23.8,
key: '1',
maxGap: 15,
uid: '',
}))
const teams = ref<station.Team[]>([])
const team = ref<number>()
api.stationApi.team.teams({}, (data) => {
teams.value = data.records ?? []
team.value = teams.value[0].id
})
const currentTeam = computed(() => teams.value.find((t) => t.id === team.value))
const stationStatusStatistic = ref<station.StationStatusStatistic>()
const loadStationStatusStatistic = () => {
api.stationApi.stationStatus.statistic((data) => {
stationStatusStatistic.value = data
})
}
const teamStatistics = ref<station.Statistic[]>([])
const loadTeamStatistics = (_teamId: number) => {
api.stationApi.team.statistics(_teamId, (data) => {
teamStatistics.value = data
})
}
const timer = ref()
const loadData = (_id?: number) => {
timer.value = setInterval(() => {
loadStationStatusStatistic()
if (_id) {
loadTeamStatistics(Number(_id))
}
}, 10000)
}
watch(
team,
(val) => {
clearInterval(timer.value)
loadData(val)
},
{ immediate: true },
)
onBeforeUnmount(() => {
clearInterval(timer.value)
})
const dayStatistic = computed(() => {
return teamStatistics.value.find((s) => s.scale === dayjs().format('YYYY-MM-DD'))
})
const monthStatistic = computed(() => {
return teamStatistics.value.find((s) => s.scale === dayjs().format('YYYY-MM'))
})
const dashboard = ref<HTMLElement | null>(null)
const { toggle, isFullscreen } = useFullscreen(dashboard)
onKeyStroke('ArrowUp', () => {
toggle()
})
const style = computed(() => {
return {
backgroundColor: '#155bd5',
color: '#fff',
}
})
const cardStyle = computed(() => {
return {
backgroundColor: '#1362e5',
color: '#fff',
}
})
</script>
<style lang="css" scoped>
@font-face {
font-family: digii;
src: url('/DS-DIGII-3.ttf');
}
</style>

View File

@ -1,161 +0,0 @@
<template>
<a-badge-ribbon :text="statusInfo.description" :color="statusInfo.color">
<a-card
:body-style="{ ...style, boxShadow: 'none' }"
:head-style="{
...style,
padding: '0',
}"
:style="{ boxShadow: 'none' }"
:bordered="false"
>
<template #title>
<div style="font-size: 20px; font-weight: 800; cursor: pointer" :style="{ ...style }" @click="toDetail">
{{ station.name }}
</div>
</template>
<a-descriptions
:column="1"
:content-style="{ textAlign: 'right', display: 'block', ...style }"
:label-style="{ fontSize: '16px', fontWeight: 600, ...style }"
>
<a-descriptions-item label="日开机">
<div class="data-digii">{{ XEUtils.commafy(dayStatistic?.powerHours ?? 0, { digits: 3 }) }}</div>
</a-descriptions-item>
<a-descriptions-item label="日焊接">
<div class="data-digii">{{ XEUtils.commafy(dayStatistic?.workingHours ?? 0, { digits: 3 }) }}</div>
</a-descriptions-item>
<a-descriptions-item label="月开机">
<div class="data-digii">{{ XEUtils.commafy(monthStatistic?.powerHours ?? 0, { digits: 3 }) }}</div>
</a-descriptions-item>
<a-descriptions-item label="月焊接">
<div class="data-digii">{{ XEUtils.commafy(monthStatistic?.workingHours ?? 0, { digits: 3 }) }}</div>
</a-descriptions-item>
</a-descriptions>
<a-descriptions
:content-style="{ textAlign: 'right', display: 'block', ...style }"
:label-style="{ fontSize: '10px', fontWeight: 600, ...style }"
>
<a-descriptions-item label="开机">
<div class="data-digii-small">{{ XEUtils.commafy(station.standby ?? 0, { digits: 1 }) }} A</div>
</a-descriptions-item>
<a-descriptions-item label="工作">
<div class="data-digii-small">{{ XEUtils.commafy(station.working ?? 0, { digits: 1 }) }} A</div>
</a-descriptions-item>
<a-descriptions-item label="间隔">
<div class="data-digii-small">{{ XEUtils.commafy(station.maxGap ?? 0, { digits: 1 }) }} S</div>
</a-descriptions-item>
</a-descriptions>
</a-card>
</a-badge-ribbon>
</template>
<script setup lang="ts">
import api from '@/api'
import dayjs from 'dayjs'
import { PropType } from 'vue'
import XEUtils from 'xe-utils'
const props = defineProps({
station: {
type: Object as PropType<station.Station>,
required: true,
},
teamId: {
type: Number,
required: true,
},
})
const { station, teamId } = toRefs(props)
const statistics = ref<station.Statistic[]>([])
const loadTeamStatistics = (_teamId: number) => {
api.stationApi.station.statistics(Number(station.value.id), _teamId, (data) => {
statistics.value = data
})
}
const dayStatistic = computed(() => {
return statistics.value.find((s) => s.scale === dayjs().format('YYYY-MM-DD'))
})
const monthStatistic = computed(() => {
return statistics.value.find((s) => s.scale === dayjs().format('YYYY-MM'))
})
const status = ref<station.StationStatus>()
const statusInfo = computed(() => {
let color = 'green'
let description = '焊接中'
if (!status.value?.powered) {
color = 'volcano'
description = '已关机'
} else if (!status.value?.working) {
color = 'cyan'
description = '待机中'
}
return {
color: color,
description: description,
}
})
const timer = ref()
const loadData = (_id?: number) => {
timer.value = setInterval(() => {
if (_id) {
loadTeamStatistics(_id)
api.stationApi.stationStatus.detail(Number(station.value.id), (data) => {
status.value = data
})
}
}, 10000)
}
watch(
teamId,
(val) => {
if (val) {
clearInterval(timer.value)
loadData(val)
}
},
{ immediate: true },
)
onBeforeUnmount(() => {
clearInterval(timer.value)
})
const router = useRouter()
const toDetail = () => {
router.push({ name: 'station-detail', params: { key: station.value.uid } })
}
const style = computed(() => {
return {
backgroundColor: '#155bd5',
color: '#fff',
}
})
</script>
<style lang="css" scoped>
@font-face {
font-family: digii;
src: url('/DS-DIGII-3.ttf');
}
.data-digii {
display: block;
padding-right: 24px;
font-family: digii, Arial, sans-serif;
font-size: 20px;
font-weight: 600;
text-align: right;
}
.data-digii-small {
display: block;
padding-right: 6px;
font-family: digii, Arial, sans-serif;
font-size: 11px;
font-weight: 600;
text-align: right;
}
:deep(.ant-descriptions-header) {
box-shadow: '0 1px 2px 0 rgba(0, 0, 0, 0.03),0 1px 6px -1px rgba(0, 0, 0, 0.02),0 2px 4px 0 rgba(0, 0, 0, 0.02)';
}
</style>

View File

@ -51,7 +51,7 @@ const props = defineProps({
const { pageType } = toRefs(props)
const searchKey = ref('')
const pagedata = ref<IPage<material.ApplyForm>>()
const pagedata = ref<IPage<material.ApplyDTO>>()
const loading = ref(false)
@ -59,9 +59,16 @@ const loading = ref(false)
//
const loadData = async (page = 1, size = 10) => {
loading.value = true
api.materialApi.apply.applies(
api.materialApi.apply.searchPage(
//1: 2: 3:
{ type: 1, page: page || pagedata.value?.current, size: size || pagedata.value?.size, key: searchKey.value },
{
applyType: 1,
page: page || pagedata.value?.current,
size: size || pagedata.value?.size,
type: searchKey.value,
code: searchKey.value,
name: searchKey.value
},
(data) => {
loading.value = false
pagedata.value = data

View File

@ -70,7 +70,7 @@ const props = defineProps(
}
} // applyType使121: 2:
)
const getTableData = () => {
const getTableData = ()=> {
const $table = tableRef.value
return $table?.getTableData().fullData;
}
@ -103,7 +103,7 @@ const formData = ref<FormData>({
// vxe-table
interface RowVO {
export interface RowVO {
id: number
name: string
code: string
@ -112,7 +112,7 @@ interface RowVO {
quantity: number
disabled: boolean
checked: boolean
assignRule: number
assignRule: string
}
const tableRef = ref<VxeTableInstance<RowVO>>()
// vxe-table
@ -145,7 +145,7 @@ const insertEvent = (value: any) => {
spec: m.spec ? m.spec : '未知',
type: m.type ? m.type : '未知',
quantity: 1,
assignRule: m.assignRule ? m.assignRule : 1,
assignRule: m.assignRule ? m.assignRule : 'HIGH_VALUE',
disabled: false,
checked: false
}

View File

@ -30,12 +30,11 @@
</template>
<script setup lang="ts">
import applyForm from '../component/applyForm.vue'
import applyForm,{RowVO} from '../component/applyForm.vue'
import scanForm from '../component/scanForm.vue'
import applyConfirm from '../component/applyConfirm.vue'
import successResul from '../component/successResul.vue'
import api from '@/api'
//
defineProps(
{
@ -66,7 +65,7 @@
totalValue.value = 0
// step1step1
selectData.value = applyFormRef.value.getTableData()
selectData.value.forEach((item) => {
selectData.value.forEach((item:RowVO) => {
if (item.assignRule === 'HIGH_VALUE') {
totalValue.value += item.quantity
}
@ -75,7 +74,7 @@
if (scanFormRef.value && current.value === 1) {
// step2step2
const items = scanFormRef.value.getTableData()
const groupedSums = items.reduce((acc, item) => {
const groupedSums = items.reduce((acc:any, item:RowVO) => {
if (!acc[item.code]) {
acc[item.code] = 0
}
@ -83,7 +82,7 @@
return acc
}, {})
//
conformData.value = selectData.value.map((item) => {
conformData.value = selectData.value.map((item :RowVO) => {
return {
id: item.id,
name: item.name,

View File

@ -138,7 +138,11 @@ const removeStep2Row = async (row: TableRowVO) => {
}
function beiginScan() {
input.value?.focus()
// input.value?.focus()
const el = input.value as HTMLInputElement | null;
if (el) {
el.focus();
}
}
//

File diff suppressed because one or more lines are too long