sige 1 year ago
parent
commit
7d842095b6
  1. 11
      src/src/main/java/com/my/graphiteDigesterBg/diframe/api/DiApiUser.java
  2. 118
      src/src/main/java/com/my/graphiteDigesterBg/task/TaskStartReset.java
  3. 11
      src/web/package-lock.json
  4. 1
      src/web/package.json
  5. 35
      src/web/src/pages/main/Page.vue
  6. 33
      src/web/src/pages/main/contents/Operation.vue
  7. 78
      src/web/src/pages/main/contents/OperationTubeRacks.vue
  8. 107
      src/web/src/pages/main/contents/UserManagement.vue
  9. 15
      src/web/src/utils/ApiClient.js

11
src/src/main/java/com/my/graphiteDigesterBg/diframe/api/DiApiUser.java

@ -57,6 +57,7 @@ public class DiApiUser extends DiApiControllerBase {
Map<String,Object> data = (Map<String,Object>)params.get("data");
var user = new DiMdbUser();
user.password = "";
user.salt = UUID.randomUUID().toString().substring(0, 8);
user.createdAt = (int)(System.currentTimeMillis() / 1000);
user.createdBy = curUser.id;
@ -83,7 +84,7 @@ public class DiApiUser extends DiApiControllerBase {
}
@ResponseBody
@PostMapping("/api/user/updatePassword")
@PostMapping("/api/user/password-update")
public DiApiResponse updatePassword( @RequestBody Map<String,Object> params ) {
Integer id = (Integer)params.get("id");
String password = (String)params.get("password");
@ -104,4 +105,12 @@ public class DiApiUser extends DiApiControllerBase {
var users = DiActiveRecord.find(DiMdbUser.class, criteria);
return this.success(Map.of("list",users));
}
@ResponseBody
@RequestMapping("/api/user/current-get")
public DiApiResponse currentGet( HttpServletRequest request ) {
String accessToken = request.getHeader("App-Access-Token");
var user = DiActiveRecord.findOne(DiMdbUser.class, Map.of("accessToken", accessToken));
return this.success(user);
}
}

118
src/src/main/java/com/my/graphiteDigesterBg/task/TaskStartReset.java

@ -14,65 +14,65 @@ public class TaskStartReset extends DiTaskBase {
runtimeVars.set("IsTaskStartResetExecuting", "YES");
this.setProgressMessage("设备初始化...");
this.setProgressMessage("设备初始化 : 关闭设备门");
DiActMotor doorMotor = this.getActuator(MyDevice.ACT_DOOR_MOTOR, DiActMotor.class);
doorMotor.setEnable(true);
doorMotor.moveToIO(1, 1);
this.setProgressMessage("设备初始化 : 关闭夹爪");
DiActServo transferClipServo = this.getActuator(MyDevice.ACT_TRANSFER_CLIP_SERVO, DiActServo.class);
transferClipServo.setEnable(true);
transferClipServo.moveTo("TransClipServoClose");
this.setProgressMessage("设备初始化 : 加液臂复位");
DiActMotor liquidMotor = this.getActuator(MyDevice.ACT_LIQUID_MOTOR, DiActMotor.class);
liquidMotor.setEnable(true);
liquidMotor.reset();
liquidMotor.moveTo("LiquidArmStandby");
// @todo http://127.0.0.1:5566/issues/38
this.setProgressMessage("设备初始化 : 搬运机械臂上下移动复位");
DiActMotor transUdMotor = this.getActuator(MyDevice.ACT_TRANSFER_UD_MOTOR, DiActMotor.class);
transUdMotor.setEnable(true);
transUdMotor.reset();
transUdMotor.moveTo("TransUdMotorStandby");
this.setProgressMessage("设备初始化 : 搬运机械臂左右移动复位");
DiActMotor transLrMotor = this.getActuator(MyDevice.ACT_TRANSFER_LR_MOTOR, DiActMotor.class);
transLrMotor.setEnable(true);
transLrMotor.reset();
transLrMotor.moveTo("TransLrMotorStandby");
for ( int i=0; i<5; i++ ) {
this.setProgressMessage("设备初始化 : 加热盘转盘槽盖关闭 " + (i+1) + "/5");
String key = "HeatingPlateMotorSlotCover_" + i;
DiActServo heatSlotCoverServo = this.getActuator(key, DiActServo.class);
heatSlotCoverServo.setEnable(true);
heatSlotCoverServo.setCurrentPosAsMiddle();
}
// @TODO : http://127.0.0.1:5566/issues/39
this.setProgressMessage("设备初始化 : 加液转盘复位");
DiActMotor liquidPlateMotor = this.getActuator(MyDevice.ACT_LIQUID_PLATE_MOTOR, DiActMotor.class);
liquidPlateMotor.setEnable(true);
liquidPlateMotor.reset();
// @TODO : http://127.0.0.1:5566/issues/40
this.setProgressMessage("设备初始化 : 加热盘转盘复位");
DiActMotor heatPlateMotor = this.getActuator(MyDevice.ACT_HEAT_PLATE_MOTOR, DiActMotor.class);
heatPlateMotor.setEnable(true);
heatPlateMotor.reset();
heatPlateMotor.moveTo("HeatPlateStandby");
int peristalticPumpCount = 1;
var actuators = this.getDevice().getActuators().getAll();
for ( var actuator : actuators ) {
if (actuator instanceof DiActPeristalticPump pump) {
this.setProgressMessage("设备初始化 : 蠕动泵复位 " + peristalticPumpCount + "/16");
pump.setEnable(true);
peristalticPumpCount++;
}
}
// this.setProgressMessage("设备初始化 : 关闭设备门");
// DiActMotor doorMotor = this.getActuator(MyDevice.ACT_DOOR_MOTOR, DiActMotor.class);
// doorMotor.setEnable(true);
// doorMotor.moveToIO(1, 1);
//
// this.setProgressMessage("设备初始化 : 关闭夹爪");
// DiActServo transferClipServo = this.getActuator(MyDevice.ACT_TRANSFER_CLIP_SERVO, DiActServo.class);
// transferClipServo.setEnable(true);
// transferClipServo.moveTo("TransClipServoClose");
//
// this.setProgressMessage("设备初始化 : 加液臂复位");
// DiActMotor liquidMotor = this.getActuator(MyDevice.ACT_LIQUID_MOTOR, DiActMotor.class);
// liquidMotor.setEnable(true);
// liquidMotor.reset();
// liquidMotor.moveTo("LiquidArmStandby");
//
// // @todo http://127.0.0.1:5566/issues/38
// this.setProgressMessage("设备初始化 : 搬运机械臂上下移动复位");
// DiActMotor transUdMotor = this.getActuator(MyDevice.ACT_TRANSFER_UD_MOTOR, DiActMotor.class);
// transUdMotor.setEnable(true);
// transUdMotor.reset();
// transUdMotor.moveTo("TransUdMotorStandby");
//
// this.setProgressMessage("设备初始化 : 搬运机械臂左右移动复位");
// DiActMotor transLrMotor = this.getActuator(MyDevice.ACT_TRANSFER_LR_MOTOR, DiActMotor.class);
// transLrMotor.setEnable(true);
// transLrMotor.reset();
// transLrMotor.moveTo("TransLrMotorStandby");
//
// for ( int i=0; i<5; i++ ) {
// this.setProgressMessage("设备初始化 : 加热盘转盘槽盖关闭 " + (i+1) + "/5");
// String key = "HeatingPlateMotorSlotCover_" + i;
// DiActServo heatSlotCoverServo = this.getActuator(key, DiActServo.class);
// heatSlotCoverServo.setEnable(true);
// heatSlotCoverServo.setCurrentPosAsMiddle();
// }
//
// // @TODO : http://127.0.0.1:5566/issues/39
// this.setProgressMessage("设备初始化 : 加液转盘复位");
// DiActMotor liquidPlateMotor = this.getActuator(MyDevice.ACT_LIQUID_PLATE_MOTOR, DiActMotor.class);
// liquidPlateMotor.setEnable(true);
// liquidPlateMotor.reset();
//
// // @TODO : http://127.0.0.1:5566/issues/40
// this.setProgressMessage("设备初始化 : 加热盘转盘复位");
// DiActMotor heatPlateMotor = this.getActuator(MyDevice.ACT_HEAT_PLATE_MOTOR, DiActMotor.class);
// heatPlateMotor.setEnable(true);
// heatPlateMotor.reset();
// heatPlateMotor.moveTo("HeatPlateStandby");
//
// int peristalticPumpCount = 1;
// var actuators = this.getDevice().getActuators().getAll();
// for ( var actuator : actuators ) {
// if (actuator instanceof DiActPeristalticPump pump) {
// this.setProgressMessage("设备初始化 : 蠕动泵复位 " + peristalticPumpCount + "/16");
// pump.setEnable(true);
// peristalticPumpCount++;
// }
// }
this.setProgressMessage("设备初始化 : 完成");
runtimeVars.set("IsDeviceReady", "YES");

11
src/web/package-lock.json

@ -9,6 +9,7 @@
"version": "0.1.0",
"dependencies": {
"@ant-design/icons-vue": "^7.0.1",
"animejs": "^3.2.2",
"ant-design-vue": "^4.1.1",
"axios": "^1.6.5",
"core-js": "^3.8.3",
@ -3546,6 +3547,11 @@
"ajv": "^6.9.1"
}
},
"node_modules/animejs": {
"version": "3.2.2",
"resolved": "https://registry.npmmirror.com/animejs/-/animejs-3.2.2.tgz",
"integrity": "sha512-Ao95qWLpDPXXM+WrmwcKbl6uNlC5tjnowlaRYtuVDHHoygjtIPfDUoK9NthrlZsQSKjZXlmji2TrBUAVbiH0LQ=="
},
"node_modules/ansi-colors": {
"version": "4.1.3",
"resolved": "https://registry.npmmirror.com/ansi-colors/-/ansi-colors-4.1.3.tgz",
@ -14707,6 +14713,11 @@
"dev": true,
"requires": {}
},
"animejs": {
"version": "3.2.2",
"resolved": "https://registry.npmmirror.com/animejs/-/animejs-3.2.2.tgz",
"integrity": "sha512-Ao95qWLpDPXXM+WrmwcKbl6uNlC5tjnowlaRYtuVDHHoygjtIPfDUoK9NthrlZsQSKjZXlmji2TrBUAVbiH0LQ=="
},
"ansi-colors": {
"version": "4.1.3",
"resolved": "https://registry.npmmirror.com/ansi-colors/-/ansi-colors-4.1.3.tgz",

1
src/web/package.json

@ -9,6 +9,7 @@
},
"dependencies": {
"@ant-design/icons-vue": "^7.0.1",
"animejs": "^3.2.2",
"ant-design-vue": "^4.1.1",
"axios": "^1.6.5",
"core-js": "^3.8.3",

35
src/web/src/pages/main/Page.vue

@ -17,9 +17,9 @@
</div>
</a-col>
<a-col :span="4" class="p-1">
<div class="h-full px-5 text-xl flex flex-row items-center justify-around">
<span class="bg-black text-white block py-2 px-4 rounded-full">A</span>
<span class="text-2xl font-bold">ADMIN</span>
<div v-if="null !== user" class="h-full px-5 text-xl flex flex-row items-center justify-around">
<span class="bg-black text-white block py-2 px-4 rounded-full">{{ user.account[0] }}</span>
<span class="text-2xl font-bold">{{ user.account }}</span>
</div>
</a-col>
</a-row>
@ -90,6 +90,8 @@ const loadingModal = ref(null);
const nowDate = ref('');
/** @var {Ref<string>} */
const nowTime = ref('');
/** @var {Ref<string>} */
const user = ref(null);
// on mounted
onMounted(mounted);
@ -97,19 +99,20 @@ onMounted(mounted);
async function mounted() {
loadingModal.value.show('设备正在初始化,请稍后...');
let client = ApiClient.getClient();
do {
let isDeviceReady = await client.deviceRuntimeVariableGet('IsDeviceReady');
if ( "YES" === isDeviceReady ) {
break ;
}
let isTaskStartResetExecuting = await client.deviceRuntimeVariableGet('IsTaskStartResetExecuting');
if ( "YES" !== isTaskStartResetExecuting ) {
await client.deviceStart();
await client.taskAppend('StartReset');
} else {
await Common.delay(1000);
}
} while (true);
user.value = await client.userCurrentGet();
// do {
// let isDeviceReady = await client.deviceRuntimeVariableGet('IsDeviceReady');
// if ( "YES" === isDeviceReady ) {
// break ;
// }
// let isTaskStartResetExecuting = await client.deviceRuntimeVariableGet('IsTaskStartResetExecuting');
// if ( "YES" !== isTaskStartResetExecuting ) {
// await client.deviceStart();
// await client.taskAppend('StartReset');
// } else {
// await Common.delay(1000);
// }
// } while (true);
loadingModal.value.hide();
refresh();
}

33
src/web/src/pages/main/contents/Operation.vue

@ -10,29 +10,7 @@
<a-col :span="10" class="p-1">
<div class="h-full flex flex-col bg-white rounded-2xl p-5">
<div class="h-0 grow flex flex-col">
<!-- <div class="text-xl text-blue-500 mb-3">
<img src="../../../assets/icon/heating.svg" class="inline-block w-6 h-6 mr-2" />
<span>石墨加热区</span>
</div> -->
<div class="heating-plate h-0 grow bg-green-400 flex flex-col justify-center items-center rounded-full">
<div class="relative w-1/4 h-1/4">
<div v-for="tubeRackSlot in tubeRackSlots" :key="tubeRackSlot.index" class="tube-rack-slot absolute h-full w-full"
:class="{active:tubeRackSlot.isLocked, heating:tubeRackSlot.isHeating}"
:style="{transform: `rotateZ(${(tubeRackSlot.index-1)*72}deg) translateY(140%)`}"
>
<div class="title absolute w-full text-center">
<p class="mb-1">A - {{ tubeRackSlot.index + 1 }}</p>
<p class="mb-0" v-if="null !== tubeRackSlot.digestionName">{{ tubeRackSlot.digestionName }}</p>
</div>
<a-row class="tube-rack p-1 rounded-lg h-full">
<a-col class="p-1" v-for="tubeIndex in 16" :key="tubeIndex" :span="6">
<div class="tube rounded-full h-full w-full"></div>
</a-col>
</a-row>
<!-- <div class="text-center" v-if="1==i"><a-badge status="success" /></div> -->
</div>
</div>
</div>
<operation-tube-racks :tube-rack-slots="tubeRackSlots"/>
</div>
<div class="mt-3">
<a-row>
@ -183,6 +161,7 @@ import ApiClient from '@/utils/ApiClient.js';
import OperationCamera from './OperationCamera.vue';
import OperationSampleAdd from './OperationSampleAdd.vue';
import OperationSampleTakeShot from './OperationSampleTakeShot.vue';
import OperationTubeRacks from './OperationTubeRacks.vue';
/** @var {Object} */
const sampleTakeout = ref({enable:false,slotIndex:0});
/** @var {Object} */
@ -211,6 +190,7 @@ function mounted() {
// unmounted
function unmounted() {
debugger;
clearTimeout(refreshTimer);
}
@ -350,11 +330,4 @@ function actionHeatingCancel() {
</script>
<style scoped>
.heating-plate {background: #EEEFF8;border: solid 12px #E5E7F2;}
.tube-rack-slot .title {font-size: 16px;font-weight: bold;letter-spacing: 0.06em;top:-45px;color: #D6D9F1;}
.tube-rack-slot.active .title {color:#26D574;}
.tube-rack-slot .tube-rack {background:#D6D9F1;}
.tube-rack-slot.active .tube-rack {background:#1B1B1B;}
.tube-rack-slot.heating .tube-rack {background:#ff5b5b;}
.tube-rack-slot .tube {background:#FFFFFF;}
.tube-rack-slot.active .tube {background:#26D574;}
</style>

78
src/web/src/pages/main/contents/OperationTubeRacks.vue

@ -0,0 +1,78 @@
<template>
<div ref="container" class="heating-plate h-0 grow bg-green-400 flex flex-col justify-center items-center rounded-full">
<div class="relative w-1/4 h-1/4">
<div v-for="tubeRackSlot in tubeRackSlots" :key="tubeRackSlot.index"
:class="getTubeRackSlotClass(tubeRackSlot)"
:style="{transform: `rotateZ(${(tubeRackSlot.index-1)*72}deg) translateY(140%)`}"
>
<div class="title absolute w-full text-center">
<p class="mb-1">
<span v-if="!tubeRackSlot.isErrorSlot">A - {{ tubeRackSlot.index + 1 }}</span>
<span v-else>异常</span>
</p>
<p class="mb-0" v-if="null !== tubeRackSlot.digestionName">{{ tubeRackSlot.digestionName }}</p>
</div>
<a-row class="tube-rack p-1 rounded-lg h-full"
:class="{'active': activeRackSlot?.index === tubeRackSlot.index }"
@click="actionActiveSlot(tubeRackSlot)"
>
<a-col class="p-1" v-for="tubeIndex in 16" :key="tubeIndex" :span="6">
<div class="tube rounded-full h-full w-full"></div>
</a-col>
</a-row>
</div>
</div>
</div>
</template>
<script setup>
import { ref } from 'vue';
import anime from 'animejs/lib/anime.es.js';
/** @var {Object} */
const props = defineProps({
tubeRackSlots: Array,
});
/** @var {Object} */
const activeRackSlot = ref(null);
/** @var {Object} */
const container = ref(null);
// get tube rack slot class
function getTubeRackSlotClass(tubeRackSlot) {
return {
'tube-rack-slot' : true,
'error-slot' : tubeRackSlot.isErrorSlot,
active: tubeRackSlot.isLocked,
heating: tubeRackSlot.isHeating,
};
}
// action active slot
function actionActiveSlot(tubeRackSlot) {
var animeOptions = {
targets: container.value,
rotate: '0deg',
duration: 1000,
easing: 'easeInOutQuad'
};
if ( tubeRackSlot.index === activeRackSlot.value?.index ) {
activeRackSlot.value = null;
anime(animeOptions);
} else {
activeRackSlot.value = tubeRackSlot;
animeOptions.rotate = `${72 - tubeRackSlot.index * 72}deg`;
anime(animeOptions);
}
}
</script>
<style scoped>
.tube-rack-slot {position: absolute;width: 100%;height: 100%;}
.tube-rack-slot .title {font-size: 16px;font-weight: bold;letter-spacing: 0.06em;top:-45px;color: #D6D9F1;}
.tube-rack-slot.active .title {color:#26D574;}
.tube-rack-slot .tube-rack {background:#D6D9F1;}
.tube-rack-slot.active .tube-rack {background:#1B1B1B;}
.tube-rack-slot.heating .tube-rack {background:#ff5b5b;}
.tube-rack-slot .tube {background:#FFFFFF;}
.tube-rack-slot.active .tube {background:#26D574;}
.tube-rack-slot.error-slot .tube {background:#8799AB;}
.tube-rack.active {border: solid 2px #007BFF;}
</style>

107
src/web/src/pages/main/contents/UserManagement.vue

@ -1,6 +1,11 @@
<template>
<div class="p-1">
<a-table :dataSource="dataSource" :columns="columns">
<template #headerCell="{column}">
<template v-if="column.key === 'action'">
<a-button @click="actionCreate"><PlusCircleOutlined /></a-button>
</template>
</template>
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'roleName'">
{{ record.role.name }}
@ -10,28 +15,67 @@
</template>
<template v-else-if="'action' === column.key">
<a-popconfirm title="是否删除该用户?" @confirm="actionDelete(record)">
<a-button class="ml-1" disabled>删除</a-button>
<a-button class="ml-1">删除</a-button>
</a-popconfirm>
<a-button class="ml-1" disabled>修改权限</a-button>
<a-button class="ml-1" disabled>修改密码</a-button>
<a-button class="ml-1" @click="actionPasswordUpdate(record)">修改密码</a-button>
<a-button class="ml-1" @click="actionUpdate(record)">编辑</a-button>
</template>
</template>
</a-table>
<!-- 用户编辑 -->
<a-modal v-if="null !== edit" :open="null !== edit"
title="用户编辑"
ok-text="确定"
cancel-text="取消"
@ok="actionEditSave"
@cancel="actionEditCancel"
>
<a-form :label-col="{span:4}" :wrapper-col="{span:20}" label-align="left">
<a-form-item label="用户名">
<a-input v-model:value="edit.account" />
</a-form-item>
<a-form-item label="角色">
<a-radio-group v-model:value="edit.roleId">
<a-radio :value="1">管理员</a-radio>
<a-radio :value="2">普通用户</a-radio>
</a-radio-group>
</a-form-item>
</a-form>
</a-modal>
<!-- 修改密码 -->
<a-modal v-if="null !== password" :open="null !== password"
title="修改密码"
ok-text="确定"
cancel-text="取消"
@ok="actionPasswordEditSave"
@cancel="actionPasswordEditCancel"
>
<a-form :label-col="{span:4}" :wrapper-col="{span:20}" label-align="left">
<a-form-item label="新密码">
<a-input v-model:value="password.content" />
</a-form-item>
</a-form>
</a-modal>
</div>
</template>
<script setup>
import ApiClient from '@/utils/ApiClient';
import { onMounted, ref } from 'vue';
/** @var {Array<Object>} */
const columns = [
const columns = ref([
{key:'account',dataIndex:'account',title:'用户名',align:'center'},
{key:'roleName',title:'权限',align:'center'},
{key:'createdAt',dataIndex: 'createdAt',title:'创建时间',align:'center'},
{key:'action',title:'操作',align:'center'},
];
{key:'action',title:'操作',align:'right'},
]);
/** @var {Array<Object>} */
const dataSource = ref([]);
/** @var {Object} */
const edit = ref(null);
/** @var {Object} */
const password = ref(null);
/** @var {ApiClient} */
let client = null;
// on mounted
@ -40,6 +84,10 @@ onMounted(mounted);
// mounted
async function mounted() {
client = ApiClient.getClient();
let currentUser = await client.userCurrentGet();
if ( 2 === currentUser.roleId ) {
columns.value = columns.value.filter(column => 'action' !== column.key);
}
await refresh();
}
@ -71,4 +119,49 @@ async function actionDelete(record) {
await client.userDelete(record.id);
await refresh();
}
// action create
function actionCreate() {
edit.value = {account:'',roleId:2};
}
// action update
function actionUpdate(record) {
edit.value = structuredClone(record);
}
// action edit save
async function actionEditSave() {
let id = edit.value.id;
await client.userSave({
id: id,
data : edit.value,
});
await refresh();
edit.value = null;
}
// action edit cancel
async function actionEditCancel() {
edit.value = null;
}
// action password update
function actionPasswordUpdate(record) {
password.value = {id:record.id,content:''};
}
// action password edit save
async function actionPasswordEditSave() {
await client.userPasswordUpdate({
id: password.value.id,
password: password.value.content,
});
password.value = null;
}
// action password edit cancel
function actionPasswordEditCancel() {
password.value = null;
}
</script>

15
src/web/src/utils/ApiClient.js

@ -63,6 +63,21 @@ export default class ApiClient {
return await this.call('user/delete', {id});
}
// user create
async userSave( params ) {
return await this.call('user/save', params);
}
// user current get
async userCurrentGet() {
return await this.call('user/current-get');
}
// user password update
async userPasswordUpdate( params ) {
return await this.call('user/password-update', params);
}
// get device runtime variable value
async deviceRuntimeVariableGet( name ) {
let response = await this.call('device/runtime-variable/get', {name});

Loading…
Cancel
Save