input type=file撤销选中图片

本文介绍了如何实现点击图片后撤销input[type='file']中已选择的图片,主要通过清除input元素的value来达到目的。

实现目标:点击图片取消input="file"里选中图片
原理:将input="file"的value清除

 <input type="file" id="file" accept="image/* name="pic">
 <img src="" alt="图片" id="img"  style="width: 50px;margin-top:10px;display: none;cursor:pointer"title="点击撤销图片">
 <script>
  $("#img").on('click', function () {
            $("#file").val("");
            $(this).attr('src', '').css('display','none');
        })
 </script>
我现在就负责把管理员模块前端完善好,你告诉我我怎么做,以下是我现有的管理员模块代码addminadd.html: <!DOCTYPE html> <html> <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"> <meta name="apple-mobile-web-app-status-bar-style" content="black"> <meta name="apple-mobile-web-app-capable" content="yes"> <meta name="format-detection" content="telephone=no"> <script type="text/javascript" src="lib/loading/okLoading.js"></script> <link rel="stylesheet" href="css/main.css" media="all"> </head> <style> .imgs{display: none;} .picture{display: none;} </style> <body> <div class="x-body"> <form class="layui-form" id="adminadd"> <input type="hidden" name="id" value=""> <div class="layui-form-item"> <label for="username" class="layui-form-label"> <span class="x-red">*</span>登录名 </label> <div class="layui-input-inline"> <input type="text" id="name" name="name" required="" lay-verify="required" autocomplete="off" class="layui-input" value=""> </div> <div class="layui-form-mid layui-word-aux"> <span class="x-red">*</span>将会成为您唯一的登入名 </div> </div> <div class="layui-form-item"> <label for="phone" class="layui-form-label"> <span class="x-red">*</span>手机 </label> <div class="layui-input-inline"> <input type="text" id="phone" name="phone" required="" lay-verify="phone" autocomplete="off" class="layui-input" value=""> </div> <div class="layui-form-mid layui-word-aux"> <span class="x-red">*</span>将会成为您唯一的登入名 </div> </div> <div class="layui-form-item"> <label for="role" class="layui-form-label"> <span class="x-red">*</span>用户组 </label> <div class="layui-input-inline"> <select name="group_id"> <option value="">请选择角色</option> <option value="1" >超级管理员</option> </select> </div> </div> <div class="layui-form-item"> <label for="link" class="layui-form-label"> <span class="x-red">*</span>缩略图 </label> <div class="layui-input-inline"> <div class="site-demo-upbar"> <div class=" layui-upload-button" style="border:#FFFFFF ;"> <button type="button" class="layui-btn" id="test1"> <i class="layui-icon"></i>上传图片 </button> <input class="layui-upload" type="file" accept="undefined" id="previewImg" name="img" onchange="upload(this,)"> </div> </div> </div> <a href="javascript:;" style="" class="layui-btn " id="cancel"><i class="layui-icon">ဂ</i>撤销上传</a> </div> <div class="layui-form-item imgs" id="imgshow"> <label class="layui-form-label">缩略图展示 </label> <img src="" id="pimages" name="pimages" style="width: 400px;height: 200px;"/> <input id="avatar" name="image" required="" type="hidden" value=""> </div> <div class="layui-form-item"> <label for="L_pass" class="layui-form-label"> <span class="x-red">*</span>密码 </label> <div class="layui-input-inline"> <input type="password" id="L_pass" name="password" required="" lay-verify="pass" autocomplete="off" class="layui-input" value=""> </div> <div class="layui-form-mid layui-word-aux"> 6到16个字符 </div> </div> <div class="layui-form-item"> <label for="L_repass" class="layui-form-label"> <span class="x-red">*</span>确认密码 </label> <div class="layui-input-inline"> <input type="password" id="L_repass" name="repass" required="" lay-verify="repass" autocomplete="off" class="layui-input"> </div> </div> <div class="layui-form-item"> <label class="layui-form-label">状态</label> <div class="layui-input-block"> <input type="radio" name="status" value="1" title="启用" checked="checked"> <div class="layui-unselect layui-form-radio layui-form-radioed"><i class="layui-anim layui-icon layui-anim-scaleSpring"></i> <div>启用</div> </div> <input type="radio" name="status" value="0" title="禁用" checked="checked"> <div class="layui-unselect layui-form-radio"><i class="layui-anim layui-icon"></i> <div>禁用</div> </div> </div> </div> <div class="layui-form-item"> <label for="L_repass" class="layui-form-label"> </label> <button class="layui-btn" lay-filter="add" lay-submit=""> 增加 </button> </div> </form> </div> <script src="lib/layui/layui.js" charset="utf-8"> </script> <script src="js/x-layui.js" charset="utf-8"> </script> <script> layui.use(['form','layer'], function(){ $ = layui.jquery; var form = layui.form() ,layer = layui.layer; okLoading.close($); //自定义验证规则 /*form.verify({ nikename: function(value){ if(value.length < 5){ return '昵称至少得5个字符啊'; } } ,pass: [/(.+){6,12}$/, '密码必须6到12位'] ,repass: function(value){ if($('#L_pass').val()!=$('#L_repass').val()){ return '两次密码不一致'; } } });*/ //监听提交 form.on('submit(add)', function(data){ var admindate=$("#adminadd").serialize(); //var data = data.field; $.ajax({ type:'post', url:"xxx", data:admindate, datatype:"json", success:function (data) { if(data.status==1){ layer.msg(data.info,{icon:1,time:1000}); setTimeout(function(){ window.parent.location.reload(); var index = parent.layer.getFrameIndex(window.name); parent.layer.close(index); },1000); return false; }else{ layer.msg(data.info,{icon:5,time:2000});return false; } } }) return false; }); }); </script> <script> //轮播图上传 function upload(obj,id) { var formData = new FormData(); formData.append('img', $('#previewImg')[0].files[0]); formData.append('id', id);//将id追加再id中 layer.msg('图片上传中', {icon: 16}); $.ajax({ type:"post", processData: false, contentType: false, url:"xxx", data:formData, success:function(data){ if(data.status == 1){ //console.log(data.image_name); layer.closeAll('loading'); //layer.msg(data.info,{icon:1,time:1000}); $("#pimages").attr('src',data.image_name); $("#avatar").val(data.image_name); $(".imgs").show(); return false; }else{ layer.msg(data.info,{icon:2,time:1000}); } } }); } </script> </body> </html> 和adminlist.html: <!DOCTYPE html> <html> <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"> <meta name="apple-mobile-web-app-status-bar-style" content="black"> <meta name="apple-mobile-web-app-capable" content="yes"> <meta name="format-detection" content="telephone=no"> <script type="text/javascript" src="lib/loading/okLoading.js"></script> <link rel="stylesheet" href="css/main.css" media="all"> <link rel="stylesheet" href="css/bootstrap.css"> </head> <body> <div class="x-nav"> <span class="layui-breadcrumb"> <a><cite>首页</cite></a> <a><cite>管理员管理</cite></a> <a><cite>管理员列表</cite></a> </span> <a class="layui-btn layui-btn-small" style="line-height:1.6em;margin-top:3px;float:right" href="javascript:location.replace(location.href);" title="刷新"><i class="layui-icon" style="line-height:30px">ဂ</i></a> </div> <div class="x-body"> <form class="layui-form x-center" action="" style="width:80%"> <div class="layui-form-pane" style="margin-top: 15px;"> <div class="layui-form-item"> <label class="layui-form-label">日期范围</label> <div class="layui-input-inline"> <input class="layui-input" placeholder="开始日" id="LAY_demorange_s"> </div> <div class="layui-input-inline"> <input class="layui-input" placeholder="截止日" id="LAY_demorange_e"> </div> <div class="layui-input-inline"> <input type="text" name="username" placeholder="请输入登录名" autocomplete="off" class="layui-input"> </div> <div class="layui-input-inline" style="width:80px"> <button class="layui-btn" lay-submit="" lay-filter="sreach"><i class="layui-icon"></i></button> </div> </div> </div> </form> <xblock> <button class="layui-btn layui-btn-danger" onclick="delAll()"><i class="layui-icon"></i>批量删除</button> <button class="layui-btn" onclick="admin_add('添加用户','adminadd.html','600','500')"><i class="layui-icon"></i>添加</button> <span class="x-right" style="line-height:40px">共有数据:88 条</span> </xblock> <table class="layui-table"> <thead> <tr> <th> <input type="checkbox" name="" value=""> </th> <th> ID </th> <th> 登录名 </th> <th> 手机 </th> <th> 邮箱 </th> <th> 角色 </th> <th> 加入时间 </th> <th> 状态 </th> <th> 操作 </th> </tr> </thead> <tbody> <tr> <td> <input type="checkbox" value="1" name=""> </td> <td> 1 </td> <td> admin </td> <td > 1111111111 </td> <td > 1111111@qq.com </td> <td > </td> <td> 1970-01-01 08:00:00 </td> <td class="td-status"> <span class="layui-btn layui-btn-normal " onclick="admin_stop(this,'1',0)"> 启用 </span> </td> <td class="td-manage"> <!--<a style="text-decoration:none" onclick="admin_stop(this,'1')" href="javascript:;" title="停用"> <i class="layui-icon"></i> </a>--> <a title="编辑" href="javascript:;" onclick="admin_edit('编辑','adminadd.html','1','','510')" class="ml-5" style="text-decoration:none"> <i class="layui-icon"></i> </a> <a title="删除" href="javascript:;" onclick="admin_del(this,'1')" style="text-decoration:none"> <i class="layui-icon"></i> </a> </td> </tr> <tr> <td> <input type="checkbox" value="1" name=""> </td> <td> 2 </td> <td> admin1 </td> <td > 1111111111 </td> <td > 111111111@qq.com </td> <td > 超级管理员 </td> <td> 1970-01-01 08:00:00 </td> <td class="td-status"> <span class="layui-btn layui-btn-normal " onclick="admin_stop(this,'2',0)"> 启用 </span> </td> <td class="td-manage"> <!--<a style="text-decoration:none" onclick="admin_stop(this,'2')" href="javascript:;" title="停用"> <i class="layui-icon"></i> </a>--> <a title="编辑" href="javascript:;" onclick="admin_edit('编辑','adminadd.html','2','','510')" class="ml-5" style="text-decoration:none"> <i class="layui-icon"></i> </a> <a title="删除" href="javascript:;" onclick="admin_del(this,'1')" style="text-decoration:none"> <i class="layui-icon"></i> </a> </td> </tr> <tr> <td> <input type="checkbox" value="1" name=""> </td> <td> 3 </td> <td> admin2 </td> <td > 11111111 </td> <td > 11111111@qq.com </td> <td > 超级管理员 </td> <td> 1970-01-01 08:00:00 </td> <td class="td-status"> <span class="layui-btn layui-btn-normal " onclick="admin_stop(this,'3',0)"> 启用 </span> </td> <td class="td-manage"> <!--<a style="text-decoration:none" onclick="admin_stop(this,'3')" href="javascript:;" title="停用"> <i class="layui-icon"></i> </a>--> <a title="编辑" href="javascript:;" onclick="admin_edit('编辑','adminadd.html','3','','510')" class="ml-5" style="text-decoration:none"> <i class="layui-icon"></i> </a> <a title="删除" href="javascript:;" onclick="admin_del(this,'1')" style="text-decoration:none"> <i class="layui-icon"></i> </a> </td> </tr> <tr> <td> <input type="checkbox" value="1" name=""> </td> <td> 4 </td> <td> admin </td> <td > 1111111111 </td> <td > 111111111@qq.com </td> <td > </td> <td> 2019-07-20 17:03:28 </td> <td class="td-status"> <span class="layui-btn layui-btn-normal " onclick="admin_stop(this,'4',0)"> 启用 </span> </td> <td class="td-manage"> <!--<a style="text-decoration:none" onclick="admin_stop(this,'4')" href="javascript:;" title="停用"> <i class="layui-icon"></i> </a>--> <a title="编辑" href="javascript:;" onclick="admin_edit('编辑','adminadd.html','4','','510')" class="ml-5" style="text-decoration:none"> <i class="layui-icon"></i> </a> <a title="删除" href="javascript:;" onclick="admin_del(this,'1')" style="text-decoration:none"> <i class="layui-icon"></i> </a> </td> </tr> <tr> <td> <input type="checkbox" value="1" name=""> </td> <td> 5 </td> <td> admin </td> <td > 11111111 </td> <td > 111111111@qq.com </td> <td > </td> <td> 2019-07-20 17:03:41 </td> <td class="td-status"> <span class="layui-btn layui-btn-normal " onclick="admin_stop(this,'5',0)"> 启用 </span> </td> <td class="td-manage"> <!--<a style="text-decoration:none" onclick="admin_stop(this,'5')" href="javascript:;" title="停用"> <i class="layui-icon"></i> </a>--> <a title="编辑" href="javascript:;" onclick="admin_edit('编辑','adminadd.html','5','','510')" class="ml-5" style="text-decoration:none"> <i class="layui-icon"></i> </a> <a title="删除" href="javascript:;" onclick="admin_del(this,'1')" style="text-decoration:none"> <i class="layui-icon"></i> </a> </td> </tr> </tbody> </table> <div id="page"></div> </div> <script src="lib/layui/layui.js" charset="utf-8"></script> <script src="js/x-layui.js" charset="utf-8"></script> <script> layui.use(['laydate','element','laypage','layer'], function(){ $ = layui.jquery;//jquery laydate = layui.laydate;//日期插件 lement = layui.element();//面包导航 laypage = layui.laypage;//分页 layer = layui.layer;//弹出层 okLoading.close($); //以上模块根据需要引入 /*laypage({ cont: 'page' ,pages: 100 ,first: 1 ,last: 100 ,prev: '<' ,next: '>' }); */ var start = { min: laydate.now() ,max: '2099-06-16 23:59:59' ,istoday: false ,choose: function(datas){ end.min = datas; //开始日选好后,重置结束日的最小日期 end.start = datas //将结束日的初始值设定为开始日 } }; var end = { min: laydate.now() ,max: '2099-06-16 23:59:59' ,istoday: false ,choose: function(datas){ start.max = datas; //结束日选好后,重置开始日的最大日期 } }; document.getElementById('LAY_demorange_s').onclick = function(){ start.elem = this; laydate(start); } document.getElementById('LAY_demorange_e').onclick = function(){ end.elem = this laydate(end); } }); //批量删除提交 function delAll () { layer.confirm('确认要删除吗?',function(index){ //捉到所有被选中的,发异步进行删除 layer.msg('删除成功', {icon: 1}); }); } /*添加*/ function admin_add(title,url,w,h){ x_admin_show(title,url,w,h); } /*停用*/ function admin_stop(obj,id,e){ layer.confirm(e==1?'你确定要启用吗?':'你确定要禁用吗?',{icon: 3, title:'提示'},function(index){ $.ajax({ type:"post", url:"xxx", data:{id:id,status:e}, dataType:"json", success:function(data) { if(data.status==1){ //发异步把用户状态进行更改 $(obj).attr("class","layui-btn layui-btn-danger "); $(obj).text("隐藏"); $(obj).remove(); layer.msg(data.info,{icon: 6,time:1000}); setTimeout(function(){ window.location.reload(); },1000);return false; }else{ //发异步把用户状态进行更改 $(obj).attr("class","layui-btn layui-btn-normal "); $(obj).text("显示"); $(obj).remove(); layer.msg(data.info,{icon: 5,time:1000});return false; } } }); }); } /*启用*/ function admin_start(obj,id){ layer.confirm('确认要启用吗?',function(index){ //发异步把用户状态进行更改 $(obj).parents("tr").find(".td-manage").prepend('<a style="text-decoration:none" onClick="admin_stop(this,id)" href="javascript:;" title="停用"><i class="layui-icon"></i></a>'); $(obj).parents("tr").find(".td-status").html('<span class="layui-btn layui-btn-normal layui-btn-mini">已启用</span>'); $(obj).remove(); layer.msg('已启用!',{icon: 6,time:1000}); }); } //编辑 function admin_edit (title,url,id,w,h) { url = url+"?id="+id; x_admin_show(title,url,w,h); } /*删除*/ function admin_del(obj,id){ layer.confirm('确认要删除吗?',function(index){ //发异步删除数据 $(obj).parents("tr").remove(); layer.msg('已删除!',{icon:1,time:1000}); }); } </script> </body> </html>,这是我的admin.js:// js/admin.js const AdminManager = { // 获取所有管理员 getAll: function() { return JSON.parse(localStorage.getItem('admins')) || []; }, // 保存所有管理员 saveAll: function(admins) { localStorage.setItem('admins', JSON.stringify(admins)); }, // 获取单个管理员 getById: function(id) { return this.getAll().find(item => item.id == id); }, // 添加或更新管理员 save: function(admin) { let admins = this.getAll(); if (admin.id) { // 更新 const index = admins.findIndex(a => a.id == admin.id); if (index !== -1) { admins[index] = admin; } } else { // 新增 admin.id = this.generateId(); admin.create_time = new Date().toLocaleString(); admins.push(admin); } this.saveAll(admins); return admin; }, // 删除管理员 delete: function(id) { let admins = this.getAll().filter(a => a.id != id); this.saveAll(admins); }, // 生成ID generateId: function() { const admins = this.getAll(); return admins.length > 0 ? Math.max(...admins.map(a => a.id)) + 1 : 1; } }现在的问题是运行出来界面添加删除按钮点了没反应,我现在只需要弄好前端不需要和后端交互,添加的信息存本地就行先不连数据库,请你帮我解决一下,并且一定要给我完整的修改后的代码,
07-04
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>流程审批系统</title> <!-- 引入Element Plus样式 --> <link rel="stylesheet" href="https://unpkg.com/element-plus/dist/index.css"> <!-- 引入LogicFlow样式 --> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@logicflow/core/lib/style/index.css"> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@logicflow/extension/lib/style/index.css"> <!-- 引入Vue 3和Element Plus --> <script src="https://unpkg.com/vue@3"></script> <script src="https://unpkg.com/element-plus"></script> <!-- 引入LogicFlow --> <script src="https://cdn.jsdelivr.net/npm/@logicflow/core/dist/logic-flow.js"></script> <script src="https://cdn.jsdelivr.net/npm/@logicflow/extension/lib/index.js"></script> <style> :root { --primary-color: #409EFF; --success-color: #67C23A; --warning-color: #E6A23C; --danger-color: #F56C6C; --info-color: #909399; } body { margin: 0; padding: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; background-color: #f5f7fa; color: #303133; } .app-container { display: flex; flex-direction: column; min-height: 100vh; } .header { background-color: var(--primary-color); color: white; padding: 0 20px; height: 60px; display: flex; align-items: center; justify-content: space-between; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); } .main-content { display: flex; flex: 1; } .sidebar { width: 220px; background-color: #304156; color: white; height: calc(100vh - 60px); overflow-y: auto; } .content { flex: 1; padding: 20px; overflow-y: auto; height: calc(100vh - 60px); } .page-title { margin-bottom: 20px; padding-bottom: 10px; border-bottom: 1px solid #ebeef5; } .card-container { background: white; border-radius: 4px; box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1); padding: 20px; margin-bottom: 20px; } .toolbar { margin-bottom: 20px; display: flex; justify-content: space-between; align-items: center; } .logicflow-container { height: 500px; border: 1px solid #e0e0e0; border-radius: 4px; overflow: hidden; } .property-panel { position: absolute; right: 20px; top: 100px; width: 300px; background: white; border: 1px solid #e0e0e0; border-radius: 4px; padding: 15px; box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1); z-index: 100; } .task-filter { margin-bottom: 20px; display: flex; gap: 10px; } .task-item { border-left: 4px solid var(--primary-color); padding: 15px; margin-bottom: 15px; background: white; border-radius: 4px; box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1); } .task-item.urgent { border-left-color: var(--danger-color); } .task-item.completed { border-left-color: var(--success-color); } .task-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px; } .task-title { font-weight: bold; font-size: 16px; } .task-meta { color: var(--info-color); font-size: 14px; margin-bottom: 10px; } .task-actions { display: flex; gap: 10px; } .process-status { display: inline-block; padding: 5px 10px; border-radius: 3px; font-size: 12px; color: white; } .status-pending { background-color: var(--warning-color); } .status-approved { background-color: var(--success-color); } .status-rejected { background-color: var(--danger-color); } .status-processing { background-color: var(--primary-color); } .menu-item { padding: 15px 20px; cursor: pointer; transition: background-color 0.3s; } .menu-item:hover, .menu-item.active { background-color: #263445; } .menu-item i { margin-right: 10px; } </style> </head> <body> <div id="app"> <div class="app-container"> <!-- 顶部导航栏 --> <div class="header"> <h2>流程审批系统</h2> <div> <el-dropdown> <span class="el-dropdown-link"> 管理员 <i class="el-icon-arrow-down el-icon--right"></i> </span> <template #dropdown> <el-dropdown-menu> <el-dropdown-item>个人信息</el-dropdown-item> <el-dropdown-item>退出登录</el-dropdown-item> </el-dropdown-menu> </template> </el-dropdown> </div> </div> <div class="main-content"> <!-- 侧边栏菜单 --> <div class="sidebar"> <div v-for="item in menuItems" :key="item.key" :class="['menu-item', { active: activeMenu === item.key }]" @click="activeMenu = item.key" > <i :class="item.icon"></i> <span>{{ item.label }}</span> </div> </div> <!-- 主内容区域 --> <div class="content"> <!-- 流程设计器 --> <div v-if="activeMenu === 'design'"> <h2 class="page-title">流程设计器</h2> <div class="card-container"> <div class="toolbar"> <div> <el-select v-model="currentTemplate" placeholder="选择流程模板" style="width: 200px;"> <el-option v-for="template in templateList" :key="template.id" :label="template.name" :value="template.id" /> </el-select> <el-button type="primary" style="margin-left: 10px;" @click="saveFlow">保存流程</el-button> <el-button @click="createNewTemplate">新建模板</el-button> </div> <div> <el-button @click="importFlow">导入</el-button> <el-button @click="exportFlow">导出</el-button> </div> </div> <div class="logicflow-container" ref="container"></div> <!-- 节点属性面板 --> <div v-if="selectedNode" class="property-panel"> <h3>节点属性</h3> <el-form label-width="80px"> <el-form-item label="节点名称"> <el-input v-model="selectedNode.properties.name"></el-input> </el-form-item> <el-form-item v-if="selectedNode.type === 'approval'" label="审批人"> <el-select v-model="selectedNode.properties.approver" multiple placeholder="选择审批人"> <el-option v-for="user in userList" :key="user.id" :label="user.name" :value="user.id"></el-option> </el-select> </el-form-item> <el-form-item v-if="selectedNode.type === 'condition'" label="条件表达式"> <el-input v-model="selectedNode.properties.condition" type="textarea" :rows="2"></el-input> </el-form-item> <el-form-item label="描述信息"> <el-input v-model="selectedNode.properties.desc" type="textarea" :rows="2"></el-input> </el-form-item> </el-form> </div> </div> </div> <!-- 我的任务 --> <div v-if="activeMenu === 'tasks'"> <h2 class="page-title">我的任务</h2> <div class="card-container"> <div class="task-filter"> <el-radio-group v-model="taskFilter"> <el-radio-button label="pending">待我审批</el-radio-button> <el-radio-button label="processed">我已审批</el-radio-button> <el-radio-button label="started">我发起的</el-radio-button> </el-radio-group> <el-input placeholder="搜索流程名称" style="width: 200px;" v-model="searchKeyword"> <template #append> <el-button icon="el-icon-search"></el-button> </template> </el-input> </div> <div v-if="filteredTasks.length > 0"> <div v-for="task in filteredTasks" :key="task.id" :class="['task-item', { urgent: task.priority === 'high', completed: task.status === 'completed' }]" > <div class="task-header"> <div class="task-title">{{ task.processName }}</div> <div> <span :class="['process-status', `status-${task.status}`]"> {{ taskStatusMap[task.status] }} </span> </div> </div> <div class="task-meta"> <div>申请人: {{ task.applicant }} | 申请时间: {{ task.applyTime }}</div> <div>当前节点: {{ task.currentNode }}</div> <div v-if="task.comment">审批意见: {{ task.comment }}</div> </div> <div class="task-actions"> <el-button v-if="task.status === 'pending'" type="primary" size="small" @click="handleApprove(task)" >审批</el-button> <el-button v-if="task.status === 'pending'" type="danger" size="small" @click="handleReject(task)" >驳回</el-button> <el-button v-if="task.status === 'pending'" type="warning" size="small" @click="handleTransfer(task)" >转办</el-button> <el-button size="small" @click="viewProcess(task)" >查看进度</el-button> </div> </div> </div> <el-empty v-else description="暂无任务"></el-empty> </div> </div> <!-- 新建流程 --> <div v-if="activeMenu === 'create'"> <h2 class="page-title">新建流程申请</h2> <div class="card-container"> <el-form :model="formData" :rules="formRules" ref="applyForm" label-width="120px"> <!-- 流程模板选择 --> <el-form-item label="流程模板" prop="templateId"> <el-select v-model="formData.templateId" placeholder="请选择流程模板" @change="handleTemplateChange"> <el-option v-for="template in templateList" :key="template.id" :label="template.name" :value="template.id" > <span style="float: left">{{ template.name }}</span> <span style="float: right; color: #8492a6; font-size: 13px"> {{ template.category }} </span> </el-option> </el-select> </el-form-item> <!-- 动态表单区域 --> <div v-if="selectedTemplate"> <el-divider content-position="left">申请信息</el-divider> <div v-for="field in selectedTemplate.fields" :key="field.name"> <el-form-item :label="field.label" :prop="'fields.' + field.name" :rules="field.rules" > <el-input v-if="field.type === 'text' || field.type === 'textarea'" v-model="formData.fields[field.name]" :type="field.type" :rows="field.type === 'textarea' ? 4 : 2" :placeholder="'请输入' + field.label" /> <el-input-number v-else-if="field.type === 'number'" v-model="formData.fields[field.name]" :placeholder="'请输入' + field.label" /> <el-date-picker v-else-if="field.type === 'date' || field.type === 'datetime'" v-model="formData.fields[field.name]" :type="field.type" :placeholder="'请选择' + field.label" style="width: 100%" /> <el-select v-else-if="field.type === 'select'" v-model="formData.fields[field.name]" :placeholder="'请选择' + field.label" style="width: 100%" > <el-option v-for="option in field.options" :key="option.value" :label="option.label" :value="option.value" /> </el-select> </el-form-item> </div> <el-divider content-position="left">附件材料</el-divider> <el-upload action="#" :auto-upload="false" :on-change="handleFileChange" :on-remove="handleFileRemove" :file-list="fileList" multiple > <el-button type="primary">点击上传</el-button> <template #tip> <div class="el-upload__tip"> 支持扩展名:.doc .docx .pdf .jpg .png,单个文件不超过10MB </div> </template> </el-upload> <div v-if="fileList.length > 0" style="margin-top: 15px;"> <div v-for="(file, index) in fileList" :key="index" style="display: flex; align-items: center; justify-content: space-between; padding: 8px; background-color: #f5f7fa; margin-bottom: 8px; border-radius: 4px;"> <div style="display: flex; align-items: center;"> <el-icon><Document /></el-icon> <span style="margin-left: 8px">{{ file.name }}</span> </div> <el-button size="small" type="danger" text @click="handleFileRemove(file)">删除</el-button> </div> </div> <el-divider content-position="left">审批流程</el-divider> <el-timeline> <el-timeline-item v-for="(approver, index) in selectedTemplate.approvers" :key="index" :timestamp="'第' + (index + 1) + '步'" placement="top" > <el-card> <h4>{{ approver.nodeName }}</h4> <p>审批人: {{ approver.userName }}</p> <p v-if="approver.description">{{ approver.description }}</p> </el-card> </el-timeline-item> </el-timeline> </div> <!-- 操作按钮 --> <el-form-item style="margin-top: 30px;"> <el-button type="primary" @click="submitForm" :loading="submitting">提交申请</el-button> <el-button @click="resetForm">重置</el-button> </el-form-item> </el-form> </div> </div> <!-- 流程监控 --> <div v-if="activeMenu === 'monitor'"> <h2 class="page-title">流程监控</h2> <div class="card-container"> <el-table :data="processInstances" style="width: 100%"> <el-table-column prop="name" label="流程名称" width="180"></el-table-column> <el-table-column prop="applicant" label="申请人" width="120"></el-table-column> <el-table-column prop="startTime" label="开始时间" width="150"></el-table-column> <el-table-column prop="currentNode" label="当前节点" width="120"></el-table-column> <el-table-column label="状态" width="100"> <template #default="scope"> <el-tag :type="statusType(scope.row.status)"> {{ scope.row.status }} </el-tag> </template> </el-table-column> <el-table-column label="操作" width="150"> <template #default="scope"> <el-button size="small" @click="viewProcessDetail(scope.row)">查看详情</el-button> </template> </el-table-column> </el-table> </div> </div> </div> </div> </div> <!-- 审批对话框 --> <el-dialog :title="dialogTitle" v-model="approvalDialogVisible" width="500px"> <el-form :model="approvalForm" label-width="80px"> <el-form-item label="审批意见"> <el-input v-model="approvalForm.comment" type="textarea" :rows="3"></el-input> </el-form-item> <el-form-item v-if="dialogType === 'transfer'" label="转办给"> <el-select v-model="approvalForm.transferTo" placeholder="选择转办人"> <el-option v-for="user in userList" :key="user.id" :label="user.name" :value="user.id"></el-option> </el-select> </el-form-item> </el-form> <template #footer> <el-button @click="approvalDialogVisible = false">取消</el-button> <el-button v-if="dialogType === 'approve'" type="primary" @click="confirmApprove" >通过</el-button> <el-button v-if="dialogType === 'reject'" type="danger" @click="confirmReject" >驳回</el-button> <el-button v-if="dialogType === 'transfer'" type="warning" @click="confirmTransfer" >确认转办</el-button> </template> </el-dialog> </div> <script> const { createApp, ref, reactive, computed, onMounted } = Vue; createApp({ setup() { // 菜单项 const menuItems = reactive([ { key: 'design', label: '流程设计', icon: 'el-icon-s-promotion' }, { key: 'tasks', label: '我的任务', icon: 'el-icon-tickets' }, { key: 'create', label: '新建流程', icon: 'el-icon-circle-plus-outline' }, { key: 'monitor', label: '流程监控', icon: 'el-icon-data-line' } ]); const activeMenu = ref('tasks'); // LogicFlow相关 const container = ref(null); let lf = null; const selectedNode = ref(null); const currentTemplate = ref(''); // 模板列表 const templateList = ref([ { id: 1, name: '请假申请', category: '人力资源', description: '用于员工请假申请审批流程', fields: [ { name: 'leaveType', label: '请假类型', type: 'select', rules: [{ required: true, message: '请选择请假类型', trigger: 'change' }], options: [ { value: 'annual', label: '年假' }, { value: 'sick', label: '病假' }, { value: 'personal', label: '事假' }, { value: 'marriage', label: '婚假' }, { value: 'maternity', label: '产假' } ] }, { name: 'startDate', label: '开始时间', type: 'datetime', rules: [{ required: true, message: '请选择开始时间', trigger: 'change' }] }, { name: 'endDate', label: '结束时间', type: 'datetime', rules: [{ required: true, message: '请选择结束时间', trigger: 'change' }] }, { name: 'duration', label: '请假时长(天)', type: 'number', rules: [ { required: true, message: '请输入请假时长', trigger: 'blur' }, { type: 'number', min: 0.5, max: 365, message: '时长应在0.5到365天之间', trigger: 'blur' } ] }, { name: 'reason', label: '请假事由', type: 'textarea', rules: [{ required: true, message: '请输入请假事由', trigger: 'blur' }] } ], approvers: [ { nodeName: '直属上级审批', userName: '张经理', description: '审批请假合理性' }, { nodeName: '人事部门审核', userName: '李人事', description: '核对假期余额及合规性' } ] }, { id: 2, name: '采购申请', category: '财务', description: '用于物品采购申请审批流程', fields: [ { name: 'itemName', label: '物品名称', type: 'text', rules: [{ required: true, message: '请输入物品名称', trigger: 'blur' }] }, { name: 'specification', label: '规格型号', type: 'text', rules: [{ required: true, message: '请输入规格型号', trigger: 'blur' }] }, { name: 'quantity', label: '数量', type: 'number', rules: [ { required: true, message: '请输入数量', trigger: 'blur' }, { type: 'number', min: 1, message: '数量必须大于0', trigger: 'blur' } ] }, { name: 'estimatedPrice', label: '预估单价', type: 'number', rules: [ { required: true, message: '请输入预估单价', trigger: 'blur' }, { type: 'number', min: 0, message: '单价不能为负数', trigger: 'blur' } ] }, { name: 'purpose', label: '用途说明', type: 'textarea', rules: [{ required: true, message: '请输入用途说明', trigger: 'blur' }] } ], approvers: [ { nodeName: '部门经理审批', userName: '王经理', description: '审核采购必要性' }, { nodeName: '财务审核', userName: '赵会计', description: '审核预算及价格合理性' }, { nodeName: '总经理审批', userName: '孙总', description: '最终审批' } ] } ]); // 用户列表 const userList = ref([ { id: 1, name: '张三', department: '技术部' }, { id: 2, name: '李四', department: '人事部' }, { id: 3, name: '王五', department: '财务部' }, { id: 4, name: '赵六', department: '市场部' }, { id: 5, name: '钱七', department: '技术部' } ]); // 初始化LogicFlow const initLogicFlow = () => { if (!container.value) return; // 使用LogicFlow的BPMN扩展 LogicFlow.use(LogicFlow.BpmnElement); LogicFlow.use(LogicFlow.Snapshot); LogicFlow.use(LogicFlow.Menu); LogicFlow.use(LogicFlow.Control); lf = new LogicFlow({ container: container.value, grid: true, width: container.value.clientWidth, height: 500, keyboard: { enabled: true }, style: { rect: { width: 100, height: 60, radius: 6 } } }); // 渲染初始流程图 lf.render({ nodes: [ { id: '1', type: 'bpmn:startEvent', x: 100, y: 100, properties: { name: '开始' } } ] }); // 监听节点选择事件 lf.on('node:click', ({ data }) => { selectedNode.value = data; }); // 监听画布点击事件(点击空白处取消选择) lf.on('blank:click', () => { selectedNode.value = null; }); }; // 保存流程 const saveFlow = () => { if (!currentTemplate.value) { ElMessage.warning('请先选择或创建流程模板'); return; } const graphData = lf.getGraphData(); console.log('保存流程数据:', graphData); // 这里应该调用API保存流程数据 ElMessage.success('流程保存成功'); }; // 新建模板 const createNewTemplate = () => { ElMessageBox.prompt('请输入新模板名称', '新建模板', { confirmButtonText: '确定', cancelButtonText: '取消', }).then(({ value }) => { if (!value) return; const newTemplate = { id: templateList.value.length + 1, name: value, category: '自定义', description: '新建的流程模板', fields: [], approvers: [] }; templateList.value.push(newTemplate); currentTemplate.value = newTemplate.id; ElMessage.success('模板创建成功'); }); }; // 导入导出 const importFlow = () => { ElMessage.info('导入功能'); }; const exportFlow = () => { const graphData = lf.getGraphData(); const dataStr = "data:text/json;charset=utf-8," + encodeURIComponent(JSON.stringify(graphData, null, 2)); const downloadAnchorNode = document.createElement('a'); downloadAnchorNode.setAttribute("href", dataStr); downloadAnchorNode.setAttribute("download", "flow.json"); document.body.appendChild(downloadAnchorNode); downloadAnchorNode.click(); downloadAnchorNode.remove(); ElMessage.success('流程已导出'); }; // 任务相关 const taskFilter = ref('pending'); const searchKeyword = ref(''); // 模拟任务数据 const tasks = ref([ { id: 1, processName: '请假申请', applicant: '张三', applyTime: '2023-10-01 09:30', currentNode: '部门审批', status: 'pending', priority: 'normal', comment: '' }, { id: 2, processName: '采购申请', applicant: '李四', applyTime: '2023-10-01 10:15', currentNode: '财务审核', status: 'pending', priority: 'high', comment: '' }, { id: 3, processName: '费用报销', applicant: '王五', applyTime: '2023-09-30 14:20', currentNode: '已完成', status: 'completed', priority: 'normal', comment: '符合公司报销政策' } ]); // 任务状态映射 const taskStatusMap = { 'pending': '待处理', 'processing': '处理中', 'completed': '已完成', 'rejected': '已驳回' }; // 过滤后的任务列表 const filteredTasks = computed(() => { let result = tasks.value; // 根据筛选条件过滤 if (taskFilter.value === 'pending') { result = result.filter(task => task.status === 'pending'); } else if (taskFilter.value === 'processed') { result = result.filter(task => task.status === 'completed' || task.status === 'rejected'); } else if (taskFilter.value === 'started') { // 这里应该是用户自己发起的流程 result = result.filter(task => task.applicant === '当前用户'); } // 根据关键词搜索 if (searchKeyword.value) { const keyword = searchKeyword.value.toLowerCase(); result = result.filter(task => task.processName.toLowerCase().includes(keyword) || task.applicant.toLowerCase().includes(keyword) ); } return result; }); // 审批对话框相关 const approvalDialogVisible = ref(false); const dialogType = ref(''); // approve, reject, transfer const dialogTitle = ref(''); const currentTask = ref(null); const approvalForm = reactive({ comment: '', transferTo: '' }); // 打开审批对话框 const handleApprove = (task) => { currentTask.value = task; dialogType.value = 'approve'; dialogTitle.value = `审批通过 - ${task.processName}`; approvalForm.comment = ''; approvalDialogVisible.value = true; }; // 打开驳回对话框 const handleReject = (task) => { currentTask.value = task; dialogType.value = 'reject'; dialogTitle.value = `驳回申请 - ${task.processName}`; approvalForm.comment = ''; approvalDialogVisible.value = true; }; // 打开转办对话框 const handleTransfer = (task) => { currentTask.value = task; dialogType.value = 'transfer'; dialogTitle.value = `转办任务 - ${task.processName}`; approvalForm.comment = ''; approvalForm.transferTo = ''; approvalDialogVisible.value = true; }; // 确认审批通过 const confirmApprove = () => { if (!approvalForm.comment) { ElMessage.warning('请填写审批意见'); return; } // 更新任务状态 const task = tasks.value.find(t => t.id === currentTask.value.id); if (task) { task.status = 'completed'; task.comment = approvalForm.comment; } approvalDialogVisible.value = false; ElMessage.success('审批通过'); }; // 确认驳回 const confirmReject = () => { if (!approvalForm.comment) { ElMessage.warning('请填写驳回原因'); return; } // 更新任务状态 const task = tasks.value.find(t => t.id === currentTask.value.id); if (task) { task.status = 'rejected'; task.comment = approvalForm.comment; } approvalDialogVisible.value = false; ElMessage.warning('申请已驳回'); }; // 确认转办 const confirmTransfer = () => { if (!approvalForm.transferTo) { ElMessage.warning('请选择转办人'); return; } // 查找转办人 const transferToUser = userList.value.find(user => user.id === approvalForm.transferTo); if (!transferToUser) { ElMessage.error('选择的转办人不存在'); return; } // 更新任务 const task = tasks.value.find(t => t.id === currentTask.value.id); if (task) { task.comment = `转办给: ${transferToUser.name}` + (approvalForm.comment ? `, 备注: ${approvalForm.comment}` : ''); // 在实际应用中,这里应该将任务转交给其他用户 } approvalDialogVisible.value = false; ElMessage.success(`任务已转办给 ${transferToUser.name}`); }; // 查看流程进度 const viewProcess = (task) => { ElMessage.info(`查看流程 ${task.processName} 的进度`); // 这里应该打开流程进度详情页面 }; // 新建流程相关 const formData = reactive({ templateId: '', fields: {} }); const fileList = ref([]); const submitting = ref(false); const applyForm = ref(null); // 当前选中的模板 const selectedTemplate = computed(() => { return templateList.value.find(t => t.id === formData.templateId) || null; }); // 表单验证规则 const formRules = reactive({ templateId: [ { required: true, message: '请选择流程模板', trigger: 'change' } ] }); // 处理模板选择变化 const handleTemplateChange = (templateId) => { // 重置表单字段 formData.fields = {}; // 为选中模板的每个字段初始化值 if (selectedTemplate.value) { selectedTemplate.value.fields.forEach(field => { formData.fields[field.name] = field.type === 'number' ? 0 : ''; }); } }; // 处理文件变化 const handleFileChange = (file, files) => { // 限制文件大小 if (file.size > 10 * 1024 * 1024) { ElMessage.error('文件大小不能超过10MB'); return false; } // 更新文件列表 fileList.value = files; }; // 处理文件移除 const handleFileRemove = (file) => { const index = fileList.value.indexOf(file); if (index !== -1) { fileList.value.splice(index, 1); } }; // 提交表单 const submitForm = () => { if (!applyForm.value) return; applyForm.value.validate((valid) => { if (valid) { submitting.value = true; // 模拟API调用 setTimeout(() => { ElMessage.success('申请提交成功!'); submitting.value = false; // 重置表单 resetForm(); // 切换到任务页面 activeMenu.value = 'tasks'; }, 1500); } else { ElMessage.error('请完善表单信息'); return false; } }); }; // 重置表单 const resetForm = () => { if (applyForm.value) { applyForm.value.resetFields(); } formData.fields = {}; fileList.value = []; }; // 流程监控相关 const processInstances = ref([ { id: 1, name: '请假申请', applicant: '张三', startTime: '2023-10-01 09:30', currentNode: '部门审批', status: '审批中' }, { id: 2, name: '采购申请', applicant: '李四', startTime: '2023-10-01 10:15', currentNode: '财务审核', status: '审批中' }, { id: 3, name: '费用报销', applicant: '王五', startTime: '2023-09-30 14:20', currentNode: '已完成', status: '已通过' } ]); // 状态标签类型 const statusType = (status) => { const map = { '审批中': 'primary', '已通过': 'success', '已拒绝': 'danger', '已撤销': 'info' }; return map[status] || 'info'; }; // 查看流程详情 const viewProcessDetail = (process) => { ElMessage.info(`查看流程 ${process.name} 的详情`); // 这里应该打开流程详情页面 }; // 初始化 onMounted(() => { initLogicFlow(); }); return { menuItems, activeMenu, container, selectedNode, currentTemplate, templateList, userList, saveFlow, createNewTemplate, importFlow, exportFlow, taskFilter, searchKeyword, filteredTasks, taskStatusMap, handleApprove, handleReject, handleTransfer, viewProcess, approvalDialogVisible, dialogType, dialogTitle, approvalForm, confirmApprove, confirmReject, confirmTransfer, formData, formRules, fileList, submitting, applyForm, selectedTemplate, handleTemplateChange, handleFileChange, handleFileRemove, submitForm, resetForm, processInstances, statusType, viewProcessDetail }; } }).use(ElementPlus).mount('#app'); </script> </body> </html>优化页面
最新发布
09-03
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值