林小张 2 mesi fa
parent
commit
5b0e224e4b

+ 164 - 0
ruoyi-modules/ruoyi-customer/src/main/java/org/dromara/customer/pc/controller/PcAddressController.java

@@ -0,0 +1,164 @@
+package org.dromara.customer.pc.controller;
+
+import java.util.List;
+
+import lombok.RequiredArgsConstructor;
+import jakarta.validation.constraints.*;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.log.annotation.Log;
+import org.dromara.common.log.enums.BusinessType;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.satoken.utils.LoginHelper;
+import org.dromara.common.web.core.BaseController;
+import org.dromara.customer.domain.bo.CustomerShippingAddressBo;
+import org.dromara.customer.domain.vo.CustomerShippingAddressVo;
+import org.dromara.customer.service.ICustomerShippingAddressService;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+import org.dromara.common.core.validate.AddGroup;
+import org.dromara.common.core.validate.EditGroup;
+import org.dromara.common.idempotent.annotation.RepeatSubmit;
+
+/**
+ * PC端 - 收货地址管理
+ * 前端访问路由地址为:/pc/enterprise/address
+ *
+ * @author Claude
+ * @date 2026-01-27
+ */
+@Validated
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/pc/enterprise/address")
+public class PcAddressController extends BaseController {
+
+    private final ICustomerShippingAddressService customerShippingAddressService;
+
+    /**
+     * 查询当前企业的收货地址列表
+     * PC端用户只能查询自己企业的地址
+     */
+    @GetMapping("/list")
+    public TableDataInfo<CustomerShippingAddressVo> list(CustomerShippingAddressBo bo, PageQuery pageQuery) {
+        // 获取当前登录用户的企业ID
+        Long customerId = LoginHelper.getUserId();
+        // 强制设置企业ID,防止越权访问
+        bo.setCustomerId(customerId);
+
+        return customerShippingAddressService.queryPageList(bo, pageQuery);
+    }
+
+    /**
+     * 获取收货地址详细信息
+     * PC端用户只能查询自己企业的地址
+     *
+     * @param id 主键
+     */
+    @GetMapping("/{id}")
+    public R<CustomerShippingAddressVo> getInfo(@NotNull(message = "主键不能为空")
+                                                @PathVariable("id") Long id) {
+        // 查询地址信息
+        CustomerShippingAddressVo vo = customerShippingAddressService.queryById(id);
+
+        // 验证地址是否属于当前用户的企业
+        if (vo != null) {
+            Long customerId = LoginHelper.getUserId();
+            if (!customerId.equals(vo.getCustomerId())) {
+                return R.fail("无权访问该地址");
+            }
+        }
+
+        return R.ok(vo);
+    }
+
+    /**
+     * 新增收货地址
+     */
+    @Log(title = "PC端-收货地址", businessType = BusinessType.INSERT)
+    @RepeatSubmit()
+    @PostMapping()
+    public R<Void> add(@Validated(AddGroup.class) @RequestBody CustomerShippingAddressBo bo) {
+        // 获取当前登录用户的企业ID
+        Long customerId = LoginHelper.getUserId();
+        // 强制设置企业ID,防止为其他企业添加地址
+        bo.setCustomerId(customerId);
+
+        return toAjax(customerShippingAddressService.insertByBo(bo));
+    }
+
+    /**
+     * 修改收货地址
+     */
+    @Log(title = "PC端-收货地址", businessType = BusinessType.UPDATE)
+    @RepeatSubmit()
+    @PutMapping()
+    public R<Void> edit(@Validated(EditGroup.class) @RequestBody CustomerShippingAddressBo bo) {
+        // 获取当前登录用户的企业ID
+        Long customerId = LoginHelper.getUserId();
+
+        // 验证地址是否属于当前用户的企业
+        CustomerShippingAddressVo existingAddress = customerShippingAddressService.queryById(bo.getId());
+        if (existingAddress == null) {
+            return R.fail("地址不存在");
+        }
+        if (!customerId.equals(existingAddress.getCustomerId())) {
+            return R.fail("无权修改该地址");
+        }
+
+        // 强制设置企业ID
+        bo.setCustomerId(customerId);
+
+        return toAjax(customerShippingAddressService.updateByBo(bo));
+    }
+
+    /**
+     * 删除收货地址
+     *
+     * @param ids 主键串
+     */
+    @Log(title = "PC端-收货地址", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{ids}")
+    public R<Void> remove(@NotEmpty(message = "主键不能为空")
+                          @PathVariable("ids") Long[] ids) {
+        // 获取当前登录用户的企业ID
+        Long customerId = LoginHelper.getUserId();
+
+        // 验证所有地址是否都属于当前用户的企业
+        for (Long id : ids) {
+            CustomerShippingAddressVo address = customerShippingAddressService.queryById(id);
+            if (address == null) {
+                return R.fail("地址ID " + id + " 不存在");
+            }
+            if (!customerId.equals(address.getCustomerId())) {
+                return R.fail("无权删除地址ID " + id);
+            }
+        }
+
+        return toAjax(customerShippingAddressService.deleteWithValidByIds(List.of(ids), true));
+    }
+
+    /**
+     * 设置默认地址
+     */
+    @Log(title = "PC端-收货地址", businessType = BusinessType.UPDATE)
+    @PutMapping("/default")
+    public R<Void> changeDefaultAddress(@RequestBody CustomerShippingAddressBo bo) {
+        // 获取当前登录用户的企业ID
+        Long customerId = LoginHelper.getUserId();
+
+        // 验证地址是否属于当前用户的企业
+        CustomerShippingAddressVo address = customerShippingAddressService.queryById(bo.getId());
+        if (address == null) {
+            return R.fail("地址不存在");
+        }
+        if (!customerId.equals(address.getCustomerId())) {
+            return R.fail("无权设置该地址为默认");
+        }
+
+        // 强制设置企业ID
+        bo.setCustomerId(customerId);
+
+        return toAjax(customerShippingAddressService.changeDefaultAddress(bo));
+    }
+}

+ 164 - 0
ruoyi-modules/ruoyi-customer/src/main/java/org/dromara/customer/pc/controller/PcContactController.java

@@ -0,0 +1,164 @@
+package org.dromara.customer.pc.controller;
+
+import java.util.List;
+
+import cn.dev33.satoken.annotation.SaIgnore;
+import lombok.RequiredArgsConstructor;
+import jakarta.validation.constraints.*;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.log.annotation.Log;
+import org.dromara.common.log.enums.BusinessType;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.satoken.utils.LoginHelper;
+import org.dromara.common.web.core.BaseController;
+import org.dromara.customer.domain.bo.CustomerContactBo;
+import org.dromara.customer.domain.vo.CustomerContactVo;
+import org.dromara.customer.service.ICustomerContactService;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+import org.dromara.common.core.validate.AddGroup;
+import org.dromara.common.core.validate.EditGroup;
+import org.dromara.common.idempotent.annotation.RepeatSubmit;
+
+/**
+ * PC端 - 人员管理
+ * 前端访问路由地址为:/pc/organization/contact
+ *
+ * @author Claude
+ * @date 2026-01-27
+ */
+@SaIgnore
+@Validated
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/pc/organization/contact")
+public class PcContactController extends BaseController {
+
+    private final ICustomerContactService customerContactService;
+
+    /**
+     * 获取当前登录用户的个人信息
+     */
+    @GetMapping("/current")
+    public R<CustomerContactVo> getCurrentUserInfo() {
+        // TODO: 需要根据当前登录用户的实际ID查询联系人信息
+        // 目前LoginHelper.getUserId()返回的是customerId(企业ID)
+        // 需要通过其他方式(如手机号、用户名)来查询当前用户的联系人记录
+        Long customerId = LoginHelper.getUserId();
+
+        // 查询该企业下的联系人(不限制是否为主联系人)
+        CustomerContactBo bo = new CustomerContactBo();
+        bo.setCustomerId(customerId);
+
+        List<CustomerContactVo> list = customerContactService.queryList(bo);
+        if (list != null && !list.isEmpty()) {
+            return R.ok(list.get(0));
+        }
+
+        return R.fail("未找到当前用户信息,customerId: " + customerId);
+    }
+
+    /**
+     * 查询当前企业的联系人列表
+     * PC端用户只能查询自己企业的联系人
+     */
+    @GetMapping("/list")
+    public TableDataInfo<CustomerContactVo> list(CustomerContactBo bo, PageQuery pageQuery) {
+        // 获取当前登录用户的企业ID
+        Long customerId = LoginHelper.getUserId();
+        // 强制设置企业ID,防止越权访问
+        bo.setCustomerId(customerId);
+
+        return customerContactService.queryPageList(bo, pageQuery);
+    }
+
+    /**
+     * 获取联系人详细信息
+     * PC端用户只能查询自己企业的联系人
+     *
+     * @param id 主键
+     */
+    @GetMapping("/{id:[0-9]+}")
+    public R<CustomerContactVo> getInfo(@NotNull(message = "主键不能为空")
+                                        @PathVariable("id") Long id) {
+        // 查询联系人信息
+        CustomerContactVo vo = customerContactService.queryById(id);
+
+        // 验证联系人是否属于当前用户的企业
+        if (vo != null) {
+            Long customerId = LoginHelper.getUserId();
+            if (!customerId.equals(vo.getCustomerId())) {
+                return R.fail("无权访问该联系人");
+            }
+        }
+
+        return R.ok(vo);
+    }
+
+    /**
+     * 新增联系人
+     */
+    @Log(title = "PC端-人员管理", businessType = BusinessType.INSERT)
+    @RepeatSubmit()
+    @PostMapping()
+    public R<Void> add(@Validated(AddGroup.class) @RequestBody CustomerContactBo bo) {
+        // 获取当前登录用户的企业ID
+        Long customerId = LoginHelper.getUserId();
+        // 强制设置企业ID,防止为其他企业添加联系人
+        bo.setCustomerId(customerId);
+
+        return toAjax(customerContactService.insertByBo(bo));
+    }
+
+    /**
+     * 修改联系人
+     */
+    @Log(title = "PC端-人员管理", businessType = BusinessType.UPDATE)
+    @RepeatSubmit()
+    @PutMapping()
+    public R<Void> edit(@Validated(EditGroup.class) @RequestBody CustomerContactBo bo) {
+        // 获取当前登录用户的企业ID
+        Long customerId = LoginHelper.getUserId();
+
+        // 验证联系人是否属于当前用户的企业
+        CustomerContactVo existingContact = customerContactService.queryById(bo.getId());
+        if (existingContact == null) {
+            return R.fail("联系人不存在");
+        }
+        if (!customerId.equals(existingContact.getCustomerId())) {
+            return R.fail("无权修改该联系人");
+        }
+
+        // 强制设置企业ID
+        bo.setCustomerId(customerId);
+
+        return toAjax(customerContactService.updateByBo(bo));
+    }
+
+    /**
+     * 删除联系人
+     *
+     * @param ids 主键串
+     */
+    @Log(title = "PC端-人员管理", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{ids}")
+    public R<Void> remove(@NotEmpty(message = "主键不能为空")
+                          @PathVariable("ids") Long[] ids) {
+        // 获取当前登录用户的企业ID
+        Long customerId = LoginHelper.getUserId();
+
+        // 验证所有联系人是否都属于当前用户的企业
+        for (Long id : ids) {
+            CustomerContactVo contact = customerContactService.queryById(id);
+            if (contact == null) {
+                return R.fail("联系人ID " + id + " 不存在");
+            }
+            if (!customerId.equals(contact.getCustomerId())) {
+                return R.fail("无权删除联系人ID " + id);
+            }
+        }
+
+        return toAjax(customerContactService.deleteWithValidByIds(List.of(ids), true));
+    }
+}

+ 155 - 0
ruoyi-modules/ruoyi-customer/src/main/java/org/dromara/customer/pc/controller/PcDeptController.java

@@ -0,0 +1,155 @@
+package org.dromara.customer.pc.controller;
+
+import java.util.List;
+
+import cn.dev33.satoken.annotation.SaIgnore;
+import lombok.RequiredArgsConstructor;
+import jakarta.validation.constraints.*;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.log.annotation.Log;
+import org.dromara.common.log.enums.BusinessType;
+import org.dromara.common.satoken.utils.LoginHelper;
+import org.dromara.common.web.core.BaseController;
+import org.dromara.customer.domain.bo.CustomerDeptBo;
+import org.dromara.customer.domain.vo.CustomerDeptTreeVo;
+import org.dromara.customer.domain.vo.CustomerDeptVo;
+import org.dromara.customer.service.ICustomerDeptService;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+import org.dromara.common.core.validate.AddGroup;
+import org.dromara.common.core.validate.EditGroup;
+import org.dromara.common.idempotent.annotation.RepeatSubmit;
+
+/**
+ * PC端 - 部门管理
+ * 前端访问路由地址为:/pc/organization/dept
+ *
+ * @author Claude
+ * @date 2026-01-27
+ */
+@SaIgnore
+@Validated
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/pc/organization/dept")
+public class PcDeptController extends BaseController {
+
+    private final ICustomerDeptService customerDeptService;
+
+    /**
+     * 查询当前企业的部门树
+     * PC端用户只能查询自己企业的部门
+     */
+    @GetMapping("/tree")
+    public R<List<CustomerDeptTreeVo>> getDeptTree() {
+        // 获取当前登录用户的企业ID
+        Long customerId = LoginHelper.getUserId();
+
+        List<CustomerDeptTreeVo> tree = customerDeptService.getCustomerDeptTree(customerId);
+        return R.ok(tree);
+    }
+
+    /**
+     * 查询当前企业的部门列表
+     * PC端用户只能查询自己企业的部门
+     */
+    @GetMapping("/list")
+    public R<List<CustomerDeptVo>> list(CustomerDeptBo bo) {
+        // 获取当前登录用户的企业ID
+        Long customerId = LoginHelper.getUserId();
+        // 强制设置企业ID,防止越权访问
+        bo.setCustomerId(customerId);
+
+        List<CustomerDeptVo> list = customerDeptService.queryList(bo);
+        return R.ok(list);
+    }
+
+    /**
+     * 获取部门详细信息
+     * PC端用户只能查询自己企业的部门
+     *
+     * @param id 主键
+     */
+    @GetMapping("/{id}")
+    public R<CustomerDeptVo> getInfo(@NotNull(message = "主键不能为空")
+                                     @PathVariable("id") Long id) {
+        // 查询部门信息
+        CustomerDeptVo vo = customerDeptService.queryById(id);
+
+        // 验证部门是否属于当前用户的企业
+        if (vo != null) {
+            Long customerId = LoginHelper.getUserId();
+            if (!customerId.equals(vo.getCustomerId())) {
+                return R.fail("无权访问该部门");
+            }
+        }
+
+        return R.ok(vo);
+    }
+
+    /**
+     * 新增部门
+     */
+    @Log(title = "PC端-部门管理", businessType = BusinessType.INSERT)
+    @RepeatSubmit()
+    @PostMapping()
+    public R<Void> add(@Validated(AddGroup.class) @RequestBody CustomerDeptBo bo) {
+        // 获取当前登录用户的企业ID
+        Long customerId = LoginHelper.getUserId();
+        // 强制设置企业ID,防止为其他企业添加部门
+        bo.setCustomerId(customerId);
+
+        return toAjax(customerDeptService.insertByBo(bo));
+    }
+
+    /**
+     * 修改部门
+     */
+    @Log(title = "PC端-部门管理", businessType = BusinessType.UPDATE)
+    @RepeatSubmit()
+    @PutMapping()
+    public R<Void> edit(@Validated(EditGroup.class) @RequestBody CustomerDeptBo bo) {
+        // 获取当前登录用户的企业ID
+        Long customerId = LoginHelper.getUserId();
+
+        // 验证部门是否属于当前用户的企业
+        CustomerDeptVo existingDept = customerDeptService.queryById(bo.getDeptId());
+        if (existingDept == null) {
+            return R.fail("部门不存在");
+        }
+        if (!customerId.equals(existingDept.getCustomerId())) {
+            return R.fail("无权修改该部门");
+        }
+
+        // 强制设置企业ID
+        bo.setCustomerId(customerId);
+
+        return toAjax(customerDeptService.updateByBo(bo));
+    }
+
+    /**
+     * 删除部门
+     *
+     * @param ids 主键串
+     */
+    @Log(title = "PC端-部门管理", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{ids}")
+    public R<Void> remove(@NotEmpty(message = "主键不能为空")
+                          @PathVariable("ids") Long[] ids) {
+        // 获取当前登录用户的企业ID
+        Long customerId = LoginHelper.getUserId();
+
+        // 验证所有部门是否都属于当前用户的企业
+        for (Long id : ids) {
+            CustomerDeptVo dept = customerDeptService.queryById(id);
+            if (dept == null) {
+                return R.fail("部门ID " + id + " 不存在");
+            }
+            if (!customerId.equals(dept.getCustomerId())) {
+                return R.fail("无权删除部门ID " + id);
+            }
+        }
+
+        return toAjax(customerDeptService.deleteWithValidByIds(List.of(ids), true));
+    }
+}

+ 72 - 0
ruoyi-modules/ruoyi-customer/src/main/java/org/dromara/customer/pc/controller/PcEnterpriseController.java

@@ -0,0 +1,72 @@
+package org.dromara.customer.pc.controller;
+
+import lombok.RequiredArgsConstructor;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.log.annotation.Log;
+import org.dromara.common.log.enums.BusinessType;
+import org.dromara.common.satoken.utils.LoginHelper;
+import org.dromara.common.web.core.BaseController;
+import org.dromara.customer.domain.bo.CustomerInfoBo;
+import org.dromara.customer.domain.vo.CustomerInfoVo;
+import org.dromara.customer.service.ICustomerInfoService;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+/**
+ * PC端 - 企业信息管理
+ * 前端访问路由地址为:/pc/enterprise
+ *
+ * @author Claude
+ * @date 2026-01-27
+ */
+@Validated
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/pc/enterprise")
+public class PcEnterpriseController extends BaseController {
+
+    private final ICustomerInfoService customerInfoService;
+
+    /**
+     * 查询当前企业信息
+     * PC端用户只能查询自己所属企业的信息
+     */
+    @GetMapping("/info")
+    public R<CustomerInfoVo> getInfo() {
+        // 获取当前登录用户的企业ID
+        Long customerId = LoginHelper.getUserId();
+        if (customerId == null) {
+            return R.fail("用户未登录或企业信息不存在");
+        }
+
+        // 查询企业信息
+        CustomerInfoVo vo = customerInfoService.queryById(customerId);
+        if (vo == null) {
+            return R.fail("企业信息不存在");
+        }
+
+        return R.ok(vo);
+    }
+
+    /**
+     * 修改当前企业信息
+     * PC端用户只能修改自己所属企业的信息
+     */
+    @Log(title = "PC端-企业信息", businessType = BusinessType.UPDATE)
+    @PutMapping("/info")
+    public R<Void> updateInfo(@Validated @RequestBody CustomerInfoBo bo) {
+        // 获取当前登录用户的企业ID
+        Long customerId = LoginHelper.getUserId();
+        if (customerId == null) {
+            return R.fail("用户未登录或企业信息不存在");
+        }
+
+        // 强制设置企业ID,防止越权修改其他企业信息
+        bo.setId(customerId);
+
+        // 调用Service更新企业信息
+        boolean result = customerInfoService.updateByBo(bo);
+        return toAjax(result);
+    }
+}

+ 140 - 0
ruoyi-modules/ruoyi-customer/src/main/java/org/dromara/customer/pc/controller/PcInvoiceController.java

@@ -0,0 +1,140 @@
+package org.dromara.customer.pc.controller;
+
+import java.util.List;
+
+import lombok.RequiredArgsConstructor;
+import jakarta.validation.constraints.*;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.log.annotation.Log;
+import org.dromara.common.log.enums.BusinessType;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.satoken.utils.LoginHelper;
+import org.dromara.common.web.core.BaseController;
+import org.dromara.customer.domain.bo.CustomerInvoiceInfoBo;
+import org.dromara.customer.domain.vo.CustomerInvoiceInfoVo;
+import org.dromara.customer.service.ICustomerInvoiceInfoService;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+import org.dromara.common.core.validate.AddGroup;
+import org.dromara.common.core.validate.EditGroup;
+import org.dromara.common.idempotent.annotation.RepeatSubmit;
+
+/**
+ * PC端 - 发票信息管理
+ * 前端访问路由地址为:/pc/enterprise/invoice
+ *
+ * @author Claude
+ * @date 2026-01-27
+ */
+@Validated
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/pc/enterprise/invoice")
+public class PcInvoiceController extends BaseController {
+
+    private final ICustomerInvoiceInfoService customerInvoiceInfoService;
+
+    /**
+     * 查询当前企业的发票信息列表
+     * PC端用户只能查询自己企业的发票
+     */
+    @GetMapping("/list")
+    public TableDataInfo<CustomerInvoiceInfoVo> list(CustomerInvoiceInfoBo bo, PageQuery pageQuery) {
+        // 获取当前登录用户的企业ID
+        Long customerId = LoginHelper.getUserId();
+        // 强制设置企业ID,防止越权访问
+        bo.setCustomerId(customerId);
+
+        return customerInvoiceInfoService.queryPageList(bo, pageQuery);
+    }
+
+    /**
+     * 获取发票信息详细信息
+     * PC端用户只能查询自己企业的发票
+     *
+     * @param id 主键
+     */
+    @GetMapping("/{id}")
+    public R<CustomerInvoiceInfoVo> getInfo(@NotNull(message = "主键不能为空")
+                                            @PathVariable("id") Long id) {
+        // 查询发票信息
+        CustomerInvoiceInfoVo vo = customerInvoiceInfoService.queryById(id);
+
+        // 验证发票是否属于当前用户的企业
+        if (vo != null) {
+            Long customerId = LoginHelper.getUserId();
+            if (!customerId.equals(vo.getCustomerId())) {
+                return R.fail("无权访问该发票信息");
+            }
+        }
+
+        return R.ok(vo);
+    }
+
+    /**
+     * 新增发票信息
+     */
+    @Log(title = "PC端-发票信息", businessType = BusinessType.INSERT)
+    @RepeatSubmit()
+    @PostMapping()
+    public R<Void> add(@Validated(AddGroup.class) @RequestBody CustomerInvoiceInfoBo bo) {
+        // 获取当前登录用户的企业ID
+        Long customerId = LoginHelper.getUserId();
+        // 强制设置企业ID,防止为其他企业添加发票
+        bo.setCustomerId(customerId);
+
+        return toAjax(customerInvoiceInfoService.insertByBo(bo));
+    }
+
+    /**
+     * 修改发票信息
+     */
+    @Log(title = "PC端-发票信息", businessType = BusinessType.UPDATE)
+    @RepeatSubmit()
+    @PutMapping()
+    public R<Void> edit(@Validated(EditGroup.class) @RequestBody CustomerInvoiceInfoBo bo) {
+        // 获取当前登录用户的企业ID
+        Long customerId = LoginHelper.getUserId();
+
+        // 验证发票是否属于当前用户的企业
+        CustomerInvoiceInfoVo existingInvoice = customerInvoiceInfoService.queryById(bo.getId());
+        if (existingInvoice == null) {
+            return R.fail("发票信息不存在");
+        }
+        if (!customerId.equals(existingInvoice.getCustomerId())) {
+            return R.fail("无权修改该发票信息");
+        }
+
+        // 强制设置企业ID
+        bo.setCustomerId(customerId);
+
+        return toAjax(customerInvoiceInfoService.updateByBo(bo));
+    }
+
+    /**
+     * 删除发票信息
+     *
+     * @param ids 主键串
+     */
+    @Log(title = "PC端-发票信息", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{ids}")
+    public R<Void> remove(@NotEmpty(message = "主键不能为空")
+                          @PathVariable("ids") Long[] ids) {
+        // 获取当前登录用户的企业ID
+        Long customerId = LoginHelper.getUserId();
+
+        // 验证所有发票是否都属于当前用户的企业
+        for (Long id : ids) {
+            CustomerInvoiceInfoVo invoice = customerInvoiceInfoService.queryById(id);
+            if (invoice == null) {
+                return R.fail("发票信息ID " + id + " 不存在");
+            }
+            if (!customerId.equals(invoice.getCustomerId())) {
+                return R.fail("无权删除发票信息ID " + id);
+            }
+        }
+
+        return toAjax(customerInvoiceInfoService.deleteWithValidByIds(List.of(ids), true));
+    }
+}

+ 49 - 0
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/pc/controller/PcAnnouncementController.java

@@ -0,0 +1,49 @@
+package org.dromara.system.pc.controller;
+
+import lombok.RequiredArgsConstructor;
+import jakarta.validation.constraints.NotNull;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.web.core.BaseController;
+import org.dromara.system.domain.bo.SysAnnouncementBo;
+import org.dromara.system.domain.vo.SysAnnouncementVo;
+import org.dromara.system.service.ISysAnnouncementService;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+/**
+ * PC端 - 平台公告查询
+ * 前端访问路由地址为:/pc/announcement
+ *
+ * @author Claude
+ * @date 2026-01-28
+ */
+@Validated
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/pc/announcement")
+public class PcAnnouncementController extends BaseController {
+
+    private final ISysAnnouncementService sysAnnouncementService;
+
+    /**
+     * 查询平台公告列表
+     * PC端用户可以查询所有已发布的公告
+     */
+    @GetMapping("/list")
+    public TableDataInfo<SysAnnouncementVo> list(SysAnnouncementBo bo, PageQuery pageQuery) {
+        return sysAnnouncementService.queryPageList(bo, pageQuery);
+    }
+
+    /**
+     * 获取平台公告详细信息
+     *
+     * @param id 主键
+     */
+    @GetMapping("/{id}")
+    public R<SysAnnouncementVo> getInfo(@NotNull(message = "主键不能为空")
+                                        @PathVariable("id") Long id) {
+        return R.ok(sysAnnouncementService.queryById(id));
+    }
+}

+ 44 - 0
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/pc/controller/PcDictController.java

@@ -0,0 +1,44 @@
+package org.dromara.system.pc.controller;
+
+import cn.hutool.core.util.ObjectUtil;
+import lombok.RequiredArgsConstructor;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.web.core.BaseController;
+import org.dromara.system.domain.vo.SysDictDataVo;
+import org.dromara.system.service.ISysDictTypeService;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * PC端 - 字典数据查询
+ * 前端访问路由地址为:/pc/dict
+ *
+ * @author Claude
+ * @date 2026-01-28
+ */
+@Validated
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/pc/dict")
+public class PcDictController extends BaseController {
+
+    private final ISysDictTypeService dictTypeService;
+
+    /**
+     * 根据字典类型查询字典数据信息
+     * PC端用户可以查询所有字典数据(字典数据是公共的)
+     *
+     * @param dictType 字典类型
+     */
+    @GetMapping("/type/{dictType}")
+    public R<List<SysDictDataVo>> getDictByType(@PathVariable String dictType) {
+        List<SysDictDataVo> data = dictTypeService.selectDictDataByType(dictType);
+        if (ObjectUtil.isNull(data)) {
+            data = new ArrayList<>();
+        }
+        return R.ok(data);
+    }
+}

+ 85 - 0
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/pc/controller/PcRoleController.java

@@ -0,0 +1,85 @@
+package org.dromara.system.pc.controller;
+
+import java.util.List;
+
+import cn.dev33.satoken.annotation.SaIgnore;
+import jakarta.validation.constraints.NotEmpty;
+import jakarta.validation.constraints.NotNull;
+import lombok.RequiredArgsConstructor;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.core.validate.AddGroup;
+import org.dromara.common.core.validate.EditGroup;
+import org.dromara.common.log.annotation.Log;
+import org.dromara.common.log.enums.BusinessType;
+import org.dromara.common.web.core.BaseController;
+import org.dromara.system.domain.bo.SysRoleBo;
+import org.dromara.system.domain.vo.SysRoleVo;
+import org.dromara.system.service.ISysRoleService;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+/**
+ * PC端 - 角色管理
+ * 前端访问路由地址为:/pc/organization/role
+ *
+ * @author Claude
+ * @date 2026-01-27
+ */
+@SaIgnore
+@Validated
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/pc/organization/role")
+public class PcRoleController extends BaseController {
+
+    private final ISysRoleService sysRoleService;
+
+    /**
+     * 查询当前租户的角色列表
+     * PC端用户只能查询自己租户的角色
+     */
+    @GetMapping("/list")
+    public R<List<SysRoleVo>> list(SysRoleBo bo) {
+        // 角色表通过tenantId自动过滤,无需手动设置
+        List<SysRoleVo> list = sysRoleService.selectRoleList(bo);
+        return R.ok(list);
+    }
+
+    /**
+     * 获取角色详细信息
+     */
+    @GetMapping("/{roleId}")
+    public R<SysRoleVo> getInfo(@NotNull(message = "角色ID不能为空") @PathVariable Long roleId) {
+        return R.ok(sysRoleService.selectRoleById(roleId));
+    }
+
+    /**
+     * 新增角色
+     */
+    @Log(title = "PC端-角色管理", businessType = BusinessType.INSERT)
+    @PostMapping
+    public R<Void> add(@Validated(AddGroup.class) @RequestBody SysRoleBo bo) {
+        sysRoleService.insertRole(bo);
+        return R.ok();
+    }
+
+    /**
+     * 修改角色
+     */
+    @Log(title = "PC端-角色管理", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public R<Void> edit(@Validated(EditGroup.class) @RequestBody SysRoleBo bo) {
+        sysRoleService.updateRole(bo);
+        return R.ok();
+    }
+
+    /**
+     * 删除角色
+     */
+    @Log(title = "PC端-角色管理", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{roleIds}")
+    public R<Void> remove(@NotEmpty(message = "角色ID不能为空") @PathVariable Long[] roleIds) {
+        sysRoleService.deleteRoleByIds(roleIds);
+        return R.ok();
+    }
+}