首页 > 其他分享 >开发一款小超市的进销存系统

开发一款小超市的进销存系统

时间:2024-11-30 23:30:10浏览次数:11  
标签:const 进销存 private 超市 public user java 一款 id

一、开发构思

1.开发一款小超市用的进销存系统,开发环境是Windows,包括销售、采购、仓库、系统等模块。
采用vue3+SpringBoot + MySql进行开发,完成后来布署在docker容器。
2、新建MySql数据库,数据库密码:*******,数据库名:JXC。

二、开发过程

1、基础的项目架构设计

1、首先创建MySQL数据库:

-- 创建数据库
CREATE DATABASE JXC DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;

-- 使用数据库
USE JXC;

2、主要数据表设计:

-- 用户表
CREATE TABLE sys_user (
    id BIGINT PRIMARY KEY AUTO_INCREMENT,
    username VARCHAR(50) NOT NULL UNIQUE,
    password VARCHAR(100) NOT NULL,
    real_name VARCHAR(50),
    phone VARCHAR(20),
    status TINYINT DEFAULT 1,
    create_time DATETIME DEFAULT CURRENT_TIMESTAMP,
    update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);

-- 商品表
CREATE TABLE product (
    id BIGINT PRIMARY KEY AUTO_INCREMENT,
    product_code VARCHAR(50) NOT NULL UNIQUE,
    product_name VARCHAR(100) NOT NULL,
    category_id BIGINT,
    unit VARCHAR(20),
    price DECIMAL(10,2),
    stock INT DEFAULT 0,
    status TINYINT DEFAULT 1,
    create_time DATETIME DEFAULT CURRENT_TIMESTAMP,
    update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);

-- 供应商表
CREATE TABLE supplier (
    id BIGINT PRIMARY KEY AUTO_INCREMENT,
    supplier_name VARCHAR(100) NOT NULL,
    contact_person VARCHAR(50),
    phone VARCHAR(20),
    address VARCHAR(200),
    status TINYINT DEFAULT 1,
    create_time DATETIME DEFAULT CURRENT_TIMESTAMP,
    update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);

-- 采购单表
CREATE TABLE purchase_order (
    id BIGINT PRIMARY KEY AUTO_INCREMENT,
    order_no VARCHAR(50) NOT NULL UNIQUE,
    supplier_id BIGINT,
    total_amount DECIMAL(10,2),
    status TINYINT DEFAULT 0,
    create_user_id BIGINT,
    create_time DATETIME DEFAULT CURRENT_TIMESTAMP,
    update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);

-- 采购单明细表
CREATE TABLE purchase_order_detail (
    id BIGINT PRIMARY KEY AUTO_INCREMENT,
    purchase_order_id BIGINT,
    product_id BIGINT,
    quantity INT,
    price DECIMAL(10,2),
    amount DECIMAL(10,2),
    create_time DATETIME DEFAULT CURRENT_TIMESTAMP
);

-- 销售单表
CREATE TABLE sale_order (
    id BIGINT PRIMARY KEY AUTO_INCREMENT,
    order_no VARCHAR(50) NOT NULL UNIQUE,
    customer_name VARCHAR(100),
    total_amount DECIMAL(10,2),
    status TINYINT DEFAULT 0,
    create_user_id BIGINT,
    create_time DATETIME DEFAULT CURRENT_TIMESTAMP,
    update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);

-- 销售单明细表
CREATE TABLE sale_order_detail (
    id BIGINT PRIMARY KEY AUTO_INCREMENT,
    sale_order_id BIGINT,
    product_id BIGINT,
    quantity INT,
    price DECIMAL(10,2),
    amount DECIMAL(10,2),
    create_time DATETIME DEFAULT CURRENT_TIMESTAMP
);

3、项目结构建议:

jxc-system/
├── frontend/                # Vue3前端项目
│   ├── src/
│   │   ├── api/            # API接口
│   │   ├── components/     # 组件
│   │   ├── router/         # 路由
│   │   ├── store/          # Pinia状态管理
│   │   └── views/          # 页面
│   └── package.json
│
├── backend/                 # SpringBoot后端项目
│   ├── src/
│   │   ├── main/
│   │   │   ├── java/com/jxc/
│   │   │   │   ├── config/     # 配置类
│   │   │   │   ├── controller/ # 控制器
│   │   │   │   ├── service/    # 服务层
│   │   │   │   ├── dao/        # 数据访问层
│   │   │   │   ├── entity/     # 实体类
│   │   │   │   └── common/     # 公共类
│   │   │   └── resources/
│   │   └── test/
│   └── pom.xml
│
└── docker/                  # Docker相关配置
    ├── docker-compose.yml
    └── Dockerfile

4、后端主要依赖(pom.xml):

<dependencies>
    <!-- Spring Boot -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    
    <!-- MyBatis Plus -->
    <dependency>
        <groupId>com.baomidou</groupId>
        <artifactId>mybatis-plus-boot-starter</artifactId>
        <version>3.5.3</version>
    </dependency>
    
    <!-- MySQL -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.33</version>
    </dependency>
    
    <!-- JWT -->
    <dependency>
        <groupId>io.jsonwebtoken</groupId>
        <artifactId>jjwt</artifactId>
        <version>0.9.1</version>
    </dependency>
    
    <!-- Lombok -->
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>
</dependencies>

5、前端主要依赖(package.json):

{
  "dependencies": {
    "vue": "^3.3.0",
    "vue-router": "^4.2.0",
    "pinia": "^2.1.0",
    "axios": "^1.4.0",
    "element-plus": "^2.3.0",
    "@element-plus/icons-vue": "^2.1.0"
  }
}

6、Docker部署配置(docker-compose.yml):

version: '3'
services:
  mysql:
    image: mysql:8.0
    container_name: jxc-mysql
    environment:
      MYSQL_ROOT_PASSWORD: ******
      MYSQL_DATABASE: JXC
    ports:
      - "3306:3306"
    volumes:
      - ./mysql-data:/var/lib/mysql
      
  backend:
    build: 
      context: ./backend
      dockerfile: Dockerfile
    container_name: jxc-backend
    ports:
      - "8080:8080"
    depends_on:
      - mysql
      
  frontend:
    build:
      context: ./frontend
      dockerfile: Dockerfile
    container_name: jxc-frontend
    ports:
      - "80:80"
    depends_on:
      - backend

基础的项目架构设计完成。

2、各模块的开发

2.1开发用户管理模块

2.1.1在后端创建相关的代码:

1.实体类:

backend\src\main\java\com\jxc\entity\SysUser.java

@Data
@TableName("sys_user")
public class SysUser {
    @TableId(type = IdType.AUTO)
    private Long id;
    private String username;
    private String password;
    private String realName;
    private String phone;
    private Integer status;
    private LocalDateTime createTime;
    private LocalDateTime updateTime;
}

2.登录请求和响应DTO:

backend\src\main\java\com\jxc\dto\LoginRequest.java

@Data
public class LoginRequest {
    private String username;
    private String password;
}

backend\src\main\java\com\jxc\dto\LoginResponse.java

@Data
public class LoginResponse {
    private String token;
    private SysUser user;
}

3. 统一响应对象:

backend\src\main\java\com\jxc\common\Result.java

@Data
public class Result<T> {
    private Integer code;
    private String message;
    private T data;

    public static <T> Result<T> success(T data) {
        Result<T> result = new Result<>();
        result.setCode(200);
        result.setMessage("success");
        result.setData(data);
        return result;
    }

    public static <T> Result<T> error(String message) {
        Result<T> result = new Result<>();
        result.setCode(500);
        result.setMessage(message);
        return result;
    }
}

4.JWT工具类:

backend\src\main\java\com\jxc\util\JwtUtil.java

@Component
public class JwtUtil {
    @Value("${jwt.secret}")
    private String secret;
    
    @Value("${jwt.expiration}")
    private Long expiration;

    public String generateToken(String username) {
        return Jwts.builder()
                .setSubject(username)
                .setIssuedAt(new Date())
                .setExpiration(new Date(System.currentTimeMillis() + expiration))
                .signWith(SignatureAlgorithm.HS512, secret)
                .compact();
    }

    public String getUsernameFromToken(String token) {
        return Jwts.parser()
                .setSigningKey(secret)
                .parseClaimsJws(token)
                .getBody()
                .getSubject();
    }

    public boolean validateToken(String token) {
        try {
            Jwts.parser().setSigningKey(secret).parseClaimsJws(token);
            return true;
        } catch (Exception e) {
            return false;
        }
    }
}

5.Service层:

backend\src\main\java\com\jxc\service\UserService.java

@Service
@RequiredArgsConstructor
public class UserService {
    private final SysUserMapper userMapper;
    private final PasswordEncoder passwordEncoder;
    private final JwtUtil jwtUtil;

    public LoginResponse login(LoginRequest request) {
        SysUser user = userMapper.selectOne(
            new QueryWrapper<SysUser>().eq("username", request.getUsername())
        );
        
        if (user == null || !passwordEncoder.matches(request.getPassword(), user.getPassword())) {
            throw new RuntimeException("用户名或密码错误");
        }
        
        if (user.getStatus() != 1) {
            throw new RuntimeException("账号已被禁用");
        }

        String token = jwtUtil.generateToken(user.getUsername());
        
        LoginResponse response = new LoginResponse();
        response.setToken(token);
        response.setUser(user);
        
        return response;
    }
}

6.Controller层:

backend\src\main\java\com\jxc\controller\AuthController.java

@RestController
@RequestMapping("/api/auth")
@RequiredArgsConstructor
public class AuthController {
    private final UserService userService;

    @PostMapping("/login")
    public Result<LoginResponse> login(@RequestBody LoginRequest request) {
        try {
            LoginResponse response = userService.login(request);
            return Result.success(response);
        } catch (Exception e) {
            return Result.error(e.getMessage());
        }
    }
}

2.1.2在前端创建相关代码:

1.创建相关代码:

frontend\src\api\auth.ts

import request from '@/utils/request'

export function login(data: {username: string, password: string}) {
    return request({
        url: '/api/auth/login',
        method: 'post',
        data
    })
}

2.创建登录页面:

frontend\src\views\login\index.vue

<template>
  <div class="login-container">
    <el-form
      ref="loginForm"
      :model="loginForm"
      :rules="loginRules"
      class="login-form"
    >
      <h3 class="title">进销存管理系统</h3>
      <el-form-item prop="username">
        <el-input
          v-model="loginForm.username"
          placeholder="用户名"
          type="text"
        />
      </el-form-item>
      <el-form-item prop="password">
        <el-input
          v-model="loginForm.password"
          placeholder="密码"
          type="password"
        />
      </el-form-item>
      <el-form-item>
        <el-button
          :loading="loading"
          type="primary"
          style="width: 100%"
          @click.prevent="handleLogin"
        >
          登录
        </el-button>
      </el-form-item>
    </el-form>
  </div>
</template>

<script setup lang="ts">
import { ref, reactive } from 'vue'
import { useRouter } from 'vue-router'
import { ElMessage } from 'element-plus'
import { login } from '@/api/auth'

const router = useRouter()
const loading = ref(false)

const loginForm = reactive({
  username: '',
  password: ''
})

const loginRules = {
  username: [{ required: true, message: '请输入用户名', trigger: 'blur' }],
  password: [{ required: true, message: '请输入密码', trigger: 'blur' }]
}

const handleLogin = async () => {
  loading.value = true
  try {
    const { data } = await login(loginForm)
    localStorage.setItem('token', data.token)
    localStorage.setItem('user', JSON.stringify(data.user))
    ElMessage.success('登录成功')
    router.push('/')
  } catch (error: any) {
    ElMessage.error(error.message || '登录失败')
  } finally {
    loading.value = false
  }
}
</script>

<style lang="scss" scoped>
.login-container {
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  background-color: #2d3a4b;
  
  .login-form {
    width: 400px;
    padding: 40px;
    background: #fff;
    border-radius: 4px;
    
    .title {
      text-align: center;
      margin-bottom: 30px;
    }
  }
}
</style>

3.添加路由配置:

frontend\src\router\index.ts

import { createRouter, createWebHistory } from 'vue-router'

const router = createRouter({
  history: createWebHistory(),
  routes: [
    {
      path: '/login',
      component: () => import('@/views/login/index.vue')
    },
    {
      path: '/',
      component: () => import('@/layout/index.vue'),
      redirect: '/dashboard',
      children: [
        {
          path: 'dashboard',
          component: () => import('@/views/dashboard/index.vue')
        }
      ]
    }
  ]
})

router.beforeEach((to, from, next) => {
  const token = localStorage.getItem('token')
  if (to.path === '/login') {
    if (token) {
      next('/')
    } else {
      next()
    }
  } else {
    if (token) {
      next()
    } else {
      next('/login')
    }
  }
})

export default router

4.在application.yml中添加JWT配置:

backend\src\main\resources\application.yml

jwt:
  secret: your-secret-key
  expiration: 86400000  # 24小时

这样,基本的用户认证模块就完成了。主要功能包括:

  1. 用户登录
  2. JWT token生成和验证
  3. 路由守卫
  4. 登录状态持久化

2.1.3开发用户管理及权限控制

2.1.3.1创建初始管理员

1.先创建一个初始管理员用户,并实现基本的用户管理功能。

-- 角色表
CREATE TABLE sys_role (
    id BIGINT PRIMARY KEY AUTO_INCREMENT,
    role_name VARCHAR(50) NOT NULL,
    role_code VARCHAR(50) NOT NULL UNIQUE,
    description VARCHAR(200),
    status TINYINT DEFAULT 1,
    create_time DATETIME DEFAULT CURRENT_TIMESTAMP,
    update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);

-- 用户角色关联表
CREATE TABLE sys_user_role (
    id BIGINT PRIMARY KEY AUTO_INCREMENT,
    user_id BIGINT NOT NULL,
    role_id BIGINT NOT NULL,
    create_time DATETIME DEFAULT CURRENT_TIMESTAMP
);

-- 插入初始角色数据
INSERT INTO sys_role (role_name, role_code, description) VALUES 
('系统管理员', 'ADMIN', '系统管理员,拥有所有权限'),
('普通用户', 'USER', '普通用户,拥有基本操作权限');

-- 插入初始管理员用户
INSERT INTO sys_user (username, password, real_name, status) VALUES 
('admin', '$2a$10$X/uME6GXZWxn.Z2P.TgqsOYCvbt3qdUcHvVTQJgBM8yWc8t9YmQdq', '系统管理员', 1);

-- 关联管理员角色
INSERT INTO sys_user_role (user_id, role_id) VALUES (1, 1);

2.创建角色实体类:

backend\src\main\java\com\jxc\entity\SysRole.java

@Data
@TableName("sys_role")
public class SysRole {
    @TableId(type = IdType.AUTO)
    private Long id;
    private String roleName;
    private String roleCode;
    private String description;
    private Integer status;
    private LocalDateTime createTime;
    private LocalDateTime updateTime;
}

3.创建用户管理相关DTO:

backend\src\main\java\com\jxc\dto\UserDTO.java

@Data
public class UserDTO {
    private Long id;
    private String username;
    private String password;
    private String realName;
    private String phone;
    private Integer status;
    private List<Long> roleIds;
}

4.扩展UserService,添加用户管理相关方法:

backend\src\main\java\com\jxc\service\UserService.java

@Service
@RequiredArgsConstructor
public class UserService {
    // ... 之前的代码 ...

    @Transactional
    public void createUser(UserDTO userDTO) {
        // 检查用户名是否存在
        if (userMapper.selectCount(new QueryWrapper<SysUser>()
                .eq("username", userDTO.getUsername())) > 0) {
            throw new RuntimeException("用户名已存在");
        }

        // 创建用户
        SysUser user = new SysUser();
        BeanUtils.copyProperties(userDTO, user);
        user.setPassword(passwordEncoder.encode(userDTO.getPassword()));
        userMapper.insert(user);

        // 保存用户角色关系
        if (userDTO.getRoleIds() != null && !userDTO.getRoleIds().isEmpty()) {
            userDTO.getRoleIds().forEach(roleId -> {
                userRoleMapper.insert(new SysUserRole(user.getId(), roleId));
            });
        }
    }

    @Transactional
    public void updateUser(UserDTO userDTO) {
        SysUser user = userMapper.selectById(userDTO.getId());
        if (user == null) {
            throw new RuntimeException("用户不存在");
        }

        // 更新用户信息
        BeanUtils.copyProperties(userDTO, user, "password");
        if (StringUtils.hasText(userDTO.getPassword())) {
            user.setPassword(passwordEncoder.encode(userDTO.getPassword()));
        }
        userMapper.updateById(user);

        // 更新用户角色关系
        if (userDTO.getRoleIds() != null) {
            userRoleMapper.delete(new QueryWrapper<SysUserRole>()
                    .eq("user_id", user.getId()));
            userDTO.getRoleIds().forEach(roleId -> {
                userRoleMapper.insert(new SysUserRole(user.getId(), roleId));
            });
        }
    }

    public void deleteUser(Long id) {
        userMapper.deleteById(id);
        userRoleMapper.delete(new QueryWrapper<SysUserRole>()
                .eq("user_id", id));
    }

    public IPage<SysUser> getUserList(Page<SysUser> page, String username, String realName) {
        return userMapper.selectPage(page, new QueryWrapper<SysUser>()
                .like(StringUtils.hasText(username), "username", username)
                .like(StringUtils.hasText(realName), "real_name", realName));
    }
}

5. 创建用户管理Controller:

backend\src\main\java\com\jxc\controller\UserController.java

@RestController
@RequestMapping("/api/users")
@RequiredArgsConstructor
public class UserController {
    private final UserService userService;

    @GetMapping
    public Result<IPage<SysUser>> list(
            @RequestParam(defaultValue = "1") Integer current,
            @RequestParam(defaultValue = "10") Integer size,
            @RequestParam(required = false) String username,
            @RequestParam(required = false) String realName) {
        Page<SysUser> page = new Page<>(current, size);
        return Result.success(userService.getUserList(page, username, realName));
    }

    @PostMapping
    public Result<?> create(@RequestBody UserDTO userDTO) {
        userService.createUser(userDTO);
        return Result.success(null);
    }

    @PutMapping("/{id}")
    public Result<?> update(@PathVariable Long id, @RequestBody UserDTO userDTO) {
        userDTO.setId(id);
        userService.updateUser(userDTO);
        return Result.success(null);
    }

    @DeleteMapping("/{id}")
    public Result<?> delete(@PathVariable Long id) {
        userService.deleteUser(id);
        return Result.success(null);
    }
}

6. 创建用户管理页面:

frontend\src\views\system\user\index.vue

<template>
  <div class="app-container">
    <div class="filter-container">
      <el-input
        v-model="queryParams.username"
        placeholder="用户名"
        style="width: 200px"
        class="filter-item"
      />
      <el-input
        v-model="queryParams.realName"
        placeholder="姓名"
        style="width: 200px"
        class="filter-item"
      />
      <el-button type="primary" @click="handleQuery">查询</el-button>
      <el-button type="primary" @click="handleAdd">新增</el-button>
    </div>

    <el-table :data="userList" style="width: 100%">
      <el-table-column prop="username" label="用户名" />
      <el-table-column prop="realName" label="姓名" />
      <el-table-column prop="phone" label="电话" />
      <el-table-column prop="status" label="状态">
        <template #default="scope">
          <el-tag :type="scope.row.status === 1 ? 'success' : 'danger'">
            {{ scope.row.status === 1 ? '启用' : '禁用' }}
          </el-tag>
        </template>
      </el-table-column>
      <el-table-column label="操作">
        <template #default="scope">
          <el-button type="text" @click="handleEdit(scope.row)">编辑</el-button>
          <el-button type="text" @click="handleDelete(scope.row)">删除</el-button>
        </template>
      </el-table-column>
    </el-table>

    <el-pagination
      v-model:current-page="queryParams.current"
      v-model:page-size="queryParams.size"
      :total="total"
      @current-change="handleQuery"
    />

    <!-- 用户表单对话框 -->
    <el-dialog
      :title="dialogTitle"
      v-model="dialogVisible"
      width="500px"
    >
      <el-form ref="userForm" :model="userForm" :rules="rules" label-width="80px">
        <el-form-item label="用户名" prop="username">
          <el-input v-model="userForm.username" />
        </el-form-item>
        <el-form-item label="密码" prop="password">
          <el-input v-model="userForm.password" type="password" />
        </el-form-item>
        <el-form-item label="姓名" prop="realName">
          <el-input v-model="userForm.realName" />
        </el-form-item>
        <el-form-item label="电话" prop="phone">
          <el-input v-model="userForm.phone" />
        </el-form-item>
        <el-form-item label="状态">
          <el-switch v-model="userForm.status" :active-value="1" :inactive-value="0" />
        </el-form-item>
        <el-form-item label="角色">
          <el-select v-model="userForm.roleIds" multiple>
            <el-option
              v-for="role in roleOptions"
              :key="role.id"
              :label="role.roleName"
              :value="role.id"
            />
          </el-select>
        </el-form-item>
      </el-form>
      <template #footer>
        <el-button @click="dialogVisible = false">取消</el-button>
        <el-button type="primary" @click="handleSubmit">确定</el-button>
      </template>
    </el-dialog>
  </div>
</template>

<script setup lang="ts">
// ... 组件逻辑代码将在下一条消息中提供
</script>
2.1.3.2实现用户管理功能(创建、修改、删除用户)

1.完成用户管理页面的组件逻辑代码:

frontend\src\views\system\user\index.vue

<script setup lang="ts">
import { ref, reactive, onMounted } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import type { FormInstance } from 'element-plus'

// 查询参数
const queryParams = reactive({
  current: 1,
  size: 10,
  username: '',
  realName: ''
})

// 用户列表数据
const userList = ref([])
const total = ref(0)
const loading = ref(false)

// 角色选项
const roleOptions = ref([])

// 对话框控制
const dialogVisible = ref(false)
const dialogTitle = ref('')
const userForm = reactive({
  id: undefined,
  username: '',
  password: '',
  realName: '',
  phone: '',
  status: 1,
  roleIds: []
})

// 表单校验规则
const rules = {
  username: [
    { required: true, message: '请输入用户名', trigger: 'blur' },
    { min: 3, max: 20, message: '长度在 3 到 20 个字符', trigger: 'blur' }
  ],
  password: [
    { required: true, message: '请输入密码', trigger: 'blur', when: () => !userForm.id },
    { min: 6, max: 20, message: '长度在 6 到 20 个字符', trigger: 'blur' }
  ],
  realName: [
    { required: true, message: '请输入姓名', trigger: 'blur' }
  ]
}

const userFormRef = ref<FormInstance>()

// 获取用户列表
const getUserList = async () => {
  loading.value = true
  try {
    const { data } = await request({
      url: '/api/users',
      method: 'get',
      params: queryParams
    })
    userList.value = data.records
    total.value = data.total
  } catch (error: any) {
    ElMessage.error(error.message || '获取用户列表失败')
  } finally {
    loading.value = false
  }
}

// 获取角色列表
const getRoleList = async () => {
  try {
    const { data } = await request({
      url: '/api/roles',
      method: 'get'
    })
    roleOptions.value = data
  } catch (error: any) {
    ElMessage.error(error.message || '获取角色列表失败')
  }
}

// 查询按钮点击事件
const handleQuery = () => {
  queryParams.current = 1
  getUserList()
}

// 重置表单
const resetForm = () => {
  userForm.id = undefined
  userForm.username = ''
  userForm.password = ''
  userForm.realName = ''
  userForm.phone = ''
  userForm.status = 1
  userForm.roleIds = []
  userFormRef.value?.resetFields()
}

// 新增按钮点击事件
const handleAdd = () => {
  resetForm()
  dialogTitle.value = '新增用户'
  dialogVisible.value = true
}

// 编辑按钮点击事件
const handleEdit = (row: any) => {
  resetForm()
  dialogTitle.value = '编辑用户'
  Object.assign(userForm, row)
  dialogVisible.value = true
}

// 删除按钮点击事件
const handleDelete = (row: any) => {
  ElMessageBox.confirm('确认删除该用户吗?', '提示', {
    type: 'warning'
  }).then(async () => {
    try {
      await request({
        url: `/api/users/${row.id}`,
        method: 'delete'
      })
      ElMessage.success('删除成功')
      getUserList()
    } catch (error: any) {
      ElMessage.error(error.message || '删除失败')
    }
  })
}

// 表单提交
const handleSubmit = async () => {
  if (!userFormRef.value) return
  
  await userFormRef.value.validate()
  
  try {
    const method = userForm.id ? 'put' : 'post'
    const url = userForm.id ? `/api/users/${userForm.id}` : '/api/users'
    
    await request({
      url,
      method,
      data: userForm
    })
    
    ElMessage.success(`${userForm.id ? '更新' : '创建'}成功`)
    dialogVisible.value = false
    getUserList()
  } catch (error: any) {
    ElMessage.error(error.message || `${userForm.id ? '更新' : '创建'}失败`)
  }
}

// 页面加载时获取数据
onMounted(() => {
  getUserList()
  getRoleList()
})
</script>

<style scoped>
.filter-container {
  padding-bottom: 10px;
}
.filter-item {
  margin-right: 10px;
}
</style>

2.还需要创建一个API请求工具:

frontend\src\utils\request.ts

import axios from 'axios'
import { ElMessage } from 'element-plus'
import router from '@/router'

const request = axios.create({
  baseURL: import.meta.env.VITE_API_URL || '/api',
  timeout: 5000
})

// 请求拦截器
request.interceptors.request.use(
  config => {
    const token = localStorage.getItem('token')
    if (token) {
      config.headers['Authorization'] = `Bearer ${token}`
    }
    return config
  },
  error => {
    return Promise.reject(error)
  }
)

// 响应拦截器
request.interceptors.response.use(
  response => {
    const res = response.data
    
    if (res.code !== 200) {
      ElMessage.error(res.message || '请求失败')
      
      if (res.code === 401) {
        localStorage.removeItem('token')
        localStorage.removeItem('user')
        router.push('/login')
      }
      
      return Promise.reject(new Error(res.message || '请求失败'))
    }
    
    return res
  },
  error => {
    ElMessage.error(error.message || '请求失败')
    return Promise.reject(error)
  }
)

export default request

3.在环境配置文件中添加API地址:

frontend\.env.development

VITE_API_URL=http://localhost:8080

用户管理模块就完成了,主要功能包括:

  1. 用户列表展示(分页、搜索)
  2. 新增用户
  3. 编辑用户
  4. 删除用户
  5. 用户状态管理
  6. 用户角色分配
2.1.3.3实现权限控制功能

我们将使用RBAC(基于角色的访问控制)模型。

1.首先创建权限表和角色-权限关联表:

-- 权限表
CREATE TABLE sys_permission (
    id BIGINT PRIMARY KEY AUTO_INCREMENT,
    parent_id BIGINT,
    name VARCHAR(50) NOT NULL,
    code VARCHAR(50) NOT NULL UNIQUE,
    type TINYINT COMMENT '1:菜单 2:按钮',
    path VARCHAR(200),
    component VARCHAR(200),
    icon VARCHAR(50),
    sort_num INT DEFAULT 0,
    status TINYINT DEFAULT 1,
    create_time DATETIME DEFAULT CURRENT_TIMESTAMP,
    update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);

-- 角色权限关联表
CREATE TABLE sys_role_permission (
    id BIGINT PRIMARY KEY AUTO_INCREMENT,
    role_id BIGINT NOT NULL,
    permission_id BIGINT NOT NULL,
    create_time DATETIME DEFAULT CURRENT_TIMESTAMP
);

-- 插入基础权限数据
INSERT INTO sys_permission (parent_id, name, code, type, path, component, icon, sort_num) VALUES 
(0, '系统管理', 'system', 1, '/system', 'Layout', 'setting', 1),
(1, '用户管理', 'system:user', 1, 'user', 'system/user/index', 'user', 1),
(1, '角色管理', 'system:role', 1, 'role', 'system/role/index', 'peoples', 2),
(2, '用户新增', 'system:user:add', 2, NULL, NULL, NULL, 1),
(2, '用户编辑', 'system:user:edit', 2, NULL, NULL, NULL, 2),
(2, '用户删除', 'system:user:delete', 2, NULL, NULL, NULL, 3);

-- 为管理员角色分配所有权限
INSERT INTO sys_role_permission (role_id, permission_id)
SELECT 1, id FROM sys_permission;

2.创建权限实体类:

backend\src\main\java\com\jxc\entity\SysPermission.java

@Data
@TableName("sys_permission")
public class SysPermission {
    @TableId(type = IdType.AUTO)
    private Long id;
    private Long parentId;
    private String name;
    private String code;
    private Integer type;
    private String path;
    private String component;
    private String icon;
    private Integer sortNum;
    private Integer status;
    private LocalDateTime createTime;
    private LocalDateTime updateTime;
    
    @TableField(exist = false)
    private List<SysPermission> children;
}

3. 创建权限注解:

backend\src\main\java\com\jxc\annotation\RequiresPermission.java

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RequiresPermission {
    String value();
}

4.创建权限拦截器:

backend\src\main\java\com\jxc\interceptor\PermissionInterceptor.java

@Component
@RequiredArgsConstructor
public class PermissionInterceptor implements HandlerInterceptor {
    private final JwtUtil jwtUtil;
    private final UserService userService;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        // 如果不是处理方法直接通过
        if (!(handler instanceof HandlerMethod)) {
            return true;
        }

        HandlerMethod handlerMethod = (HandlerMethod) handler;
        RequiresPermission requiresPermission = handlerMethod.getMethodAnnotation(RequiresPermission.class);
        
        // 如果没有权限注解直接通过
        if (requiresPermission == null) {
            return true;
        }

        // 获取token中的用户名
        String token = request.getHeader("Authorization");
        if (token != null && token.startsWith("Bearer ")) {
            token = token.substring(7);
        }
        String username = jwtUtil.getUsernameFromToken(token);

        // 检查用户权限
        Set<String> permissions = userService.getUserPermissions(username);
        if (!permissions.contains(requiresPermission.value())) {
            throw new RuntimeException("没有操作权限");
        }

        return true;
    }
}

5.扩展UserService,添加获取用户权限的方法:

backend\src\main\java\com\jxc\service\UserService.java

@Service
public class UserService {
    // ... 之前的代码 ...

    public Set<String> getUserPermissions(String username) {
        return userMapper.getUserPermissions(username);
    }

    public List<SysPermission> getUserMenus(String username) {
        List<SysPermission> permissions = userMapper.getUserPermissions(username)
            .stream()
            .filter(p -> p.getType() == 1)
            .collect(Collectors.toList());
        
        return buildTree(permissions);
    }

    private List<SysPermission> buildTree(List<SysPermission> permissions) {
        List<SysPermission> tree = new ArrayList<>();
        Map<Long, SysPermission> map = new HashMap<>();
        
        // 构建节点Map
        permissions.forEach(permission -> map.put(permission.getId(), permission));
        
        // 构建树形结构
        permissions.forEach(permission -> {
            if (permission.getParentId() == 0) {
                tree.add(permission);
            } else {
                SysPermission parent = map.get(permission.getParentId());
                if (parent != null) {
                    if (parent.getChildren() == null) {
                        parent.setChildren(new ArrayList<>());
                    }
                    parent.getChildren().add(permission);
                }
            }
        });
        
        return tree;
    }
}

6.在Controller中使用权限注解:

backend\src\main\java\com\jxc\controller\UserController.java

@RestController
@RequestMapping("/api/users")
public class UserController {
    // ... 之前的代码 ...

    @GetMapping
    @RequiresPermission("system:user:list")
    public Result<IPage<SysUser>> list(/* ... */) {
        // ... 
    }

    @PostMapping
    @RequiresPermission("system:user:add")
    public Result<?> create(@RequestBody UserDTO userDTO) {
        // ...
    }

    @PutMapping("/{id}")
    @RequiresPermission("system:user:edit")
    public Result<?> update(@PathVariable Long id, @RequestBody UserDTO userDTO) {
        // ...
    }

    @DeleteMapping("/{id}")
    @RequiresPermission("system:user:delete")
    public Result<?> delete(@PathVariable Long id) {
        // ...
    }
}

7.在前端添加权限指令:

frontend\src\directives\permission.ts

import { DirectiveBinding } from 'vue'

function checkPermission(el: HTMLElement, binding: DirectiveBinding) {
    const { value } = binding
    const permissions = JSON.parse(localStorage.getItem('permissions') || '[]')

    if (value && value instanceof Array) {
        const hasPermission = value.some(permission => permissions.includes(permission))
        if (!hasPermission) {
            el.parentNode?.removeChild(el)
        }
    } else {
        throw new Error('need permissions! Like v-permission="[\'system:user:add\']"')
    }
}

export default {
    mounted(el: HTMLElement, binding: DirectiveBinding) {
        checkPermission(el, binding)
    },
    updated(el: HTMLElement, binding: DirectiveBinding) {
        checkPermission(el, binding)
    }
}

8.在用户管理页面中使用权限指令:

frontend\src\views\system\user\index.vue

<template>
  <div class="app-container">
    <!-- ... 其他代码 ... -->
    <el-button 
      v-permission="['system:user:add']"
      type="primary" 
      @click="handleAdd"
    >
      新增
    </el-button>

    <el-table :data="userList">
      <!-- ... 其他列 ... -->
      <el-table-column label="操作">
        <template #default="scope">
          <el-button 
            v-permission="['system:user:edit']"
            type="text" 
            @click="handleEdit(scope.row)"
          >
            编辑
          </el-button>
          <el-button 
            v-permission="['system:user:delete']"
            type="text" 
            @click="handleDelete(scope.row)"
          >
            删除
          </el-button>
        </template>
      </el-table-column>
    </el-table>
  </div>
</template>

9.在登录成功后获取用户权限:

frontend\src\views\login\index.vue

const handleLogin = async () => {
  try {
    const { data } = await login(loginForm)
    localStorage.setItem('token', data.token)
    localStorage.setItem('user', JSON.stringify(data.user))
    
    // 获取用户权限和菜单
    const { data: permissions } = await getUserPermissions()
    localStorage.setItem('permissions', JSON.stringify(permissions))
    
    const { data: menus } = await getUserMenus()
    store.commit('SET_MENUS', menus)
    
    router.push('/')
  } catch (error) {
    ElMessage.error(error.message)
  }
}
2.13.4实现角色管理功能

1.首先创建角色管理相关的DTO:

backend\src\main\java\com\jxc\dto\RoleDTO.java

@Data
public class RoleDTO {
    private Long id;
    private String roleName;
    private String roleCode;
    private String description;
    private Integer status;
    private List<Long> permissionIds;
}

2.创建角色Service:

backend\src\main\java\com\jxc\service\RoleService.java

@Service
@RequiredArgsConstructor
public class RoleService {
    private final SysRoleMapper roleMapper;
    private final SysRolePermissionMapper rolePermissionMapper;

    public IPage<SysRole> getRoleList(Page<SysRole> page, String roleName) {
        return roleMapper.selectPage(page, new QueryWrapper<SysRole>()
                .like(StringUtils.hasText(roleName), "role_name", roleName));
    }

    @Transactional
    public void createRole(RoleDTO roleDTO) {
        // 检查角色编码是否存在
        if (roleMapper.selectCount(new QueryWrapper<SysRole>()
                .eq("role_code", roleDTO.getRoleCode())) > 0) {
            throw new RuntimeException("角色编码已存在");
        }

        // 创建角色
        SysRole role = new SysRole();
        BeanUtils.copyProperties(roleDTO, role);
        roleMapper.insert(role);

        // 保存角色权限关系
        if (roleDTO.getPermissionIds() != null && !roleDTO.getPermissionIds().isEmpty()) {
            roleDTO.getPermissionIds().forEach(permissionId -> {
                rolePermissionMapper.insert(new SysRolePermission(role.getId(), permissionId));
            });
        }
    }

    @Transactional
    public void updateRole(RoleDTO roleDTO) {
        SysRole role = roleMapper.selectById(roleDTO.getId());
        if (role == null) {
            throw new RuntimeException("角色不存在");
        }

        // 检查角色编码是否重复
        if (!role.getRoleCode().equals(roleDTO.getRoleCode())) {
            if (roleMapper.selectCount(new QueryWrapper<SysRole>()
                    .eq("role_code", roleDTO.getRoleCode())) > 0) {
                throw new RuntimeException("角色编码已存在");
            }
        }

        // 更新角色信息
        BeanUtils.copyProperties(roleDTO, role);
        roleMapper.updateById(role);

        // 更新角色权限关系
        if (roleDTO.getPermissionIds() != null) {
            rolePermissionMapper.delete(new QueryWrapper<SysRolePermission>()
                    .eq("role_id", role.getId()));
            roleDTO.getPermissionIds().forEach(permissionId -> {
                rolePermissionMapper.insert(new SysRolePermission(role.getId(), permissionId));
            });
        }
    }

    @Transactional
    public void deleteRole(Long id) {
        // 检查是否有用户使用该角色
        if (roleMapper.hasUsers(id) > 0) {
            throw new RuntimeException("该角色已被用户使用,无法删除");
        }
        
        roleMapper.deleteById(id);
        rolePermissionMapper.delete(new QueryWrapper<SysRolePermission>()
                .eq("role_id", id));
    }

    public List<Long> getRolePermissions(Long roleId) {
        return rolePermissionMapper.selectList(new QueryWrapper<SysRolePermission>()
                .eq("role_id", roleId))
                .stream()
                .map(SysRolePermission::getPermissionId)
                .collect(Collectors.toList());
    }
}

3.创建角色Controller:

backend\src\main\java\com\jxc\controller\RoleController.java

@RestController
@RequestMapping("/api/roles")
@RequiredArgsConstructor
public class RoleController {
    private final RoleService roleService;

    @GetMapping
    @RequiresPermission("system:role:list")
    public Result<IPage<SysRole>> list(
            @RequestParam(defaultValue = "1") Integer current,
            @RequestParam(defaultValue = "10") Integer size,
            @RequestParam(required = false) String roleName) {
        Page<SysRole> page = new Page<>(current, size);
        return Result.success(roleService.getRoleList(page, roleName));
    }

    @PostMapping
    @RequiresPermission("system:role:add")
    public Result<?> create(@RequestBody RoleDTO roleDTO) {
        roleService.createRole(roleDTO);
        return Result.success(null);
    }

    @PutMapping("/{id}")
    @RequiresPermission("system:role:edit")
    public Result<?> update(@PathVariable Long id, @RequestBody RoleDTO roleDTO) {
        roleDTO.setId(id);
        roleService.updateRole(roleDTO);
        return Result.success(null);
    }

    @DeleteMapping("/{id}")
    @RequiresPermission("system:role:delete")
    public Result<?> delete(@PathVariable Long id) {
        roleService.deleteRole(id);
        return Result.success(null);
    }

    @GetMapping("/{id}/permissions")
    @RequiresPermission("system:role:edit")
    public Result<List<Long>> getRolePermissions(@PathVariable Long id) {
        return Result.success(roleService.getRolePermissions(id));
    }
}

4.创建角色管理页面:

frontend\src\views\system\role\index.vue

<template>
  <div class="app-container">
    <div class="filter-container">
      <el-input
        v-model="queryParams.roleName"
        placeholder="角色名称"
        style="width: 200px"
        class="filter-item"
      />
      <el-button type="primary" @click="handleQuery">查询</el-button>
      <el-button 
        v-permission="['system:role:add']"
        type="primary" 
        @click="handleAdd"
      >
        新增
      </el-button>
    </div>

    <el-table :data="roleList" style="width: 100%">
      <el-table-column prop="roleName" label="角色名称" />
      <el-table-column prop="roleCode" label="角色编码" />
      <el-table-column prop="description" label="描述" />
      <el-table-column prop="status" label="状态">
        <template #default="scope">
          <el-tag :type="scope.row.status === 1 ? 'success' : 'danger'">
            {{ scope.row.status === 1 ? '启用' : '禁用' }}
          </el-tag>
        </template>
      </el-table-column>
      <el-table-column label="操作">
        <template #default="scope">
          <el-button 
            v-permission="['system:role:edit']"
            type="text" 
            @click="handleEdit(scope.row)"
          >
            编辑
          </el-button>
          <el-button 
            v-permission="['system:role:delete']"
            type="text" 
            @click="handleDelete(scope.row)"
          >
            删除
          </el-button>
        </template>
      </el-table-column>
    </el-table>

    <el-pagination
      v-model:current-page="queryParams.current"
      v-model:page-size="queryParams.size"
      :total="total"
      @current-change="handleQuery"
    />

    <!-- 角色表单对话框 -->
    <el-dialog
      :title="dialogTitle"
      v-model="dialogVisible"
      width="500px"
    >
      <el-form ref="roleForm" :model="roleForm" :rules="rules" label-width="80px">
        <el-form-item label="角色名称" prop="roleName">
          <el-input v-model="roleForm.roleName" />
        </el-form-item>
        <el-form-item label="角色编码" prop="roleCode">
          <el-input v-model="roleForm.roleCode" />
        </el-form-item>
        <el-form-item label="描述">
          <el-input v-model="roleForm.description" type="textarea" />
        </el-form-item>
        <el-form-item label="状态">
          <el-switch v-model="roleForm.status" :active-value="1" :inactive-value="0" />
        </el-form-item>
        <el-form-item label="权限">
          <el-tree
            ref="permissionTree"
            :data="permissionOptions"
            :props="{ label: 'name', children: 'children' }"
            show-checkbox
            node-key="id"
          />
        </el-form-item>
      </el-form>
      <template #footer>
        <el-button @click="dialogVisible = false">取消</el-button>
        <el-button type="primary" @click="handleSubmit">确定</el-button>
      </template>
    </el-dialog>
  </div>
</template>

<script setup lang="ts">
// ... 组件逻辑代码将在下一条消息中提供
</script>

5.组件逻辑代码:

frontend\src\views\system\role\index.vue

<script setup lang="ts">
import { ref, reactive, onMounted } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import type { FormInstance, ElTree } from 'element-plus'
import request from '@/utils/request'

// 查询参数
const queryParams = reactive({
  current: 1,
  size: 10,
  roleName: ''
})

// 角色列表数据
const roleList = ref([])
const total = ref(0)
const loading = ref(false)

// 权限树选项
const permissionOptions = ref([])
const permissionTree = ref<InstanceType<typeof ElTree>>()

// 对话框控制
const dialogVisible = ref(false)
const dialogTitle = ref('')
const roleForm = reactive({
  id: undefined,
  roleName: '',
  roleCode: '',
  description: '',
  status: 1,
  permissionIds: [] as number[]
})

// 表单校验规则
const rules = {
  roleName: [
    { required: true, message: '请输入角色名称', trigger: 'blur' }
  ],
  roleCode: [
    { required: true, message: '请输入角色编码', trigger: 'blur' },
    { pattern: /^[A-Z_]+$/, message: '角色编码只能包含大写字母和下划线', trigger: 'blur' }
  ]
}

const roleFormRef = ref<FormInstance>()

// 获取角色列表
const getRoleList = async () => {
  loading.value = true
  try {
    const { data } = await request({
      url: '/api/roles',
      method: 'get',
      params: queryParams
    })
    roleList.value = data.records
    total.value = data.total
  } catch (error: any) {
    ElMessage.error(error.message || '获取角色列表失败')
  } finally {
    loading.value = false
  }
}

// 获取权限树数据
const getPermissionTree = async () => {
  try {
    const { data } = await request({
      url: '/api/permissions/tree',
      method: 'get'
    })
    permissionOptions.value = data
  } catch (error: any) {
    ElMessage.error(error.message || '获取权限列表失败')
  }
}

// 获取角色权限
const getRolePermissions = async (roleId: number) => {
  try {
    const { data } = await request({
      url: `/api/roles/${roleId}/permissions`,
      method: 'get'
    })
    permissionTree.value?.setCheckedKeys(data)
  } catch (error: any) {
    ElMessage.error(error.message || '获取角色权限失败')
  }
}

// 查询按钮点击事件
const handleQuery = () => {
  queryParams.current = 1
  getRoleList()
}

// 重置表单
const resetForm = () => {
  roleForm.id = undefined
  roleForm.roleName = ''
  roleForm.roleCode = ''
  roleForm.description = ''
  roleForm.status = 1
  roleForm.permissionIds = []
  roleFormRef.value?.resetFields()
  permissionTree.value?.setCheckedKeys([])
}

// 新增按钮点击事件
const handleAdd = () => {
  resetForm()
  dialogTitle.value = '新增角色'
  dialogVisible.value = true
}

// 编辑按钮点击事件
const handleEdit = async (row: any) => {
  resetForm()
  dialogTitle.value = '编辑角色'
  Object.assign(roleForm, row)
  dialogVisible.value = true
  await getRolePermissions(row.id)
}

// 删除按钮点击事件
const handleDelete = (row: any) => {
  ElMessageBox.confirm('确认删除该角色吗?', '提示', {
    type: 'warning'
  }).then(async () => {
    try {
      await request({
        url: `/api/roles/${row.id}`,
        method: 'delete'
      })
      ElMessage.success('删除成功')
      getRoleList()
    } catch (error: any) {
      ElMessage.error(error.message || '删除失败')
    }
  })
}

// 表单提交
const handleSubmit = async () => {
  if (!roleFormRef.value) return
  
  await roleFormRef.value.validate()
  
  // 获取选中的权限ID
  const checkedKeys = permissionTree.value?.getCheckedKeys(false) as number[]
  const halfCheckedKeys = permissionTree.value?.getHalfCheckedKeys() as number[]
  roleForm.permissionIds = [...checkedKeys, ...halfCheckedKeys]
  
  try {
    const method = roleForm.id ? 'put' : 'post'
    const url = roleForm.id ? `/api/roles/${roleForm.id}` : '/api/roles'
    
    await request({
      url,
      method,
      data: roleForm
    })
    
    ElMessage.success(`${roleForm.id ? '更新' : '创建'}成功`)
    dialogVisible.value = false
    getRoleList()
  } catch (error: any) {
    ElMessage.error(error.message || `${roleForm.id ? '更新' : '创建'}失败`)
  }
}

// 页面加载时获取数据
onMounted(() => {
  getRoleList()
  getPermissionTree()
})
</script>

<style scoped>
.filter-container {
  padding-bottom: 10px;
}
.filter-item {
  margin-right: 10px;
}
</style>

6.创建一个权限树的接口:

backend\src\main\java\com\jxc\controller\PermissionController.java

@RestController
@RequestMapping("/api/permissions")
@RequiredArgsConstructor
public class PermissionController {
    private final UserService userService;

    @GetMapping("/tree")
    @RequiresPermission("system:role:edit")
    public Result<List<SysPermission>> getPermissionTree() {
        List<SysPermission> permissions = userService.getAllPermissions();
        return Result.success(permissions);
    }
}

7.在UserService中添加获取所有权限的方法:

backend\src\main\java\com\jxc\service\UserService.java

@Service
public class UserService {
    // ... 之前的代码 ...

    public List<SysPermission> getAllPermissions() {
        List<SysPermission> permissions = permissionMapper.selectList(new QueryWrapper<>());
        return buildTree(permissions);
    }
}

角色管理功能就完成了,主要包括:

  1. 角色的增删改查
  2. 角色权限分配
  3. 权限树形展示
  4. 表单验证

  1. 添加权限控制

您想继续哪个部分?

  1. 开发商品管理功能
  2. 开发采购管理功能
  3. 开发销售管理功能
  4. 开发库存管理功能
  5. 开发报表统计功能

标签:const,进销存,private,超市,public,user,java,一款,id
From: https://blog.csdn.net/weixin_64401027/article/details/144158969

相关文章

  • 开发一款小超市的进销存系统02-商品管理模块
    2.2开发商品管理模块2.2.1创建商品分类功能1.创建商品分类表:--商品分类表CREATETABLEproduct_category(idBIGINTPRIMARYKEYAUTO_INCREMENT,parent_idBIGINTDEFAULT0,nameVARCHAR(50)NOTNULL,sort_numINTDEFAULT0,statusTINYINT......
  • 一款.NET开源的Windows资源管理器标签页工具
    前言今天大姚给大家分享一款基于.NET开发的可以让你在Windows资源管理器中使用Tab多标签功能的小工具:QTTabBar。工具介绍QTTabBar是一款基于.NET开发的可以让你在Windows资源管理器中使用Tab多标签功能的小工具。从此以后工作时不再遍布文件夹窗口,还有给力的文件夹预览功能,大......
  • 空壳应用分身 一款强大的分身软件
    空壳分身是一款功能强大的应用分身工具,支持主流应用的多开功能,用户可以在同一部手机上创建多个相同应用的分身,如微信、QQ等,满足用户多账号管理的需求。每个分身应用都可以独立运行,互不干扰,且拥有独立的应用权限设置,保障用户隐私和数据安全。界面布局简洁明了,用户可以轻松上手,......
  • 公司自研发的一款亚马逊跟卖一体化软件
    NIU-BOX是一款专注于亚马逊跟卖全流程运营一体化的管理软件,系统功能覆盖了跟卖模式中数据采集、批量选品、自动跟卖、订单管理、物流发货等核心业务需求,能够帮助卖家实现店铺自动化、高效化的管理,提升运营效率。一、数据采集跟卖选品的第一步就是要获取到亚马逊在售商品的数......
  • 一款迟到10年的游戏神器,在ToDesk云电脑里复活了
    2015年,索尼推出云游戏,让玩家可以无需购买实体游戏光盘或下载游戏的情况下,通过云端服务器直接畅玩游戏,一度被视为未来游戏界革命性产品的“游戏神器”,但受限于当时的技术和机器,云游戏没有进行更大范围的推广开发。在2024年的今天,随着网络传输速度的提升和技术深度开发,借助国产软......
  • [2106]基于JAVA的渔具进销存智慧管理系统的设计与实现
    毕业设计(论文)开题报告表姓名学院专业班级题目基于JAVA的渔具进销存智慧管理系统的设计与实现指导老师(一)选题的背景和意义开题报告背景与意义:在当前数字化经济时代背景下,各行各业的经营管理活动都在向信息化、智能化转变,以提高效率、降低成本、增强决策科学性。渔具行......
  • 基于java ssm springboot生鲜超市管理系统生鲜商城仓库采购出入库登记(源码+文档+运行
     文章目录系列文章目录目的前言一、详细视频演示二、项目部分实现截图三、技术栈后端框架springboot前端框架vue持久层框架MyBaitsPlus系统测试四、代码参考源码获取目的摘要: 本文介绍了基于JavaSSM和SpringBoot构建的生鲜超市管理系统。该系统在生鲜超市的运......
  • 2024年不同行业都适用的10款项目管理工具推荐,总有一款适合你!
    在当今快节奏的商业环境中,项目管理工具的选择对于项目的成功至关重要。不同的行业和项目类型需要不同的工具来满足其特定的需求。本文将介绍10款适用于不同行业的项目管理工具,帮助您在2024年找到最适合您项目的解决方案。禅道项目管理软件 禅道项目管理软件是一款开源的项......
  • 震惊!推荐一款AI驱动的自动化测试神器:TestCraft
    在当今快速迭代的软件开发环境中,自动化测试已经成为确保软件质量的重要一环。然而,传统的手动录制和编写测试脚本的方式不仅耗时耗力,还难以跟上敏捷开发的节奏。本文将为大家介绍一款基于AI技术的自动化测试工具——TestCraft,它凭借其智能化、易用性和高效性,正逐渐成为测试工程师......
  • AutoHotkey (AHK) 是一款开源的自动化脚本语言,AutoHotkey(AHK)具备广泛的应用场景,适用于
    AutoHotkey(AHK)是一款开源的自动化脚本语言,主要用于Windows平台上的桌面应用程序自动化、键盘鼠标操作模拟、热键设置、窗口管理等任务。它的简单性和强大的灵活性使得AHK成为许多用户进行日常自动化和重复性任务的首选工具。1. AutoHotkey是什么?AutoHotkey是一种脚本......