| src/main/java/com/zy/asrs/controller/OpenController.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/main/java/com/zy/asrs/enums/RedisKeyType.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/main/java/com/zy/system/controller/AnnouncementController.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/main/java/com/zy/system/entity/Announcement.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/main/java/com/zy/system/mapper/AnnouncementMapper.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/main/java/com/zy/system/service/AnnouncementService.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/main/java/com/zy/system/service/impl/AnnouncementServiceImpl.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/main/resources/mapper/AnnouncementMapper.xml | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/main/webapp/views/announcement/announcement.html | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/main/webapp/views/tvDevice/tvDevice.html | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 |
src/main/java/com/zy/asrs/controller/OpenController.java
@@ -1,7 +1,9 @@ package com.zy.asrs.controller; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.baomidou.mybatisplus.mapper.EntityWrapper; import com.core.annotations.ManagerAuth; import com.core.common.Cools; import com.core.common.R; import com.zy.asrs.entity.BasStationTv; @@ -16,6 +18,8 @@ import com.zy.asrs.utils.StationUtils; import com.zy.asrs.utils.Utils; import com.zy.common.utils.RedisUtil; import com.zy.system.entity.Announcement; import com.zy.system.service.AnnouncementService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; import org.springframework.web.bind.annotation.*; @@ -40,6 +44,8 @@ private StationUtils stationUtils; @Autowired private RedisUtil redisUtil; @Autowired private AnnouncementService announcementService; @Value("${app.version:1.0.0}") private String appVersion; @@ -77,6 +83,12 @@ } String manualError = ""; Object manualErrorObj = redisUtil.get(RedisKeyType.TV_MANUAL_ERROR_MSG.key); if (manualErrorObj != null) { manualError = String.valueOf(manualErrorObj); } List<TvDataDto> list = new ArrayList<>(); for (BasStationTv relation : relations) { WcsStationDto wcsStationDto = stationUtils.stationMap.get(relation.getStationId()); @@ -97,6 +109,12 @@ if (!Cools.isEmpty(wcsStationDto.getSystemWarning())) { errorMsg += wcsStationDto.getSystemWarning(); } if (!Cools.isEmpty(manualError)) { if (!Cools.isEmpty(errorMsg)) { errorMsg += ";"; } errorMsg += manualError; } TvDataDto tvDataDto = new TvDataDto(); tvDataDto.setStationId(wcsStationDto.getStationId()); @@ -118,6 +136,84 @@ return R.ok().add(list); } @GetMapping("/getError") public R getError(HttpServletRequest request) { Set<String> errors = new LinkedHashSet<>(); Object manualErrorObj = redisUtil.get(RedisKeyType.TV_MANUAL_ERROR_MSG.key); String manualError = manualErrorObj == null ? "" : String.valueOf(manualErrorObj); if (!Cools.isEmpty(manualError)) { errors.add(manualError); } String remoteAddr = request.getRemoteAddr(); TvDevice tvDevice = tvDeviceService.selectOne( new EntityWrapper<TvDevice>().eq("ip", remoteAddr)); if (tvDevice != null) { List<BasStationTv> relations = basStationTvService .selectList(new EntityWrapper<BasStationTv>().eq("tv_id", tvDevice.getId())); if (relations != null && !relations.isEmpty()) { for (BasStationTv relation : relations) { WcsStationDto wcsStationDto = stationUtils.stationMap.get(relation.getStationId()); if (wcsStationDto == null) { continue; } if (wcsStationDto.getLoading() != 1) { continue; } String deviceError = ""; if (!Cools.isEmpty(wcsStationDto.getErrorMsg())) { deviceError += wcsStationDto.getErrorMsg(); } if (!Cools.isEmpty(wcsStationDto.getSystemWarning())) { if (!Cools.isEmpty(deviceError)) { deviceError += ";"; } deviceError += wcsStationDto.getSystemWarning(); } if (!Cools.isEmpty(deviceError)) { errors.add(deviceError); } } } } String errorMsg = String.join(";", errors); Map<String, Object> result = new HashMap<>(); result.put("errorMsg", errorMsg); return R.ok(result); } @GetMapping("/manualError/auth") @ManagerAuth public R getManualErrorAuth() { Object manualErrorObj = redisUtil.get(RedisKeyType.TV_MANUAL_ERROR_MSG.key); String manualError = manualErrorObj == null ? "" : String.valueOf(manualErrorObj); Map<String, Object> result = new HashMap<>(); result.put("manualError", manualError); return R.ok(result); } @PostMapping("/manualError/auth") @ManagerAuth public R setManualError(@RequestBody JSONObject param) { String manualError = param.getString("manualError"); if (Cools.isEmpty(manualError)) { redisUtil.del(RedisKeyType.TV_MANUAL_ERROR_MSG.key); return R.ok(); } redisUtil.set(RedisKeyType.TV_MANUAL_ERROR_MSG.key, manualError); return R.ok(); } @GetMapping("/announcement") public R top5(){ EntityWrapper<Announcement> wrapper = new EntityWrapper<>(); wrapper.eq("status", 1); wrapper.orderBy("create_time", false); wrapper.last("limit 5"); return R.ok(announcementService.selectList(wrapper)); } /** * 获取当前时间 */ src/main/java/com/zy/asrs/enums/RedisKeyType.java
@@ -5,6 +5,7 @@ TV_LOC_DATA_DTO("tvLocDataDto"), TV_LINE_CHARTS("tvLineCharts"), TV_LOC_DETL_STATISTICS("tvLocDetlStatistics"), TV_MANUAL_ERROR_MSG("tvManualErrorMsg"), ; public String key; src/main/java/com/zy/system/controller/AnnouncementController.java
New file @@ -0,0 +1,128 @@ package com.zy.system.controller; import com.alibaba.fastjson.JSONObject; import com.baomidou.mybatisplus.mapper.EntityWrapper; import com.baomidou.mybatisplus.plugins.Page; import com.core.annotations.ManagerAuth; import com.core.common.Cools; import com.core.common.DateUtils; import com.core.common.R; import com.core.controller.AbstractBaseController; import com.zy.system.entity.Announcement; import com.zy.system.service.AnnouncementService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; import java.util.*; @RestController public class AnnouncementController extends AbstractBaseController { @Autowired private AnnouncementService announcementService; @RequestMapping(value = "/announcement/{id}/auth") @ManagerAuth public R get(@PathVariable("id") Long id) { return R.ok(announcementService.selectById(String.valueOf(id))); } @RequestMapping(value = "/announcement/list/auth") @ManagerAuth public R list(@RequestParam(defaultValue = "1")Integer curr, @RequestParam(defaultValue = "10")Integer limit, @RequestParam(required = false)String orderByField, @RequestParam(required = false)String orderByType, @RequestParam Map<String, Object> param){ excludeTrash(param); EntityWrapper<Announcement> wrapper = new EntityWrapper<>(); convert(param, wrapper); if (!Cools.isEmpty(orderByField)){ wrapper.orderBy(humpToLine(orderByField), "asc".equals(orderByType)); } return R.ok(announcementService.selectPage(new Page<>(curr, limit), wrapper)); } private void convert(Map<String, Object> map, EntityWrapper wrapper){ for (Map.Entry<String, Object> entry : map.entrySet()){ if ("status".equals(entry.getKey())) { wrapper.eq(entry.getKey(), entry.getValue()); continue; } if (entry.getKey().endsWith(">")) { wrapper.ge(Cools.deleteChar(entry.getKey()), DateUtils.convert(String.valueOf(entry.getValue()))); } else if (entry.getKey().endsWith("<")) { wrapper.le(Cools.deleteChar(entry.getKey()), DateUtils.convert(String.valueOf(entry.getValue()))); } else { wrapper.like(entry.getKey(), String.valueOf(entry.getValue())); } } } @RequestMapping(value = "/announcement/edit/auth") @ManagerAuth public R edit(Announcement announcement) { if (Cools.isEmpty(announcement)){ return R.error(); } if (null == announcement.getId()){ announcement.setCreateTime(new Date()); announcement.setUpdateTime(new Date()); announcementService.insert(announcement); } else { announcement.setUpdateTime(new Date()); announcementService.updateById(announcement); } return R.ok(); } @RequestMapping(value = "/announcement/add/auth") @ManagerAuth public R add(Announcement announcement) { announcement.setCreateTime(new Date()); announcement.setUpdateTime(new Date()); announcementService.insert(announcement); return R.ok(); } @RequestMapping(value = "/announcement/update/auth") @ManagerAuth public R update(Announcement announcement){ if (Cools.isEmpty(announcement) || null==announcement.getId()){ return R.error(); } announcement.setUpdateTime(new Date()); announcementService.updateById(announcement); return R.ok(); } @RequestMapping(value = "/announcement/delete/auth") @ManagerAuth public R delete(Integer[] ids){ if (Cools.isEmpty(ids)){ return R.error(); } announcementService.deleteBatchIds(Arrays.asList(ids)); return R.ok(); } @RequestMapping(value = "/announcement/export/auth") @ManagerAuth public R export(@RequestBody JSONObject param){ List<String> fields = JSONObject.parseArray(param.getJSONArray("fields").toJSONString(), String.class); EntityWrapper<Announcement> wrapper = new EntityWrapper<>(); Map<String, Object> map = excludeTrash(param.getJSONObject("announcement")); convert(map, wrapper); List<Announcement> list = announcementService.selectList(wrapper); return R.ok(exportSupport(list, fields)); } @GetMapping("/announcement/top5") public R top5(){ EntityWrapper<Announcement> wrapper = new EntityWrapper<>(); wrapper.eq("status", 1); wrapper.orderBy("create_time", false); wrapper.last("limit 5"); return R.ok(announcementService.selectList(wrapper)); } } src/main/java/com/zy/system/entity/Announcement.java
New file @@ -0,0 +1,108 @@ package com.zy.system.entity; import com.baomidou.mybatisplus.annotations.TableField; import com.baomidou.mybatisplus.annotations.TableId; import com.baomidou.mybatisplus.annotations.TableName; import com.baomidou.mybatisplus.enums.IdType; import com.core.common.Cools; import java.io.Serializable; import java.text.SimpleDateFormat; import java.util.Date; @TableName("sys_announcement") public class Announcement implements Serializable { private static final long serialVersionUID = 1L; @TableId(value = "id", type = IdType.AUTO) private Long id; private String title; private String content; private Integer status; @TableField("create_time") private Date createTime; @TableField("update_time") private Date updateTime; public Announcement() {} public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public String getContent() { return content; } public void setContent(String content) { this.content = content; } public Integer getStatus() { return status; } public String getStatus$() { if (null == this.status) { return null; } switch (this.status) { case 1: return "正常"; case 0: return "禁用"; default: return String.valueOf(this.status); } } public void setStatus(Integer status) { this.status = status; } public Date getCreateTime() { return createTime; } public String getCreateTime$() { if (Cools.isEmpty(this.createTime)) { return ""; } return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(this.createTime); } public void setCreateTime(Date createTime) { this.createTime = createTime; } public Date getUpdateTime() { return updateTime; } public String getUpdateTime$() { if (Cools.isEmpty(this.updateTime)) { return ""; } return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(this.updateTime); } public void setUpdateTime(Date updateTime) { this.updateTime = updateTime; } } src/main/java/com/zy/system/mapper/AnnouncementMapper.java
New file @@ -0,0 +1,11 @@ package com.zy.system.mapper; import com.baomidou.mybatisplus.mapper.BaseMapper; import com.zy.system.entity.Announcement; import org.apache.ibatis.annotations.Mapper; import org.springframework.stereotype.Repository; @Mapper @Repository public interface AnnouncementMapper extends BaseMapper<Announcement> { } src/main/java/com/zy/system/service/AnnouncementService.java
New file @@ -0,0 +1,7 @@ package com.zy.system.service; import com.baomidou.mybatisplus.service.IService; import com.zy.system.entity.Announcement; public interface AnnouncementService extends IService<Announcement> { } src/main/java/com/zy/system/service/impl/AnnouncementServiceImpl.java
New file @@ -0,0 +1,11 @@ package com.zy.system.service.impl; import com.baomidou.mybatisplus.service.impl.ServiceImpl; import com.zy.system.entity.Announcement; import com.zy.system.mapper.AnnouncementMapper; import com.zy.system.service.AnnouncementService; import org.springframework.stereotype.Service; @Service("announcementService") public class AnnouncementServiceImpl extends ServiceImpl<AnnouncementMapper, Announcement> implements AnnouncementService { } src/main/resources/mapper/AnnouncementMapper.xml
New file @@ -0,0 +1,14 @@ <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.zy.system.mapper.AnnouncementMapper"> <resultMap id="BaseResultMap" type="com.zy.system.entity.Announcement"> <id column="id" property="id" /> <result column="title" property="title" /> <result column="content" property="content" /> <result column="status" property="status" /> <result column="create_time" property="createTime" /> <result column="update_time" property="updateTime" /> </resultMap> </mapper> src/main/webapp/views/announcement/announcement.html
New file @@ -0,0 +1,405 @@ <!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="utf-8"> <title>系统公告管理</title> <meta name="renderer" content="webkit"> <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"> <link rel="stylesheet" href="../../static/vue/element/element.css"> <style> * { margin: 0; padding: 0; box-sizing: border-box; } body { font-family: 'Helvetica Neue', Helvetica, 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', Arial, sans-serif; background: #f5f7fa; padding: 15px; } .app-container { background: #fff; border-radius: 8px; box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1); padding: 20px; } .header-section { display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px; flex-wrap: wrap; gap: 10px; } .search-section { display: flex; gap: 10px; flex-wrap: wrap; align-items: center; } .action-buttons { display: flex; gap: 10px; } .table-section { margin-top: 15px; } .pagination-section { margin-top: 20px; display: flex; justify-content: flex-end; } </style> </head> <body> <div id="app"> <div class="app-container" v-loading="tableLoading"> <div class="header-section"> <div class="search-section"> <el-input v-model="searchForm.title" placeholder="标题" size="small" clearable style="width: 180px;"> </el-input> <el-select v-model="searchForm.status" placeholder="状态" clearable size="small" style="width: 120px;"> <el-option label="正常" value="1"></el-option> <el-option label="禁用" value="0"></el-option> </el-select> <el-button type="primary" size="small" icon="el-icon-search" @click="handleSearch">搜索</el-button> <el-button size="small" icon="el-icon-refresh-left" @click="handleReset">重置</el-button> </div> <div class="action-buttons"> <el-button type="primary" size="small" icon="el-icon-plus" @click="openAdd">新增</el-button> <el-button type="danger" size="small" icon="el-icon-delete" @click="handleBatchDelete" :disabled="selectedRows.length === 0">删除</el-button> <!-- <el-button size="small" icon="el-icon-download" @click="handleExport">导出</el-button> --> </div> </div> <div class="table-section"> <el-table :data="tableData" border stripe @selection-change="handleSelectionChange" style="width: 100%;" :header-cell-style="{ background: '#f5f7fa', color: '#606266' }"> <el-table-column type="selection" width="50" align="center"></el-table-column> <el-table-column prop="id" label="ID" width="70" align="center"></el-table-column> <el-table-column prop="title" label="标题" min-width="160" show-overflow-tooltip></el-table-column> <el-table-column prop="content" label="内容" min-width="260" show-overflow-tooltip></el-table-column> <el-table-column prop="status$" label="状态" width="90" align="center"></el-table-column> <el-table-column prop="createTime$" label="创建时间" width="170" align="center"></el-table-column> <el-table-column prop="updateTime$" label="修改时间" width="170" align="center"></el-table-column> <el-table-column label="操作" width="160" align="center" fixed="right"> <template slot-scope="scope"> <el-button type="text" size="small" @click="openDetail(scope.row)">详情</el-button> <el-button type="text" size="small" @click="openEdit(scope.row)">编辑</el-button> <el-button type="text" size="small" style="color:#f56c6c" @click="handleDelete(scope.row)">删除</el-button> </template> </el-table-column> </el-table> </div> <div class="pagination-section"> <el-pagination background layout="total, sizes, prev, pager, next, jumper" :total="total" :page-size="pageSize" :current-page="currentPage" :page-sizes="[10, 20, 50, 100]" @size-change="handleSizeChange" @current-change="handlePageChange"> </el-pagination> </div> </div> <el-dialog :title="dialogTitle" :visible.sync="dialogVisible" width="520px" :close-on-click-modal="false"> <el-form ref="formRef" :model="formData" :rules="formRules" label-width="80px"> <el-form-item label="标题" prop="title"> <el-input v-model="formData.title" :disabled="isDetail"></el-input> </el-form-item> <el-form-item label="内容" prop="content"> <el-input type="textarea" v-model="formData.content" :rows="5" :disabled="isDetail"></el-input> </el-form-item> <el-form-item label="状态" prop="status"> <el-select v-model="formData.status" :disabled="isDetail" style="width: 140px;"> <el-option label="正常" value="1"></el-option> <el-option label="禁用" value="0"></el-option> </el-select> </el-form-item> </el-form> <div slot="footer" class="dialog-footer"> <el-button @click="dialogVisible = false">取消</el-button> <el-button type="primary" @click="submitForm" v-if="!isDetail" :loading="submitting">保存</el-button> </div> </el-dialog> </div> <script src="../../static/vue/js/vue.min.js"></script> <script src="../../static/vue/element/element.js"></script> <script src="../../static/js/jquery/jquery-3.3.1.min.js"></script> <script src="../../static/js/common.js"></script> <script> new Vue({ el: '#app', data: { tableData: [], tableLoading: false, total: 0, currentPage: 1, pageSize: 10, selectedRows: [], searchForm: { title: '', status: '' }, dialogVisible: false, dialogMode: 'add', submitting: false, formData: { id: '', title: '', content: '', status: '1' }, formRules: { title: [{ required: true, message: '请输入标题', trigger: 'blur' }], content: [{ required: true, message: '请输入内容', trigger: 'blur' }], status: [{ required: true, message: '请选择状态', trigger: 'change' }] } }, computed: { isDetail() { return this.dialogMode === 'detail'; }, dialogTitle() { if (this.dialogMode === 'add') { return '新增公告'; } if (this.dialogMode === 'edit') { return '编辑公告'; } return '公告详情'; } }, created() { this.loadData(); }, methods: { getHeaders() { return { 'token': localStorage.getItem('token') }; }, loadData() { this.tableLoading = true; const params = { curr: this.currentPage, limit: this.pageSize, ...this.searchForm }; $.ajax({ url: baseUrl + '/announcement/list/auth', headers: this.getHeaders(), data: params, success: (res) => { this.tableLoading = false; if (res.code === 200) { this.tableData = res.data.records || []; this.total = res.data.total || 0; } else if (res.code === 403) { top.location.href = baseUrl + '/'; } else { this.$message.error(res.msg || '加载失败'); } }, error: () => { this.tableLoading = false; this.$message.error('请求失败'); } }); }, handleSearch() { this.currentPage = 1; this.loadData(); }, handleReset() { this.searchForm = { title: '', status: '' }; this.currentPage = 1; this.loadData(); }, handleSizeChange(size) { this.pageSize = size; this.currentPage = 1; this.loadData(); }, handlePageChange(page) { this.currentPage = page; this.loadData(); }, handleSelectionChange(rows) { this.selectedRows = rows; }, openAdd() { this.dialogMode = 'add'; this.formData = { id: '', title: '', content: '', status: '1' }; this.dialogVisible = true; this.$nextTick(() => { if (this.$refs.formRef) { this.$refs.formRef.clearValidate(); } }); }, openEdit(row) { this.dialogMode = 'edit'; this.formData = { id: row.id, title: row.title, content: row.content, status: String(row.status) }; this.dialogVisible = true; this.$nextTick(() => { if (this.$refs.formRef) { this.$refs.formRef.clearValidate(); } }); }, openDetail(row) { this.dialogMode = 'detail'; this.formData = { id: row.id, title: row.title, content: row.content, status: String(row.status) }; this.dialogVisible = true; }, submitForm() { this.$refs.formRef.validate((valid) => { if (!valid) { return; } this.submitting = true; const payload = { id: this.formData.id, title: this.formData.title, content: this.formData.content, status: this.formData.status }; $.ajax({ url: baseUrl + '/announcement/edit/auth', headers: this.getHeaders(), data: payload, method: 'POST', success: (res) => { this.submitting = false; if (res.code === 200) { this.$message.success('保存成功'); this.dialogVisible = false; this.loadData(); } else if (res.code === 403) { top.location.href = baseUrl + '/'; } else { this.$message.error(res.msg || '保存失败'); } }, error: () => { this.submitting = false; this.$message.error('请求失败'); } }); }); }, handleDelete(row) { this.$confirm('确定删除该公告吗?', '提示', { type: 'warning' }).then(() => { $.ajax({ url: baseUrl + '/announcement/delete/auth', headers: this.getHeaders(), data: { ids: [row.id] }, method: 'POST', traditional: true, success: (res) => { if (res.code === 200) { this.$message.success('删除成功'); this.loadData(); } else if (res.code === 403) { top.location.href = baseUrl + '/'; } else { this.$message.error(res.msg || '删除失败'); } } }); }).catch(() => {}); }, handleBatchDelete() { const ids = this.selectedRows.map(item => item.id); if (!ids.length) { this.$message.warning('请选择数据'); return; } this.$confirm('确定删除选中的公告吗?', '提示', { type: 'warning' }).then(() => { $.ajax({ url: baseUrl + '/announcement/delete/auth', headers: this.getHeaders(), data: { ids: ids }, method: 'POST', traditional: true, success: (res) => { if (res.code === 200) { this.$message.success('删除成功'); this.selectedRows = []; this.loadData(); } else if (res.code === 403) { top.location.href = baseUrl + '/'; } else { this.$message.error(res.msg || '删除失败'); } } }); }).catch(() => {}); }, handleExport() { const fields = ['id', 'title', 'content', 'status', 'createTime', 'updateTime']; const titles = ['ID', '标题', '内容', '状态', '创建时间', '修改时间']; const params = { announcement: { ...this.searchForm }, fields: fields }; $.ajax({ url: baseUrl + '/announcement/export/auth', headers: this.getHeaders(), data: JSON.stringify(params), dataType: 'json', contentType: 'application/json;charset=UTF-8', method: 'POST', success: (res) => { if (res.code === 200) { const rows = res.data || []; const csvRows = [titles.join(',')]; rows.forEach(row => { const values = fields.map(field => { const value = row[field]; const text = value == null ? '' : String(value).replace(/"/g, '""'); return `"${text}"`; }); csvRows.push(values.join(',')); }); const blob = new Blob([csvRows.join('\n')], { type: 'text/csv;charset=utf-8;' }); const link = document.createElement('a'); link.href = URL.createObjectURL(blob); link.download = 'announcement.csv'; document.body.appendChild(link); link.click(); document.body.removeChild(link); } else if (res.code === 403) { top.location.href = baseUrl + '/'; } else { this.$message.error(res.msg || '导出失败'); } } }); } } }); </script> </body> </html> src/main/webapp/views/tvDevice/tvDevice.html
@@ -157,6 +157,24 @@ </div> </div> <div style="margin-bottom: 15px;"> <el-card shadow="hover"> <div slot="header"> <span>手动异常信息</span> </div> <el-form label-position="top" size="small"> <el-form-item label="异常信息"> <el-input type="textarea" v-model="manualError" :rows="3" placeholder="输入需要下发到设备的异常信息"></el-input> </el-form-item> <el-button type="primary" size="small" @click="saveManualError" :loading="manualErrorSaving">保存</el-button> <el-button size="small" @click="clearManualError" :disabled="manualErrorSaving">清空</el-button> </el-form> </el-card> </div> <!-- 表格区域 --> <div class="table-section"> <el-table :data="tableData" border stripe @selection-change="handleSelectionChange" style="width: 100%;" @@ -222,12 +240,9 @@ <el-select v-model="installForm.taskId" placeholder="请选择已完成的打包任务" style="width: 100%;" filterable> <el-option v-for="task in completedTasks" :key="task.id" :label="task.projectName || task.taskId" :value="task.id" :label="buildTaskLabel(task)" :value="task.id" :disabled="!task.apkPath"> <span>{{ task.projectName || task.repoAlias }}</span> <span style="float: right; color: #909399; font-size: 12px;"> {{ task.apkPath ? '已下载' : '未下载' }} </span> <span>{{ buildTaskLabel(task) }}</span> </el-option> </el-select> </el-form-item> @@ -430,7 +445,10 @@ screenshotImage: '', screenshotLoading: false, autoRefreshScreenshot: false, screenshotTimer: null screenshotTimer: null, manualError: '', manualErrorSaving: false }, computed: { @@ -449,12 +467,60 @@ this.loadData(); this.loadAllDevices(); this.loadCompletedTasks(); this.loadManualError(); }, methods: { // 获取请求头 getHeaders() { return { 'token': localStorage.getItem('token') }; }, loadManualError() { $.ajax({ url: baseUrl + '/openapi/manualError/auth', headers: this.getHeaders(), method: 'GET', success: (res) => { if (res.code === 200) { this.manualError = (res.data && res.data.manualError) ? res.data.manualError : ''; } else if (res.code === 403) { top.location.href = baseUrl + '/'; } else { this.$message.error(res.msg || '加载失败'); } }, error: () => { this.$message.error('请求失败'); } }); }, saveManualError() { this.manualErrorSaving = true; $.ajax({ url: baseUrl + '/openapi/manualError/auth', headers: this.getHeaders(), method: 'POST', contentType: 'application/json;charset=UTF-8', data: JSON.stringify({ manualError: this.manualError }), success: (res) => { this.manualErrorSaving = false; if (res.code === 200) { this.$message.success('保存成功'); } else if (res.code === 403) { top.location.href = baseUrl + '/'; } else { this.$message.error(res.msg || '保存失败'); } }, error: () => { this.manualErrorSaving = false; this.$message.error('请求失败'); } }); }, clearManualError() { this.manualError = ''; this.saveManualError(); }, // 加载数据 @@ -951,6 +1017,14 @@ this.$message.error('上传失败'); }, buildTaskLabel(task) { const name = task.projectName || task.repoAlias || task.taskId || ''; const time = this.formatDate(task.createdAt) || '-'; const id = task.id != null ? task.id : ''; const status = task.apkPath ? '已下载' : '未下载'; return `${name} | ID: ${id} | ${time} | ${status}`; }, // 格式化日期 formatDate(timestamp) { if (!timestamp) return ''; @@ -968,4 +1042,4 @@ </script> </body> </html> </html>