活动介绍

``` btn.click = on click; ```

时间: 2024-12-06 11:14:42 浏览: 46
这段代码是JavaScript语法,看起来像是尝试给一个名为"btn"的按钮对象添加点击事件处理函数。原始的写法`btn.click = on click;`在JavaScript中是错误的,应该是使用括号和参数来定义回调函数,如下: ```javascript // 原始错误的写法(假设on click是一个函数) // btn.click = on click; // 错误 // 正确的写法 btn.addEventListener('click', onClickFunction); function onClickFunction() { // 在这里编写你的点击事件处理逻辑 } ``` 优化说明: 1. 使用`addEventListener`方法替代直接赋值,这样可以更好地支持事件代理和防止重复绑定。 2. 定义一个独立的函数作为事件处理器,使代码更清晰且易于维护。 优化后的完整代码: ```markdown ```javascript // 定义事件处理函数 function onClickFunction() { // 在这里编写你的点击事件处理逻辑 } // 绑定点击事件 var btn = document.getElementById('yourButtonId'); // 替换为实际的按钮元素ID btn.addEventListener('click', onClickFunction); ``` ``` 这里假设`yourButtonId`是你需要操作的实际按钮的ID。确保已经替换为正确的元素ID,并且`onClickFunction`函数已经被正确实现。
阅读全文

相关推荐

<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>语音识别工具</title> <style> body { font-family: Arial, sans-serif; max-width: 600px; margin: 20px auto; padding: 20px; } button { padding: 10px 20px; font-size: 16px; cursor: pointer; } .status { margin-top: 20px; font-weight: bold; min-height: 24px; } .result { margin-top: 10px; min-height: 60px; border: 1px solid #ccc; padding: 10px; background-color: #f9f9f9; } .btn-active { background-color: #ff4d4f; color: white; } #retry-btn { margin-top: 10px; background-color: #1890ff; color: white; border: none; } </style> </head> <body> 语音识别助手 <button id="start-btn" class="start-btn">开始识别</button>

<button id="end-btn" class="end-btn" disabled>停止识别</button>
等待开始... <script> // 检查浏览器支持 if (!('SpeechRecognition' in window || 'webkitSpeechRecognition' in window)) { document.getElementById('status').textContent = '抱歉,您的浏览器不支持语音识别'; } else { var SpeechRecognition = SpeechRecognition || webkitSpeechRecognition; let sr = new SpeechRecognition(); // 配置识别参数 sr.continuous = true; // 持续识别 sr.interimResults = true; // 返回中间结果 sr.lang = 'zh-CN'; // 设置语言为中文 // 元素引用 let startBtn = document.getElementById('start-btn'); let endBtn = document.getElementById('end-btn'); let status = document.getElementById('status'); let result = document.getElementById('result'); // 处理识别结果 sr.onresult = function(e) { let transcript = ''; for (let i = e.resultIndex; i < e.results.length; i++) { transcript += e.results[i][0].transcript; } result.textContent = transcript; console.log("识别结果: " + transcript); }; // 识别开始 sr.onstart = function() { status.textContent = '正在识别...'; startBtn.disabled = true; endBtn.disabled = false; startBtn.classList.add('btn-active'); }; // 识别结束 sr.onend = function() { status.textContent = '识别已结束'; startBtn.disabled = false; endBtn.disabled = true; startBtn.classList.remove('btn-active'); // 移除重试按钮 let retryBtn = document.getElementById('retry-btn'); if (retryBtn) { document.body.removeChild(retryBtn); } }; // 错误处理 - 增强版 sr.onerror = function(e) { let errorMsg = '识别错误: ' + e.error; status.textContent = errorMsg; console.error(errorMsg, e); // 针对网络错误的特殊处理 if (e.error === 'network') { status.textContent += ' - 网络连接问题'; // 添加重试按钮(如果不存在) if (!document.getElementById('retry-btn')) { let retryBtn = document.createElement('button'); retryBtn.id = 'retry-btn'; retryBtn.textContent = '重试识别'; retryBtn.onclick = function() { document.body.removeChild(retryBtn); startBtn.click(); // 触发开始识别 }; document.body.appendChild(retryBtn); } } }; // 网络状态监测 window.addEventListener('online', function() { status.textContent = '网络已恢复,可尝试重新开始识别'; }); window.addEventListener('offline', function() { status.textContent = '网络连接已断开'; if (sr) sr.stop(); // 网络断开时停止识别 }); // 按钮事件 startBtn.onclick = function() { console.log("请求麦克风权限并开始识别"); // 检查网络状态 if (!navigator.onLine) { status.textContent = '请检查网络连接'; return; } try { sr.start(); } catch (err) { status.textContent = '请在安全连接下使用(HTTPS)'; console.error('启动识别失败:', err); } }; endBtn.onclick = function() { console.log("停止识别"); sr.stop(); }; // 初始网络状态检查 if (!navigator.onLine) { status.textContent = '请检查网络连接'; } } </script> </body> </html>如何实现离线语音识别功能

解读学习代码: <script setup> import { carManGetService, carManStartService, carManStopService, carManDelService, vidallDataGetService } from '@/api/cloud.js' import { Plus, Delete, Edit, Search, Refresh } from '@element-plus/icons-vue' import { ref } from 'vue' import AddCar from './components/AddCar.vue' import SureDevice from './components/SureDevice.vue' import zhCn from 'element-plus/dist/locale/zh-cn.mjs' import CarvidSelect from '@/views/manage/components/CarvidSelect.vue' import DevcidSelect from '@/views/manage/components/DevcidSelect.vue' import { Picture as IconPicture } from '@element-plus/icons-vue' import { ElMessage, ElMessageBox, ElEmpty } from 'element-plus' const tableRef = ref([]) const carManDataList = ref([]) const total = ref(0) const updateDialog = ref() const deviceDialog = ref() // const editDialog = ref() const tableSelection = ref([]) const loading = ref(true) //定义请求参数对象 const params = ref({ pageNum: 1, pageSize: 10, cid: '', vid: '', key: '', status: '', enableStatus: '' }) //导入列表数据 const getCarManDataList = async () => { const res = await carManGetService(params.value) // 增加健壮性判断 if (res && res.data && res.data.data) { carManDataList.value = res.data.data.records total.value = res.data.data.total } else { carManDataList.value = [] total.value = 0 } loading.value = false } getCarManDataList() // 获取所属车辆 const vidDataList = ref([]) const getRoleDataList = async () => { const res = await vidallDataGetService() vidDataList.value = res.data.data } getRoleDataList() //搜索 const onSearch = () => { params.value.pageNum = 1 getCarManDataList() } //重置 const onReset = () => { params.value.pageNum = 1 params.value.cid = '' params.value.vid = '' params.value.key = '' params.value.enableStatus = '' params.value.status = '' getCarManDataList() } //多选框 let ids = [] const handleSelectionChange = (selects) => { ids = [] tableSelection.value = selects selects.forEach((rows) => { ids.push(rows.id) }) console.log(ids) console.log(tableSelection.value) } // 表格样式 // const rowStyle = (val) => { // // console.log('1111', val) // if (val.rowIndex % 2 === 0) { // // 奇数行 // return { // 'text-align': 'center', // color: '#fff', // background: '#2e3a54' // // color: 'red' // } // } // // 偶数行 // else // return { // 'text-align': 'center', // color: '#fff', // backgroundColor: '#1f2940' // } // } // 搜索式输入框 const handleSearch = () => {} //新增 const onAddMessage = () => { updateDialog.value.open({}) } //编辑 const onEditTable = (row) => { console.log(row.status) updateDialog.value.open(row) } // 添加或者编辑 成功的回调 const onSuccess = (type) => { if (type === 'add') { // // 如果是添加,最好渲染最后一页 // const lastPage = Math.ceil((total.value + 1) / params.value.pageSize) // // 更新成最大页码数,再渲染 // params.value.pageNum = lastPage params.value.pageNum = 1 } getCarManDataList() } //启用禁用 const onStart = async (row) => { // console.log(row.status) // console.log(row.id) if (row.enableStatus === 0) { // params.value.id = row.id const res = await carManStartService({ id: row.id }) if (res.data.code === 200) { // console.log('错误', res) ElMessage.success('车辆已启用') } else if (res.data.code !== 200) { ElMessage.error(${res.data.msg}) } } else if (row.enableStatus === 1) { // params.value.id = row.id const res = await carManStopService({ id: row.id }) if (res.data.code === 200) { // console.log('错误', res) ElMessage.success('车辆已禁用') } else if (res.data.code !== 200) { ElMessage.error(${res.data.msg}) } } getCarManDataList() } // 绑定台架 const inSureDevice = async (row) => { deviceDialog.value.open(row) } // 删除逻辑 const onDeleteMessage = async () => { // 提示用户是否要删除 await ElMessageBox.confirm('此操作将永久删除该数据, 是否继续?', '提示', { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning' }) const res = await carManDelService(ids) if (res.data.code == 200) { ElMessage.success('删除成功') getCarManDataList() tableRef.value.clearSelection() } else if (res.data.code !== 200) { ElMessage.error(${res.data.msg}) } } //处理分页逻辑 const handleSizeChange = (size) => { //每页条数改变后,从第一页开始渲染 params.value.pageNum = 1 params.value.pageSize = size getCarManDataList() } const handleCurrentChange = (page) => { params.value.pageNum = page getCarManDataList() } zhCn.el.pagination = { goto: '跳至', pageClassifier: '页', total: '共 {total} 条', pagesize: '条/页' } </script> <template> <el-breadcrumb separator="/"> <el-breadcrumb-item ></el-breadcrumb-item> <el-breadcrumb-item>车辆管理</el-breadcrumb-item> <el-breadcrumb-item :to="{ path: '/manage/car' }" >车辆信息</el-breadcrumb-item > </el-breadcrumb> <AddCar ref="updateDialog" @success="onSuccess"></AddCar> <SureDevice ref="deviceDialog" @success="onSuccess"></SureDevice> <el-form inline class="search_form"> <el-form-item label="关键字:"> <el-input v-model="params.key" placeholder="请输入车辆名称、车牌号" clearable @input="handleSearch" ></el-input> </el-form-item> <el-form-item label="车辆编号:"> <CarvidSelect v-model="params.vid" placeholder="请选择车辆编号" clearable @input="handleSearch" ></CarvidSelect> </el-form-item> <el-form-item label="驾驶舱编号:"> <DevcidSelect v-model="params.cid" placeholder="请选择驾驶舱编号" clearable @input="handleSearch" ></DevcidSelect> </el-form-item> <el-form-item label="在线状态:"> <el-select v-model="params.status" placeholder="请选择在线状态" clearable > <el-option label="离线" :value="0"></el-option> <el-option label="在线" :value="1"></el-option> </el-select> </el-form-item> <el-form-item label="启用状态:"> <el-select v-model="params.enableStatus" placeholder="请选择启用状态" clearable > <el-option label="禁用" :value="0"></el-option> <el-option label="启用" :value="1"></el-option> </el-select> </el-form-item> <el-form-item> <el-button @click="onSearch" style="background-color: #165dff; color: #fff" ><el-icon style="padding-right: 5px"><Search /></el-icon> 搜索</el-button > <el-button @click="onReset" style="background-color: #fff; color: #000"> <el-icon style="padding-right: 5px"><Refresh /></el-icon> 重置</el-button > </el-form-item> </el-form> <el-form class="function_form" inline style="justify-content: end; display: flex" > <el-form-item style="margin-right: 0"> <el-button @click="onAddMessage" style="background-color: #165dff; color: #fff" > <el-icon style="padding-right: 5px"></el-icon> 新增</el-button > <el-button @click="onDeleteMessage" :disabled="tableSelection.length === 0" style="background-color: #f53f3f; color: #fff" > <el-icon style="padding-right: 5px"><Delete /></el-icon> 删除</el-button > </el-form-item> </el-form> <el-table id="table" ref="tableRef" :row-key="(row) => row.id" @selection-change="handleSelectionChange" :data="carManDataList" style="width: 100%; margin-top: 10px" :header-cell-style="{ 'text-align': 'center', background: '#f2f3f5', color: '#000' }" :cell-style="{ 'text-align': 'center', color: '#000' }" > <el-table-column fixed type="selection" :reserve-selection="true" width="40" /> <el-table-column prop="vid" label="车辆编号" min-width="160" :show-overflow-tooltip="true" ><template #default="{ row }"> {{ vidDataList.find((item) => row.vid == item.id)?.name || '-' }} - </template> </el-table-column> <el-table-column prop="cid" label="驾驶舱编号" min-width="100" :show-overflow-tooltip="true" ><template #default="{ row }"> - </template> </el-table-column> <el-table-column prop="name" label="车辆名称" min-width="120" :show-overflow-tooltip="true" ><template #default="{ row }"> - </template> </el-table-column> <el-table-column prop="plateNumber" label="车辆牌照" min-width="120" :show-overflow-tooltip="true" ><template #default="{ row }"> - </template> </el-table-column> <el-table-column prop="picture" label="车辆图片" min-width="110" :show-overflow-tooltip="true" > <template #default="{ row }"> <el-image v-if="row.picture" :src="row.picture" alt="" style="width: 50px; height: 50px" > <template #error> <el-icon><icon-picture /></el-icon> </template> </el-image> - </template> </el-table-column> <el-table-column prop="status" label="在线状态" min-width="110" :show-overflow-tooltip="true" > <template #default="{ row }"> <el-tag v-if="row.status === 0" type="info">离线</el-tag> <el-tag v-if="row.status === 1" type="success">在线</el-tag> - </template> </el-table-column> <el-table-column prop="enableStatus" label="启用状态" min-width="110" :show-overflow-tooltip="true" > <template #default="{ row }"> <el-tag v-if="row.enableStatus === 0" type="danger">禁用</el-tag> <el-tag v-if="row.enableStatus === 1" type="success">启用</el-tag> - </template> </el-table-column> <el-table-column prop="hasGateway" label="是否具备网关" min-width="110" :show-overflow-tooltip="true" > <template #default="{ row }"> - </template> </el-table-column> <el-table-column prop="model" label="型号" min-width="110" :show-overflow-tooltip="true" > <template #default="{ row }"> - </template> </el-table-column> <el-table-column prop="manufactureDate" label="出厂日期" min-width="110" :show-overflow-tooltip="true" > <template #default="{ row }"> - </template> </el-table-column> <el-table-column prop="organizeId" label="组织号" min-width="110" :show-overflow-tooltip="true" > <template #default="{ row }"> - </template> </el-table-column> <el-table-column prop="created" label="创建时间" min-width="170" /> <el-table-column prop="last" label="更新时间" min-width="170" /> <el-table-column label="操作" width="260" fixed="right"> <template #default="{ row }"> <el-button class="operate" style="color: #165dff" link @click="onEditTable(row)" ><el-icon style="padding-right: 3px"><Edit /></el-icon >编辑</el-button > <el-text class="mx-1" style="color: #165dff; padding-left: 3px" >|</el-text > <el-button link @click="onStart(row)"> <el-button link v-if="row.enableStatus === 0" style="color: #00ff48" >启用</el-button > <el-button class="operate" link v-if="row.enableStatus === 1" style="color: #ff4646" >禁用</el-button > </el-button> <el-text class="mx-1" style="color: #165dff; padding-left: 3px" >|</el-text > <el-button link @click="inSureDevice(row)"> <el-button link style="color: #165dff" >绑定驾驶舱</el-button > </el-button> </template> </el-table-column> <template #empty> <el-empty description="没有数据"></el-empty> </template> </el-table> <el-pagination :teleported="false" v-model:current-page="params.pageNum" v-model:page-size="params.pageSize" :page-sizes="[5, 10]" layout="total,prev, pager, next,sizes" :total="total" @size-change="handleSizeChange" @current-change="handleCurrentChange" style="margin-top: 40px; margin-bottom: 40px; justify-content: end" /> </template> <style lang="scss" scoped> .operate { margin-left: 0px !important; } // :deep .el-input__wrapper { // background-color: #f2f3f5; // } // 面包屑 .bread { height: 50px; display: flex; align-items: center; padding-left: 20px; :deep .el-breadcrumb__item:last-child .el-breadcrumb__inner { cursor: pointer !important; } } :deep .el-breadcrumb { display: flex; align-items: center; .el-breadcrumb__inner { color: #4e5969; } .el-breadcrumb__item { &:nth-child(1), &:last-child { .el-breadcrumb__inner { color: #1d2129; } } } } // 表格 :deep .el-scrollbar__wrap { max-height: 48vh; } // 分页 :deep .el-pagination { .el-pager li { // background-color: #fff; color: #000; // border: 1px solid #e5e5ea; border-radius: 2px; min-width: 32px; height: 32px; margin: 0 5px; } .el-pager li:hover { background-color: #e8f3ff; color: #165dff; } .el-pager li.is-active { background-color: #e8f3ff !important; color: #165dff !important; font-size: medium; } .btn-next, .btn-prev { // background-color: #fff; // border: 1px solid #e5e5ea; // border-radius: 5px; width: 32px; height: 32px; } } :deep .image-slot { display: flex; justify-content: center; align-items: center; width: 100%; height: 100%; background: var(--el-fill-color-light); color: var(--el-text-color-secondary); font-size: 20px; } </style>

下面的代码是干什么用的,请生成说明注释,同时还有什么改进: 【import sys from PyQt6.QtWidgets import QGridLayout from PyQt5.QtWidgets import QMainWindow,QWidget,QAction,QApplication,QListWidget,QLabel,QGridLayout class MainWindow(QMainWindow): def __init__(self): super().__init__() self.title = "自适应大小UI" self.desktop = QApplication.desktop() self.screenRect = self.desktop.screenGeometry() self.screenheight = self.screenRect.height() self.screenwidth = self.screenRect.width() self.height = int(self.screenheight * 0.7) self.width = int(self.screenwidth * 0.7) print("Screen height {}".format(self.screenheight)) print("Screen width {}".format(self.screenwidth)) self.resize(self.width, self.height) self.wid = QWidget(self) self.setCentralWidget(self.wid) self.setWindowTitle(self.title) self.initUI() self.show() def initUI(self): self.layout = QGridLayout() # 预览四个边都预留20pixs的边界 self.layout.setContentsMargins(20, 20, 20, 20) # 网格之间设置10pixs的间隔 self.layout.setSpacing(10) self.initMenu() self.initBrowser() self.initImageWindow() self.statusBar().showMessage("准备就绪") self.wid.setLayout(self.layout) def initMenu(self): openImageFolderAct = QAction("打开", self) openImageFolderAct.setStatusTip("选择一个文件夹,开始标注") openImageFolderAct.setShortcut("Ctrl+O") menubar = self.menuBar() fileMenu = menubar.addMenu('&文件') fileMenu.addAction(openImageFolderAct) def initBrowser(self): self.imageBrowser = QListWidget(self) self.imageBrowserWidth = self.width * 0.1 self.imageBrowserHeight = self.height self.imageBrowser.setMinimumSize(self.imageBrowserWidth, self.imageBrowserHeight) self.layout.addWidget(self.imageBrowser, 0, 0) def initImageWindow(self): self.imageWindow = QLabel("Hello World!", self) # self.imageWindow.resize(800,750) # self.imageWindow.move(250,30) self.imageWindow.setStyleSheet("background-color: darkgray;border: 1px solid black;") self.imageWindowWidth = self.width * 0.9 self.imageWindowHeight = self.height self.imageWindow.setMinimumSize(self.imageWindowWidth, self.imageWindowHeight) # 将imageBrowser放置到网格的第0行,第1列 self.layout.addWidget(self.imageWindow, 0, 1) if __name__ == '__main__': #把窗口实例化 app = QApplication(sys.argv) #使其显示 win = MainWindow() sys.exit(app.exec())】

<template> <el-dialog title="OTA批量升级" :visible.sync="dialogVisible"> <el-button type="primary" @click="downloadTemplate">下载模板</el-button> <el-upload action="/https/wenku.csdn.net/api/upload" :on-success="handleUploadSuccess" :before-upload="beforeUpload" :limit="1" :on-exceed="handleExceed" :file-list="fileList" > <el-button type="success">上传文件</el-button> </el-upload> <el-button type="primary" @click="otaBatchUpgradeCinfirm()">确 定</el-button> <el-button @click="dialogVisible = false">取 消</el-button> </el-dialog> </template> <script> import { init } from 'echarts'; export default { data() { return { dialogVisible: false, // 控制弹窗显示状态 fileList: [] // 存储已上传的文件列表 }; }, methods: { init() { this.dialogVisible=true }, //OTA批量升级 otaBatchUpgradeCinfirm(){ }, // 下载模板方法 downloadTemplate() { const link = document.createElement('a'); link.href = '/path/to/template.xlsx'; // 替换为实际的模板路径 link.download = '模板.xlsx'; // 指定下载文件名 link.click(); }, // 上传成功回调 handleUploadSuccess(response, file, fileList) { this.$message.success('文件上传成功'); this.fileList = fileList; }, // 上传前校验文件类型 beforeUpload(file) { const isValidType = file.type === 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' || file.type === 'application/vnd.ms-excel'; if (!isValidType) { this.$message.error('只能上传 Excel 文件'); } return isValidType; }, // 超出限制时提示 handleExceed(files, fileList) { this.$message.warning('最多只能上传一个文件'); } } }; </script> <style scoped> .dialog-content { margin-bottom: 20px; } </style> 优化此界面ui和交互,不加新功能

把我的这个文件改成 vue2的版本 <template> <input id="fileUpload" type="file" @change="handleFileChange"> <el-button class="btn-file" size="small" type="primary" @click="btnFile" >选择文件</el-button> <el-button v-if="fileName !== '未选择任何文件'" type="primary" size="small" @click="uploadFile" >上传</el-button> <el-progress class="progress-bar" :percentage="progress" :stroke-width="20" striped :striped-flow="isUploadRunning" :duration="10" /> <el-button type="primary" size="small" @click="pauseUpload"> {{ isUploadRunning ? "暂停" : "继续" }} </el-button> 上传成功!<el-button size="small" @click="onShow = 1">再传一个</el-button> </template> <script setup > import * as tus from 'tus-js-client' import { ref } from 'vue' const isUploadRunning = ref(true) const onShow = ref(1) const fileName = ref('未选择任何文件') const progress = ref() const file = ref() const btnFile = () => { document.getElementById('fileUpload')?.click() } const handleFileChange = (e) => { file.value = null file.value = e.target.files[0] fileName.value = file.value.name onShow.value = 1 } var upload const uploadFile = () => { upload = new tus.Upload(file.value, { // Endpoint is the upload creation URL from your tus server endpoint: 'http://192.168.10.21/File/Upload/', // 这里写自己服务器地址 // Retry delays will enable tus-js-client to automatically retry on errors // retryDelays: [0, 3000, 5000, 10000, 20000],//重发 // Attach additional meta data about the file for the server metadata: { filename: file.value?.name, filetype: file.value?.type }, // Callback for errors which cannot be fixed using retries onError: function(error) { this.$message.error(上传失败:${error}) // console.log("Failed because: " + error); }, // Callback for reporting upload progress onProgress: function(bytesUploaded, bytesTotal) { var percentage = ((bytesUploaded / bytesTotal) * 100).toFixed(2) progress.value = Number(percentage) if (progress.value === 100) { onShow.value = 3 } // console.log(bytesUploaded, bytesTotal, percentage + "%"); }, // Callback for once the upload is completed onSuccess: function() { console.log('上传成功') } }) onShow.value = 2 // Check if there are any previous uploads to continue. upload.findPreviousUploads().then(function(previousUploads) { // Found previous uploads so we select the first one. if (previousUploads.length) { upload.resumeFromPreviousUpload(previousUploads[0]) } // Start the upload upload.start() }) } // 暂停上传 function pauseUpload() { isUploadRunning.value = !isUploadRunning.value if (isUploadRunning.value) { upload.start()// 继续 } else { upload.abort()// 暂停 } } </script> <style lang="scss" scoped> .upload-container { width: 300px; } .btn-container { display: flex; position: relative; .progress-bar { width: 200px; } .btn-file { position: absolute; left: 0px; } } </style>

<!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>💗 Love you 💗 My Dear XXX💗</title> <style type="text/css"> body { margin: 0; overflow: hidden; background: #000; } canvas { position: absolute; width: 100%; height: 100%; } #pinkboard { animation: anim 1.5s ease-in-out infinite; -webkit-animation: anim 1.5s ease-in-out infinite; -o-animation: anim 1.5s ease-in-out infinite; -moz-animation: anim 1.5s ease-in-out infinite; } @keyframes anim { 0% { transform: scale(0.8); } 25% { transform: scale(0.7); } 50% { transform: scale(1); } 75% { transform: scale(0.7); } 100% { transform: scale(0.8); } } @-webkit-keyframes anim { 0% { -webkit-transform: scale(0.8); } 25% { -webkit-transform: scale(0.7); } 50% { -webkit-transform: scale(1); } 75% { -webkit-transform: scale(0.7); } 100% { -webkit-transform: scale(0.8); } } @-o-keyframes anim { 0% { -o-transform: scale(0.8); } 25% { -o-transform: scale(0.7); } 50% { -o-transform: scale(1); } 75% { -o-transform: scale(0.7); } 100% { -o-transform: scale(0.8); } } @-moz-keyframes anim { 0% { -moz-transform: scale(0.8); } 25% { -moz-transform: scale(0.7); } 50% { -moz-transform: scale(1); } 75% { -moz-transform: scale(0.7); } 100% { -moz-transform: scale(0.8); } } #name { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); margin-top: -20px; font-size: 46px; color: #ea80b0; } </style> </head> <body> <canvas id="pinkboard" width="1920" height="947"></canvas> <canvas id="canvas" width="1920" height="947"></canvas> <script type="text/javascript"> var loverName = "💗李文昊,爱你哟💗" // ��要更改的名字 const colors = [ "#eec996", "#8fb7d3", "#b7d4c6", "#c3bedd", "#f1d5e4", "#cae1d3", "#f3c89d", "#d0b0c3", "#819d53", "#c99294", "#cec884", "#ff8e70", "#e0a111", "#fffdf6", "#cbd7ac", "#e8c6c0", "#dc9898", "#ecc8ba", ]; //用来设置的颜�� var canvas = document.getElementById("canvas"); var ctx = canvas.getContext("2d"); let count = 1; var ww = window.innerWidth; var wh = window.innerHeight; var hearts = []; function init() { requestAnimationFrame(render); canvas.width = ww; canvas.height = wh; for (var i = 0; i < 100; i++) { hearts.push(new Heart()); } } function Heart() { this.x = Math.random() * ww; this.y = Math.random() * wh; this.opacity = Math.random() * 0.5 + 0.5; this.vel = { x: (Math.random() - 0.5) * 4, y: (Math.random() - 0.5) * 4, }; this.targetScale = Math.random() * 0.15 + 0.02; this.scale = this.targetScale * Math.random(); } Heart.prototype.update = function (i) { this.x += this.vel.x; this.y += this.vel.y; this.scale += (this.targetScale - this.scale) * 0.01; if (this.x - this.width > ww || this.x + this.width < 0) { this.scale = 0; this.x = Math.random() * ww; } if (this.y - this.height > wh || this.y + this.height < 0) { this.scale = 0; this.y = Math.random() * wh; } this.width = 473.8; this.height = 408.6; }; Heart.prototype.draw = function (i) { ctx.globalAlpha = this.opacity; ctx.font = ${180 * this.scale}px "微软雅黑"; // ctx.font="20px"; ctx.fillStyle = colors[i % 18]; ctx.fillText( loverName, this.x - this.width * 0.5, this.y - this.height * 0.5, this.width, this.height ); // ctx.drawImage( // heartImage, // this.x - this.width * 0.5, // this.y - this.height * 0.5, // this.width, // this.height // ); }; function render() { ctx.clearRect(0, 0, ww, wh); // ctx.globalAlpha = 1; // ctx.fillStyle = "rgba(255,255,255,0.3)"; // ctx.fillRect(0, 0, ww, wh); for (var i = 0; i < 100; i++) { hearts[i].update(i); hearts[i].draw(i); } requestAnimationFrame(render); } init(); // var heartImage = new Image(); // heartImage.onload = init(); // heartImage.src = // "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI0NzMuOHB4IiBoZWlnaHQ9IjQwOC42cHgiIHZpZXdCb3g9IjAgMCA0NzMuOCA0MDguNiI+PHBhdGggZmlsbD0iI2QzMjkzMiIgZD0iTTQwNC42LDE2LjZDMzg1LjQsNi4xLDM2My41LDAsMzQwLDBjLTQxLjUsMC03OC41LDE4LjktMTAzLDQ4LjVDMjEyLjMsMTguOSwxNzUuMywwLDEzMy44LDAgYy0yMy4zLDAtNDUuMyw2LjEtNjQuNSwxNi42QzI3LjksMzkuNSwwLDgzLjQsMCwxMzMuOWMwLDE0LjQsMi40LDI4LjMsNi42LDQxLjJDMjkuNiwyNzguNCwyMzcsNDA4LjYsMjM3LDQwOC42IHMyMDcuMi0xMzAuMiwyMzAuMi0yMzMuNWM0LjMtMTIuOSw2LjYtMjYuOCw2LjYtNDEuMkM0NzMuOCw4My40LDQ0NS45LDM5LjYsNDA0LjYsMTYuNnoiLz48L3N2Zz4="; window.addEventListener("resize", function () { ww = window.innerWidth; wh = window.innerHeight; }); </script> <script> /* * Settings */ var settings = { particles: { length: 500, // maximum amount of particles duration: 2, // particle duration in sec velocity: 100, // particle velocity in pixels/sec effect: -0.75, // play with this for a nice effect size: 30, // particle size in pixels }, }; /* * RequestAnimationFrame polyfill by Erik M?ller */ (function () { var b = 0; var c = ["ms", "moz", "webkit", "o"]; for (var a = 0; a < c.length && !window.requestAnimationFrame; ++a) { window.requestAnimationFrame = window[c[a] + "RequestAnimationFrame"]; window.cancelAnimationFrame = window[c[a] + "CancelAnimationFrame"] || window[c[a] + "CancelRequestAnimationFrame"]; } if (!window.requestAnimationFrame) { window.requestAnimationFrame = function (h, e) { var d = new Date().getTime(); var f = Math.max(0, 16 - (d - b)); var g = window.setTimeout(function () { h(d + f); }, f); b = d + f; return g; }; } if (!window.cancelAnimationFrame) { window.cancelAnimationFrame = function (d) { clearTimeout(d); }; } })(); /* * Point class */ var Point = (function () { function Point(x, y) { this.x = typeof x !== "undefined" ? x : 0; this.y = typeof y !== "undefined" ? y : 0; } Point.prototype.clone = function () { return new Point(this.x, this.y); }; Point.prototype.length = function (length) { if (typeof length == "undefined") return Math.sqrt(this.x * this.x + this.y * this.y); this.normalize(); this.x *= length; this.y *= length; return this; }; Point.prototype.normalize = function () { var length = this.length(); this.x /= length; this.y /= length; return this; }; return Point; })(); /* * Particle class */ var Particle = (function () { function Particle() { this.position = new Point(); this.velocity = new Point(); this.acceleration = new Point(); this.age = 0; } Particle.prototype.initialize = function (x, y, dx, dy) { this.position.x = x; this.position.y = y; this.velocity.x = dx; this.velocity.y = dy; this.acceleration.x = dx * settings.particles.effect; this.acceleration.y = dy * settings.particles.effect; this.age = 0; }; Particle.prototype.update = function (deltaTime) { this.position.x += this.velocity.x * deltaTime; this.position.y += this.velocity.y * deltaTime; this.velocity.x += this.acceleration.x * deltaTime; this.velocity.y += this.acceleration.y * deltaTime; this.age += deltaTime; }; Particle.prototype.draw = function (context, image) { function ease(t) { return --t * t * t + 1; } var size = image.width * ease(this.age / settings.particles.duration); context.globalAlpha = 1 - this.age / settings.particles.duration; context.drawImage( image, this.position.x - size / 2, this.position.y - size / 2, size, size ); }; return Particle; })(); /* * ParticlePool class */ var ParticlePool = (function () { var particles, firstActive = 0, firstFree = 0, duration = settings.particles.duration; function ParticlePool(length) { // create and populate particle pool particles = new Array(length); for (var i = 0; i < particles.length; i++) particles[i] = new Particle(); } ParticlePool.prototype.add = function (x, y, dx, dy) { particles[firstFree].initialize(x, y, dx, dy); // handle circular queue firstFree++; if (firstFree == particles.length) firstFree = 0; if (firstActive == firstFree) firstActive++; if (firstActive == particles.length) firstActive = 0; }; ParticlePool.prototype.update = function (deltaTime) { var i; // update active particles if (firstActive < firstFree) { for (i = firstActive; i < firstFree; i++) particles[i].update(deltaTime); } if (firstFree < firstActive) { for (i = firstActive; i < particles.length; i++) particles[i].update(deltaTime); for (i = 0; i < firstFree; i++) particles[i].update(deltaTime); } // remove inactive particles while ( particles[firstActive].age >= duration && firstActive != firstFree ) { firstActive++; if (firstActive == particles.length) firstActive = 0; } }; ParticlePool.prototype.draw = function (context, image) { // draw active particles if (firstActive < firstFree) { for (i = firstActive; i < firstFree; i++) particles[i].draw(context, image); } if (firstFree < firstActive) { for (i = firstActive; i < particles.length; i++) particles[i].draw(context, image); for (i = 0; i < firstFree; i++) particles[i].draw(context, image); } }; return ParticlePool; })(); /* * Putting it all together */ (function (canvas) { var context = canvas.getContext("2d"), particles = new ParticlePool(settings.particles.length), particleRate = settings.particles.length / settings.particles.duration, // particles/sec time; // get point on heart with -PI <= t <= PI function pointOnHeart(t) { return new Point( 160 * Math.pow(Math.sin(t), 3), 130 * Math.cos(t) - 50 * Math.cos(2 * t) - 20 * Math.cos(3 * t) - 10 * Math.cos(4 * t) + 25 ); } // creating the particle image using a dummy canvas var image = (function () { var canvas = document.createElement("canvas"), context = canvas.getContext("2d"); canvas.width = settings.particles.size; canvas.height = settings.particles.size; // helper function to create the path function to(t) { var point = pointOnHeart(t); point.x = settings.particles.size / 2 + (point.x * settings.particles.size) / 350; point.y = settings.particles.size / 2 - (point.y * settings.particles.size) / 350; return point; } // create the path context.beginPath(); var t = -Math.PI; var point = to(t); context.moveTo(point.x, point.y); while (t < Math.PI) { t += 0.01; // baby steps! point = to(t); context.lineTo(point.x, point.y); } context.closePath(); // create the fill context.fillStyle = "#ea80b0"; context.fill(); // create the image var image = new Image(); image.src = canvas.toDataURL(); return image; })(); // render that thing! function render() { // next animation frame requestAnimationFrame(render); // update time var newTime = new Date().getTime() / 1000, deltaTime = newTime - (time || newTime); time = newTime; // clear canvas context.clearRect(0, 0, canvas.width, canvas.height); // create new particles var amount = particleRate * deltaTime; for (var i = 0; i < amount; i++) { var pos = pointOnHeart(Math.PI - 2 * Math.PI * Math.random()); var dir = pos.clone().length(settings.particles.velocity); particles.add( canvas.width / 2 + pos.x, canvas.height / 2 - pos.y, dir.x, -dir.y ); } // update and draw particles particles.update(deltaTime); particles.draw(context, image); } // handle (re-)sizing of the canvas function onResize() { canvas.width = canvas.clientWidth; canvas.height = canvas.clientHeight; } window.onresize = onResize; // delay rendering bootstrap setTimeout(function () { onResize(); render(); }, 10); })(document.getElementById("pinkboard")); </script> </body> </html> 续写、改写

<template> 查询条件 <a-form-model :model="searchForm" layout="inline" ref="searchForm" class="searchForm"> <a-form-model-item label="题库名称" prop="title"> <a-input v-model="searchForm.title" placeholder="请输入题库名称" /> </a-form-model-item> <a-form-model-item class="searchButton"> <a-button type="primary" v-if="QX.read" @click="getSearch">查询</a-button> <a-button type="default" v-if="QX.read" @click="restSearch('searchForm')">重置</a-button> </a-form-model-item> </a-form-model> <a-button type="primary" @click="addBank" icon="plus" v-if="QX.add">新增</a-button> <a-table :columns="columns" :data-source="dataList" :pagination="false" :loading="loading" rowKey="questionBankId" :scroll="{ y: this.$getViewportSize().height - 300 }" > <a-icon class="iconBtn" type="edit" />编辑 <a-divider v-if="QX.edit && QX.delete" type="vertical" /> <a-popconfirm title="确认是否删除?" ok-text="是" cancel-text="否" @confirm="removeBank(record)" > <a-icon class="iconBtn" type="delete" />删除 </a-popconfirm> </a-table> <template slot="action" slot-scope="text, record, index"> 删除 </template> <a-pagination show-size-changer :total="totalPage" :current="pageIndex" :pageSize="pageSize" @showSizeChange="onShowSizeChange" @change="onChangePage" style="float: right; margin-top: 15px" /> <a-drawer :closable="true" :title="title" width="auto" :visible="visible" @close="visible = !visible" > <a-spin class="submitLoading" :spinning="submitLoading"> <a-form-model :model="form" :label-col="labelCol" :wrapper-col="wrapperCol" :rules="rules" ref="form" class="lay-drawer-form"> <a-row> <a-col :span="12"> <a-form-model-item label="题库名称" prop="title"> <a-input v-model="form.title" :maxLength="25" placeholder="请输入题库名称" style="width: 380px" /> </a-form-model-item> </a-col> <a-col :span="12"> <a-form-model-item label="关联岗位" prop="positionId"> <a-select v-model="form.positionId" style="width: 380px" placeholder="请选择岗位"> <a-select-option v-for="(label, value) in positionDict" :key="value" :value="value"> {{ label }} </a-select-option> </a-select> </a-form-model-item> </a-col> <a-col :span="12"> <a-form-model-item label="参与PK" prop="participateInPk"> <a-switch v-model="form.participateInPk" :checkedValue="1" :unCheckedValue="0" /> </a-form-model-item> </a-col> </a-row> </a-form-model> <a-button type="primary" @click="downloadTemplate">下载模板</a-button> <a-upload name="file" :showUploadList="false" :beforeUpload="beforeUpload" accept=".xlsx,.xls" :disabled="!importEnabled" > <a-button :disabled="!importEnabled"><a-icon type="upload" /> 导入题目</a-button> </a-upload> <a-button type="dashed" @click="addTopicVisible = true" :disabled="!addEnabled" > <a-icon type="plus" /> 添加题目 </a-button> {{ index + 1 }}. {{ topic.content }} <label v-for="option in getOptions(topic)" :key="option.key"> <input type="radio" :name="'topic' + topic.topicId" :value="option.key" :checked="topic.correctAnswer === option.key" /> {{ option.key }}. {{ option.value }} </label> <label> <input type="radio" :name="'topic' + topic.topicId" value="正确" :checked="topic.correctAnswer === '正确'" /> 正确 </label> <label> <input type="radio" :name="'topic' + topic.topicId" value="错误" :checked="topic.correctAnswer === '错误'" /> 错误 </label> <a-icon type="delete" /> 删除 <a-pagination v-model="topicPageNum" :pageSize="topicPageSize" :total="totalTopicCount" @change="handleTopicPageChange" style="text-align: right;" /> <a-button type="default" @click="visible = !visible" > 取消 </a-button> <a-button type="primary" @click="submitForm" > 确认 </a-button> </a-spin> </a-drawer> <a-drawer title="新增题目" :visible="addTopicVisible" @close="addTopicVisible = false" width="500" > <a-form-model :model="addTopicForm" layout="vertical" :rules="rulesForAddTopic" ref="addTopicFormRef"> <a-form-model-item label="题目类型" prop="topicType"> <a-select v-model="addTopicForm.topicType" style="width: 100%"> <a-select-option :value="1">选择题</a-select-option> <a-select-option :value="2">判断题</a-select-option> </a-select> </a-form-model-item> <a-form-model-item label="题目内容" prop="content"> <a-input v-model="addTopicForm.content" placeholder="请输入题目内容" /> </a-form-model-item> <a-form-model-item label="选项A" prop="optionA"> <a-input v-model="addTopicForm.optionA" placeholder="请输入选项A内容" /> </a-form-model-item> <a-form-model-item label="选项B" prop="optionB"> <a-input v-model="addTopicForm.optionB" placeholder="请输入选项B内容" /> </a-form-model-item> <a-form-model-item label="选项C" prop="optionC"> <a-input v-model="addTopicForm.optionC" placeholder="请输入选项C内容" /> </a-form-model-item> <a-form-model-item label="选项D" prop="optionD"> <a-input v-model="addTopicForm.optionD" placeholder="请输入选项D内容" /> </a-form-model-item> <a-form-model-item label="正确答案" prop="correctAnswer"> <a-select v-model="addTopicForm.correctAnswer" style="width: 100%"> <a-select-option value="A">A</a-select-option> <a-select-option value="B">B</a-select-option> <a-select-option value="C">C</a-select-option> <a-select-option value="D">D</a-select-option> </a-select> </a-form-model-item> <a-form-model-item label="正确答案" prop="correctAnswer"> <a-select v-model="addTopicForm.correctAnswer" style="width: 100%"> <a-select-option value="正确">正确</a-select-option> <a-select-option value="错误">错误</a-select-option> </a-select> </a-form-model-item> <a-button @click="addTopicVisible = false">取消</a-button> <a-button type="primary" @click="saveNewTopic">保存</a-button> </a-form-model> </a-drawer> </template> <script> import { req, fileDownload } from '../../../api/axiosFun'; import preventBack from 'vue-prevent-browser-back'; export default { name: 'Bank', mixins: [preventBack], data() { return { QX: {}, topicQX: {}, topicList: [], totalTopicCount: 0, // 题目总数 topicPageNum: 1, // 当前页码 topicPageSize: 10, // 每页数量 addTopicVisible: false, addTopicForm: { content: '', // 题目内容 topicType: 1, // 题目类型:1=选择题,2=判断题 optionA: '', optionB: '', optionC: '', optionD: '', correctAnswer: '', }, disabled: false, checkedKeys: [], selectAuth: [], treeData: [], positionDict: {}, title: '', labelCol: { span: 4 }, wrapperCol: { span: 20 }, tableHeight: 0, expanded: false, // 筛选条件是否展开 form: { questionBankId: 0, bankCode: '', title: '', positionId: '', participateInPk: true, }, isEdit: false, // 是否是编辑状态 isAdd: false, // 是否是新增状态 importEnabled: false, // 导入题目按钮是否可用 - 默认为不可用 addEnabled: false, // 添加题目按钮是否可用 - 默认为不可用 rules: { positionId: [ { required: true, message: '请选择岗位', trigger: 'blur' }, ], title: [ { required: true, message: '请输入题库名称', trigger: 'blur' }, ], }, rulesForAddTopic: { content: [ { required: true, message: '请输入题目内容', trigger: ['blur', 'change'] }, ], topicType: [ { required: true, message: '请选择题目类型', trigger: 'change' }, ], optionA: [ { required: (rule, value) => this.addTopicForm.topicType === 1, message: '选择题必须输入选项A', trigger: ['blur', 'change'], }, ], optionB: [ { required: (rule, value) => this.addTopicForm.topicType === 1, message: '选择题必须输入选项B', trigger: ['blur', 'change'], }, ], optionC: [ { required: (rule, value) => this.addTopicForm.topicType === 1, message: '选择题必须输入选项C', trigger: ['blur', 'change'], }, ], optionD: [ { required: (rule, value) => this.addTopicForm.topicType === 1, message: '选择题必须输入选项D', trigger: ['blur', 'change'], }, ], correctAnswer: [ { required: true, message: '请选择正确答案', trigger: 'change' }, ], }, searchForm: { title: '', }, visible: false, dataList: [], columns, loading: false, submitLoading: false, pageIndex: 1, pageSize: 10, totalPage: 0, ops: { vuescroll: {}, scrollPanel: {}, rail: { keepShow: true, }, bar: { hoverStyle: true, onlyShowBarOnScroll: false, // 是否只有滚动的时候才显示滚动条 background: '#F5F5F5', // 滚动条颜色 opacity: 1, // 滚动条透明度 'overflow-x': 'hidden', }, }, }; }, watch: { 'addTopicForm.topicType': function (newVal) { // 当题目类型变化时,触发相关字段的验证 this.$nextTick(() => { if (this.$refs.addTopicFormRef) { // 验证选项字段 if (newVal === 1) { this.$refs.addTopicFormRef.validateFields(['optionA', 'optionB', 'optionC', 'optionD']); } else { // 清除非必填字段的验证状态 this.$refs.addTopicFormRef.clearValidate(['optionA', 'optionB', 'optionC', 'optionD']); } } }); }, visible(newVal, oldVal) { if (!newVal) { this.restForm('form'); this.form.questionBankId = 0; this.checkedKeys = []; this.selectAuth = []; this.treeData = []; // 重置状态标志 this.isEdit = false; this.isAdd = false; } else { // 当抽屉打开时强制更新按钮状态 this.$nextTick(() => { this.$forceUpdate(); }); } }, }, mounted() { this.actionTitle = '操作'; this.getDict('position').then(res => { const dictMap = {}; res.data.forEach(item => { dictMap[item.dicValue] = item.dicDisplayName; }); this.positionDict = dictMap; }); this.getBankList(); }, methods: { // 获取字典数据方法 getDict(type) { return req('get', /dict/getDictItemByNo, { dicNo: type }) .then((res) => { if (res.result === 'success') { return res; } throw new Error(res.message || '获取字典数据失败'); }) .catch((error) => { console.error(获取${type}字典失败:, error); throw error; }); }, /* 新增题库 */ addBank() { this.visible = true; this.disabled = false; this.title = '新增题库'; // 获取功能权限树 req('get', '/bank/getTree', {}).then((res) => { this.treeData = res.data; }); // 初始化题目列表为空 this.topicList = []; this.totalTopicCount = 0; this.topicPageNum = 1; this.isEdit = false; // 不是编辑状态 this.isAdd = true; // 设置为新增状态 // 在新增状态下禁用导入和添加功能 this.importEnabled = false; this.addEnabled = false; // 强制更新按钮状态 this.$nextTick(() => { this.$forceUpdate(); }); }, // 查询 getSearch() { this.pageIndex = 1; this.getBankList(); }, /* 重置查询 */ restSearch(form) { this.restForm(form); this.pageIndex = 1; this.getBankList(); }, /* 删除题库 */ removeBank(record) { this.loading = true; req('post', '/bank/removeBQuestionBank', { questionBankId: record.questionBankId, }).then((res) => { this.loading = false; if (res.result === 'success') { this.$message.success(res.message); this.getBankList(); } }); }, downloadTemplate() { fileDownload('get', '/topic/downloadTemplate', null).then((res) => { const blob = new Blob([res], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', }); const link = document.createElement('a'); link.href = window.URL.createObjectURL(blob); link.download = '题库模板.xlsx'; link.click(); window.URL.revokeObjectURL(link.href); }).catch(() => { this.$message.error('下载失败'); }); }, beforeUpload(file) { // 显示加载状态 this.loading = true; const formData = new FormData(); formData.append('file', file); formData.append('questionBankId', this.form.questionBankId); // 添加 questionBankId 字段 req('post', '/topic/import', formData, { headers: { 'Content-Type': 'multipart/form-data', }, }) .then((res) => { // 隐藏加载状态 this.loading = false; if (res.result === 'success') { // 确保在DOM更新后再刷新题目列表 this.$nextTick(() => { // 刷新题目列表 this.getTopicList(this.form.questionBankId, this.topicPageNum, this.topicPageSize) .then(() => { this.$message.success('导入成功'); }) .catch(() => { this.$message.error('刷新题目列表失败'); }); }); } else { this.$message.error(res.message || '导入失败'); } }) .catch((error) => { // 隐藏加载状态 this.loading = false; this.$message.error('导入失败,请重试'); console.error('导入题目出错:', error); }); return false; // 阻止默认上传行为 }, // 获取题库下的题目列表(返回Promise以便链式调用) getTopicList(questionBankId, pageNum = 1, pageSize = 10) { return new Promise((resolve, reject) => { req('post', '/topic/list', { questionBankId, page: pageNum, rows: pageSize, }).then((res) => { if (res.result === 'success') { this.topicQX = res.QX; if (!this.topicQX.edit && !this.topicQX.delete) { this.hideAction(); } else { this.topicList = res.data.map((item, index) => ({ index: (pageNum - 1) * pageSize + index + 1, content: item.content, optionA: item.optionA, optionB: item.optionB, optionC: item.optionC, optionD: item.optionD, topicId: item.topicId, correctAnswer: item.correctAnswer, topicType: item.topicType, })); } // 更新总条数用于分页组件 this.totalTopicCount = res.page.totalResult; resolve(res); } else { this.$message.error(res.message || '获取题目列表失败'); reject(res); } }).catch((error) => { this.$message.error('获取题目列表失败'); reject(error); }); }); }, handleTopicPageChange(page) { this.topicPageNum = page; this.getTopicList(this.form.questionBankId, page, this.topicPageSize); }, // 获取选择题的选项 getOptions(topic) { if (topic.topicType === 1) { // 选择题:返回 A/B/C/D 选项 const options = []; if (topic.optionA) options.push({ key: 'A', value: topic.optionA }); if (topic.optionB) options.push({ key: 'B', value: topic.optionB }); if (topic.optionC) options.push({ key: 'C', value: topic.optionC }); if (topic.optionD) options.push({ key: 'D', value: topic.optionD }); return options; } else if (topic.topicType === 2) { // 判断题:直接返回 正确/错误 return [ { key: '正确', value: '正确' }, { key: '错误', value: '错误' }, ]; } return []; }, checkAnswer(topic, selectedAnswer) { // 仅记录用户选择的答案,不进行是否正确的判断 this.$set(topic, 'userAnswer', selectedAnswer); }, resetAddTopicForm() { this.addTopicForm = { content: '', topicType: 1, optionA: '', optionB: '', optionC: '', optionD: '', correctAnswer: '', }; }, saveNewTopic() { this.$refs.addTopicFormRef.validate((valid, fields) => { if (!valid) { console.log('表单验证失败:', fields); // 找出第一个错误字段并聚焦 const firstErrorField = Object.keys(fields).find(key => fields[key]); if (firstErrorField && this.$refs.addTopicFormRef) { const formItem = this.$refs.addTopicFormRef.$children.find( child => child.prop === firstErrorField, ); if (formItem && formItem.$el) { const input = formItem.$el.querySelector('input, select, textarea'); if (input) input.focus(); } } return; } // 验证通过,处理保存逻辑 const newTopic = { ...this.addTopicForm }; // 发送请求保存题目 req('post', '/topic/add', { questionBankId: this.form.questionBankId, optionA: newTopic.optionA, optionB: newTopic.optionB, optionC: newTopic.optionC, optionD: newTopic.optionD, correctAnswer: newTopic.correctAnswer, content: newTopic.content, topicType: newTopic.topicType, }).then((res) => { if (res.result === 'success') { this.$message.success('题目添加成功'); this.addTopicVisible = false; this.getTopicList(this.form.questionBankId); // 刷新题目列表 } else { this.$message.error(res.message || '保存失败'); } this.resetAddTopicForm(); }).catch((err) => { this.$message.error('网络异常,请重试'); }); }); }, /* 删除题库下的题目 */ removeQuestion(topicId) { this.$confirm({ title: '确认删除该题目?', content: '删除后将无法恢复', okText: '是', cancelText: '否', onOk: () => { req('post', '/topic/removeBTopic', { topicId, questionBankId: this.form.questionBankId, }).then((res) => { if (res.result === 'success') { this.$message.success(res.message); // 刷新题目列表 this.getTopicList(this.form.questionBankId, this.topicPageNum, this.topicPageSize); } else { this.$message.error(res.message || '删除失败'); } }); }, }); }, editAuth(record) { this.loading = true; req('post', '/bank/getBQuestionBank', { questionBankId: record.questionBankId, }).then((res) => { this.loading = false; if (res.result === 'success') { this.visible = true; this.disabled = true; this.title = '修改题库'; this.isEdit = true; // 设置为编辑状态 this.isAdd = false; // 不是新增状态 // 在编辑状态下启用导入和添加功能 this.importEnabled = true; this.addEnabled = true; // 强制更新按钮状态 this.$nextTick(() => { this.$forceUpdate(); }); const bank = res.data; this.$nextTick(() => { this.form.questionBankId = bank.questionBankId; this.form.title = bank.title; this.form.participateInPk = Boolean(bank.participateInPk); this.form.positionId = bank.positionId; this.treeData = bank.treeData; this.checkedKeys = bank.auths; // 获取题目列表 this.topicPageNum = 1; this.getTopicList(bank.questionBankId, this.topicPageNum, this.topicPageSize); }); } }); }, /* 保存or修改题库信息 */ submitForm() { this.$refs.form.validate((valid) => { if (valid) { this.form.participateInPk = this.form.participateInPk ? 1 : 0; const url = this.form.questionBankId ? 'edit' : 'add'; const selectAuth = this.selectAuth; this.form.selectAuth = JSON.stringify(selectAuth); this.submitLoading = true; req('post', /bank/${url}, this.form).then((res) => { if (res.result === 'success') { this.visible = false; this.getBankList(); // 如果是新增题库且成功,获取题目列表 if (!this.form.questionBankId && res.data && res.data.questionBankId) { this.form.questionBankId = res.data.questionBankId; this.topicPageNum = 1; this.getTopicList(res.data.questionBankId, this.topicPageNum, this.topicPageSize); // 新增成功后启用导入和添加功能 this.importEnabled = true; this.addEnabled = true; } this.$message.success(res.message); // 重置新增/编辑状态 this.isEdit = false; this.isAdd = false; } this.submitLoading = false; }); } }); }, /* 重置表单 */ restForm(form) { this.$refs[form].resetFields(); }, /* 改变页数事件 */ onChangePage(page, pageSize) { this.pageIndex = page; this.getBankList(); }, /* 改变每页显示条数 */ onShowSizeChange(current, pageSize) { this.pageIndex = 1; this.pageSize = pageSize; this.getBankList(); }, /* 题库信息列表 */ getBankList() { this.loading = true; this.searchForm.page = this.pageIndex; this.searchForm.rows = this.pageSize; req('post', '/bank/list', this.searchForm) .then((res) => { if (res.result === 'success') { this.dataList = res.data; this.QX = res.QX; // 无权限隐藏操作列 if (!this.QX.edit && !this.QX.delete) { this.hideAction(); } else if (columns[columns.length - 1].title != '操作') { columns.push(actionShow); } this.totalPage = res.page.totalResult; } this.loading = false; }).catch((error) => { this.loading = false; }); }, /* 无所有行操作权限时,隐藏操作栏 */ hideAction() { if (columns[columns.length - 1].title == '操作') { columns.splice(columns.length - 1, 1); } }, /* 校验代号类型 */ validCode(value) { if (value.length > 20) { value = value.slice(0, 20); } for (let i = value.length - 1; i >= 0; i--) { const unicode = value.charCodeAt(i); if (unicode > 65280 && unicode < 65375) { value = value.substr(0, i); } } this.value = value; }, }, }; const actionShow = { title: '操作', width: '200px', hide: true, dataIndex: 'action', key: 'action', align: 'center', scopedSlots: { customRender: 'action' }, }; const columns = [ { title: '序号', width: '50px', align: 'center', customRender: (text, row, index) => index + 1, }, { title: '题库名称', align: 'center', dataIndex: 'title', key: 'title', width: '120px', }, { title: '涉及岗位', align: 'center', dataIndex: 'positionName', key: 'positionName', width: '110px', }, { title: '题目数量', dataIndex: 'topicCount', key: 'topicCount', align: 'center', width: '180px', }, { title: '操作', width: '150px', hide: true, dataIndex: 'action', key: 'action', align: 'center', scopedSlots: { customRender: 'action' }, }, ]; </script> <style scoped> .topic-list-container { max-height: calc(100vh - 400px); /* 根据实际布局调整最大高度 */ overflow-y: auto; } .pagination-wrapper { position: sticky; bottom: 0; left: 0; right: 0; background: #fff; padding: 10px; z-index: 1; box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); margin-top: 15px; } .topic-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 20px; } .topic-item { border: 1px solid #e8e8e8; padding: 15px; border-radius: 4px; position: relative; /* 为绝对定位的子元素提供定位上下文 */ } .topic-content { font-size: 16px; margin-bottom: 10px; } .options label { display: block; margin: 5px 0; font-size: 14px; } .options input[type="radio"] { margin-right: 5px; } /* 按钮禁用状态样式优化 */ .ant-upload.ant-upload-disabled .ant-upload-list, .ant-btn[disabled] { cursor: not-allowed; opacity: 0.5; } .topic-delete { position: absolute; top: 10px; right: 10px; } </style> <style scoped> @import "../../../assets/css/maincss.css"; </style> 在编辑页面中选择某个题目的选项后,再次打开该题时,默认显示的是上次选择的选项而不是正确答案。修改此问题

<template> <template v-slot:btnBox> <import-download-document :exportParams="exportParams" :importParams="importParams" :exportData="exportData"> <a-button slot="export" icon="upload" type="primary" class="mgr10">{{ $t('导出') }}</a-button> </import-download-document> </template> <template v-slot:serchBox> {{ item.name }} <a-month-picker :allowClear="false" format="YYYY-M" v-model="searchData.dateTime" v-if="tabActive == 0" :placeholder="$t('请选择月份')" /> <a-date-picker :allowClear="false" :open="open" @openChange="openYearDatePicker" v-else v-model="searchData.dateTime" mode="year" :placeholder="$t('请选择年份')" format="YYYY" @panelChange="onSearchDateEvent" /> <a-button type="primary" @click="onSearch"> {{ $t('common.scf.btn.search') }} </a-button> </template> <template v-slot:tableBox> <a-table :scroll="{ x: '100%', y: tableHeight }" :bordered="false" :columns.sync="columns" :dataSource="tableData" :pagination="false" rowKey="detector_code" > </a-table> </template> <template v-slot:paginationBox> <my-pagination style="padding: 0" :showSizeChanger="true" :pageIndex.sync="pagination.currentPage" @changePage="changePage" :pageSize="pagination.pageSize" :total="pagination.totalRows" @onShowSizeChange="onShowSizeChange" v-if="tableData.length" ></my-pagination> </template> </template> <script> import factory from '../factory' import myPagination from '@/components/scfComponents/paginationFormwork/myPagination' import tableFormworkPage from '@/components/scfComponents/tableFormwork/tableFormworkPage' import importDownloadDocument from '../../../components/importDownloadDocument.vue' export default { components: { tableFormworkPage, myPagination, importDownloadDocument, }, data() { return { tableHeight: 0, searchData: { analysisType: 'MONTH', dateTime: moment(), }, tabActive: 0, open: false, baseColumns: [ { key: 'departmen_name', title: this.$t('所属部门'), dataIndex: 'department_name', ellipsis: true, resizable: true, minWidth: 100, }, { key: 'detector_name', title: this.$t('设备名称'), dataIndex: 'detector_name', ellipsis: true, resizable: true, minWidth: 100, }, { key: 'detector_code', title: this.$t('设备编号'), dataIndex: 'detector_code', ellipsis: true, resizable: true, minWidth: 100, }, ], dynamicColumns: [], actionColumn: [ { key: 'rowTotal', title: this.$t('总计'), dataIndex: 'rowTotal', ellipsis: true, resizable: true, minWidth: 100, }, ], columns: [], tableData: [], pagination: { pageSize: 10, currentPage: 1, totalRows: 0, }, importParams: { isShowImport: false, }, } }, props: { companyInfo: { type: Object, default: {}, }, }, computed: { tabs() { return [ { name: this.$t('月'), value: 0 }, { name: this.$t('年'), value: 1 }, ] }, exportParams() { const exportUrl = this.tabActive == 0 ? 'abnormalAnalysis/monthInfo' : 'abnormalAnalysis/yearInfo' return { isExtract: true, isShowExport: true, exportUrl, } }, exportData() { const dateFormat = this.tabActive == 0 ? 'YYYY-M' : 'YYYY' return { analysisType: this.searchData.analysisType, value: this.searchData.dateTime.format(dateFormat), deptIdListSelect: [1, 2], // 选中部门Id列表 } }, }, created() { this.getTableData() }, mounted() { this.tableHeight = 0 this.tableHeight = document.getElementsByClassName('tableBox')[0].offsetHeight - 48 window.onresize = () => { this.tableHeight = 0 this.tableHeight = document.getElementsByClassName('tableBox')[0].offsetHeight - 48 } }, methods: { onTabEvent(key) { if (key != this.tabActive) { this.tabActive = key this.searchData.analysisType = key == 0 ? 'MONTH' : 'YEAR' } this.getTableData() }, onSearchDateEvent(val) { this.searchData.dateTime = val this.open = false }, openYearDatePicker(status) { this.open = status }, // 搜索 onSearch() { this.pagination.currentPage = 1 this.getTableData() }, // 获取表格数据 async getTableData() { try { const dateFormat = this.tabActive == 0 ? 'YYYY-M' : 'YYYY' const dateValue = this.searchData.dateTime.format(dateFormat) const params = { analysisType: this.searchData.analysisType, value: dateValue, deptIdListSelect: [1, 2], page: this.pagination.currentPage, pageSize: this.pagination.pageSize, } console.log(params, 'paramsparamsparamsparams') const apiMap = { 0: factory.getMonthInfo, 1: factory.getYearInfo } const apiMethod = apiMap[this.tabActive] const res = await apiMethod(params) if (res && res.success) { let headerData = res.data.headers || [] this.dynamicColumns = headerData.map(item => ({ title: item.headerName, dataIndex: item.headerKey, ellipsis: true, resizable: true, minWidth: 100, width: 100, })) this.columns = [...this.baseColumns, ...this.dynamicColumns, ...this.actionColumn] this.tableData = res.data.data.pageData || [] this.pagination.totalRows = res.data.data.totalCount || 0 } else { this.columns = [...this.baseColumns, ...this.dynamicColumns, ...this.actionColumn] } } catch (error) { this.columns = [...this.baseColumns, ...this.dynamicColumns, ...this.actionColumn] this.$message.error(error) } }, // 分页 changePage(currentPage) { this.pagination.currentPage = currentPage this.getTableData() }, // 每页条数发生变化 onShowSizeChange(pageSize) { this.pagination.currentPage = 1 this.pagination.pageSize = pageSize this.getTableData() }, }, } </script> <style lang="less" scoped> .abnormal-statistics { width: 100%; height: 100%; box-sizing: border-box; position: relative; .type-tabs { margin-right: 4px; .tabs-item { padding: 0 18px; line-height: 30px; border: 1px solid #e9ebee; cursor: pointer; font-size: 14px; color: #fff; margin-right: -1px; &:first-child { border-radius: 3px 0 0 3px; } &:last-child { border-radius: 0 3px 3px 0; } &-active { color: #1c79f4; border: 1px solid #1c79f4; background: rgba(28, 121, 244, 0.1); z-index: 2; } } } } </style> 代码评审

from ascript.android.ui import FloatWindow import time class AutomationUI(FloatWindow): # 继承自悬浮窗口类 def init(self): super().init(width=300, height=400, title=“自动点击器”) self.clicknum = 0 self.build_ui() def build_ui(self): # 构建UI布局 self.container = Container( layout="vertical", padding=20, children=[ Label( text="资讯自动点击器", font_size=24, color="#FFFFFF", background="#2196F3", padding=10 ), Button( id="btn_start", text="▶ 开始执行", font_size=20, background="#4CAF50", padding=15, on_click=self.start_automation ), Label( id="lbl_status", text="就绪", font_size=18, color="#666666", margin_top=20 ), Label( id="lbl_count", text="已点击次数:0", font_size=16, color="#333333", margin_top=10 ) ] ) self.add_view(self.container) # 启动自动化线程 def start_automation(self, widget): widget.text = "⏸ 运行中" widget.background = "#FF9800" self.update_label("lbl_status", "正在初始化...") Thread(target=self.run_automation).start() # 自动化主逻辑 def run_automation(self): try: action.slide(157,834,946,734) Selector().text("资讯").parent(1).click().find() self.clicknum = 0 while True: matches = FindImages.find_all_template( [R.img("2.png")], confidence=0.95 ) if matches: for match in matches: x = match["center_x"] y = match["center_y"] action.click(x, y) self.clicknum += 1 self.update_label("lbl_count", f"已点击次数:{self.clicknum}") time.sleep(3.5) if self.clicknum > 30: self.stop_automation() return action.slide(157,834,946,734,30) time.sleep(2) except Exception as e: self.show_error(str(e)) # 更新UI状态 def update_label(self, widget_id, text): for child in self.container.children: if child.id == widget_id: child.text = text break # 异常处理 def show_error(self, msg): self.update_label("lbl_status", f"错误:{msg}") self.reset_ui() # 重置UI状态 def stop_automation(self): self.update_label("btn_start", "▶ 开始执行") self.container.children[1].background = "#4CAF50" # 更新按钮背景色 self.update_label("lbl_status", "已完成30次点击") 启动悬浮窗 ui = AutomationUI() ui.show()TypeError: object.init() takes exactly one argument (the instance to initialize) 2025-03-05 19:57:10:961: .test.init(init.py:6) 2025-03-05 19:57:10:961: .test.<module>(init.py:107)

<template> <el-card class="search-card"> <el-form-item label="上课日期:"> <el-radio-group class="custom-radio-group" @change="getData" v-model="query.timeType"> <el-radio-button label="不限" :value="-1" /> <el-radio-button label="本周" :value="1" /> <el-radio-button label="本月" :value="2" /> <el-radio-button label="上月" :value="3" /> <el-radio-button label="自定义" :value="4" /> </el-radio-group> </el-form-item> <el-divider border-style="dashed" class="query-split-line" /> <el-form-item label="补课状态:"> <el-radio-group class="custom-radio-group" @change="getData" v-model="query.makeupStatus"> <el-radio-button label="不限" :value="-1" /> <el-radio-button label="已补课" :value="1" /> <el-radio-button label="未补课" :value="0" /> </el-radio-group> </el-form-item> <el-divider border-style="dashed" v-if="showMore" class="query-split-line" /> <el-form-item label="更多筛选:" class="more-filter" v-show="showMore"> <el-select placeholder="授课模式" clearable v-model="query.teachType" @change="getData"> <el-option label="班课" :value="1" /> <el-option label="1对1" :value="2" /> </el-select> <CampusSelect placeholder="校区" multiple @change="getData" clearable v-model="query.campusIds" /> <GradeSelect placeholder="年级" multiple @change="getData" clearable v-model="query.grades" /> <SubjectSelect placeholder="科目" multiple @change="getData" clearable v-model="query.subjectIds" /> <CourseTypeSelect placeholder="课程类型" v-model="query.courseTypeIds" clearable multiple @change="getData" /> <TeacherSelect placeholder="请选择老师" @change="getData" clearable v-model="query.teacherId" filterable /> <TeacherSelect placeholder="请选择教务" @change="getData" clearable v-model="query.assistantId" filterable /> <DatePicker transfer type="daterange" placeholder="补课日期" :value="query.makeupDateRange" style="width: 200px" @on-change="onMakeupDateRangeChange" /> <el-select placeholder="上课时间段" /> <el-select placeholder="上课教室" @change="getData" /> </el-form-item> <el-divider border-style="dashed" class="cursor-pointer query-split-line" @click="showMore = !showMore"> {{ showMore ? "收起" : "更多筛选" }} <el-icon> <ArrowUp v-if="showMore" /> <ArrowDown v-else /> </el-icon> </el-divider> </el-card> <el-card> {{ total }} 条班级记录 <el-input placeholder="输入学生关键字查询" v-model="input" class="input-with-select"> <template #prepend> <el-select v-model="selectType" style="width: 80px"> <el-option label="课程" value="course" /> <el-option label="班级" value="class" /> <el-option label="学生" value="student" /> </el-select> </template> </el-input> <el-dropdown @command="(command: string) => handleMakeupAction(selectedRows, command, true)"> <el-button class="batch-action-btn"> 批量操作 <el-icon><arrow-down /></el-icon> </el-button> <template #dropdown> <el-dropdown-menu> <el-dropdown-item @click="handleBatchMakeup">直接补课</el-dropdown-item> <el-dropdown-item command="cancel">取消补课</el-dropdown-item> </el-dropdown-menu> </template> </el-dropdown> <SelectionTable ref="tableRef" :data="tableData" header-cell-class-name="table-header" border v-model="selectedRows"> <el-table-column label="上课日期" show-overflow-tooltip min-width="180"> <template #default="scope">{{ moment(scope.row.date).format("YYYY-MM-DD ") }}</template> </el-table-column> <el-table-column label="上课时间" show-overflow-tooltip min-width="180" prop="classItem.classTime" /> <el-table-column label="ID" show-overflow-tooltip min-width="100" prop="student.id" /> <el-table-column label="班级" show-overflow-tooltip min-width="300" prop="classGroup.name" /> <el-table-column label="学员" show-overflow-tooltip min-width="100" prop="student.name" /> <el-table-column label="老师" show-overflow-tooltip min-width="100"> <template #default="scope"> {{ getNames(scope.row.classItem.teachers).join(",") }} </template> </el-table-column> <el-table-column label="教务" show-overflow-tooltip min-width="100"> <template #default="scope"> {{ getNames(scope.row.classGroup.assistants).join(",") }} </template> </el-table-column> <el-table-column label="考勤状态" width="100"> <template #default="scope"> <el-tag v-if="scope.row.classItem.status == 1" type="success">出勤</el-tag> <el-tag v-else-if="scope.row.classItem.status == 2" type="warning">请假</el-tag> <el-tag v-else-if="scope.row.classItem.status == 3" type="danger">缺勤</el-tag> <el-tag v-else type="info">未知</el-tag> </template> </el-table-column> <el-table-column label="补课状态" width="100"> <template #default="scope"> <el-tag v-if="scope.row.makeupStatus == 0" type="info">未补课</el-tag> <el-tag v-else-if="scope.row.makeupStatus == 1" type="success">已补课</el-tag> </template> </el-table-column> <el-table-column label="补课类型" width="100"> <template #default="scope"> <el-tag v-if="scope.row.makeupType == MakeupType.Direct" type="success">直接补课</el-tag> <el-tag v-else-if="scope.row.makeupType == MakeupType.MakeupInOtherClass" type="success">插班补课</el-tag> </template> </el-table-column> <el-table-column label="补课老师" width="100"> <template #default="scope"> {{ getNames([scope.row.teacherId]).join(",") }} </template> </el-table-column> <el-table-column label="补课日期" width="100" prop="makeupDate"> <template #default="scope"> {{ scope.row.makeupDate ? moment(scope.row.makeupDate).format("YYYY-MM-DD") : "" }} </template> </el-table-column> <el-table-column label="备注" show-overflow-tooltip width="120" prop="remark" /> <el-table-column label="操作" width="80" fixed="right"> <template #default="{ row }"> <el-dropdown trigger="click"> 更多 <el-icon class="arrow-icon"><ArrowDown /></el-icon> <template #dropdown> <el-dropdown-menu> <el-dropdown-item v-if="row.makeupStatus === 0" @click="handleMakeup">直接补课</el-dropdown-item> <el-dropdown-item v-if="row.makeupStatus === 1" @click="cancelMakeup(row)">取消补课</el-dropdown-item> </el-dropdown-menu> </template> </el-dropdown> </template> </el-table-column> </SelectionTable> </el-card> <el-dialog v-model="directMakeup" title="直接补课" width="600px"> <el-form :model="form" label-position="top" ref="formRef" :rules="rules"> <el-form-item label="补课老师" prop="teacherId"> <TeacherSelect v-model="form.teacherId" filterable clearable placeholder="请选择老师" /> </el-form-item> <el-form-item label="补课日期" prop="makeupDate"> <el-date-picker v-model="form.makeupDate" type="date" value-format="YYYY-MM-DD" placeholder="请选择补课日期" style="width: 40%" /> </el-form-item> <el-form-item label="补课时间段" prop="makeUpTimeRange"> <TimePicker confirm type="timerange" :value="form.makeUpTimeRange" @on-change="onTimeRangeChange" placeholder="请选择上课时段" :steps="[1, 15]" :format="timeFormat" /> </el-form-item> <el-form-item label="备注" prop="remark"> <el-input v-model="form.remark" placeholder="请填写备注" type="textarea" /> </el-form-item> </el-form> <template #footer> <el-button type="primary" :disabled="loading" @click="handleConfirmMakeup">确定</el-button> <el-button @click="handleDialogClose">取消</el-button> </template> </el-dialog> <el-dialog v-model="inclassMakeup" title="插班补课" width="1000px"> <el-alert title="只支持同课程下的班级安排补课,每个月3号过后,不能插入上个月及以前月份的班级" type="warning" class="mb-4" /> <CampusSelect placeholder="请选择" v-model="classItemQuery.campusIds" multiple @change="getClassItemList" style="width: 90px" /> <el-autocomplete placeholder="请选择班级" style="width: 180px" clearable /> <el-date-picker type="daterange" value-format="YYYY-MM-DD" start-placeholder="开始日期" end-placeholder="结束日期" class="w-64" /> <el-table :data="classItemList" border header-cell-class-name="table-header" @selection-change="handleClassItemSelectionChange"> <el-table-column type="selection" width="55" align="center" :selectable="() => true" :reserve-selection="false"> <template #header> </template> </el-table-column> <el-table-column label="班级" show-overflow-tooltip min-width="180" prop="classGroup.name" /> <el-table-column label="上课时间" show-overflow-tooltip min-width="180"> <template #default="scope">{{ moment(scope.row.date).format("YYYY-MM-DD ") }}{{ scope.row.startTime }} - {{ scope.row.endTime }}</template> </el-table-column> <el-table-column label="老师" show-overflow-tooltip min-width="100"> <template #default="scope"> {{ getNames(scope.row.teachers).join(",") }} </template> </el-table-column> <el-table-column label="教室" show-overflow-tooltip min-width="100" prop="classRoomName" /> </el-table> <template #footer> <el-button type="primary" :disabled="loading" @click="submitMakeupInclass">确定</el-button> <el-button @click="inclassMakeup = false">取消</el-button> </template> </el-dialog> </template> <script setup lang="ts"> import type { ElTable, FormInstance } from "element-plus"; import moment from "moment"; import { useUserStore } from "@/store"; import { Makeup, MakeupQuery, MakeupStatus, MakeupType, rules } from "@/models/enroll/Makeup"; import { useRouter } from "vue-router"; import { MakeupAPI } from "@/api/MakeupApi"; import { DatePicker } from "view-ui-plus"; import { ClassItem } from "@/models/routine/ClassGroup"; import { RoutineAPI } from "@/api/RoutineAPI"; import { ClassItemQuery } from "@/models/routine/scheduleTable/Query"; import { TimePicker } from "view-ui-plus"; const classItemList = ref<ClassItem[]>([]); const userStore = useUserStore(); const directMakeup = ref(false); const inclassMakeup = ref(false); const timeFormat: any = "HH:mm"; // 状态管理 const loading = ref(false); const showMore = ref(true); const tableData = ref<Makeup[]>([]); const total = ref(0); const input = ref(""); const selectType = ref("student"); const tableRef = ref(); const selectedRows = ref<Makeup[]>([]); const query = ref<MakeupQuery>(new MakeupQuery()); const classItemQuery = ref<ClassItemQuery>(new ClassItemQuery()); //插班补课表格复选框 const selectedClassItems = ref<ClassItem[]>([]); function handleClassItemSelectionChange(rows: ClassItem[]) { selectedClassItems.value = rows; } //直接补课表单 const formRef = ref<FormInstance>(); const form = ref(new Makeup()); //重置直接补课表单,清除验证状态 function resetForm() { form.value = new Makeup(); nextTick(() => { if (formRef.value) { formRef.value.clearValidate(); // 清除验证状态 } }); } //统一对话框关闭处理 function handleDialogClose() { resetForm(); directMakeup.value = false; } function onTimeRangeChange(range: string[]) { form.value.makeUpTimeRange = range[0] ? range : []; } //提交补课 async function handleConfirmMakeup() { formRef.value?.validate(async (pass) => { if (pass) { if (form.value.id) { loading.value = true; form.value.makeupStatus = MakeupStatus.Completed; const res = await MakeupAPI.updateMakeup(form.value); loading.value = false; if (res) { handleDialogClose(); getData(); } } else { const datas = selectedRows.value.map((item) => { item.makeupStatus = MakeupStatus.Completed; const data = new Makeup(); Object.assign(data, item); data.makeupType = form.value.makeupType; data.makeUpTimeRange = form.value.makeUpTimeRange; data.makeupDate = item.makeupDate; data.teacherId = form.value.teacherId; data.makeupDate = form.value.makeupDate; data.makeupStatus = item.makeupStatus; data.remark = form.value.remark; return data; }); loading.value = true; const res = await MakeupAPI.updateMakeupBatch(datas); loading.value = false; if (res) { handleDialogClose(); getData(); } } } }); } /** 提交插班补课 */ function submitMakeupInclass() {} function handleMakeup(row: Makeup) { form.value = JSON.parse(JSON.stringify(row)); form.value.makeupType = MakeupType.Direct; directMakeup.value = true; } function handleBatchMakeup() { if (selectedRows.value.length === 0) { ElMessage.warning("请先选择需要补课的数据"); return; } if (selectedRows.value.some((item) => item.makeupStatus !== 0)) { ElMessage.warning("请选择未补课的数据"); return; } form.value = new Makeup(); form.value.makeupType = MakeupType.Direct; directMakeup.value = true; } async function cancelMakeup(row: Makeup) { ElMessageBox.confirm("确定要取消补课吗?", "提示", { confirmButtonText: "确定", cancelButtonText: "取消", }) .then(async () => { loading.value = true; const res = await MakeupAPI.cancelMakeup([row.id]); loading.value = false; if (res) { getData(); } }) .catch(() => { ElMessage.info("操作取消"); }); } //补课类型选择 const handleMakeupAction = async (rows: Makeup[], action: string, isBatch = false) => { try { if (!isBatch) { // 单条操作,直接执行,无需校验 const row = rows[0]; switch (action) { case "in-class": selectedRows.value = rows; (async () => { await getClassItemList(); inclassMakeup.value = true; })(); return; case "cancel": //cancelMakeup接口 try { await ElMessageBox.confirm("确定要取消这条补课记录吗?", "取消确认", { confirmButtonText: "确定", cancelButtonText: "取消", type: "warning", }); } catch (cancel) { return; // 用户取消操作 } const cancelSuccess = await MakeupAPI.cancelMakeup([row.id]); if (cancelSuccess) { ElMessage.success("取消成功"); getData(); // 刷新数据 } return; } return; } // 批量操作校验 const makeStatuses = new Set(rows.map((r) => r.makeupStatus)); if (makeStatuses.size > 1 && action === "cancel") { ElMessage.warning("请选择相同补课状态的记录进行批量操作"); return; } const makeStatuse = rows[0].makeupStatus; if (action === "cancel" && makeStatuse !== 1) { ElMessage.warning("只有已补课状态的记录才允许取消补课"); return; } // if ((action === "direct" || action === "in-class") && makeStatuse !== 0) { // ElMessage.warning("只有未补课状态的记录才允许进行补课操作"); // return; //} // 批量操作取消补课 if (action === "cancel") { // 添加用户确认 try { await ElMessageBox.confirm(确定要取消选中的${rows.length}条补课记录吗?, "批量取消确认", { confirmButtonText: "确定", cancelButtonText: "取消", type: "warning", }); } catch (cancel) { return; // 用户取消操作 } // 调用取消补课API const ids = rows.map((r) => r.id); const cancelSuccess = await MakeupAPI.cancelMakeup(ids); if (cancelSuccess) { ElMessage.success("批量取消成功"); getData(); // 刷新数据 // 清空选择 selectedRows.value = []; tableRef.value?.clearSelection(); } return; } else { if (action === "direct") { selectedRows.value = rows; directMakeup.value = true; return; } else if (action === "in-class") { rows.forEach((r) => { selectedRows.value = rows; inclassMakeup.value = true; }); getData(); } } } finally { loading.value = false; } }; async function getData() { loading.value = true; const res = await MakeupAPI.queryMakeup(query.value); loading.value = false; tableData.value = Array.isArray(res?.records) ? res.records : []; total.value = res?.total || 0; nextTick(() => { tableRef.value.toggleSelection(selectedRows.value); }); } async function getClassItemList() { loading.value = true; const res = (await RoutineAPI.queryClassItem(classItemQuery.value)) as PageResult<ClassItem>; loading.value = false; classItemList.value = (res?.records ?? []) as ClassItem[]; total.value = (res?.total ?? 0) as number; } function getNames(row: string[]) { return row?.map((r) => userStore.userNameMap.get(parseInt(r))) ?? []; } function handleSelectionChange(rows: Makeup[]) { selectedRows.value = rows; } function onMakeupDateRangeChange(range: string[]) { query.value.makeupDateRange = range[0] ? [range[0] + " 00:00:00", range[1] + " 23:59:59"] : []; getData(); } onMounted(() => { getData(); getClassItemList(); }); </script> <style lang="scss" scoped></style> 你帮我检查一下,为什么我现在直接补课直接用不了了,请求内容[] No properties 回复{ "success": false, "code": 500, "message": "补课失败", "data": null }

最新推荐

recommend-type

中孚密保卫士是由中孚信息股份有限公司开发的一款信息安全产品,主要用于终端计算机的保密管理和数据防泄漏 它主要面向政府机关、军工单位、科研院所等对信息安全有较高要求的涉密单位,帮助其实现对涉密信息的全

终端保密管理:对计算机终端的操作行为进行监控和审计,防止违规外联、非法拷贝、打印、截屏等行为。 数据防泄漏(DLP):通过内容识别、加密、权限控制等手段,防止敏感或涉密数据通过U盘、网络、邮件等途径泄露。 文件加密与权限控制:对涉密文件进行透明加密,确保文件在授权范围内使用,防止未授权人员查看或传播。 行为审计与日志记录:详细记录用户的操作行为(如文件访问、外发、打印等),便于事后追溯和审计。 违规外联监控:防止涉密计算机违规连接互联网或其他非授权网络,保障网络边界安全。 移动存储介质管理:对U盘、移动硬盘等设备进行授权管理,区分普通盘和专用盘,防止非法数据拷贝。
recommend-type

Python批量发送短信验证码的实现方法.doc

Python批量发送短信验证码的实现方法.doc
recommend-type

信号处理领域中经验模态分解(EMD)对复杂信号进行IMF分量提取与应用

内容概要:本文介绍了经验模态分解(EMD)这一强大的信号处理技术,详细解释了EMD如何将复杂信号分解为多个内在模态函数(IMF)分量,从而揭示信号的局部特征。文中不仅提供了理论背景介绍,还给出了具体的Python代码实例,展示了EMD在去除心电图基线漂移和分析多层信号方面的实际应用场景。同时指出了EMD存在的局限性和优化方法,如边界效应和模态混叠问题及其解决方案。 适合人群:从事信号处理相关工作的研究人员和技术人员,尤其是对非平稳信号处理感兴趣的从业者。 使用场景及目标:适用于需要从复杂信号中提取有用信息的各种场合,如金融数据分析、生物医学工程等领域。目标是帮助读者掌握EMD的基本原理和具体应用,提高处理非平稳信号的能力。 阅读建议:建议读者结合提供的代码片段动手实践,深入理解EMD的工作机制以及如何针对不同类型的数据选择合适的参数设置。
recommend-type

快速浏览Hacker News热门故事的浏览器扩展

Hacker News Browser-crx插件是一款专为浏览器设计的扩展程序,它允许用户从任何网页上浏览Hacker News上的热门故事,该网站是科技界尤其是编程和创业圈子中非常受欢迎的信息交流平台。Hacker News上的内容主要包括编程、科技创业、互联网趣闻以及相关的讨论。它由Y Combinator(一家知名的硅谷创业孵化器)所维护。 ### 关键知识点解析: 1. **扩展程序(Extension)**: - 扩展程序是一种软件,旨在为浏览器提供额外功能和定制选项。它们可以增强用户的浏览体验,提高效率和安全性。扩展程序通常开发于HTML、CSS和JavaScript技术栈,可以针对不同的浏览器开发,如Chrome、Firefox、Safari等。 2. **Hacker News简介**: - Hacker News(也称为Hacker News或者HN)是一个新闻社交网站,由Paul Graham和Trevor Blackwell等人于2007年发起,隶属于Y Combinator。它提供了一个平台,让用户分享、讨论技术新闻和创业公司的相关文章。Hacker News社区以其高质量的讨论和新闻而闻名,吸引了大量程序员、企业家和科技爱好者。 3. **Hacker News Browser-crx插件功能**: - **浏览过去24小时的热门故事**:插件允许用户查看Hacker News中最近24小时内的热门内容。这为用户提供了快速获取当前科技界热门话题的途径。 - **保存故事到Pocket**:Pocket是一个服务,允许用户保存文章、视频和网页以便离线阅读。Hacker News Browser-crx插件可以与用户的Pocket账户集成,方便用户保存他们感兴趣的内容到自己的Pocket列表中。 - **直接从扩展发推文**:社交媒体是现代信息传播的一个重要渠道。通过这个功能,用户可以将他们在Hacker News上的发现直接通过Twitter分享给他们的关注者。 - **搜索特定主题**:用户可以使用这个功能来搜索Hacker News上的特定主题或关键词,从而快速定位他们感兴趣的内容。 4. **如何使用Hacker News Browser-crx插件**: - 安装扩展:用户需要从浏览器的扩展商店下载并安装Hacker News Browser-crx插件。由于给定信息中提供的文件名为Hacker_News_Browser.crx,这表明这可能是一个Chrome扩展。 - 启用扩展:安装完成后,用户需要在浏览器的扩展管理界面启用该插件。 - 进行配置(可选):根据需要,用户可能需要对插件进行一些基本配置,比如设置Pocket账户等。 - 使用功能:安装并配置完成后,用户可以开始使用扩展提供的各项功能,包括浏览热门故事、保存内容到Pocket、发推文和搜索特定主题。 ### 总结: Hacker News Browser-crx插件作为一个扩展程序,为用户提供了便捷的途径去浏览和参与Hacker News上的讨论。该插件整合了多种功能,让读者能够实时关注科技动态,并与他人分享讨论。对于科技爱好者以及相关行业的专业人士,这是一个极具价值的工具,它能够帮助他们保持信息的及时更新和知识的持续吸收。
recommend-type

【MATLAB通信建模秘籍】:5个技巧让你为通信系统打下坚实基础

# 1. MATLAB通信建模基础概览 MATLAB(矩阵实验室)作为一种强大的科学计算软件,在通信系统建模和仿真领域扮演着重要角色。对于初学者而言,了解MATLAB的基础操作和通信建模的基本概念是开启深入学习之旅的第一步。 ## 1.1 MATLAB简介及其在通信领域的应用 MATLAB是一个高性能的数值计算和可视化软件,广泛应用于工程计算、算法开发、数据分析等领域。在通
recommend-type

汽车车载通讯技术

<think>我们正在讨论汽车车载通讯技术。根据之前的引用,我们知道汽车通信网络分为车内(有线)和车外(无线)两部分。同时,车载SOA架构使用多种通信技术(如CAN总线、以太网、MQTT等)来实现模块化和可扩展的通信。 用户的问题:汽车车载通讯技术原理及应用 回答结构: 1. 概述:简要介绍汽车车载通讯技术的定义和分类。 2. 原理部分:分别介绍车内网络和车外网络的主要技术原理。 2.1 车内网络:重点介绍CAN总线、LIN总线、FlexRay、MOST、Automotive Ethernet等。 2.2 车外网络:介绍V2X(包括V2V、V2I、V2P、V2N)及相
recommend-type

Dev Context Menu Utils (beta)-快速开发浏览器扩展

Dev Context Menu Utils (beta)-crx插件是一款面向开发者群体的浏览器扩展程序,其beta版本的命名暗示了它目前还在开发的早期阶段,可能尚未完全稳定或者未包含全部功能。从标题来看,这款扩展程序旨在为开发者提供便捷的上下文菜单功能。 上下文菜单(Context Menu)通常指的是当用户在软件或网页上右键点击时弹出的菜单。上下文菜单的内容根据点击的位置和对象会有所不同,它可以为用户提供快捷、针对当前情境的操作选项。在浏览器中,上下文菜单经常被用于快速访问开发者工具、页面操作、或是网页内容处理等功能。 标题中提到的“CNPJ”和“CPF”是巴西的法人和自然人的税务识别代码。CNPJ(Cadastro Nacional de Pessoas Jurídicas)是巴西所有公司和企业的全国性注册代码,而CPF(Cadastro de Pessoas Físicas)是巴西公民的个人税务识别码。在Dev Context Menu Utils (beta)中加入这两个菜单项,可能意味着插件能够让开发者在遇到需要验证或输入这些税务识别码的场景时,通过浏览器的右键菜单快速生成示例代码或进行其他相关操作。 “Lorem Ipsum”是设计和排版行业常用的一种占位文本,它起源于拉丁文学,经常用于设计软件的文本预览,以便设计师在不影响最终版式的情况下测试页面布局。在这款插件的上下文菜单中加入这一项,可能允许用户快速生成一段Lorem Ipsum文本,用于测试网页布局或者排版效果,从而让开发者在设计过程中获得更真实的视觉体验。 “电话”菜单项则可能用于提供快速生成或者验证电话号码格式的功能,这对于处理与电话相关的用户输入或数据录入工作非常有用。考虑到不同国家和地区的电话号码格式可能有所不同,这一功能可能允许用户选择特定的地区代码,从而生成相应格式的电话号码样例。 【标签】中提到的“扩展程序”一词,是指能够被浏览器安装并添加额外功能的软件。扩展程序可以改变浏览器的基本界面、行为和功能,是Web开发和测试中常见的工具。它们通常由浏览器的开发者或者第三方开发者创建,对于提升开发效率、调试和测试网站有着重要的作用。 【压缩包子文件的文件名称列表】中的“Dev_Context_Menu_Utils_(beta).crx”是这款插件的文件名,CRX是Chrome扩展程序的文件格式,类似于Windows平台上的.exe可执行文件格式,只不过CRX是为Chrome浏览器特别设计的。扩展程序开发者需要通过Chrome Web Store或者其他途径将CRX文件分发给用户,用户可以通过下载并安装CRX文件来使用扩展程序。 总体来说,Dev Context Menu Utils (beta) 插件通过为开发者提供便捷的上下文菜单项来增强开发效率,允许快速生成重要的代码片段和数据格式,从而简化开发过程中的常见任务。对于那些在开发阶段需要频繁使用这些功能的开发者来说,这款插件将是一个非常有价值的工具。然而,由于它目前还是beta版本,使用时可能需要注意可能存在的一些错误或功能限制,并建议开发者在实际项目中使用前先在测试环境中进行充分的测试。
recommend-type

【Coz进阶秘籍】:解锁工作流高级功能,提升效率的终极技巧

# 1. Coz工作流基础概述 工作流系统是现代IT运营不可或缺的一部分,它通过自动化执行任务和协调业务流程来提高效率。在本章节中,我们将首先介绍Coz工作流的基础概念和其在业务流程自动化中的应用。Coz工作流利用一系列预定义的任务、规则以及任务之间的依赖关系,按照既定规
recommend-type

HR和HRBP区别

<think>首先,用户意图是了解HR和HRBP的区别。用户问题是“HR和HRBP的区别”。我需要根据任务要求进行网络搜索。 任务要求: 1. 调用网络搜索工具进行检索。 2. 整合检索到的内容,生成详细且清晰的回答。 3. 禁止将所有引用内容集中在回答末尾。 4. 避免使用第一人称如“我”。 5. 避免步骤词汇如“首先”、“然后”。 6. 尽量将答案组织为多个方法或步骤,并在每个步骤间换行。 7. 对于代码和公式:如果有,必须使用指定格式。 8. 在回答最后添加相关问题部分,标题为“§§相关问题§§:”,后跟至少3个相关问题,每个用阿拉伯数字标号。 由于问题是关于HR和HRBP的区别,不
recommend-type

阻止Web加密货币挖掘的Miner Away扩展

### 知识点分析 #### 标题:“Miner Away-crx插件” **知识点**: 1. **CRX插件格式**:CRX是Chrome扩展程序的文件格式,它是一个ZIP压缩包,包含了扩展程序的所有文件和文件夹,例如HTML、JavaScript、CSS文件,以及扩展程序的清单文件(manifest.json)。CRX文件可以直接在Chrome浏览器的扩展管理界面拖拽安装。 2. **扩展程序(Extension)**:浏览器扩展程序是一种增加或改进浏览器功能的软件模块。它可以通过第三方开发者创建,用以提供特定的功能,比如用户界面定制、广告拦截、内容过滤等。 #### 描述:“在网上停止硬币矿工!” **知识点**: 3. **加密货币挖掘(Cryptocurrency Mining)**:指的是利用计算机的处理能力来计算加密货币的交易并维护区块链的过程。传统的加密货币挖掘需要大量的计算资源和电力消耗,近年来出现了基于Web的挖矿,即在网页中嵌入JavaScript代码,利用访问者的浏览器进行挖掘。 4. **矿工拒绝(Cryptominer Blocking)**:矿工拒绝功能的扩展通常用于识别和阻止这类JavaScript代码运行,从而保护用户设备的性能不受影响。这类扩展程序通常会维护一个黑名单,其中包含已知的挖矿脚本或网站地址。 5. **Opera Web Store**:Opera浏览器的官方扩展商店,类似于Chrome Web Store或Firefox Add-ons,是用户下载、安装和管理Opera浏览器扩展程序的平台。 6. **特征(Features)**: - **阻止JavaScript或Web矿工**:扩展能够检测并阻止网页加载的挖矿脚本。 - **域名选择性允许**:用户可以自行选择允许哪些特定网站加载JavaScript。 - **状态显示**:扩展程序会实时显示当前是否有挖矿行为发生。 - **通知功能**:当有网站尝试进行挖矿时,用户会即时收到桌面通知。 7. **技术实现细节**: - **黑名单机制**:扩展使用黑名单文件(*blacklist.txt*),其中包含被识别为执行挖矿行为的域名。 - **请求拦截**:对与黑名单中域名匹配的网站请求进行拦截,从而防止挖矿脚本运行。 #### 标签:“扩展程序” **知识点**: 8. **浏览器扩展程序的分类**:扩展程序通常根据其功能进行分类,如广告拦截器、密码管理器、下载管理器等。 9. **扩展程序的管理**:用户通常可以在浏览器的扩展管理界面中开启/关闭扩展、管理扩展权限、删除扩展等。 #### 压缩包子文件的文件名称列表:“Miner_Away.crx” **知识点**: 10. **文件命名约定**:扩展程序的文件名通常与其功能相关,例如本例中的“Miner_Away”暗示了该扩展用于阻止挖矿行为。 11. **文件的安装**:CRX文件可以通过多种方式进行安装,最常见的方式是直接从浏览器的扩展管理界面导入(通常通过拖拽文件到浏览器窗口),或者从扩展商店下载安装。 12. **文件的安全性**:用户应从可信来源下载扩展程序,避免下载可能含有恶意软件的非官方版本。 总结以上知识点,Miner Away扩展程序是一种专门设计用于阻止Web矿工的浏览器扩展,它通过黑名单机制拦截和阻止网站加载的加密货币挖掘脚本,保护用户的设备免受未经授权的资源消耗。该扩展还提供实时状态通知和请求拦截功能,为用户提供了更为安全和高效的网络浏览体验。