1 Star 5 Fork 0

AliothLi/Milink

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
贡献代码
同步代码
取消
提示: 由于 Git 不支持空文件夾,创建文件夹后会生成空的 .keep 文件
Loading...
README
MulanPSL-2.0

milinks后台资金管理系统

启动

npm run dev

使用技术

  • express.js:搭建服务器
  • node.js:整个项目的基础
  • mysql2:实现数据库连接
  • passport:生成token
  • passport-jwt:验证token
  • jsonwebtoken:生成token
  • crypto.js:密码的加密和解密
  • concurrently:实现前后端连载
  • element-UI:前台搭建页面的UI框架
  • Vue:前台框架
  • axios:数据请求第三方包
  • jwt-decode:解析后台传过来的token
  • echar:数据可视化

项目展示

  1. 登陆

Snipaste_2022-08-17_17-36-24

  1. 注册

Snipaste_2022-08-17_17-36-31

  1. 后台首页数据面板

Snipaste_2022-08-17_17-35-17

  1. 资金详情

Snipaste_2022-08-17_17-35-27

  1. 个人主页

Snipaste_2022-08-17_17-35-34

项目日志

2022/8/12

搭建node.js服务器,引入express.js,配置package.json

1.安装express.js,搭建服务器

npm i express   

搭建项目入口文件

const express = require('express')
const app = express()

app.listen(5100, () => {
  console.log('express is running at http://127.0.0.1:5100');
})

2. 配置package.json,根据不同的开发环境配置对应的启动命令

  "scripts": {
    "start": "node index.js",
    "serve": "nodemon index.js",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
npm run serve 
npm run start

3.安装body-parser

npm i body-parser

使用body-parser获取前端传送过来的数据 首先第一步引入

const bodyParser = require('body-parser');
//对body-parser进行配置
app.use( bodyParser.urlencoded({extended: true}) )
//设置完毕之后,会在req对象上面新增一个req.body的一个对象

再来说说node后台对这两种请求格式的处理:

首先是最新express版本4.7.2:

4.7.2版本的express没有了bodyParser方法,需要另外安装body-parser模板:于是另外安装了body-parser模板1.5.2版本

使用代码如下:

var express = require('express');
var bodyParser = require('body-parser');
var app = express();

// parse application/x-www-form-urlencoded
app.use(bodyParser.urlencoded({ extended: false }));

// parse application/json
app.use(bodyParser.json());

使用bodyParser.urlencoded(),使node后台支持了第一种请求体. 使用bodyParser.json(),使node后台支持了第二种请求体.

后定义的不会覆盖先定义的… 也就是说,这段代码同时支持了这两种请求体. 另外,虽然请求体的格式不同,但是经过node解析后,他们最终得到的都是json格式的对象.

express4.18.1版本不需要使用这样的方法获取post请求的数据了。 req.body

4.密码加密 bcrypt

  1. 安装
npm i bcrypt

相关参数

const bcrypt = require('bcrypt');
const saltRounds = 10;
const myPlaintextPassword = 's0/\/\P4$$w0rD';
const someOtherPlaintextPassword = 'not_bacon';

使用

const bcrypt = require('bcrypt');

bcrypt.genSalt(saltRounds, function(err, salt) {
    bcrypt.hash(myPlaintextPassword, salt, function(err, hash) {
        // Store hash in your password DB.
    });
});

这块不适用于mysql,如果是mysql加密可以使用crypto

5.头像上传gravatar

  1. 安装
npm i gravatar
  1. 再哪里使用
var gravatar = require('gravatar');

gravatar.url(email);
gravatar.url(email, options);
gravatar.url(email, options, protocol);

gravatar.profile_url(email);
gravatar.profile_url(email, options);
gravatar.profile_url(email, options, protocol);
  1. 例子
var gravatar = require('gravatar');

var url = gravatar.url('emerleite@gmail.com', {s: '200', r: 'pg', d: 'mm'});
//returns //www.gravatar.com/avatar/93e9084aa289b7f1f5e4ab6716a56c3b?s=200&r=pg&d=404

var unsecureUrl = gravatar.url('emerleite@gmail.com', {s: '100', r: 'x', d: 'retro'}, false);
//returns http://www.gravatar.com/avatar/93e9084aa289b7f1f5e4ab6716a56c3b?s=100&r=x&d=retro

var secureUrl = gravatar.url('emerleite@gmail.com', {s: '100', r: 'x', d: 'retro'}, true);
//returns https://s.gravatar.com/avatar/93e9084aa289b7f1f5e4ab6716a56c3b?s=100&r=x&d=retro

var httpUrl = gravatar.url('emerleite@gmail.com', {protocol: 'http', s: '100'});
//returns http://www.gravatar.com/avatar/93e9084aa289b7f1f5e4ab6716a56c3b?s=100

var httpsUrl = gravatar.url('emerleite@gmail.com', {protocol: 'https', s: '100'});
//returns https://s.gravatar.com/avatar/93e9084aa289b7f1f5e4ab6716a56c3b?s=100

var profile1 = gravatar.profile_url('emerleite@gmail.com', {protocol: 'https'});
//returns https://secure.gravatar.com/93e9084aa289b7f1f5e4ab6716a56c3b.json

var profile2 = gravatar.profile_url('emerleite@gmail.com', {protocol: 'http', format:'qr'});
//returns http://www.gravatar.com/93e9084aa289b7f1f5e4ab6716a56c3b.qr
  1. 如何再项目中使用
const gravatar = require('gravatar');

var avatars = gravatar.url(req.body.email, { s: '200', r: 'pg', d: 'mm' });

这样的话它会生成一个网址,只要你的邮箱在www.gravatar.com里注册过的化就会有一个头像

6. 生成Token jwt passport

jsonwebtoken

  1. 安装
npm i jsonwebtoken
  1. 引入
const jwt = require('jsonwebtoken')s
  1. 定义规则
const rule = { id: result[0].id, name: result[0].name }

由于id,和name都是通过数据库获取过来的,所以用的这种方式

  1. 设置jwt.sign方法/生成token
jwt.sign("规则", "加密名字", "过期时间", "箭头函数")
        jwt.sign(rule, key.secretOrkey, { expiresIn: 3600 }, (err, token) => {
          if (err) return err.message
          return res.send({
            code: 1,
            msg: `Bearer ${token}`
          })
        })

这里的rule就是上面所说的校验规则,key.secretOrkey就是加密名字,只不过封装到了外部,expiresIn:3600,就说明是3600秒,msg返回的就是生成的Token

  1. 验证token
// $router get api/user/current
// @desc return current user
// @access private
router.get("/current", "验证Token", (req, res) => {
  res.send({
    code: 1,
    msg: '验证成功'
  })
})

我们需要在"验证Token"那里对Token进行验证

7. 使用passpport-jwt||passport验证Token

passport

passport-jwt

  1. 安装
npm install passport-jwt
npm i passport
  1. 使用

passport

passport.use(new LocalStrategy(
  function(username, password, done) {
    User.findOne({ username: username }, function (err, user) {
      if (err) { return done(err); }
      if (!user) { return done(null, false); }
      if (!user.verifyPassword(password)) { return done(null, false); }
      return done(null, user);
    });
  }
));

这个方法中的User.findOne方法可以删除,写上自己的业务逻辑,我用的是mysql,所以没有用User.findeOne方法

初始化passport

app.use(passport.initialize());

passport-jwt

new JwtStrategy(options, verify)
  1. 实际使用

index.js(项目入口文件)

const passport = require("passport")

//在入口文件中配置和引用
//初始化passport
app.use(passport.initialize());
require("./config/passport")(passport)

这里单独抽离了passport配置文件,同时将上面引入的passprot进行引入

config/passport.js

const db = require("../db/index")
const JwtStrategy = require('passport-jwt').Strategy
const ExtractJwt = require('passport-jwt').ExtractJwt

const key = require("../config/key")
const opts = {}
opts.jwtFromRequest = ExtractJwt.fromAuthHeaderAsBearerToken();
opts.secretOrKey = key.secretOrkey;


module.exports = passport => {
  passport.use(new JwtStrategy(opts, (jwt_payload, done) => {
    // { id: 1, name: 'wz', iat: 1660299838, exp: 1660303438 }
    console.log(jwt_payload);
    sqlcc = `SELECT * FROM user WHERE id=${jwt_payload.id};`
    db.query(sqlcc, (err, result) => {
      console.log(result[0]);
      if (err) {
        return done(null, err.message)
      }
      if (result.length != 0) {
        return done(null, result[0])
      } else {
        return done(null, false)
      }
    })
  }));

}

注意,生成的token应该带有统一的格式。一个正确的token应该是这样的Bearer ${token},注意Bearer和生成的Token之间的空格。

接下来在需要校验的地方验证Token

// $router get api/user/current
// @desc return current user
// @access private
router.get("/current", passport.authenticate("jwt", { session: false }), (req, res) => {
  res.send({
    code: 1,
    msg: req.user
  })
})

注意,在需要使用的路由中,添加第二个参数passport.authenticate("jwt", { session: false }) 验证token如果通过,就会执行passport.use里的方法,同时jwt_jpayload会输出结果,得到结果后,我们在用id在User表中查询数据,然后通过req.user(数据库表名)拿到。

// { id: 1, name: 'wz', iat: 1660299838, exp: 1660303438 }
console.log(jwt_payload);

8. express-jwt || jsonwebtoken生成Token验证Token

  1. 安装
npm install jsonwebtoken express-jwt

注意

jsonwebtoken用于生成JWT字符串

express-jwt用于将Jwt字符串解析为JSON对象

  1. 新建文件夹config/key.js
module.exports = {
  keyOringe: "secret"
}

将设置的key值暴露出去

  1. 在需要的地方引入
const jwt = require("jsonwebtoken")
    if (password == tools.setPassword(results[0].password)) {
      //如果成功,传1,页面跳转交给vue
+      const rule = {
+        id: results[0].id,
+        adminname: results[0].adminname
+      }

+      const tokenstr = jwt.sign(rule, key.keyOringe, { expiresIn: 3600 })
+      res.send({

        code: 1,
        msg: '登陆成功',
+        token: tokenstr
      })
    }
  1. 调用 jwt.sign() 方法生成JWT字符串 并通过 token 属性发送给客户端
  2. 参数1: 用户的信息对象
  3. 参数2: 加密的密钥
  4. 参数3: 配置对象 可以配置当前 token 的有效期
  5. rule只是抽离出去,其实直接写也没问题

在中间件中使用

const { expressjwt: jwt } = require("express-jwt")
const key = require('../config/key')



router.use(jwt({
  secret: key.keyOringe,
  algorithms: ["HS256"],
}).unless({ path: ["/admin/login", "/admin/register"] })
)

之后使用私有接口去访问

//$route GET admin/banner/
//@desc 修改轮播图接口
router.get('/', (req, res) => {
  console.log(req);
  res.send({
    code: 1,
    msg: '获取用户信息成功',
    data: req.auth
  })
})

这样就会返回带有用户信息的Token了!

捕获解析JWT失败后产生的错误

当使用express-jwt解析Token字符串时,如果客户端发送的Token字符串过期不合法,会产生一个解析失败的错误,影响项目的正常运行,可以通过Express的错误中间件,捕获这个错误并且进行相关的处理,示例代码如下:

//在所有路由后面定义错误中间件
//使用全局错误处理中间件 捕获解析 JWT 失败后产生的错误
app.use((err, req, res, next) => {
  //判断是否由 Token 解析失败导致的
  if (err.name == 'UnauthorizedError') {
    return res.send({
      status: 401,
      message: '无效的Token'
    })
  }
  res.send({
    status: 500,
    message: '未知的错误'
  })
})

2022/8/13

1. 完成查询所有profile接口和查询单个profile接口信息

传递单个接口信息使用动态路由传递id,使用req.params获取值

router.get("/query/:id", (req, res) => {
  console.log(req.params);
  const { id } = req.params

  const sqlcc = 'xxx'
  db.query(sqlcc, (err, result) => {
    if (err) {
      return res.send({
        code: 0,
        msg: err.message
      })
    }
    if (result.length == 0) {
      res.send({
        code: 0,
        msg: "查询失败"
      })
    } else {
      res.send({
        code: 1,
        msg: "查询成功",
        data: result
      })
    }

  })
})

2. profile的增加删除和修改

3. 搭建Vue项目

vue create milinku

4. 使用concurrently实现前后端连载

  1. 安装concurrently模块
npm i concurrently
  1. 给Vue项目起一个名字
  "scripts": {
    "serve": "vue-cli-service serve",
    "build": "vue-cli-service build",
    "start": "npm run serve"
  },
  1. 返回到服务端pack.json文件
  "scripts": {
+    "milinku-install": "npm install --prefix milinku",
+    "mulinku": "npm start --prefix milinku",
    "start": "node index.js",
    "serve": "nodemon index.js",
    "test": "echo \"Error: no test specified\" && exit 1",
+    "dev": "concurrently \"npm run serve\" \"npm run mulinku\""
  },
npm install --prefix milinku

这行命令是指定安装依赖包到milinku目录下

npm start --prefix milinku

这行命令是启动指定目录的目录,由于之前在mulinku/package.json中设置了"start": "npm run serve",所以这里其实就是启动了mulinku项目.

使用currently实现连载

"dev": "concurrently \"npm run serve\" \"npm run mulinku\""

其中npm run serve是启动前台,npm run mulinku是启动后台

  1. 目录结构

Snipaste_2022-08-13_23-03-52

2022/8/13

1. vue-router配置404页面

在项目中添加相关样式和相关代码和组件后,引入到vue-router

import NotFound from '@/views/404'
  {
    path: '*',
    name: '/404',
    component: NotFound
  },

这样在匹配不到任何路由的时候就会找到当前的404组件

2. 利用钩子函数自动生成时间

  mounted() {
    let data = new Date();
    Datestr = `${data.getFullYear()}-${data.getMonth() + 1}-${data.getDate()}`;
    this._data.registerUser.date = Datestr;
  },

3.表单提交

    submitForm(formName) {
      this.$refs[formName].validate((valid) => {
        if (valid) {
          alert("submit!");
        } else {
          console.log("error submit!!");
          return false;
        }
      });
    },

注意这里的forName就是表单的ref:ref="ruleForm",这个方法会对表单进行校验.

4.学习Loading动画,在使用axios请求数据时,调用对应的方法添加加载动画

  1. 安装axiox
npm i axios
  1. 在项目入口文件中进行配置
import axios from './config/axios'
Vue.prototype.$axios = axios
  1. 在项目中添加配置文件,添加element-ui的loading插件和Message插件

@/config/axios.js 在该文件中编写代码

import axios from 'axios'
import { Loading,Message } from 'element-ui';
let loading;

function startLoading() {
  loading = Loading.service(
    {
      lock: true,
      text: '拼命加载中...',
      background: 'rgba(0,0,0,.7)'
    }
  );
}
function endLoading() {
  loading.close();
}
//请求拦截
//响应拦截
export default axios

引入加载插件,定义了两个方法,一个用来开启动画,一个用来结束动画,lock:true是锁定页面,用户无法操作.text:加载动画时,显示的文本.background:加载动画时的背景.

  1. 设置动画启动的配置
//请求拦截
axios.interceptors.request.use(config => {
  //加载动画
  startLoading();
  return config;
}, error => {
  return Promise.reject(error);
})
//响应拦截
axios.interceptors.response.use(response => {
  //结束加载动画
  endLoading();
  return response;
}, error => {
  //错误提醒
  endLoading();
  Message.error(error.response.data)
  return Promise.reject(error)
})

这里使用了element-ui的Message模块,用来给用户反馈请求结果

5.Vue前端配置跨域

在vue.config.js里进行配置

  devServer: {
    proxy: {
      //配置跨域
      '/api': {
        target: 'http://127.0.0.1:5100/api/',
        ws: true,
        changOrigin: true,
        pathRewrite: {
          '^/api': ''
        }
      }
    }
  }

6.处理token

拿到后台传过来的token,就先保存到localStorage

localStorage.setItem("milink", msg);

msg里的就是token信息

7.Vue中路由守卫以及token的过期处理

使用localStorage.milink获取token,milink是我们之前设置过的 在router/index.js里进行配置全局路由守卫

//路由守卫
router.beforeEach((to, from, next) => {
  const isLogin = localStorage.milink ? true : false
  if (to.path == '/login' || to.path == '/register') {
    next();
  } else {
    isLogin ? next() : next("/login")
  }
})

这时,如果有名称为milink的token,就可以通过,否则就会重新定向到"/login"路由.

8. 在请求拦截和响应拦截部分进行设置

  1. 在请求拦截这里,我们给设置一下统一的请求头
//请求拦截
axios.interceptors.request.use(config => {
  //加载动画
  startLoading();
+  if (localStorage.milink) {
+    //设置统一的请求头
+    config.headers.Authorization = localStorage.milink
  }

  return config;
}, error => {
  return Promise.reject(error);
})
  1. 在响应拦截里,我们可以对返回的状态码进行判断,如果是401,就说明Token失效了,这时候,我们就可以将token进行清除,同时跳转到登陆页面.
  //获取错误状态码
  const { status } = error.response;
+ if (status == 401) {
+    //token失效
+    Message.error("Token失效,请重新登陆")
+    //清除token
+    localStorage.removeItem('milink');
+    //跳转到登陆页面
+    router.push('/login')
  }

注意:使用router的前提是引入router

9. 解析token,获取用户数据(jwt-decode)

  1. 使用jwt-decode解析token
npm i jwt-decode
  1. 在login.vue里,引入jwt-decode
import jwt from "jwt-decode";
  1. 在存储token后,解析token
const decode = jwt(msg);

输出msg

{
  avatar: "//www.gravatar.com/avatar/bf58432148b643a8b4c41c3901b81d1b?s=200&r=pg&d=mm"
  exp: 1660471454    //生成时间
  iat: 1660467854    //失效时间
  id: 11
  identity: "employee"
  name: "test"
}

10.将解析的数据保存到Vux中

这里设计到了数据的校验,所以可能不太一样. 可以去store/index.js里去看代码

  1. 判断状态值为空的方法
    isEmpty(value) {
      return (
        value == undefined ||
        value == null ||
        (typeof value == "object" && Object.keys(value).length === 0) ||
        (typeof value == "string" && value.trim().length === 0)
      );
    },

这些小方法可以复用,挺灵活

2.将解析出来的值添加到Vuex中

this.$store.dispatch("setAuthenticated", !this.isEmpty(decode));
this.$store.dispatch("setUser", decode);
  1. 解决刷新后vuex里的保存的值丢失的问题 在app.vue里进行判断,如果有这个token,我们就解析,并添加到vuex里.
  created() {
    if (localStorage.milink) {
      const decode = jwt(localStorage.milink);
      this.$store.dispatch("setAuthenticated", !isEmpty(decodethis));
      this.$store.dispatch("setUser", decode);
    }
  },

将该方法挂载到create函数中.

2022/8/15

1. 学习下拉菜单(element-ui)Dropdown

官方文档

2. 完成退出登陆功能

    logout() {
      //清除token
      localStorage.removeItem("milink");
      //设置store
      this.$store.dispatch("clearCurrentState");
      //跳转
      this.$router.push("/login");
    },

清除token,然后设置store,将状态值设置为空。

  • 状态值设置为空的方法,在actions配置清除方法
    clearCurrentState: ({ commit }) => {
      commit(types.SET_AUTHENTICATED, false);
      commit(types.SET_USER, null)
    }

在前台将vuex里的数据清除

3. 学习element-ui的导航栏Navigation

导航栏 导航栏中的数据使用v-for指令渲染到页面上。

2022/8/16

1. 学习表单(element-ui)Dropdown

表单 使用模板表单

  1. 首先要有

  2. 配置表格的列

<el-table-column prop="type" label="收支类型" width="150"> </el-table-column>

注意这里prop属性,对应的是请求回来数据的属性名,这样才能显示出来。

  1. 从后台接口拿数据,使用axios,由于在main.js对该axios进行了封装,所有每个vue组件都可以使用this.$axios发起请求。
    getProfile() {
      this.$axios
        .get("/api/profile/query")
        .then((res) => {
          this.tableData = res.data.data;
          console.log(res);
        })
        .catch((err) => {
          console.log(err);
        });
    },

将数据保存到tableData[]

2. 学会了如何在表格中使用模板

  1. 例子
<el-table-column prop="date" label="创建时间" width="250">
  <template slot-scope="scope">
    <i class="el-icon-time"></i>
    <span style="margin-left: 10px; color: #f56767;">{{ scope.row.date }}</span>
  </template>
</el-table-column>

在该案例中,我们可以根据自己的需要指定相关模板,这里就设置了字体图标,同时通过style可以设置对应的颜色。

  • 效果

element-ui表格模版使用效果

3. 学会使用面包屑来美化页面

<el-breadcrumb separator-class="el-icon-arrow-right">
  <el-breadcrumb-item :to="{ path: '/index/home' }"
    >首页</el-breadcrumb-item
  >
  <el-breadcrumb-item>资金管理</el-breadcrumb-item>
  <el-breadcrumb-item>资金流水</el-breadcrumb-item>
</el-breadcrumb>

同时可以配置跳转路由,都可以去element-ui上去找到这些配置

4. 学习使用Dialog 对话框在点击添加按钮时触发

dialog

<el-dialog
  title="添加订单"
  :visible.sync="dialogVisible.show"
  width="30%"
  :close-on-click-modal="false"
  :before-close="handleClose"
>
//表单内容
</el-dialog>


props: {
  dialogVisible: Object,
},

参数的话我们定义为Object类型,同时在父组件Fundlist.vue中,将其引入并注册,同时将值传入当前组件中,从而达到显示于隐藏效果。

  • Fundlist.vue
<Dialog :dialogVisible="dialog"></Dialog>


data() {
  return {
    dialog: {
      show: false,
    },
  };
},

5. 学习如何让表格重载

描述,也就是说在添加成功后,让表单自动刷新一次。

子组件中使用自定义事件,让父组件中的方法去执行.

  • 子组件
//自定义事件,让表单重新刷新
this.$emit("update");
  • 父组件
<Dialog :dialogVisible="dialog" @update="getProfile"></Dialog>

执行指定方法,从而让表单刷新。

5. 要学会组件复用,就比如添加和修改组件

这里在父组件中传递过相关参数后,子组件根据不同的选项进行渲染,主要体现在两方面。

  1. 标题
  2. axios发起路径的请求

6. 学会表格分页

element

<el-pagination
  @size-change="handleSizeChange"
  @current-change="handleCurrentChange"
  :current-page="currentPage4"
  :page-sizes="[100, 200, 300, 400]"
  :page-size="100"
  layout="total, sizes, prev, pager, next, jumper"
  :total="400">
</el-pagination>

这里的写死的参数都可以在data里定义后传上去的。有两个方法:handleSizeChange,handleCurrentChange

  • 思路 这里定义了一个变量用来保存分页数据allTableData,我们在allTableData中使用filter方法过滤数据后,赋给TableData在表格中渲染出来。

2022/8/17

1. 添加数据可视化,美化页面

想要让数据显示出来,1.设置盒子宽度高度.2.给数据。

木兰宽松许可证, 第2版 木兰宽松许可证, 第2版 2020年1月 http://license.coscl.org.cn/MulanPSL2 您对“软件”的复制、使用、修改及分发受木兰宽松许可证,第2版(“本许可证”)的如下条款的约束: 0. 定义 “软件”是指由“贡献”构成的许可在“本许可证”下的程序和相关文档的集合。 “贡献”是指由任一“贡献者”许可在“本许可证”下的受版权法保护的作品。 “贡献者”是指将受版权法保护的作品许可在“本许可证”下的自然人或“法人实体”。 “法人实体”是指提交贡献的机构及其“关联实体”。 “关联实体”是指,对“本许可证”下的行为方而言,控制、受控制或与其共同受控制的机构,此处的控制是指有受控方或共同受控方至少50%直接或间接的投票权、资金或其他有价证券。 1. 授予版权许可 每个“贡献者”根据“本许可证”授予您永久性的、全球性的、免费的、非独占的、不可撤销的版权许可,您可以复制、使用、修改、分发其“贡献”,不论修改与否。 2. 授予专利许可 每个“贡献者”根据“本许可证”授予您永久性的、全球性的、免费的、非独占的、不可撤销的(根据本条规定撤销除外)专利许可,供您制造、委托制造、使用、许诺销售、销售、进口其“贡献”或以其他方式转移其“贡献”。前述专利许可仅限于“贡献者”现在或将来拥有或控制的其“贡献”本身或其“贡献”与许可“贡献”时的“软件”结合而将必然会侵犯的专利权利要求,不包括对“贡献”的修改或包含“贡献”的其他结合。如果您或您的“关联实体”直接或间接地,就“软件”或其中的“贡献”对任何人发起专利侵权诉讼(包括反诉或交叉诉讼)或其他专利维权行动,指控其侵犯专利权,则“本许可证”授予您对“软件”的专利许可自您提起诉讼或发起维权行动之日终止。 3. 无商标许可 “本许可证”不提供对“贡献者”的商品名称、商标、服务标志或产品名称的商标许可,但您为满足第4条规定的声明义务而必须使用除外。 4. 分发限制 您可以在任何媒介中将“软件”以源程序形式或可执行形式重新分发,不论修改与否,但您必须向接收者提供“本许可证”的副本,并保留“软件”中的版权、商标、专利及免责声明。 5. 免责声明与责任限制 “软件”及其中的“贡献”在提供时不带任何明示或默示的担保。在任何情况下,“贡献者”或版权所有者不对任何人因使用“软件”或其中的“贡献”而引发的任何直接或间接损失承担责任,不论因何种原因导致或者基于何种法律理论,即使其曾被建议有此种损失的可能性。 6. 语言 “本许可证”以中英文双语表述,中英文版本具有同等法律效力。如果中英文版本存在任何冲突不一致,以中文版为准。 条款结束 如何将木兰宽松许可证,第2版,应用到您的软件 如果您希望将木兰宽松许可证,第2版,应用到您的新软件,为了方便接收者查阅,建议您完成如下三步: 1, 请您补充如下声明中的空白,包括软件名、软件的首次发表年份以及您作为版权人的名字; 2, 请您在软件包的一级目录下创建以“LICENSE”为名的文件,将整个许可证文本放入该文件中; 3, 请将如下声明文本放入每个源文件的头部注释中。 Copyright (c) [Year] [name of copyright holder] [Software Name] is licensed under Mulan PSL v2. You can use this software according to the terms and conditions of the Mulan PSL v2. You may obtain a copy of Mulan PSL v2 at: http://license.coscl.org.cn/MulanPSL2 THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. See the Mulan PSL v2 for more details. Mulan Permissive Software License,Version 2 Mulan Permissive Software License,Version 2 (Mulan PSL v2) January 2020 http://license.coscl.org.cn/MulanPSL2 Your reproduction, use, modification and distribution of the Software shall be subject to Mulan PSL v2 (this License) with the following terms and conditions: 0. Definition Software means the program and related documents which are licensed under this License and comprise all Contribution(s). Contribution means the copyrightable work licensed by a particular Contributor under this License. Contributor means the Individual or Legal Entity who licenses its copyrightable work under this License. Legal Entity means the entity making a Contribution and all its Affiliates. Affiliates means entities that control, are controlled by, or are under common control with the acting entity under this License, ‘control’ means direct or indirect ownership of at least fifty percent (50%) of the voting power, capital or other securities of controlled or commonly controlled entity. 1. Grant of Copyright License Subject to the terms and conditions of this License, each Contributor hereby grants to you a perpetual, worldwide, royalty-free, non-exclusive, irrevocable copyright license to reproduce, use, modify, or distribute its Contribution, with modification or not. 2. Grant of Patent License Subject to the terms and conditions of this License, each Contributor hereby grants to you a perpetual, worldwide, royalty-free, non-exclusive, irrevocable (except for revocation under this Section) patent license to make, have made, use, offer for sale, sell, import or otherwise transfer its Contribution, where such patent license is only limited to the patent claims owned or controlled by such Contributor now or in future which will be necessarily infringed by its Contribution alone, or by combination of the Contribution with the Software to which the Contribution was contributed. The patent license shall not apply to any modification of the Contribution, and any other combination which includes the Contribution. If you or your Affiliates directly or indirectly institute patent litigation (including a cross claim or counterclaim in a litigation) or other patent enforcement activities against any individual or entity by alleging that the Software or any Contribution in it infringes patents, then any patent license granted to you under this License for the Software shall terminate as of the date such litigation or activity is filed or taken. 3. No Trademark License No trademark license is granted to use the trade names, trademarks, service marks, or product names of Contributor, except as required to fulfill notice requirements in Section 4. 4. Distribution Restriction You may distribute the Software in any medium with or without modification, whether in source or executable forms, provided that you provide recipients with a copy of this License and retain copyright, patent, trademark and disclaimer statements in the Software. 5. Disclaimer of Warranty and Limitation of Liability THE SOFTWARE AND CONTRIBUTION IN IT ARE PROVIDED WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED. IN NO EVENT SHALL ANY CONTRIBUTOR OR COPYRIGHT HOLDER BE LIABLE TO YOU FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO ANY DIRECT, OR INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES ARISING FROM YOUR USE OR INABILITY TO USE THE SOFTWARE OR THE CONTRIBUTION IN IT, NO MATTER HOW IT’S CAUSED OR BASED ON WHICH LEGAL THEORY, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 6. Language THIS LICENSE IS WRITTEN IN BOTH CHINESE AND ENGLISH, AND THE CHINESE VERSION AND ENGLISH VERSION SHALL HAVE THE SAME LEGAL EFFECT. IN THE CASE OF DIVERGENCE BETWEEN THE CHINESE AND ENGLISH VERSIONS, THE CHINESE VERSION SHALL PREVAIL. END OF THE TERMS AND CONDITIONS How to Apply the Mulan Permissive Software License,Version 2 (Mulan PSL v2) to Your Software To apply the Mulan PSL v2 to your work, for easy identification by recipients, you are suggested to complete following three steps: i Fill in the blanks in following statement, including insert your software name, the year of the first publication of your software, and your name identified as the copyright owner; ii Create a file named “LICENSE” which contains the whole context of this License in the first directory of your software package; iii Attach the statement to the appropriate annotated syntax at the beginning of each source file. Copyright (c) [Year] [name of copyright holder] [Software Name] is licensed under Mulan PSL v2. You can use this software according to the terms and conditions of the Mulan PSL v2. You may obtain a copy of Mulan PSL v2 at: http://license.coscl.org.cn/MulanPSL2 THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. See the Mulan PSL v2 for more details.

简介

milink银行后端管理系统:基于vue2/Element-ui/echarts/node.js(express)/mysql搭建/echarts 展开 收起
Vue 等 4 种语言
MulanPSL-2.0
取消

发行版 (1)

全部

贡献者

全部

近期动态

加载更多
不能加载更多了
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
1
https://gitee.com/super_li_yu/milink.git
git@gitee.com:super_li_yu/milink.git
super_li_yu
milink
Milink
master

搜索帮助

A270a887 8829481 3d7a4017 8829481