[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"article-public-A6caJxFd":3,"public-project-articles-A6caJxFd":17},{"id":4,"uuid":5,"project_id":6,"title":7,"content":8,"type":9,"status":10,"public_enabled":10,"views":11,"sort":12,"created_at":13,"updated_at":14,"project_title":15,"project_slug":16},1123,"A6caJxFd",54,"09. 开发物品申请交换功能","## SQL\n\n```sql\nCREATE TABLE `charge` (\n  `id` int NOT NULL AUTO_INCREMENT COMMENT 'ID',\n  `item_id` int DEFAULT NULL COMMENT '被交换物品ID',\n  `content` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '交换物品',\n  `remark` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '交换理由',\n  `user_id` int DEFAULT NULL COMMENT '申请人',\n  `time` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '申请时间',\n  `status` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '审核状态',\n  `reason` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '审核理由',\n  `location` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '交换地点',\n  `share_time` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '交换时间',\n  `item_userid` int DEFAULT NULL COMMENT '物品主人ID',\n  PRIMARY KEY (`id`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='物品交换信息';\n```\n\n\n\n## ELement-Plus 笔记\n\n[https:\u002F\u002Fwww.yuque.com\u002Fxiaqing-en2ii\u002Fskflxg\u002Fhzi02h8qfizne3yv](https:\u002F\u002Fwww.yuque.com\u002Fxiaqing-en2ii\u002Fskflxg\u002Fhzi02h8qfizne3yv)\t\n\n\n\n## 后端的接口\n\nCharge.java\n\n```java\npackage com.example.entity;\n\npublic class Charge {\n\n    \u002F**ID *\u002F\n    private Integer id;\n    \u002F**被交换物品ID *\u002F\n    private Integer itemId;\n    private String itemName;\n    private String requirement;\n    \u002F**交换物品 *\u002F\n    private String content;\n    \u002F**交换理由 *\u002F\n    private String remark;\n    \u002F**申请人 *\u002F\n    private Integer userId;\n    private String userName;\n    \u002F**申请时间 *\u002F\n    private String time;\n    \u002F**审核状态 *\u002F\n    private String status;\n    \u002F**审核理由 *\u002F\n    private String reason;\n    \u002F**交换地点 *\u002F\n    private String location;\n    \u002F**交换时间 *\u002F\n    private String shareTime;\n    \u002F**物品主人ID *\u002F\n    private Integer itemUserid;\n    private String itemUserName;\n    private String comment;\n\n    public String getComment() {\n        return comment;\n    }\n\n    public void setComment(String comment) {\n        this.comment = comment;\n    }\n\n    public Integer getId() {\n        return id;\n    }\n\n    public void setId(Integer id) {\n        this.id = id;\n    }\n\n    public Integer getItemId() {\n        return itemId;\n    }\n\n    public void setItemId(Integer itemId) {\n        this.itemId = itemId;\n    }\n\n    public String getItemName() {\n        return itemName;\n    }\n\n    public void setItemName(String itemName) {\n        this.itemName = itemName;\n    }\n\n    public String getRequirement() {\n        return requirement;\n    }\n\n    public void setRequirement(String requirement) {\n        this.requirement = requirement;\n    }\n\n    public String getContent() {\n        return content;\n    }\n\n    public void setContent(String content) {\n        this.content = content;\n    }\n\n    public String getRemark() {\n        return remark;\n    }\n\n    public void setRemark(String remark) {\n        this.remark = remark;\n    }\n\n    public Integer getUserId() {\n        return userId;\n    }\n\n    public void setUserId(Integer userId) {\n        this.userId = userId;\n    }\n\n    public String getUserName() {\n        return userName;\n    }\n\n    public void setUserName(String userName) {\n        this.userName = userName;\n    }\n\n    public String getTime() {\n        return time;\n    }\n\n    public void setTime(String time) {\n        this.time = time;\n    }\n\n    public String getStatus() {\n        return status;\n    }\n\n    public void setStatus(String status) {\n        this.status = status;\n    }\n\n    public String getReason() {\n        return reason;\n    }\n\n    public void setReason(String reason) {\n        this.reason = reason;\n    }\n\n    public String getLocation() {\n        return location;\n    }\n\n    public void setLocation(String location) {\n        this.location = location;\n    }\n\n    public String getShareTime() {\n        return shareTime;\n    }\n\n    public void setShareTime(String shareTime) {\n        this.shareTime = shareTime;\n    }\n\n    public Integer getItemUserid() {\n        return itemUserid;\n    }\n\n    public void setItemUserid(Integer itemUserid) {\n        this.itemUserid = itemUserid;\n    }\n\n    public String getItemUserName() {\n        return itemUserName;\n    }\n\n    public void setItemUserName(String itemUserName) {\n        this.itemUserName = itemUserName;\n    }\n}\n\n```\n\n\n\n\n\nChargeService.java\n\n```java\npackage com.example.service;\n\nimport cn.hutool.core.date.DateUtil;\nimport com.example.entity.Charge;\nimport com.example.entity.Items;\nimport com.example.mapper.ChargeMapper;\nimport com.github.pagehelper.PageHelper;\nimport com.github.pagehelper.PageInfo;\nimport jakarta.annotation.Resource;\nimport org.springframework.stereotype.Service;\nimport org.springframework.transaction.annotation.Transactional;\n\nimport java.util.List;\n\n\u002F**\n * 业务处理\n **\u002F\n@Service\npublic class ChargeService {\n\n    @Resource\n    private ChargeMapper chargeMapper;\n    @Resource\n    ItemsService itemsService;\n\n    \u002F**\n     * 新增\n     *\u002F\n    public void add(Charge charge) {\n        charge.setTime(DateUtil.now());\n        charge.setStatus(\"待审核\");\n        chargeMapper.insert(charge);\n    }\n\n    \u002F**\n     * 删除\n     *\u002F\n    public void deleteById(Integer id) {\n        chargeMapper.deleteById(id);\n    }\n\n    \u002F**\n     * 修改\n     *\u002F\n    @Transactional\n    public void updateById(Charge charge) {\n        if (\"通过\".equals(charge.getStatus())) {\n            Items items = itemsService.selectById(charge.getItemId());\n            items.setStatus(false);\n            itemsService.updateById(items);\n        }\n        chargeMapper.updateById(charge);\n    }\n\n    \u002F**\n     * 根据ID查询\n     *\u002F\n    public Charge selectById(Integer id) {\n        return chargeMapper.selectById(id);\n    }\n\n    \u002F**\n     * 查询所有\n     *\u002F\n    public List\u003CCharge> selectAll(Charge charge) {\n        return chargeMapper.selectAll(charge);\n    }\n\n    \u002F**\n     * 分页查询\n     *\u002F\n    public PageInfo\u003CCharge> selectPage(Charge charge, Integer pageNum, Integer pageSize) {\n        PageHelper.startPage(pageNum, pageSize);\n        List\u003CCharge> list = chargeMapper.selectAll(charge);\n        return PageInfo.of(list);\n    }\n\n}\n```\n\n\n\nChargeMapper.xml\n\n```xml\n\u003C?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\u003C!DOCTYPE mapper\n        PUBLIC \"-\u002F\u002Fmybatis.org\u002F\u002FDTD Mapper 3.0\u002F\u002FEN\"\n        \"http:\u002F\u002Fmybatis.org\u002Fdtd\u002Fmybatis-3-mapper.dtd\">\n\u003Cmapper namespace=\"com.example.mapper.ChargeMapper\">\n\n    \u003Cselect id=\"selectAll\" resultType=\"com.example.entity.Charge\">\n        select charge.*, user1.name as userName, user2.name as itemUserName,\n                items.name as itemName, items.requirement\n        from `charge`\n        left join user user1 on charge.user_id = user1.id\n        left join user user2 on charge.item_userid = user2.id\n        left join items on charge.item_id = items.id\n        \u003Cwhere>\n            \u003Cif test=\"itemName != null\"> and items.name like concat('%', #{itemName}, '%')\u003C\u002Fif>\n            \u003Cif test=\"userId != null\"> and charge.user_id = #{userId}\u003C\u002Fif>\n            \u003Cif test=\"itemUserid != null\"> and charge.item_userid = #{itemUserid}\u003C\u002Fif>\n        \u003C\u002Fwhere>\n        order by charge.id desc\n    \u003C\u002Fselect>\n\n    \u003Cinsert id=\"insert\" parameterType=\"com.example.entity.Charge\" useGeneratedKeys=\"true\">\n        insert into `charge`\n        \u003Ctrim prefix=\"(\" suffix=\")\" suffixOverrides=\",\">\n            \u003Cif test=\"id != null\">id,\u003C\u002Fif>\n            \u003Cif test=\"itemId != null\">item_id,\u003C\u002Fif>\n            \u003Cif test=\"content != null\">content,\u003C\u002Fif>\n            \u003Cif test=\"remark != null\">remark,\u003C\u002Fif>\n            \u003Cif test=\"userId != null\">user_id,\u003C\u002Fif>\n            \u003Cif test=\"time != null\">time,\u003C\u002Fif>\n            \u003Cif test=\"status != null\">status,\u003C\u002Fif>\n            \u003Cif test=\"reason != null\">reason,\u003C\u002Fif>\n            \u003Cif test=\"location != null\">location,\u003C\u002Fif>\n            \u003Cif test=\"shareTime != null\">share_time,\u003C\u002Fif>\n            \u003Cif test=\"itemUserid != null\">item_userid,\u003C\u002Fif>\n            \u003Cif test=\"comment != null\">comment,\u003C\u002Fif>\n        \u003C\u002Ftrim>\n        values\n        \u003Ctrim prefix=\"(\" suffix=\")\" suffixOverrides=\",\">\n            \u003Cif test=\"id != null\">#{id},\u003C\u002Fif>\n            \u003Cif test=\"itemId != null\">#{itemId},\u003C\u002Fif>\n            \u003Cif test=\"content != null\">#{content},\u003C\u002Fif>\n            \u003Cif test=\"remark != null\">#{remark},\u003C\u002Fif>\n            \u003Cif test=\"userId != null\">#{userId},\u003C\u002Fif>\n            \u003Cif test=\"time != null\">#{time},\u003C\u002Fif>\n            \u003Cif test=\"status != null\">#{status},\u003C\u002Fif>\n            \u003Cif test=\"reason != null\">#{reason},\u003C\u002Fif>\n            \u003Cif test=\"location != null\">#{location},\u003C\u002Fif>\n            \u003Cif test=\"shareTime != null\">#{shareTime},\u003C\u002Fif>\n            \u003Cif test=\"itemUserid != null\">#{itemUserid},\u003C\u002Fif>\n            \u003Cif test=\"comment != null\">#{comment},\u003C\u002Fif>\n        \u003C\u002Ftrim>\n    \u003C\u002Finsert>\n\n    \u003Cupdate id=\"updateById\" parameterType=\"com.example.entity.Charge\">\n        update `charge`\n        \u003Cset>\n            \u003Cif test=\"id != null\">\n                id = #{id},\n            \u003C\u002Fif>\n            \u003Cif test=\"itemId != null\">\n                item_id = #{itemId},\n            \u003C\u002Fif>\n            \u003Cif test=\"content != null\">\n                content = #{content},\n            \u003C\u002Fif>\n            \u003Cif test=\"remark != null\">\n                remark = #{remark},\n            \u003C\u002Fif>\n            \u003Cif test=\"userId != null\">\n                user_id = #{userId},\n            \u003C\u002Fif>\n            \u003Cif test=\"time != null\">\n                time = #{time},\n            \u003C\u002Fif>\n            \u003Cif test=\"status != null\">\n                status = #{status},\n            \u003C\u002Fif>\n            \u003Cif test=\"reason != null\">\n                reason = #{reason},\n            \u003C\u002Fif>\n            \u003Cif test=\"location != null\">\n                location = #{location},\n            \u003C\u002Fif>\n            \u003Cif test=\"shareTime != null\">\n                share_time = #{shareTime},\n            \u003C\u002Fif>\n            \u003Cif test=\"itemUserid != null\">\n                item_userid = #{itemUserid},\n            \u003C\u002Fif>\n        \u003C\u002Fset>\n        where id = #{id}\n    \u003C\u002Fupdate>\n\n\u003C\u002Fmapper>\n```\n\n## 前端页面\n\n### 物品申请信息 Charge.vue\n\n```vue\n\u003Ctemplate>\n  \u003Cdiv>\n\n    \u003Cdiv class=\"card\" style=\"margin-bottom: 5px;\">\n      \u003Cel-input v-model=\"data.itemName\" style=\"width: 300px; margin-right: 10px\" placeholder=\"请输入物品名称查询\">\u003C\u002Fel-input>\n      \u003Cel-button type=\"primary\" @click=\"load\">查询\u003C\u002Fel-button>\n      \u003Cel-button type=\"info\" style=\"margin: 0 10px\" @click=\"reset\">重置\u003C\u002Fel-button>\n    \u003C\u002Fdiv>\n\n    \u003Cdiv class=\"card\" style=\"margin-bottom: 5px\">\n      \u003Cel-table :data=\"data.tableData\" stripe>\n        \u003Cel-table-column prop=\"itemName\" label=\"被交换物品\">\u003C\u002Fel-table-column>\n        \u003Cel-table-column prop=\"requirement\" label=\"交换条件\">\u003C\u002Fel-table-column>\n        \u003Cel-table-column prop=\"content\" label=\"交换物品\">\u003C\u002Fel-table-column>\n        \u003Cel-table-column prop=\"remark\" label=\"交换理由\">\u003C\u002Fel-table-column>\n        \u003Cel-table-column prop=\"time\" label=\"申请时间\">\u003C\u002Fel-table-column>\n        \u003Cel-table-column prop=\"status\" label=\"审核状态\">\n          \u003Ctemplate v-slot=\"scope\">\n            \u003Cel-tag type=\"warning\" v-if=\"scope.row.status === '待审核'\">待审核\u003C\u002Fel-tag>\n            \u003Cel-tag type=\"success\" v-if=\"scope.row.status === '通过'\">通过\u003C\u002Fel-tag>\n            \u003Cel-tag type=\"danger\" v-if=\"scope.row.status === '拒绝'\">拒绝\u003C\u002Fel-tag>\n          \u003C\u002Ftemplate>\n        \u003C\u002Fel-table-column>\n        \u003Cel-table-column prop=\"reason\" label=\"审核理由\">\u003C\u002Fel-table-column>\n        \u003Cel-table-column prop=\"location\" label=\"交换地点\">\u003C\u002Fel-table-column>\n        \u003Cel-table-column prop=\"shareTime\" label=\"交换时间\">\u003C\u002Fel-table-column>\n        \u003Cel-table-column prop=\"itemUserName\" label=\"物品主人\">\u003C\u002Fel-table-column>\n        \u003Cel-table-column prop=\"comment\" label=\"物品主人留言\">\u003C\u002Fel-table-column>\n\n        \u003Cel-table-column label=\"操作\" align=\"center\" width=\"160\">\n          \u003Ctemplate #default=\"scope\">\n            \u003Cel-button :disabled=\"scope.row.status === '通过'\" type=\"danger\" @click=\"handleDelete(scope.row.id)\">删除\u003C\u002Fel-button>\n          \u003C\u002Ftemplate>\n        \u003C\u002Fel-table-column>\n      \u003C\u002Fel-table>\n    \u003C\u002Fdiv>\n\n    \u003Cdiv class=\"card\">\n      \u003Cel-pagination @current-change=\"load\" background layout=\"total, prev, pager, next\" v-model:page-size=\"data.pageSize\" v-model:current-page=\"data.pageNum\" :total=\"data.total\"\u002F>\n    \u003C\u002Fdiv>\n\n  \u003C\u002Fdiv>\n\u003C\u002Ftemplate>\n\n\u003Cscript setup>\nimport request from \"@\u002Futils\u002Frequest\";\nimport {reactive, ref} from \"vue\";\nimport {ElMessageBox, ElMessage} from \"element-plus\";\n\nconst formRef = ref()\nconst data = reactive({\n  user: JSON.parse(localStorage.getItem('system-user') || '{}'),\n  pageNum: 1,\n  pageSize: 10,\n  total: 0,\n  formVisible: false,\n  form: {},\n  tableData: [],\n  itemName: null,\n})\n\n\u002F\u002F 分页查询\nconst load = () => {\n  request.get('\u002Fcharge\u002FselectPage', {\n    params: {\n      pageNum: data.pageNum,\n      pageSize: data.pageSize,\n      itemName: data.itemName,\n      userId: data.user.id\n    }\n  }).then(res => {\n    if (res.code === '200') {\n      data.tableData = res.data?.list\n      data.total = res.data?.total\n    } else {\n      ElMessage.error(res.msg)\n    }\n  })\n}\n\n\u002F\u002F 新增\nconst handleAdd = () => {\n  data.form = {}\n  data.formVisible = true\n}\n\n\u002F\u002F 编辑\nconst handleEdit = (row) => {\n  data.form = JSON.parse(JSON.stringify(row))\n  data.formVisible = true\n}\n\n\u002F\u002F 新增保存\nconst add = () => {\n  request.post('\u002Fcharge\u002Fadd', data.form).then(res => {\n    if (res.code === '200') {\n      load()\n      ElMessage.success('操作成功')\n      data.formVisible = false\n    } else {\n      ElMessage.error(res.msg)\n    }\n  })\n}\n\n\u002F\u002F 编辑保存\nconst update = () => {\n  request.put('\u002Fcharge\u002Fupdate', data.form).then(res => {\n    if (res.code === '200') {\n      load()\n      ElMessage.success('操作成功')\n      data.formVisible = false\n    } else {\n      ElMessage.error(res.msg)\n    }\n  })\n}\n\n\u002F\u002F 弹窗保存\nconst save = () => {\n  formRef.value.validate(valid => {\n    if (valid) {\n      \u002F\u002F data.form有id就是更新，没有就是新增\n      data.form.id ? update() : add()\n    }\n  })\n}\n\n\u002F\u002F 删除\nconst handleDelete = (id) => {\n  ElMessageBox.confirm('删除后数据无法恢复，您确定删除吗?', '删除确认', { type: 'warning' }).then(res => {\n    request.delete('\u002Fcharge\u002Fdelete\u002F' + id).then(res => {\n      if (res.code === '200') {\n        load()\n        ElMessage.success('操作成功')\n      } else {\n        ElMessage.error(res.msg)\n      }\n    })\n  }).catch(err => {})\n}\n\n\u002F\u002F 重置\nconst reset = () => {\n  data.title = null\n  load()\n}\n\nload()\n\u003C\u002Fscript>\n\n\u003Cstyle scoped>\n:deep(.el-tag--warning) {\n  color: #ff5900;\n}\n\u003C\u002Fstyle>\n```\n\n### 申请审核 Charge1.vue\n\n```vue\n\u003Ctemplate>\n  \u003Cdiv>\n\n    \u003Cdiv class=\"card\" style=\"margin-bottom: 5px;\">\n      \u003Cel-input v-model=\"data.itemName\" style=\"width: 300px; margin-right: 10px\" placeholder=\"请输入物品名称查询\">\u003C\u002Fel-input>\n      \u003Cel-button type=\"primary\" @click=\"load\">查询\u003C\u002Fel-button>\n      \u003Cel-button type=\"info\" style=\"margin: 0 10px\" @click=\"reset\">重置\u003C\u002Fel-button>\n    \u003C\u002Fdiv>\n\n    \u003Cdiv class=\"card\" style=\"margin-bottom: 5px\">\n      \u003Cel-table :data=\"data.tableData\" stripe>\n        \u003Cel-table-column prop=\"itemName\" label=\"被交换物品\">\u003C\u002Fel-table-column>\n        \u003Cel-table-column prop=\"requirement\" label=\"交换条件\">\u003C\u002Fel-table-column>\n        \u003Cel-table-column prop=\"content\" label=\"交换物品\">\u003C\u002Fel-table-column>\n        \u003Cel-table-column prop=\"remark\" label=\"交换理由\">\u003C\u002Fel-table-column>\n        \u003Cel-table-column prop=\"userName\" label=\"申请人\">\u003C\u002Fel-table-column>\n        \u003Cel-table-column prop=\"time\" label=\"申请时间\">\u003C\u002Fel-table-column>\n        \u003Cel-table-column prop=\"status\" label=\"审核状态\">\n          \u003Ctemplate v-slot=\"scope\">\n            \u003Cel-tag type=\"warning\" v-if=\"scope.row.status === '待审核'\">待审核\u003C\u002Fel-tag>\n            \u003Cel-tag type=\"success\" v-if=\"scope.row.status === '通过'\">通过\u003C\u002Fel-tag>\n            \u003Cel-tag type=\"danger\" v-if=\"scope.row.status === '拒绝'\">拒绝\u003C\u002Fel-tag>\n          \u003C\u002Ftemplate>\n        \u003C\u002Fel-table-column>\n        \u003Cel-table-column prop=\"reason\" label=\"审核理由\">\u003C\u002Fel-table-column>\n        \u003Cel-table-column prop=\"location\" label=\"交换地点\">\u003C\u002Fel-table-column>\n        \u003Cel-table-column prop=\"shareTime\" label=\"交换时间\">\u003C\u002Fel-table-column>\n        \u003Cel-table-column prop=\"comment\" label=\"物品主人留言\">\u003C\u002Fel-table-column>\n        \u003Cel-table-column label=\"操作\" align=\"center\" width=\"120\">\n          \u003Ctemplate #default=\"scope\">\n            \u003Cel-button :disabled=\"scope.row.status !== '待审核'\" type=\"primary\" @click=\"handleEdit(scope.row)\">审核\u003C\u002Fel-button>\n          \u003C\u002Ftemplate>\n        \u003C\u002Fel-table-column>\n      \u003C\u002Fel-table>\n    \u003C\u002Fdiv>\n\n    \u003Cdiv class=\"card\">\n      \u003Cel-pagination @current-change=\"load\" background layout=\"total, prev, pager, next\" v-model:page-size=\"data.pageSize\" v-model:current-page=\"data.pageNum\" :total=\"data.total\"\u002F>\n    \u003C\u002Fdiv>\n\n    \u003Cel-dialog title=\"审核信息\" width=\"40%\" v-model=\"data.formVisible\" :close-on-click-modal=\"false\" destroy-on-close>\n      \u003Cel-form ref=\"formRef\" :model=\"data.form\" :rules=\"data.rules\" label-width=\"100px\" style=\"padding-right: 50px\">\n        \u003Cel-form-item label=\"审核状态\" prop=\"status\">\n          \u003Cel-radio-group v-model=\"data.form.status\">\n            \u003Cel-radio-button label=\"通过\" value=\"通过\">\u003C\u002Fel-radio-button>\n            \u003Cel-radio-button label=\"拒绝\" value=\"拒绝\">\u003C\u002Fel-radio-button>\n          \u003C\u002Fel-radio-group>\n        \u003C\u002Fel-form-item>\n        \u003Cdiv v-if=\"data.form.status === '通过'\">\n          \u003Cel-form-item label=\"交换地点\" prop=\"location\">\n            \u003Cel-input placeholder=\"请输入交换地点\" v-model=\"data.form.location\" autocomplete=\"off\" \u002F>\n          \u003C\u002Fel-form-item>\n          \u003Cel-form-item label=\"交换时间\" prop=\"shareTime\">\n            \u003Cel-date-picker style=\"width: 100%\" v-model=\"data.form.shareTime\" type=\"datetime\" placeholder=\"交换时间\" format=\"YYYY-MM-DD HH:mm:ss\" value-format=\"YYYY-MM-DD HH:mm:ss\" \u002F>\n          \u003C\u002Fel-form-item>\n        \u003C\u002Fdiv>\n        \u003Cdiv v-if=\"data.form.status === '拒绝'\">\n          \u003Cel-form-item label=\"拒绝理由\" prop=\"reason\">\n            \u003Cel-input placeholder=\"请输入拒绝理由\" v-model=\"data.form.reason\" autocomplete=\"off\" \u002F>\n          \u003C\u002Fel-form-item>\n        \u003C\u002Fdiv>\n      \u003C\u002Fel-form>\n      \u003Ctemplate #footer>\n      \u003Cspan class=\"dialog-footer\">\n        \u003Cel-button @click=\"data.formVisible = false\">取 消\u003C\u002Fel-button>\n        \u003Cel-button type=\"primary\" @click=\"save\">保 存\u003C\u002Fel-button>\n      \u003C\u002Fspan>\n      \u003C\u002Ftemplate>\n    \u003C\u002Fel-dialog>\n\n  \u003C\u002Fdiv>\n\u003C\u002Ftemplate>\n\n\u003Cscript setup>\nimport request from \"@\u002Futils\u002Frequest\";\nimport {reactive, ref} from \"vue\";\nimport {ElMessageBox, ElMessage} from \"element-plus\";\n\nconst formRef = ref()\nconst data = reactive({\n  user: JSON.parse(localStorage.getItem('system-user') || '{}'),\n  pageNum: 1,\n  pageSize: 10,\n  total: 0,\n  formVisible: false,\n  form: {},\n  tableData: [],\n  itemName: null,\n  rules: {\n    status: [\n      { required: true, message: '请选择审核状态', trigger: 'change' }\n    ],\n    location: [\n      { required: true, message: '请输入交换地点', trigger: 'blur' }\n    ],\n    shareTime: [\n      { required: true, message: '请输入交换时间', trigger: 'change' }\n    ],\n    reason: [\n      { required: true, message: '请输入拒绝理由', trigger: 'blur' }\n    ],\n  }\n})\n\n\u002F\u002F 分页查询\nconst load = () => {\n  request.get('\u002Fcharge\u002FselectPage', {\n    params: {\n      pageNum: data.pageNum,\n      pageSize: data.pageSize,\n      itemName: data.itemName,\n      itemUserid: data.user.id\n    }\n  }).then(res => {\n    data.tableData = res.data?.list\n    data.total = res.data?.total\n  })\n}\n\n\u002F\u002F 新增\nconst handleAdd = () => {\n  data.form = {}\n  data.formVisible = true\n}\n\n\u002F\u002F 编辑\nconst handleEdit = (row) => {\n  data.form = JSON.parse(JSON.stringify(row))\n  data.formVisible = true\n}\n\n\u002F\u002F 新增保存\nconst add = () => {\n  request.post('\u002Fcharge\u002Fadd', data.form).then(res => {\n    if (res.code === '200') {\n      load()\n      ElMessage.success('操作成功')\n      data.formVisible = false\n    } else {\n      ElMessage.error(res.msg)\n    }\n  })\n}\n\n\u002F\u002F 编辑保存\nconst update = () => {\n  request.put('\u002Fcharge\u002Fupdate', data.form).then(res => {\n    if (res.code === '200') {\n      load()\n      ElMessage.success('操作成功')\n      data.formVisible = false\n    } else {\n      ElMessage.error(res.msg)\n    }\n  })\n}\n\n\u002F\u002F 弹窗保存\nconst save = () => {\n  formRef.value.validate(valid => {\n    if (valid) {\n      \u002F\u002F data.form有id就是更新，没有就是新增\n      data.form.id ? update() : add()\n    }\n  })\n}\n\n\u002F\u002F 删除\nconst handleDelete = (id) => {\n  ElMessageBox.confirm('删除后数据无法恢复，您确定删除吗?', '删除确认', { type: 'warning' }).then(res => {\n    request.delete('\u002Fcharge\u002Fdelete\u002F' + id).then(res => {\n      if (res.code === '200') {\n        load()\n        ElMessage.success('操作成功')\n      } else {\n        ElMessage.error(res.msg)\n      }\n    })\n  }).catch(err => {})\n}\n\n\u002F\u002F 重置\nconst reset = () => {\n  data.title = null\n  load()\n}\n\nload()\n\u003C\u002Fscript>\n\n\u003Cstyle scoped>\n:deep(.el-tag--warning) {\n  color: #ff5900;\n}\n\u003C\u002Fstyle>\n```\n\n### ItemsView.vue\n\n```vue\n\u003Ctemplate>\n  \u003Cdiv>\n    \u003Cdiv class=\"card\" style=\"margin-bottom: 10px\">\n      \u003Cel-button @click=\"changeCategoryItem(null)\" :type=\"data.categoryId === null ? 'primary' : 'default'\">全部\u003C\u002Fel-button>\n      \u003Cel-button @click=\"changeCategoryItem(item.id)\" :type=\"data.categoryId === item.id ? 'primary' : 'default'\" v-for=\"item in data.categoryList\" :key=\"item.id\">{{ item.name }}\u003C\u002Fel-button>\n    \u003C\u002Fdiv>\n\n    \u003Cdiv v-if=\"data.total > 0\">\n      \u003Cel-row :gutter=\"10\">\n       \u003Cel-col :span=\"6\" v-for=\"item in data.tableData\" :key=\"item.id\">\n         \u003Cdiv class=\"card\" style=\"padding: 0\">\n           \u003Cimg :src=\"item.img\" alt=\"\" style=\"width: 100%; height:350px; display: block; border-radius: 5px 5px 0 0\">\n           \u003Cdiv style=\"padding: 10px\">\n             \u003Cdiv style=\"margin: 10px 0; font-size: 20px; font-weight: 400\">物品：{{ item.name }}\u003C\u002Fdiv>\n             \u003Cdiv class=\"ellipsis2\" style=\"margin: 10px 0; text-align: justify; color: #666;\" >\u003Cspan style=\"color: #333\">描述信息：\u003C\u002Fspan>{{ item.description }}\u003C\u002Fdiv>\n             \u003Cdiv class=\"ellipsis2\" style=\"margin: 10px 0; text-align: justify; color: #666;\" >\u003Cspan style=\"color: #333\">交换条件：\u003C\u002Fspan>{{ item.requirement }}\u003C\u002Fdiv>\n             \u003Cdiv style=\"margin: 10px 0; display: flex; color: #666\">\n               \u003Cdiv style=\"flex: 1\">\u003Cspan style=\"color: #333\">上传人：\u003C\u002Fspan>{{item.userName}}\u003C\u002Fdiv>\n               \u003Cdiv>\u003Cspan style=\"color: #333\">上传时间：\u003C\u002Fspan>{{ item.time }}\u003C\u002Fdiv>\n             \u003C\u002Fdiv>\n             \u003Cdiv style=\"text-align: right\">\n               \u003Cel-button @click=\"handleCharge(item)\" type=\"primary\" :disabled=\"item.userId === data.user.id\">申请交换\u003C\u002Fel-button>\n             \u003C\u002Fdiv>\n           \u003C\u002Fdiv>\n         \u003C\u002Fdiv>\n       \u003C\u002Fel-col>\n      \u003C\u002Fel-row>\n    \u003C\u002Fdiv>\n\n    \u003Cdiv v-else>\n      \u003Cdiv class=\"card\" style=\"padding: 50px; display: flex; justify-content: center; align-items: center; font-size: 20px; color: #666\">暂无物品...\u003C\u002Fdiv>\n    \u003C\u002Fdiv>\n\n    \u003Cel-dialog title=\"申请信息\" width=\"40%\" v-model=\"data.formVisible\" :close-on-click-modal=\"false\" destroy-on-close>\n      \u003Cel-form ref=\"formRef\" :model=\"data.form\" :rules=\"data.rules\" label-width=\"100px\" style=\"padding-right: 50px\">\n        \u003Cdiv style=\"padding-left: 30px; margin-bottom: 20px; color: #1890ff\">当前申请交换：\u003Cb>{{ data.form.itemName }}\u003C\u002Fb>\u003C\u002Fdiv>\n        \u003Cel-form-item label=\"交换物品\" prop=\"content\">\n          \u003Cel-input placeholder=\"请输入您提供的交换物品\" v-model=\"data.form.content\" autocomplete=\"off\" \u002F>\n        \u003C\u002Fel-form-item>\n        \u003Cel-form-item label=\"交换理由\" prop=\"remark\">\n          \u003Cel-input type=\"textarea\" :rows=\"3\" maxlength=\"200\" placeholder=\"请输入交换理由\" v-model=\"data.form.remark\" autocomplete=\"off\" \u002F>\n        \u003C\u002Fel-form-item>\n      \u003C\u002Fel-form>\n      \u003Ctemplate #footer>\n      \u003Cspan class=\"dialog-footer\">\n        \u003Cel-button @click=\"data.formVisible = false\">取 消\u003C\u002Fel-button>\n        \u003Cel-button type=\"primary\" @click=\"saveCharge\">保 存\u003C\u002Fel-button>\n      \u003C\u002Fspan>\n      \u003C\u002Ftemplate>\n    \u003C\u002Fel-dialog>\n\n  \u003C\u002Fdiv>\n\u003C\u002Ftemplate>\n\n\u003Cscript setup>\nimport { reactive, ref } from \"vue\";\nimport request from \"@\u002Futils\u002Frequest\";\nimport {ElMessage} from \"element-plus\";\n\nconst formRef = ref()\nconst data = reactive({\n  user: JSON.parse(localStorage.getItem('system-user') || '{}'),\n  categoryList: [],\n  categoryId: null,  \u002F\u002F 当前选中的分类ID\n  pageNum: 1,\n  pageSize: 10,\n  total: 0,\n  tableData: [],\n  form: {},\n  rules: {\n    content: [\n      { required: true, message: '请输入交换物品', trigger: 'blur' }\n    ],\n  }\n})\n\nconst handleCharge = (item) => {\n  data.formVisible = true\n  data.form = { itemName: item.name, itemId: item.id, itemUserid: item.userId }\n}\n\nconst saveCharge = () => {\n  formRef.value.validate(valid => {\n    if (valid) {\n      data.form.userId = data.user.id\n      request.post('\u002Fcharge\u002Fadd', data.form).then(res => {\n        if (res.code === '200') {\n          load()\n          ElMessage.success('操作成功')\n          data.formVisible = false\n        } else {\n          ElMessage.error(res.msg)\n        }\n      })\n    }\n  })\n}\n\n\u002F\u002F 查询分类数据\nrequest.get('\u002Fcategory\u002FselectAll').then(res => {\n  data.categoryList = res.data\n})\n\nconst changeCategoryItem = (categoryId) => {\n  data.categoryId = categoryId\n  load()\n}\n\n\u002F\u002F 分页查询\nconst load = () => {\n  request.get('\u002Fitems\u002FselectPage', {\n    params: {\n      pageNum: data.pageNum,\n      pageSize: data.pageSize,\n      status: true,\n      checkStatus: '通过',\n      categoryId: data.categoryId\n    }\n  }).then(res => {\n    if (res.code === '500') {\n      ElMessage.error(res.msg)\n      return\n    }\n    data.tableData = res.data?.list\n    data.total = res.data?.total\n  })\n}\nload()\n\u003C\u002Fscript>\n\n\u003Cstyle>\n.ellipsis2 {\n  word-break: break-all;\n  text-overflow: ellipsis;\n  display: -webkit-box;\n  -webkit-box-orient: vertical;\n  -webkit-line-clamp: 1; \u002F* 超出几行省略 *\u002F\n  overflow: hidden;\n}\n\u003C\u002Fstyle>\n```\n\n","coding",1,322,2196,"2025-12-19 16:16:03","2026-05-03 22:49:02","基于SpringBoot3+Vue3的校园物品分享系统","campus-item-sharing",{"project":18,"items":19},{"id":6,"title":15,"slug":16},[20,27,34,41,48,56,63,70,77,78,85,92,99],{"id":21,"uuid":22,"project_id":6,"title":23,"type":9,"status":10,"public_enabled":10,"views":24,"sort":25,"created_at":26,"updated_at":14,"project_title":15,"project_slug":16},1085,"bKvz3GMB","01. 校园物品分享系统介绍",1584,2118,"2026-04-01 22:12:21",{"id":28,"uuid":29,"project_id":6,"title":30,"type":9,"status":10,"public_enabled":10,"views":31,"sort":32,"created_at":33,"updated_at":14,"project_title":15,"project_slug":16},1086,"G7CRiFiL","02. 导入并运行项目脚手架",670,2119,"2025-12-09 16:59:49",{"id":35,"uuid":36,"project_id":6,"title":37,"type":9,"status":10,"public_enabled":10,"views":38,"sort":39,"created_at":40,"updated_at":14,"project_title":15,"project_slug":16},1087,"pgDLuOpz","03. 开发普通用户信息管理功能",544,2121,"2025-12-09 16:59:38",{"id":42,"uuid":43,"project_id":6,"title":44,"type":9,"status":10,"public_enabled":10,"views":45,"sort":46,"created_at":47,"updated_at":14,"project_title":15,"project_slug":16},1090,"2l7FVzgx","04. 开发普通用户登录、注册、个人信息、修改密码功能",365,2131,"2025-12-10 16:11:48",{"id":49,"uuid":50,"project_id":6,"title":51,"type":9,"status":10,"public_enabled":10,"views":52,"sort":53,"created_at":54,"updated_at":55,"project_title":15,"project_slug":16},1091,"l5SB4JYK","05. 开发系统公告管理功能",417,2132,"2025-12-10 16:12:08","2026-05-07 15:36:12.649662+00",{"id":57,"uuid":58,"project_id":6,"title":59,"type":9,"status":10,"public_enabled":10,"views":60,"sort":61,"created_at":62,"updated_at":14,"project_title":15,"project_slug":16},1098,"mXLOXdBC","06. 开发物品分类信息管理功能",297,2143,"2025-12-11 16:37:57",{"id":64,"uuid":65,"project_id":6,"title":66,"type":9,"status":10,"public_enabled":10,"views":67,"sort":68,"created_at":69,"updated_at":14,"project_title":15,"project_slug":16},1099,"nj87VT4L","07. 开发物品信息管理功能",406,2144,"2025-12-11 16:38:16",{"id":71,"uuid":72,"project_id":6,"title":73,"type":9,"status":10,"public_enabled":10,"views":74,"sort":75,"created_at":76,"updated_at":14,"project_title":15,"project_slug":16},1107,"nGHKfpf4","08. 开发用户端物品展示功能",329,2162,"2025-12-15 17:27:07",{"id":4,"uuid":5,"project_id":6,"title":7,"type":9,"status":10,"public_enabled":10,"views":11,"sort":12,"created_at":13,"updated_at":14,"project_title":15,"project_slug":16},{"id":79,"uuid":80,"project_id":6,"title":81,"type":9,"status":10,"public_enabled":10,"views":82,"sort":83,"created_at":84,"updated_at":14,"project_title":15,"project_slug":16},1135,"s5I1gomY","10. 开发物品收藏功能",285,2223,"2025-12-23 17:38:15",{"id":86,"uuid":87,"project_id":6,"title":88,"type":9,"status":10,"public_enabled":10,"views":89,"sort":90,"created_at":91,"updated_at":14,"project_title":15,"project_slug":16},1159,"qadunvVA","11. 开发论坛帖子管理功能",263,2266,"2025-12-30 16:08:47",{"id":93,"uuid":94,"project_id":6,"title":95,"type":9,"status":10,"public_enabled":10,"views":96,"sort":97,"created_at":98,"updated_at":14,"project_title":15,"project_slug":16},1202,"CpPqHdiT","12. 开发论坛帖子展示功能",220,2339,"2026-01-19 17:04:21",{"id":100,"uuid":101,"project_id":6,"title":102,"type":9,"status":10,"public_enabled":10,"views":103,"sort":104,"created_at":105,"updated_at":14,"project_title":15,"project_slug":16},1203,"7YABYvbd","13. 开发论坛帖子点赞和评论功能",239,2340,"2026-01-19 17:04:37"]