input问题点总结:placeholder的默认字体颜色,type=”hidden”,max,maxlength

本文总结了input元素的相关知识点,包括如何改变placeholder的默认字体颜色,理解type='hidden'的作用,即用于隐藏信息的收集和发送。同时,探讨了表单中id和name的区别,主要在于name用于数据提交。还提到了input的maxlength属性问题,它限制输入字符串的最长长度,而max则定义了允许的最大数值。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

如何修改 input框的placeholder的默认字体颜色

input::-webkit-input-placeholde{
	color:red;
}

参考:https://jingyan.baidu.com/article/e75aca853e05bf142edac620.html

表单元素input type=”hidden”的作用
在表单插入中隐藏域的目的在于收集和发送信息
参考 https://blog.youkuaiyun.com/wjnf012/article/details/72773275

在表单(input)中id和name的区别
表单(form)的控件名,提交的数据都用控件的name而不是id来控制
参考 https://www.cnblogs.com/YYvam1288/p/4845737.html

input maxlength 属性不起作用

 /*
   * id 主键id
   * len 控制长度
   * 输入长度控制
   * */
  var onInput = function(id, len) {
    $("#" + id).on("keydown", function() {
      var value = $(this).val(),
        vLen = value.length;
      vLen >= len ? $(this).val(value.slice(0, len - 1)) : "";
    });

参考 https://blog.youkuaiyun.com/u012982629/article/details/80588438

max,maxlength的区别
max是指最大值
maxlength 是指输入字符串的最长长度

<form id="inputForm" action="update.jhtml" method="post" type="ajax" validate-type="validate" style="width: 100%"> <input type="hidden" name="id" value="${followUpRecord.id}" /> <div class="tabContent"> <table class="input input-edit"> <tr> <th> <span class="requiredField">*</span>${message("跟进类型")}: </th> <td colspan="2"> <select class="text followType" name="followType" id="followType" required btn-fun="clear"> <option value="">--请选择--</option> <option value="1" [#if followUpRecord.followType == 1] selected [/#if]>商机跟进</option> <option value="2" [#if followUpRecord.followType == 2] selected [/#if]>客户跟进</option> </select> </td> <th> <span class="requiredField">*</span>${message("跟进对象")}: </th> <td colspan="2"> <span class="search" style="position:relative"> <input type="hidden" id="objId" name="objId" class="text objId" value="${followUpRecord.objId}" btn-fun="clear" required/> <input type="text" id="objName" name="objName" class="text objName" value="${followUpRecord.objName}" onkeyup="clearSelect(this)" required/> <input type="button" class="iconSearch" value="" id="selectObj"> </span> </td> <th class="t_projectStageValue" style="display: none;"> ${message("商机阶段")}: </th> <td class="t_projectStageValue" style="display: none;"> <input type="text" name="projectStageValue" class="text projectStageValue" maxlength="200" value="${followUpRecord.projectStageValue}"/> </td> <th> <span class="requiredField">*</span>${message("状态")}: </th> <td colspan="2"> <select class="text recordStatus" name="recordStatus" required btn-fun="clear" style="pointer-events: none;background-color: #f7f7f7"> <option value="1" [#if followUpRecord.recordStatus == 1] selected [/#if]>未提交</option> <option value="2" [#if followUpRecord.recordStatus == 2] selected [/#if]>已提交</option> <option value="3" [#if followUpRecord.recordStatus == 3] selected [/#if]>审批中</option> </select> </td> </tr> <tr> <th> ${message("标段划分")}: </th> <td> <input type="text" name="sectionDivision" class="text sectionDivision" maxlength="200" /> </td> <th> ${message("跟进阶段")}: </th> <td> <select class="text followUpState" name="followUpState" id="followUpState" required btn-fun="clear"> <option value="">--请选择--</option> [#list followUpStates as followUpState] <option value="${followUpState.value}" [#if followUpRecord.followUpState == followUpState.value] selected [/#if] >${followUpState.remark}</option> [/#list] [#-- <option value="1" [#if followUpRecord.followUpState == 1] selected [/#if]>发现阶段</option>--] [#-- <option value="2" [#if followUpRecord.followUpState == 2] selected [/#if]>客户接触阶段</option>--] [#-- <option value="3" [#if followUpRecord.followUpState == 3] selected [/#if]>需求了解阶段</option>--] [#-- <option value="4" [#if followUpRecord.followUpState == 4] selected [/#if]>评估阶段</option>--] </select> </td> <th> ${message("是否关闭商机")}: </th> <td> <select class="text isCloseNiche" name="isCloseNiche" id="isCloseNiche" required btn-fun="clear"> <option value="">--请选择--</option> <option value="1" [#if followUpRecord.isCloseNiche == 1] selected [/#if]>否</option> <option value="2" [#if followUpRecord.isCloseNiche == 2] selected [/#if]>是</option> </select> </td> </tr> <tr> <th> ${message("项目进度详细描述")}: </th> <td colspan=" 10" style="width: 95%"> <textarea name="projectScheduleDescription" class="text projectScheduleDescription" cols="30" rows="2"/>${followUpRecord.projectScheduleDescription}</textarea> </td> </tr> <tr> <th> ${message("项目运作思路及关键")}: </th> <td colspan="10" style="width: 95%"> <textarea name="ideaPoint" class="text ideaPoint" cols="30" rows="2"/>${followUpRecord.ideaPoint}</textarea> </td> </tr> <tr> <th> ${message("下一步工作计划")}: </th> <td colspan="10" style="width: 95%"> <textarea name="nextPlan" class="text nextPlan" cols="15" rows="2"/>${followUpRecord.nextPlan} </textarea> </td> </tr> <tr> <th> ${message("需公司其他部门支撑事项")}: </th> <td colspan="10" style="width: 95%"> <textarea name="needBackup" class="text needBackup" cols="15" rows="2"/>${followUpRecord.needBackup}</textarea> </td> </tr> <tr> <th> <span class="requiredField">*</span>${message("总结")}: </th> <td colspan="10" style="width: 95%"> <textarea cols="20" rows="2" name="sumUp" class="text sumUp" required/>${followUpRecord.sumUp} </textarea> </td> </tr> <tr style="display: none" class="t_closeResult"> <th> <span class="requiredField" >*</span>${message("商机关闭原因")}: </th> <td colspan=" 10" style="width: 95%"> <textarea name="closeResult" class="text closeResult" cols="30" rows="2" [#if followUpRecord.isCloseNiche == 2] required [/#if]/>${followUpRecord.closeResult}</textarea> </td> </tr> <tr> <th>${message("图片")}</th> <td colspan="10" style="width: 95%"> <div class="box-wrap"> <div class="box-main" style="overflow:visible;"> <div class="upload-list tc" style="overflow:initial;width:260px;"> [#list followUpRecord.images as image] <div class="ul-box" style="padding:13px 0px 0px"> <div class="pic" style="margin-left:65px; width:80px"><a href="${image.source}" target="_blank"><img src="${image.thumbnail}"></a></div> <b> </b> <a class="del delProductImage1" href="#"></a> <input type="hidden" name="images[${image_index}].title" value="${image.title}"> <input type="hidden" name="images[${image_index}].source" value="${image.source}"> <input type="hidden" name="images[${image_index}].large" value="${image.large}"> <input type="hidden" name="images[${image_index}].medium" value="${image.medium}"> <input type="hidden" name="images[${image_index}].thumbnail" value="${image.thumbnail}"> </div> [/#list] <a href="javascript:;" class="a-upload" id="addProductImage"></a> </div> </div> </div> </td> </tr> </table> <div> <table> <tr> <th>111</th> <td> <textarea rows="2" cols="30"></textarea> </td> </tr> </table> </div> <div class="task-content"> [#include "/crm/follow_up_record/edit/task-form.ftl" /] </div> <br/> <div class="title-style"> 附件上传: <div class="btns"> <a href="javascript:;" id="addAttach" class="button">添加附件</a> </div> </div> <table id="table-attach"></table> <div class="title-style"> 抄送人: <div class="btns"> <a href="javascript:;" id="addMember" class="button">添加抄送人</a> </div> </div> <table id="table-addMember"></table> <div class="title-style"> 定位:提示:你可以放大地图以便更准确标记。 </div> <div> <table class="input tabContent"> <tr> <td colspan="4" style="line-height: 25px;padding: 5px;border-bottom: 1px solid #dde9f5;"> <!-- <span class="fieldSet"> <input type="hidden" id="areaId" name="areaId" /> </span>   详细地址:<input type="text" name="address" class="txt" maxlength="200"/> --> <br/> 定位地址:<input type="text" id="searchText" style="line-height: 20px;width: 400px;border: solid 1px #dcdcdc;"/> <input type="button" value="搜索" id="searchButton" style="border: revert;"/>    详细地址:<input type="text" id="address" name="address" readonly="readonly" value="${followUpRecord.address}" style="line-height: 20px;width: 400px;border: solid 1px #dcdcdc;"/> 经度:<input type="text" name="longitude" id="mapy" readonly="readonly" value="${followUpRecord.longitude}" style="line-height: 20px;border: solid 1px #dcdcdc;"/>   纬度:<input type="text" name="latitude" id="mapx" readonly="readonly" value="${followUpRecord.latitude}" style="line-height: 20px;border: solid 1px #dcdcdc;"/> </td> </tr> <tr> <td style="height:400px;display:block;" colspan="3"> <div id="allmap"></div> </td> <td style="height:400px;"> <ul id="searchResUl"> </ul> </td> <tr> </table> </div> </div> <div class="fixed-top"> [#if followUpRecord.recordStatus == 1] [#if followUpRecord.isCloseNiche != 2] <a href="javascript:void(0);" class="button sureButton" onclick="submitData(this)">${message("提交")}</a> [/#if] <a href="javascript:void(0);" class="button sureButton" onclick="save(this)">${message("保存")}</a> [#if followUpRecord.isCloseNiche == 2 && followUpRecord.wfState == 0] <a href="javascript:void(0);" class="button sureButton" onclick="check_wf(this)">${message("12501")}</a> [/#if] [/#if] <input type="button" onclick="location.reload(true);" class="button resetButton ml15" value="${message("重置")}"> </div> </form>修改该代码 使得文本框能使用回车换行并出现滚动条
07-31
<template> <div> <el-dialog :title="type === 'add' ? '新增' : '修改'" :visible="dialogVisible" width="570px" top="20px" @close="close" > <el-form ref="addEditDataRef" :model="addEditData" :rules="rules" label-width="140px" > <el-form-item label="合集名称" prop="name"> <el-input v-model="addEditData.name" placeholder="请输入课程合集名称" clearable maxlength="50" show-word-limit /> </el-form-item> <el-form-item prop="img" label="插图"> <img-upload :img.sync="addEditData.img" accept="jpg,png,jpeg" tips="上传插图" :scale="[670, 500]" is-style /> </el-form-item> <div style="display: flex; width: 100%"> <el-form-item label="添加课程" prop="classIdList" /> <el-button type="primary" class="top-left-btn" icon="el-icon-plus" @click="addClick" > 添加课程 </el-button> </div> <div v-for="item in courseList" :key="item.index" style="display: flex" class="course-item" > <!-- <div class="course-index">{{ index + 1 }}</div> --> <div>{{ item.section }}</div> <div style="display: flex; align-items: center; gap: 10px" class="cover-container" > <div class=""> <img :src="item.img" alt="课程封面" class="cover-img" /> </div> <div style="width: 300px">{{ item.name }}</div> <span> <el-button type="text" size="small" icon="el-icon-rank" class="add-btn" @click="handleAdd(item)" /> <span> <el-button type="text" size="small" icon="el-icon-delete" class="add-btn" @click="handleAdd(item)" /> </span> </span> </div> </div> </el-form> <div slot="footer" class="dialog-footer"> <el-button @click="close">取 消</el-button> <el-button type="primary" @click="save">确 定</el-button> </div> </el-dialog> <div> <!-- 表格 --> <el-dialog title="选择课程" :visible="dialogCourse" width="1600px" top="20px" @close="closeCourse" > <div class="search-group mb-20"> <el-input v-model="searchText" placeholder="请输入搜索内容" suffix-icon="el-icon-search" clearable style="width: 300px; float: right; margin: 10px 0" @keyup.enter.native="handleSearch" /> <!-- <el-button type="primary" style="margin-left: 10px" @click="handleSearch" > 搜索 </el-button> --> </div> <el-table :data="pageInfo.list" :height="$baseTableHeight()" max-height="500px" > <!-- 复选框列 --> <el-table-column type="selection" width="55" /> <el-table-column label="ID" prop="id" min-width="100" show-overflow-tooltip :formatter="$formatCell" /> <el-table-column label="分类" prop="typeName" min-width="200" show-overflow-tooltip :formatter="(row) => row.groupName + row.typeName" /> <el-table-column label="课程标题" prop="title" min-width="150" show-overflow-tooltip /> <el-table-column label="封面图" width="100"> <template #default="{ row }"> <span v-if="!row.videoCover">-</span> <el-image v-else style="width: 34px; height: 19px" :preview-src-list="[$imageSrc(row.videoCover, 2)]" :src="$imageSrc(row.videoCover)" /> </template> </el-table-column> <el-table-column label="作者" prop="lecturerUser" min-width="200" show-overflow-tooltip > <template #default="{ row }"> <div class="flex-center"> <div> <el-image v-if="row.lecturerUser" style="width: 30px; height: 30px" :preview-src-list="[ $imageSrc(row.lecturerUser.userIcon, 2), ]" :src="$imageSrc(row.lecturerUser.userIcon)" /> <span v-else>-</span> </div> <div style="margin-left: 10px"> <div>{{ row.lecturerUser.nickName || '' }}</div> <div>{{ row.lecturerUser.phone || '' }}</div> </div> </div> </template> </el-table-column> <el-table-column label="发布时间" prop="pushTime" width="170" /> </el-table> <!-- 分页组件 --> <el-pagination class="pagination" :current-page="pageInfo.pageNum" :page-sizes="[10, 20, 50, 100]" :page-size="pageInfo.pageSize" layout="total, sizes, prev, pager, next, jumper" :total="pageInfo.total" @size-change="setPageSize" @current-change="listPage" /> <div slot="footer" class="dialog-footer"> <el-button @click="closeCourse">取 消</el-button> <el-button type="primary" @click="saveCourse">确 定</el-button> </div> </el-dialog> </div> </div> </template> <script> import ImgUpload from '@/components/imgUpload/imgUpload' export default { name: 'NodesAdd', components: { ImgUpload }, props: { dialogVisible: { type: Boolean, default: false, }, type: { type: String, default: '', }, rowData: { type: Object, default: () => {}, }, }, data() { return { addEditData: { name: '', // 标题 img: '', // 插图 classIdList: [], // 课程id列表 }, searchText: '', // 搜索内容 hasSearched: false, // 弹窗 dialogCourse: false, // 课程弹窗 courseList: [ { id: 1, section: '第一讲', name: '课程介绍与环境搭建去去去去去去去去去去七七七七七七七七七七七七七七七七七七七七七七七七七七七七', img: 'https://picsum.photos/seed/course1/200/150', }, { id: 2, section: '第二讲', name: 'Vue 2 基础语法与响应式原理', img: 'https://picsum.photos/seed/course2/200/150', }, { id: 3, section: '第三讲', name: '组件化开发与通信机制', img: 'https://picsum.photos/seed/course3/200/150', }, { id: 4, section: '第四讲', name: 'Vue Router 与状态管理', img: 'https://picsum.photos/seed/course4/200/150', }, { id: 5, section: '第五讲', name: '构建工具与生产部署', img: 'https://picsum.photos/seed/course5/200/150', }, ], rules: { name: [{ required: true, message: '请输入标题', trigger: 'blur' }], img: [{ required: true, message: '请上传插图', trigger: 'blur' }], classIdList: [ { required: true, message: '请添加课程', trigger: 'blur' }, ], }, // ****** 列表相关 ****** pageNum: 1, // 页码 pageSize: 10, // 分页条数 total: 0, // 总数 listTable: [], // 列表list reqCond: { // 请求参数 pageNum: 1, pageSize: 20, }, pageInfo: { list: [], }, } }, watch: { dialogVisible(val) { if (val) { if (this.type === 'edit') { this.addEditData = { ...this.rowData, } this.getUserList(this.rowData.createUserName) } else { this.getUserList() } } }, }, created() { this.getUserList() this.listPage() }, methods: { handleSearch() { this.hasSearched = true // 模拟搜索请求(实际项目中应调用 API) setTimeout(() => { // 模拟搜索结果过滤逻辑 const mockResults = [ { id: 321, title: 'Vue3 实战教程:从入门到精通', category: '前端开发', author: '技术大牛', publishTime: '2025.06.15 20:34:34', isNew: true, }, { id: 320, title: 'Element UI 组件库高级应用', category: 'UI框架', author: 'UI专家', publishTime: '2025.06.12 20:12:31', isNew: false, }, { id: 319, title: 'JavaScript 性能优化技巧大全', category: '前端开发', author: '性能大师', publishTime: '2025.06.10 15:45:22', isNew: false, }, ] // 根据搜索词和搜索类型过滤结果 if (!this.searchText) { this.searchResults = mockResults } else { this.searchResults = mockResults.filter((item) => { if (this.searchType === 'all') { return ( item.title.includes(this.searchText) || item.author.includes(this.searchText) || item.category.includes(this.searchText) ) } else if (this.searchType === 'title') { return item.title.includes(this.searchText) } else if (this.searchType === 'author') { return item.author.includes(this.searchText) } else if (this.searchType === 'category') { return item.category.includes(this.searchText) } return false }) } }, 500) }, addClick() { this.dialogCourse = true }, closeCourse() { this.dialogCourse = false }, saveCourse() { this.dialogCourse = false }, // 课程分页列表查询 async listPage(pageNum) { pageNum > 0 && (this.reqCond.pageNum = pageNum) const { data } = await this.$http.get( this.$api.classInfo.listPageClassInfo, this.reqCond ) this.pageInfo = data }, setPageSize(pageSize) { this.reqCond.pageSize = pageSize this.listPage() }, // 关闭弹窗 close() { this.addEditData = {} this.$refs.addEditDataRef.resetFields() this.$emit('update:dialogVisible', false) }, // 保存 save() { this.$refs.addEditDataRef.validate(async (valid) => { if (valid) { let text = this.type === 'add' ? '新增' : '修改' let param = {} const { title, insertImage, id, mainContent, qrCodeUrl, createUser, status, releaseTime, } = this.addEditData param = { title, insertImage, mainContent, qrCodeUrl, createUser, status, releaseTime, } if (this.type === 'edit') { param.id = id } this.$baseConfirm(`你确定是否${text}这条数据吗?`, async () => { await this.$http.post(this.$api.newsNote.addOrUpdate, { ...param, }) this.$baseMessage(`操作成功`) this.$emit('queryPage') this.close() }) } }) }, // 获取作者下拉列表 async getUserList(key) { const { data } = await this.$http.get(this.$api.user.searchUser, { key, }) this.userList = data }, }, } </script> <style lang="scss" scoped> .c-ml-10 { margin-left: 10px; } ::v-deep .el-dialog__body { height: 650px; overflow-y: auto; } .cover-img { width: 60px; /* 设置图片宽度 */ height: 60px; /* 设置图片高度 */ object-fit: cover; /* 保持图片比例并覆盖容器 */ border-radius: 4px; /* 圆角 */ } .course-item { // width: 100%; margin-top: 10px; margin-left: 100px; height: 84px; } .cover-container { width: 80%; border: 1px solid #ccc; padding: 10px; border-radius: 4px; /* 圆角 */ margin-left: 10px; } </style> 完善代码
07-02
<template> <div class="app-container"> <el-row :gutter="20"> <!-- 项目树菜单 --> <el-col :span="6" :xs="24"> <div class="head-container"> <el-input v-model="projectName" placeholder="请输入项目名称" clearable size="mini" prefix-icon="el-icon-search" style="margin-bottom: 20px" @input="filterProjectTree" /> </div> <el-row :gutter="10" class="mb8"> <el-col :span="1.5"> <el-button type="info" plain icon="el-icon-sort" size="mini" @click="toggleExpandAll" >{{ isExpandAll ? '折叠' : '展开' }}</el-button> </el-col> <el-col :span="1.5"> <el-button type="primary" plain icon="el-icon-folder-add" size="mini" @click="handleAddProject" v-hasPermi="['cms:project:add']" >新增项目</el-button> </el-col> </el-row> <el-tree v-if="refreshTable" style="margin-top: 0.8rem;" :data="filteredProjectTreeData" :props="defaultProps" :expand-on-click-node="false" :filter-node-method="filterNode" :highlight-current="true" :default-expand-all="isExpandAll" ref="projectTree" empty-text="加载中,请稍候" node-key="id" @node-click="handleProjectClick" > <span class="custom-tree-node" slot-scope="{ node, data }"> <div class="tree-node-content"> <el-icon class="tree-icon" :size="16"> <svg-icon v-if="node.expanded" icon-class="folder-open" /> <svg-icon v-else icon-class="folder" /> </el-icon> <div v-if="node.label && node.label.length > 25" class="node-label"> <el-tooltip :show-after="300" :content="node.label + (data.version ? ` (v${data.version})` : '')" placement="top-start"> <span>{{ ellipsis(node.label, 20) }}{{ data.version ? ` (v${data.version})` : '' }}</span> </el-tooltip> </div> <div v-else class="node-label"> <span>{{ node.label }}{{ data.version ? ` (v${data.version})` : '' }}</span> </div> </div> <span class="node-actions"> <span class="node-actions"> <el-button type="text" size="mini" icon="el-icon-edit" v-hasPermi="['cms:project:update']" @click.stop="() => handleEditProject(data)" > </el-button> <el-button type="text" size="mini" icon="el-icon-plus" v-hasPermi="['cms:project:add']" @click.stop="() => handleAddSubProject(data)" > </el-button> <el-button type="text" size="mini" icon="el-icon-delete" v-hasPermi="['cms:project:delete']" @click.stop="() => handleDeleteProject(data)" > </el-button> </span> </span> </span> </el-tree> </el-col> <!-- 文档区域 --> <el-col :span="18" :xs="24"> <!-- 文档列表视图 --> <div v-if="activeView === 'list'" class="doc-list-container"> <el-form :model="docQueryParams" ref="docQueryForm" :inline="true" label-width="68px"> <el-form-item label="文档标题" prop="title"> <el-input v-model="docQueryParams.title" placeholder="请输入文档标题" clearable size="mini" @keyup.enter.native="getDocumentList" prefix-icon="el-icon-search" /> </el-form-item> <el-form-item label="状态" prop="status"> <el-select v-model="docQueryParams.status" placeholder="状态" size="mini" clearable> <el-option label="编制中✍" value="0" /> <el-option label="待评审✊" value="1" /> <el-option label="已评审👍" value="2" /> <el-option label="修改中🔧" value="3" /> <el-option label="开发中💪" value="4" /> <el-option label="已完成开发🆗" value="5" /> </el-select> </el-form-item> <el-form-item> <el-button type="primary" icon="el-icon-search" size="mini" @click="getDocumentList">搜索</el-button> <el-button icon="el-icon-refresh" size="mini" @click="resetDocQuery">重置</el-button> </el-form-item> </el-form> <div class="batch-actions"> <el-button type="success" icon="el-icon-download" size="mini" :disabled="selectedDocs.length === 0" @click="handleBatchExport" > 批量导出 ({{ selectedDocs.length }}) </el-button> <el-button type="danger" size="mini" :disabled="selectedDocs.length === 0" v-hasPermi="['cms:project:deleteArticleFromProject']" @click="handleBatchDeleteDocument" > 批量删除({{ selectedDocs.length }}) </el-button> </div> <el-table v-loading="docLoading" :data="documentList" highlight-current-row @selection-change="handleSelectionChange" ref="docTable" > <el-table-column type="selection" width="55" align="center" /> <el-table-column label="序号" type="index" width="50" align="center" /> <el-table-column label="编号" align="center" prop="serialNum" /> <el-table-column label="标题" align="center" prop="title" class-name="small-padding fixed-width" width="200" :show-overflow-tooltip="true" sortable > <template slot-scope="scope"> <div v-show="scope.row.title.startsWith('[诊断项]')">{{scope.row.title}}<span style="color: #303133;font-family: 'Arial', sans-serif;font-size: 12px;font-weight: normal;font-style: italic;">(v{{scope.row.articleVersion}}版本)</span></div> <el-button v-show="!scope.row.title.startsWith('[诊断项]')" size="normal" type="text" icon="el-icon-tickets" @click="getArticleInfo(scope.row.id)">{{scope.row.title}}<span style="color: #303133;font-family: 'Arial', sans-serif;font-size: 12px;font-weight: normal;font-style: italic;">(v{{scope.row.articleVersion}}版本)</span></el-button> </template> </el-table-column> <el-table-column label="进度" prop="status" width="100"> <template slot-scope="scope"> <el-tag v-if="scope.row.status === '0'" type="info" size="small">编制中✍</el-tag> <el-tag v-if="scope.row.status === '1'" type="warning" size="small">待评审✊</el-tag> <el-tag v-if="scope.row.status === '2'" type="success" size="small">已评审👍</el-tag> <el-tag v-if="scope.row.status === '3'" type="success" size="small">修改中🔧</el-tag> <el-tag v-if="scope.row.status === '4'" type="success" size="small">开发中💪</el-tag> <el-tag v-if="scope.row.status === '5'" type="success" size="small">已完成开发🆗</el-tag> </template> </el-table-column> <el-table-column label="创建人" prop="createBy" width="100" /> <el-table-column label="负责人" prop="director" width="100"/> <el-table-column label="创建时间" prop="createTime" width="140" /> <el-table-column label="操作" width="180" align="center"> <template slot-scope="scope"> <el-button size="mini" type="text" icon="el-icon-edit" @click.stop="handleEditDocument(scope.row)" ></el-button> <el-button size="mini" type="text" icon="el-icon-delete" @click.stop="handleDeleteDocument(scope.row)" v-hasPermi="['cms:project:deleteArticleFromProject']"></el-button> </template> </el-table-column> </el-table> <pagination v-show="docTotal>0" :total="docTotal" :page.sync="docQueryParams.pageNum" :limit.sync="docQueryParams.pageSize" @pagination="getDocumentList" /> </div> <!-- 文档详情视图 --> <div v-else-if="activeView === 'detail'" class="doc-detail-container"> <div class="doc-header"> <el-button type="text" icon="el-icon-back" @click="backToList">返回文档列表</el-button> <h2 class="doc-title"> <el-icon class="title-icon"><svg-icon icon-class="document" /></el-icon> {{ currentDocument.title }} </h2> </div> <!-- 富文本编辑器 --> <el-form :model="currentDocument" ref="docForm" label-width="80px"> <el-form-item label="文档内容"> <Tinymce :height='600' v-model='currentDocument.content'></Tinymce> </el-form-item> <el-form-item> <el-button type="primary" icon="el-icon-check" @click="saveDocument">保存</el-button> <el-button icon="el-icon-close" @click="backToList">取消</el-button> </el-form-item> </el-form> </div> </el-col> </el-row> <!-- 项目编辑对话框 --> <el-dialog :title="projectDialogTitle" :visible.sync="projectDialogVisible" width="50%"> <el-form :model="projectForm" ref="projectForm" label-width="100px"> <el-form-item label="项目名称" prop="name" required> <el-input v-model="projectForm.name" placeholder="请输入项目名称" prefix-icon="el-icon-folder" /> </el-form-item> <el-form-item label="上级项目" prop="parentId"> <treeselect v-model="projectForm.parentId" :options="projectTreeData" :normalizer="normalizer" placeholder="选择上级项目" /> </el-form-item> <el-form-item label="项目版本号" prop="version" > <el-input v-model="projectForm.version" placeholderequiredr="请输入项目名称" /> </el-form-item> <el-form-item label="项目描述" prop="remark"> <el-input type="textarea" v-model="projectForm.remark" :rows="3" /> </el-form-item> </el-form> <div slot="footer"> <el-button @click="projectDialogVisible = false">取消</el-button> <el-button type="primary" icon="el-icon-check" @click="saveProject">保存</el-button> </div> </el-dialog> </div> </template> <script> import { getData, updateData } from "@/api/cms/data"; import { getProjectTree, getDocuments, saveProject, updateProject, deleteProject, removeArticleFromProject } from "@/api/cms/articleProject"; import Tinymce from '@/components/Tinymce'; import Treeselect from "@riophae/vue-treeselect"; import "@riophae/vue-treeselect/dist/vue-treeselect.css"; import axios from 'axios'; export default { name: "ProjectManagement", components: { Treeselect, Tinymce }, data() { return { // 项目树相关数据 projectName: '', projectTreeData: [], filteredProjectTreeData: [], refreshTable: true, isExpandAll: true, defaultProps: { children: "children", label: "label" }, // 项目对话框相关 projectDialogVisible: false, projectDialogTitle: '', projectForm: { id: null, name: '', version: '', parentId: null, remark: '' }, // 文档列表相关 activeView: 'list', // 'list' 或 'detail' docQueryParams: { ids: null, title: '', status: '', pageNum: 1, pageSize: 10 }, documentList: [], docTotal: 0, docLoading: false, selectedDocs: [], // 选中的文档 ids: [], // 选中文档ID集合 // 文档详情相关 currentDocument: { id: null, dataIds: null, title: '', content: '', status: '0' }, // 当前选中的项目ID(用于删除操作) currentProjectId: null, // 导出相关数据 form: { ids: [], // 导出的文档ID集合 notesExportFlag: 1 // 默认导出详细 } }; }, created() { this.getProjectTree(); }, methods: { // ================= 项目树方法 ================= ellipsis(text, maxLength) { return text.length > maxLength ? text.substring(0, maxLength) + '...' : text; }, toggleExpandAll() { this.refreshTable = false; this.isExpandAll = !this.isExpandAll; this.$nextTick(() => { this.refreshTable = true; }); }, filterNode(value, data) { if (!value) return true; return data.label.toLowerCase().includes(value.toLowerCase()); }, filterProjectTree() { this.$refs.projectTree.filter(this.projectName); }, handleProjectClick(data) { // 检查是否是根节(所有项目) if (data.isRoot) { this.currentProjectId = null; this.docQueryParams.dataIds = null; } else { this.currentProjectId = data.id; this.docQueryParams.ids =data.dataIds; } this.getDocumentList(); }, handleAddProject() { this.projectForm = { id: null, name: '', version: '', parentId: null, remark: '' }; this.projectDialogTitle = '新增项目'; this.projectDialogVisible = true; }, handleAddSubProject(data) { this.projectForm = { id: null, name: '', version: '', parentId: data.id, remark: '' }; this.projectDialogTitle = '新增子项目'; this.projectDialogVisible = true; }, handleEditProject(data) { this.projectForm = { id: data.id, name: data.name, version: data.version, parentId: data.parentId, remark: data.remark || '' }; this.projectDialogTitle = '编辑项目'; this.projectDialogVisible = true; }, collectProjectIds(node) { let ids = [node.id]; if (node.children && node.children.length > 0) { node.children.forEach(child => { ids = ids.concat(this.collectProjectIds(child)); }); } return ids; }, handleDeleteProject(data) { this.$confirm(`确定删除项目 "${data.name}" 及其所有子项目吗?`, '提示', { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning' }).then(() => { // 递归收集所有节ID const ids = this.collectProjectIds(data); // 调用批量删除API deleteProject(ids).then(response => { if (response.code === 200) { this.$message.success('删除成功'); this.getProjectTree(); } else { this.$message.error(response.msg || '删除失败'); } }).catch(error => { this.$message.error('删除失败: ' + error.message); }); }); }, saveProject() { this.$refs.projectForm.validate(valid => { if (valid) { const saveMethod = this.projectForm.id ? updateProject : saveProject; saveMethod(this.projectForm).then(response => { if (response.code === 200) { this.$message.success('保存成功'); this.projectDialogVisible = false; this.getProjectTree(); } else { this.$message.error(response.msg || '保存失败'); } }).catch(error => { this.$message.error('保存失败: ' + error.message); }); } }); }, normalizer(node) { return { id: node.id, label: `${node.name} ${node.version? '【 v' + node.version +'】': ''}`, children: node.children && node.children.length > 0 ? node.children : undefined }; }, // 修改后的 getProjectTree 方法 getProjectTree() { getProjectTree().then(response => { if (response.code === 200 && response.data) { const rootNode = response.data; rootNode.isRoot = true; this.projectTreeData = this.transformTreeData([rootNode]); this.filteredProjectTreeData = [...this.projectTreeData]; this.$nextTick(() => { if (this.projectTreeData.length > 0) { const firstNode = this.findFirstNonRootNode(this.projectTreeData); if (firstNode) { this.$refs.projectTree.setCurrentKey(firstNode.id); this.handleProjectClick(firstNode.rawData); } } }); } }).catch(error => { console.error("获取项目树失败:", error); this.$message.error('获取项目树失败: ' + error.message); }); }, // 查找第一个非根节 findFirstNonRootNode(nodes) { for (const node of nodes) { if (node.isRoot) continue; return node; } return null; }, // 修改后的 transformTreeData 方法 transformTreeData(nodes) { if (!nodes || !Array.isArray(nodes)) return []; return nodes.map(node => { // 如果是根节,直接返回其子节 if (node.isRoot) { return this.transformTreeData(node.children || []); } return { id: node.id, label: node.name, name: node.name, parentId: node.parentId, dataIds: node.dataIds, remark: node.remark, version: node.version || '', createBy: node.createBy, createTime: node.createTime, updateBy: node.updateBy, updateTime: node.updateTime, children: this.transformTreeData(node.children || []), rawData: node }; }).flat(); }, // ================= 文档管理方法 ================= // 在 methods 中添加递归收集 serialNum 的方法 collectAlldataIds(node) { let dataIds = []; // 添加当前节的 serialNum if (node.dataIds) { const ids = node.dataIds.split(',').map(id => id.trim()); dataIds = [...dataIds, ...ids]; } // 递归处理子节 if (node.children && node.children.length > 0) { node.children.forEach(child => { dataIds = [...dataIds, ...this.collectAlldataIds(child)]; }); } return dataIds; }, // 修改后的 getDocumentList 方法 getDocumentList() { this.docLoading = true; getDocuments(this.docQueryParams).then(response => { if (response.code === 200) { this.documentList = response.rows; this.docTotal = response.total; this.selectedDocs = []; // 清空选择 this.ids = []; // 清空ID集合 } else { this.$message.error(response.msg || '获取文档列表失败'); } this.docLoading = false; }).catch(error => { this.$message.error('获取文档列表失败: ' + error.message); this.docLoading = false; }); }, resetDocQuery() { this.docQueryParams.title = ''; this.docQueryParams.status = ''; this.getDocumentList(); }, handleEditDocument(row) { getData(row.id).then(response => { if (response.code === 200) { this.currentDocument = { id: response.data.id, serialNum: response.data.serialNum, title: response.data.title, content: response.data.content, status: response.data.status }; this.activeView = 'detail'; } else { this.$message.error(response.msg || '获取文档详情失败'); } }).catch(error => { this.$message.error('获取文档详情失败: ' + error.message); }); }, // 修改后的 handleDeleteDocument 方法 handleDeleteDocument(row) { // 检查当前是否选择了项目 if (!this.currentProjectId) { this.$message.warning('请先选择一个具体项目'); return; } this.$confirm(`确定从项目中移除文档 "${row.title}" 吗?`, '提示', { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning' }).then(() => { const params = { projectId: this.currentProjectId, dataIds: [row.id] }; removeArticleFromProject(params).then(response => { if (response.code === 200) { this.getProjectTree(); this.getDocumentList(); this.$message.success('文档已从项目中移除'); } else { this.$message.error(response.msg || '移除文档失败'); } }).catch(error => { this.$message.error('移除文档失败: ' + error.message); }); }); }, handleBatchDeleteDocument() { if (!this.currentProjectId) { this.$message.warning('请先选择一个具体项目'); return; } this.$confirm(`确定从项目中移除所选文档吗?`, '提示', { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning' }).then(() => { // 获取选中的文档的serialNum,并去重 const dataIds = Array.from(new Set( this.selectedDocs.map(item => item.id) )); const params = { projectId: this.currentProjectId, dataIds: this.selectedDocs.map(item => item.id) }; removeArticleFromProject(params).then(response => { if (response.code === 200) { this.getProjectTree(); this.getDocumentList(); this.$message.success('文档已从项目中移除'); } else { this.$message.error(response.msg || '移除文档失败'); } }).catch(error => { this.$message.error('移除文档失败: ' + error.message); }); }); }, backToList() { this.activeView = 'list'; }, saveDocument() { const saveMethod = this.currentDocument.id ? updateData : addData; saveMethod(this.currentDocument).then(response => { if (response.code === 200) { this.$message.success('保存成功'); this.getDocumentList(); this.backToList(); } else { this.$message.error(response.msg || '保存失败'); } }).catch(error => { this.$message.error('保存失败: ' + error.message); }); }, // ================= 导出功能方法 ================= // 多选处理 handleSelectionChange(selection) { this.selectedDocs = selection; this.ids = selection.map(item => item.id); }, // 导出文档(单篇) handleExportHttp(row, isDetail) { const params = { ids: row.id, notesExportFlag: isDetail ? 1 : 0 }; this.download( 'cms/data/createArticleOutputHttp', params, `word文档_${row.title}_${new Date().getTime()}.docx`, { timeout: 60000 } ); }, // 批量导出文档 handleBatchExport() { if (this.selectedDocs.length === 0) { this.$message.warning('请选择要导出的文档'); return; } // 弹出选择导出类型的对话框 this.$confirm('请选择导出方式', '提示', { distinguishCancelAndClose: true, confirmButtonText: '导出详细', cancelButtonText: '导出简版', type: 'info' }).then(() => { // 导出详细 this.batchExportHttp(true); }).catch(action => { if (action === 'cancel') { // 导出简版 this.batchExportHttp(false); } }); }, // 批量导出文档实现 batchExportHttp(isDetail) { const params = { ids: this.ids, notesExportFlag: isDetail ? 1 : 0 }; this.download('cms/data/createArticleOutputHttp', { ...params }, `word文档_${new Date().getTime()}.docx`, { timeout: 60000 }) // 超时设置 }, // 排序格式化方法 sortableFormatter(row, column) { if (this.ids.includes(row.id)) { return 1; } else { return 2; } }, // 跳转到文章详情页 getArticleInfo(articleId) { // id加密 const articleIdStr = EncryptJs(articleId, "f1827100d08ff039", "ed363078893c0329"); console.log('阅读的文档跳转加密后的ID:'+articleIdStr) let routeUrl = this.$router.resolve({ path: '/cms/doucumentView', query: { id: articleIdStr } }); window.open(routeUrl.href, '_blank'); } } }; </script> <style scoped> /* 新增节信息容器样式 */ .node-info { display: flex; flex-direction: column; margin-left: 8px; } /* 版本号样式 */ .node-version { font-size: 12px; color: #909399; margin-top: 2px; font-style: italic; } /* 调整节内容布局 */ .tree-node-content { display: flex; align-items: center; flex: 1; } /* 调整节标签样式 */ .node-label { font-size: 14px; font-weight: normal; } /* 确保操作按钮在右侧 */ .node-actions { display: flex; align-items: center; } /* 响应式调整 */ @media (max-width: 768px) { .node-version { font-size: 10px; } } <style scoped> .app-container { padding: 20px; background-color: #f5f7fa; } .head-container { padding: 10px; background-color: #ffffff; border-radius: 4px; box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1); } .custom-tree-node { flex: 1; display: flex; align-items: center; justify-content: space-between; font-size: 14px; padding-right: 8px; } .tree-node-content { display: flex; align-items: center; } .tree-icon { margin-right: 8px; color: #409EFF; } .node-label { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .node-actions { display: flex; align-items: center; } .doc-list-container { background-color: #ffffff; padding: 20px; border-radius: 4px; box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1); } .batch-actions { margin-bottom: 15px; } .doc-detail-container { background-color: #ffffff; padding: 20px; border-radius: 4px; box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1); } .doc-header { display: flex; align-items: center; margin-bottom: 20px; } .doc-title { display: flex; align-items: center; margin-left: 15px; margin-bottom: 0; font-size: 18px; color: #303133; } .title-icon { margin-right: 10px; color: #409EFF; } .doc-title .doc-icon { margin-right: 8px; color: #909399; } .el-tree { border: 1px solid #ebeef5; border-radius: 4px; padding: 10px; max-height: 70vh; overflow-y: auto; background-color: #ffffff; box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1); } .custom-tree-node .el-button { padding: 4px; margin-left: 5px; } .el-table { margin-top: 10px; border-radius: 4px; overflow: hidden; box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1); } .el-form-item { margin-bottom: 18px; } .el-tag { margin: 2px; } /* 响应式调整 */ @media (max-width: 768px) { .el-col-xs-24 { width: 100%; margin-bottom: 20px; } .doc-list-container, .doc-detail-container { padding: 10px; } .doc-header h2 { font-size: 16px; } } </style> 刪除不必要的代碼,不要改變原來的變量和方法,优化树的ui
最新发布
08-06
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值