├── .idea ├── .gitignore ├── MessageWall.iml ├── inspectionProfiles │ └── Project_Default.xml ├── modules.xml └── vcs.xml ├── API ├── app.js ├── config │ ├── default.js │ └── wall.sql ├── controller │ └── dbServe.js ├── lib │ └── db.js ├── package-lock.json ├── package.json └── routes │ ├── files.js │ └── index.js ├── README.md └── Web ├── .gitignore ├── index.html ├── package-lock.json ├── package.json ├── public └── favicon.ico ├── src ├── App.vue ├── assets │ ├── api │ │ └── index.js │ ├── fonts │ │ └── icon │ │ │ ├── demo.css │ │ │ ├── demo_index.html │ │ │ ├── iconfont.css │ │ │ ├── iconfont.js │ │ │ ├── iconfont.json │ │ │ ├── iconfont.ttf │ │ │ ├── iconfont.woff │ │ │ └── iconfont.woff2 │ ├── images │ │ ├── card.svg │ │ ├── favicon.ico │ │ ├── favicon.svg │ │ ├── loading.json │ │ ├── photo.svg │ │ └── qm1.mp4 │ ├── router │ │ └── index.js │ ├── store │ │ └── index.js │ ├── styles │ │ ├── common.css │ │ └── common.less │ ├── utils │ │ ├── axios.js │ │ ├── data.js │ │ ├── env.js │ │ └── methods.js │ └── views │ │ ├── WallMessage.vue │ │ └── index.vue ├── components │ ├── KMR │ │ ├── index.js │ │ └── message │ │ │ ├── IMessage.vue │ │ │ └── message.js │ ├── mobile │ │ ├── CardDetail.vue │ │ ├── IModal.vue │ │ ├── Ibutton.vue │ │ ├── NewCard.vue │ │ ├── NodeCard.vue │ │ ├── PhotoCard.vue │ │ ├── TopBar.vue │ │ ├── WallMessage.vue │ │ └── index.vue │ └── pc │ │ ├── CardDetail.vue │ │ ├── FootBar.vue │ │ ├── IModal.vue │ │ ├── Ibutton.vue │ │ ├── NewCard.vue │ │ ├── NodeCard.vue │ │ ├── PhotoCard.vue │ │ ├── TopBar.vue │ │ └── Viewer.vue └── main.js └── vite.config.js /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # 默认忽略的文件 2 | /shelf/ 3 | /workspace.xml 4 | # 基于编辑器的 HTTP 客户端请求 5 | /httpRequests/ 6 | # Datasource local storage ignored files 7 | /dataSources/ 8 | /dataSources.local.xml 9 | -------------------------------------------------------------------------------- /.idea/MessageWall.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.idea/inspectionProfiles/Project_Default.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 73 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /API/app.js: -------------------------------------------------------------------------------- 1 | const express = require('express') 2 | const path = require('path') 3 | const ejs = require('ejs') 4 | const config = require('./config/default') 5 | const router = require('./routes/files') 6 | const routerApi = require('./routes/index') 7 | const app = express() 8 | const fs = require('fs') 9 | // 递归创建路径 10 | const mkdirs = (dirpath) => { 11 | console.log(path.dirname(dirpath)) 12 | if (!fs.existsSync(path.dirname(dirpath))) { 13 | mkdirs(path.dirname(dirpath)) 14 | } 15 | fs.mkdirSync(dirpath) 16 | console.log('路径创建成功') 17 | } 18 | var img_dir = path.join(__dirname, './assets/wallimgs/') 19 | fs.existsSync(img_dir) == false ? mkdirs(img_dir) : console.log('路径已经存在') 20 | app.use('/assets/wallimgs',express.static(path.join(__dirname,'./assets/wallimgs'))) 21 | //配置跨域 22 | app.all('*',(req,res,next) => { 23 | res.header('Access-Control-Allow-Origin','*') 24 | res.header('Access-Control-Allow-Headers','Origin, X-Requested-With, Content-Type, Accept') 25 | res.header('Access-Control-Allow-Credentials',true) 26 | res.header('Access-Control-Allow-Methods','PUT,POST,GET,DELETE,OPTIONS') 27 | 28 | //返回json 29 | res.header('Content-Type','application/json;charset=utf-8') 30 | if(req.method == 'OPTIONS'){ 31 | //让options请求快速返回 32 | res.sendStatus(200) 33 | }else{ 34 | next() 35 | } 36 | }) 37 | 38 | 39 | //加入html视图 40 | app.engine('html',ejs.__express) 41 | app.set('view engine','html') 42 | 43 | //解析前端数据 44 | app.use(express.json()) 45 | app.use(express.urlencoded({ extended : true })) 46 | //引入路由 47 | app.use('/walls',routerApi) 48 | app.use('/walls',router) 49 | // require('./routes/files')(app) 50 | app.listen(config.port,() => { 51 | console.log(`我启动了端口${config.port}`) 52 | }) -------------------------------------------------------------------------------- /API/config/default.js: -------------------------------------------------------------------------------- 1 | const config = { 2 | //node程序启动端口 3 | port : 3000, 4 | database : { 5 | HOST : '',//数据库地址 6 | USER : '',//数据库用户名 7 | PASSWORD : '',//数据库密码 8 | WALL : ''//数据库表名 9 | } 10 | } 11 | module.exports = config -------------------------------------------------------------------------------- /API/config/wall.sql: -------------------------------------------------------------------------------- 1 | /* 2 | Navicat Premium Data Transfer 3 | 4 | Source Server : 苦苦的码人 5 | Source Server Type : MySQL 6 | Source Server Version : 80024 7 | Source Host : 111.180.204.169:3306 8 | Source Schema : wall 9 | 10 | Target Server Type : MySQL 11 | Target Server Version : 80024 12 | File Encoding : 65001 13 | 14 | Date: 05/02/2023 15:06:38 15 | */ 16 | 17 | SET NAMES utf8mb4; 18 | SET FOREIGN_KEY_CHECKS = 0; 19 | 20 | -- ---------------------------- 21 | -- Table structure for comments 22 | -- ---------------------------- 23 | DROP TABLE IF EXISTS `comments`; 24 | CREATE TABLE `comments` ( 25 | `id` int NOT NULL AUTO_INCREMENT, 26 | `wallId` int NOT NULL COMMENT '墙留言ID', 27 | `userId` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '评论者ID', 28 | `imgurl` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '头像路径', 29 | `comment` varchar(1000) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '评论内容', 30 | `name` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '用户名', 31 | `moment` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '时间', 32 | PRIMARY KEY (`id`) USING BTREE 33 | ) ENGINE = InnoDB AUTO_INCREMENT = 9 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; 34 | 35 | -- ---------------------------- 36 | -- Table structure for feedbacks 37 | -- ---------------------------- 38 | DROP TABLE IF EXISTS `feedbacks`; 39 | CREATE TABLE `feedbacks` ( 40 | `id` int NOT NULL AUTO_INCREMENT, 41 | `wallId` int NOT NULL COMMENT '墙留言ID', 42 | `userId` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '反馈者ID', 43 | `type` int NOT NULL COMMENT '反馈类型0喜欢1举报2撤销', 44 | `moment` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '时间', 45 | PRIMARY KEY (`id`) USING BTREE 46 | ) ENGINE = InnoDB AUTO_INCREMENT = 114 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; 47 | 48 | -- ---------------------------- 49 | -- Table structure for walls 50 | -- ---------------------------- 51 | DROP TABLE IF EXISTS `walls`; 52 | CREATE TABLE `walls` ( 53 | `id` int NOT NULL AUTO_INCREMENT, 54 | `type` int NOT NULL COMMENT '类型0信息1图片', 55 | `message` varchar(1000) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '留言', 56 | `name` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '用户名', 57 | `userId` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '创建者ID', 58 | `moment` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '时间', 59 | `label` int NOT NULL COMMENT '标签', 60 | `color` int NULL DEFAULT NULL COMMENT '颜色', 61 | `imgurl` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '图片路径', 62 | PRIMARY KEY (`id`) USING BTREE 63 | ) ENGINE = InnoDB AUTO_INCREMENT = 84 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; 64 | 65 | SET FOREIGN_KEY_CHECKS = 1; 66 | -------------------------------------------------------------------------------- /API/controller/dbServe.js: -------------------------------------------------------------------------------- 1 | 2 | const dbModel = require('../lib/db') 3 | //新建walls 4 | exports.insertWall = async (req,res) =>{ 5 | let data = req.body 6 | await dbModel.insertWall([data.type,data.message,data.name,data.userId,data.moment,data.label,data.color,data.imgurl]) 7 | .then(result => { 8 | res.send({ 9 | code : 200, 10 | message : result 11 | }) 12 | }) 13 | } 14 | //新建反馈 15 | exports.insertFeedback = async (req,res) =>{ 16 | let data = req.body 17 | await dbModel.insertFeedback([data.wallId,data.userId,data.type,data.moment]) 18 | .then(result => { 19 | res.send({ 20 | code : 200, 21 | message : result 22 | }) 23 | }) 24 | } 25 | //新建评论 26 | exports.insertComment = async (req,res) =>{ 27 | let data = req.body 28 | await dbModel.insertComment([data.wallId,data.userId,data.imgurl,data.moment,data.comment,data.name]) 29 | .then(result => { 30 | res.send({ 31 | code : 200, 32 | message : result 33 | }) 34 | }) 35 | } 36 | //删除墙 37 | exports.deleteWall = async(req,res) => { 38 | let data = req.body 39 | // if(data.imgurl){ 40 | 41 | // } 42 | await dbModel.deleteWall(data.id).then(result=>{ 43 | res.send({ 44 | code : 200, 45 | message : result 46 | }) 47 | }) 48 | } 49 | //删除反馈 50 | exports.deleteFeedback = async(req,res) => { 51 | let data = req.body 52 | await dbModel.deleteFeedback(data.id).then(result=>{ 53 | res.send({ 54 | code : 200, 55 | message : result 56 | }) 57 | }) 58 | } 59 | //删除评论 60 | exports.deleteComment = async(req,res) => { 61 | let data = req.body 62 | await dbModel.deleteComment(data.id).then(result=>{ 63 | res.send({ 64 | code : 200, 65 | message : result 66 | }) 67 | }) 68 | } 69 | //分页查询wall并获取赞、举报、撤销数据 70 | exports.findWallPage = async(req,res) => { 71 | let data = req.body 72 | await dbModel.findWallPage(data.page,data.pagesize,data.type,data.label) 73 | .then(async result=>{ 74 | for(let i = 0;i < result.length;i++){ 75 | //查找相应wall的赞、举报、撤销数据 76 | //喜欢 77 | result[i].like = await dbModel.feedbackCount(result[i].id,0) 78 | //举报 79 | result[i].report = await dbModel.feedbackCount(result[i].id,1) 80 | //撤销 81 | result[i].revoke = await dbModel.feedbackCount(result[i].id,2) 82 | //是否点赞 83 | result[i].islike = await dbModel.likeCount(result[i].id,data.userId) 84 | //评论数 85 | result[i].comcount = await dbModel.commentCount(result[i].id) 86 | } 87 | res.send({ 88 | code : 200, 89 | message : result 90 | }) 91 | }) 92 | } 93 | // 倒序分页查询墙的评论 94 | exports.findCommentPage = async(req,res) => { 95 | let data = req.body 96 | await dbModel.findCommentPage(data.page,data.pagesize,data.id). 97 | then(result=>{ 98 | res.send({ 99 | code : 200, 100 | message : result 101 | }) 102 | }) 103 | } -------------------------------------------------------------------------------- /API/lib/db.js: -------------------------------------------------------------------------------- 1 | const mysql = require('mysql') 2 | const config = require('../config/default') 3 | const db = mysql.createConnection({ 4 | host: config.database.HOST, 5 | user: config.database.USER, 6 | password: config.database.PASSWORD, 7 | port: 3306 8 | }) 9 | //链接指定数据库 10 | const pool = mysql.createPool({ 11 | host: config.database.HOST, 12 | user: config.database.USER, 13 | password: config.database.PASSWORD, 14 | database: config.database.WALL, 15 | port: 3306 16 | }) 17 | //直接使用 18 | let bdbs = (sql, values) => { 19 | return new Promise((resolve, reject) => { 20 | db.query(sql, values, (err, res) => { 21 | if (err) { 22 | reject(err) 23 | 24 | } else { 25 | resolve(res) 26 | } 27 | }) 28 | }) 29 | } 30 | //通过pool.getConnection获取链接 31 | let query = (sql, values) => { 32 | return new Promise((resolve, reject) => { 33 | pool.getConnection((err, connection) => { 34 | if (err) { 35 | reject(err) 36 | } else { 37 | connection.query(sql, values, (err, res) => { 38 | if (err) { 39 | reject(err) 40 | } else { 41 | resolve(res) 42 | } 43 | //释放链接 44 | connection.release() 45 | }) 46 | } 47 | }) 48 | }) 49 | } 50 | 51 | //创建数据库 52 | let WALL = 'create database if not exists WALL default charset utf8 collate utf8_general_ci;' 53 | let createDatabase = (db) => { 54 | return bdbs(db, []) 55 | } 56 | 57 | //创建数据表 58 | //留言/照片 59 | let walls = `create table if not exists walls( 60 | id INT NOT NULL AUTO_INCREMENT, 61 | type INT NOT NULL COMMENT '类型0信息1图片', 62 | message VARCHAR(1000) COMMENT '留言', 63 | name VARCHAR(100) NOT NULL COMMENT '用户名', 64 | userId VARCHAR(100) NOT NULL COMMENT '创建者ID', 65 | moment VARCHAR(100) NOT NULL COMMENT '时间', 66 | label INT NOT NULL COMMENT "标签", 67 | color INT COMMENT '颜色', 68 | imgurl VARCHAR(100) COMMENT '图片路径', 69 | PRIMARY KEY ( id ) 70 | );` 71 | //留言反馈 72 | let feedbacks = `create table if not exists feedbacks(id INT NOT NULL AUTO_INCREMENT,wallId INT NOT NULL COMMENT '墙留言ID',userId VARCHAR(100) NOT NULL COMMENT '反馈者ID',type INT NOT NULL COMMENT '反馈类型0喜欢1举报2撤销',moment VARCHAR(100) NOT NULL COMMENT '时间',PRIMARY KEY ( id ) 73 | );` 74 | //评论 75 | let comments = `create table if not exists comments(id INT NOT NULL AUTO_INCREMENT, 76 | wallId INT NOT NULL COMMENT '墙留言ID', 77 | userId VARCHAR(100) NOT NULL COMMENT '评论者ID', 78 | imgurl VARCHAR(100) COMMENT '头像路径', 79 | comment VARCHAR(1000) COMMENT '评论内容', 80 | name VARCHAR(100) NOT NULL COMMENT '用户名', 81 | moment VARCHAR(100) NOT NULL COMMENT '时间', 82 | PRIMARY KEY ( id ) 83 | );` 84 | let createTable = (sql) => { 85 | return query(sql, []) 86 | } 87 | //先创建数据库 再创建表 88 | async function create() { 89 | await createDatabase(WALL) 90 | createTable(walls) 91 | createTable(feedbacks) 92 | createTable(comments) 93 | } 94 | create() 95 | 96 | //新建wall 97 | exports.insertWall = (value) => { 98 | let _sql = 'insert into walls set type=?,message=?,name=?,userId=?,moment=?,label=?,color=?,imgurl=?' 99 | return query(_sql, value) 100 | } 101 | //新增反馈 102 | exports.insertFeedback = (value) => { 103 | let _sql = 'insert feedbacks set wallId=?,userId=?,type=?,moment=?;' 104 | return query(_sql, value) 105 | } 106 | //新增评论 107 | exports.insertComment = (value) => { 108 | let _sql = 'insert comments set wallId=?,userId=?,imgurl=?,moment=?,comment=?,name=?;' 109 | return query(_sql, value) 110 | } 111 | //删除墙,主表对应多条子表一起删除 112 | exports.deleteWall = (id) => { 113 | let _sql = `delete a,b,c from walls a left join feedbacks b on a.id = b.wallId left join comments c on a.id = c.wallId where a.id='${id}'` 114 | return query(_sql) 115 | } 116 | //删除反馈 117 | exports.deleteFeedback = (id) => { 118 | let _sql = `delete from feedbacks where id = '${id}';` 119 | return query(_sql) 120 | } 121 | //删除评论 122 | exports.deleteFeedback = (id) => { 123 | let _sql = `delete from comments where id = '${id}';` 124 | return query(_sql) 125 | } 126 | //分页查询墙 127 | exports.findWallPage = (page, pagesize, type, label) => { 128 | let _sql; 129 | if (label == -1) { 130 | _sql = `select * from walls where type = ${type} order by id desc limit ${(page - 1) * pagesize}, ${pagesize};` 131 | } else { 132 | _sql = `select * from walls where type = ${type} and label='${label}' order by id desc limit ${(page - 1) * pagesize}, ${pagesize};` 133 | } 134 | return query(_sql) 135 | } 136 | //倒序分页查墙的评论 137 | exports.findCommentPage = (page, pagesize, id) => { 138 | let _sql = `select * from comments where wallId = '${id}' order by id desc limit ${(page - 1) * pagesize}, ${pagesize};` 139 | return query(_sql) 140 | } 141 | //查询各反馈总数据 142 | exports.feedbackCount = (wid, type) => { 143 | let _sql = `select count(*) as count from feedbacks where wallId = '${wid}' and type = '${type}';` 144 | return query(_sql) 145 | } 146 | //查询评论总数 147 | exports.commentCount = (wid) => { 148 | let _sql = `select count(*) as count from comments where wallId = '${wid}';` 149 | return query(_sql) 150 | } 151 | //查询点赞 152 | exports.likeCount = (wid, uid) => { 153 | let _sql = ` select count(*) as count from feedbacks where wallId ='${wid}' and userId='${uid}' and type=0;` 154 | return query(_sql) 155 | } -------------------------------------------------------------------------------- /API/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "cors": "^2.8.5", 4 | "ejs": "^3.1.8", 5 | "express": "^4.18.2", 6 | "multer": "^1.4.5-lts.1", 7 | "mysql": "^2.18.1" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /API/routes/files.js: -------------------------------------------------------------------------------- 1 | const multer = require('multer') 2 | const express = require('express') 3 | const router = express.Router() 4 | //生成随机数 5 | const random = (min,max) => { 6 | return Math.floor(Math.random()*(max-min)) + min; 7 | } 8 | const storage = multer.diskStorage({ 9 | //保存路径 10 | destination : function(req,file,cb){ 11 | cb(null,'./assets/wallimgs') 12 | //不是相对路径 13 | }, 14 | filename : (req,file,cb) => { 15 | //正则匹配后缀名 16 | let type = file.originalname.replace(/.+\./,'.') 17 | cb(null,Date.now() + random(1,100) + type) 18 | } 19 | }) 20 | const upload = multer({storage : storage }) 21 | router.post('/profile',upload.single('file'),(req,res)=>{ 22 | let imgurl = `/assets/wallimgs/${req.file.filename}` 23 | res.send(imgurl) 24 | }) 25 | 26 | module.exports = router -------------------------------------------------------------------------------- /API/routes/index.js: -------------------------------------------------------------------------------- 1 | const controller = require('../controller/dbServe') 2 | const express = require('express') 3 | const router = express.Router() 4 | router.get('/test',(req,res) => { 5 | res.type('html') 6 | res.render('test') 7 | }) 8 | //新建数据 9 | router.post('/insertwall',(req,res)=>{ 10 | controller.insertWall(req,res) 11 | }) 12 | //新建反馈 13 | router.post('/insertfeedback',(req,res)=>{ 14 | controller.insertFeedback(req,res) 15 | }) 16 | //新建评论 17 | router.post('/insertcomment',(req,res)=>{ 18 | controller.insertComment(req,res) 19 | }) 20 | //删除墙 21 | router.post('/deletewall',(req,res)=>{ 22 | controller.deleteWall(req,res) 23 | }) 24 | //删除反馈 25 | router.post('/deletefeedback',(req,res)=>{ 26 | controller.deleteFeedback(req,res) 27 | }) 28 | //删除评论 29 | router.post('/deletecomment',(req,res)=>{ 30 | controller.deleteComment(req,res) 31 | }) 32 | //分页查询wall并获取赞、举报、撤销数据 33 | router.post('/findwallpage',(req,res)=>{ 34 | controller.findWallPage(req,res) 35 | }) 36 | // 倒序分页查询墙的评论 37 | router.post('/findcommentpage',(req,res)=>{ 38 | controller.findCommentPage(req,res) 39 | }) 40 | 41 | //查询IP 42 | router.post('/signip',(req,res)=>{ 43 | var ip = req.ip 44 | res.send({ 45 | code : 200, 46 | ip : ip 47 | }) 48 | }) 49 | module.exports = router -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 留言墙 2 | 本留言墙来源自B站UP主yike陈,分为留言墙与照片墙两部分 3 | [视频链接](https://www.bilibili.com/video/BV11t4y157L2/?spm_id_from=333.999.0.0&vd_source=290b6b566a6de4759a1517c89cdae2c8) 4 | 5 | **Web文件夹为前端,API文件夹为后端,前端配置文件位置为:src/assets/utils/env.js,后端配置文件位置为:config/default.js,并且需要导入相关sql文件,与配置反向代理** 6 | 7 | 8 | **由于本项目后端使用Nodejs编写,请在Web/src/assets/utils/env.js中修改后端API地址,其中的avatarUrl为留言墙右上方小图标** 9 | 10 | - 本项目采用前后端分离方式编写,前端使用Vue3改写,后端使用Nodejs编写 11 | - 本项目改写自B站UP主**yike陈**,并在其视频基础上增添移动端与适当改写 12 | - 如果喜欢该项目就给个Star吧! 13 | 14 | ## 部署教程 15 | ### 后端 16 | - 将后端文件导入网站,使用npm install命令安装模块 17 | ![导入后端文件](https://img.5i21.cn/LightPicture/2023/07/0bea3485c3077674.png) 18 | ![Alt text](https://img.5i21.cn/LightPicture/2023/07/00959330117886b2.png) 19 | - 将config文件夹中的walls数据库文件导入后端数据库 20 | ![导入数据库](https://img.5i21.cn/LightPicture/2023/07/181b36b753e22058.png) 21 | - 之后配置反向代理(防火墙放行) 22 | ![配置反向代理,端口取决于config里面port参数](https://img.5i21.cn/LightPicture/2023/07/729a876ea023dfce.png) 23 | - 之后使用pm2持久化运行 24 | ![持久化运行](https://img.5i21.cn/LightPicture/2023/07/0e34b01e6645ec0a.png) 25 | 26 | ## 前端 27 | - 首先npm install安装相关包,之后修改env.js文件的baseUrl与baseImgPath为后端API地址、avatarUrl为头像地址 28 | ![安装相关包](https://img.5i21.cn/LightPicture/2023/07/c506983796661f2d.png) 29 | - 之后npm run build构建后直接上传服务器即可使用 30 | 31 | ## 项目地址 32 | **Demo地址:[一刻时空-苦苦的码人](https://wall.5i21.cn/)** 33 | ## 项目截图 34 | ### PC端 35 | ![留言墙](https://img.5i21.cn/LightPicture/2023/02/ec3624a0132679e9.png) 36 | ![照片墙](https://img.5i21.cn/LightPicture/2023/02/55b4a4c6aaa6d16f.png) 37 | ![添加留言](https://img.5i21.cn/LightPicture/2023/02/12c70efe9cf0484d.png) 38 | ![添加图片](https://img.5i21.cn/LightPicture/2023/02/686af7a16b47f9de.png) 39 | 40 | ### 移动端 41 | ![留言墙](https://img.5i21.cn/LightPicture/2023/02/f6038a02f914de92.png) 42 | ![照片墙](https://img.5i21.cn/LightPicture/2023/02/9fdfc73c8e65ba6c.png) 43 | -------------------------------------------------------------------------------- /Web/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /Web/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 一刻时光-苦苦的码人 8 | 9 | 10 |
11 | 12 | 13 | 14 | 16 | -------------------------------------------------------------------------------- /Web/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "web", 3 | "private": true, 4 | "version": "0.0.0", 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite", 8 | "build": "vite build", 9 | "preview": "vite preview" 10 | }, 11 | "dependencies": { 12 | "axios": "^1.2.2", 13 | "less": "^4.1.3", 14 | "less-loader": "^11.1.0", 15 | "lottie-web": "^5.10.1", 16 | "mockjs": "^1.1.0", 17 | "vue": "^3.2.45", 18 | "vue-axios": "^3.5.2", 19 | "vue-router": "^4.1.6", 20 | "vuex": "^4.0.2" 21 | }, 22 | "devDependencies": { 23 | "@types/node": "^18.11.18", 24 | "@vitejs/plugin-vue": "^4.0.0", 25 | "vite": "^4.0.0" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Web/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wxy05240/MessageWall/4f6fbd2c4c963fc47e46260af1ff1ddb49914050/Web/public/favicon.ico -------------------------------------------------------------------------------- /Web/src/App.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 9 | 27 | -------------------------------------------------------------------------------- /Web/src/assets/api/index.js: -------------------------------------------------------------------------------- 1 | import fetch from '../utils/axios' 2 | //新建数据 3 | export function insertWallApi(data){ 4 | return fetch.post('/insertwall',data) 5 | } 6 | //获取IP 7 | export function signIpApi(){ 8 | return fetch.post('/signip') 9 | } 10 | //查询墙 11 | export function findWallPageApi(data){ 12 | return fetch.post('/findwallpage',data) 13 | } 14 | //新建反馈 15 | export function insertFeedBackApi(data){ 16 | return fetch.post('/insertfeedback',data) 17 | } 18 | //新建评论 19 | export function insertCommentApi(data){ 20 | return fetch.post('/insertcomment',data) 21 | } 22 | //获取评论 23 | export function findCommentPage(data){ 24 | return fetch.post('/findcommentpage',data) 25 | } 26 | //上传图片 27 | export function proFileApi(data){ 28 | return fetch.post('/profile',data) 29 | } -------------------------------------------------------------------------------- /Web/src/assets/fonts/icon/demo.css: -------------------------------------------------------------------------------- 1 | /* Logo 字体 */ 2 | @font-face { 3 | font-family: "iconfont logo"; 4 | src: url('https://at.alicdn.com/t/font_985780_km7mi63cihi.eot?t=1545807318834'); 5 | src: url('https://at.alicdn.com/t/font_985780_km7mi63cihi.eot?t=1545807318834#iefix') format('embedded-opentype'), 6 | url('https://at.alicdn.com/t/font_985780_km7mi63cihi.woff?t=1545807318834') format('woff'), 7 | url('https://at.alicdn.com/t/font_985780_km7mi63cihi.ttf?t=1545807318834') format('truetype'), 8 | url('https://at.alicdn.com/t/font_985780_km7mi63cihi.svg?t=1545807318834#iconfont') format('svg'); 9 | } 10 | 11 | .logo { 12 | font-family: "iconfont logo"; 13 | font-size: 160px; 14 | font-style: normal; 15 | -webkit-font-smoothing: antialiased; 16 | -moz-osx-font-smoothing: grayscale; 17 | } 18 | 19 | /* tabs */ 20 | .nav-tabs { 21 | position: relative; 22 | } 23 | 24 | .nav-tabs .nav-more { 25 | position: absolute; 26 | right: 0; 27 | bottom: 0; 28 | height: 42px; 29 | line-height: 42px; 30 | color: #666; 31 | } 32 | 33 | #tabs { 34 | border-bottom: 1px solid #eee; 35 | } 36 | 37 | #tabs li { 38 | cursor: pointer; 39 | width: 100px; 40 | height: 40px; 41 | line-height: 40px; 42 | text-align: center; 43 | font-size: 16px; 44 | border-bottom: 2px solid transparent; 45 | position: relative; 46 | z-index: 1; 47 | margin-bottom: -1px; 48 | color: #666; 49 | } 50 | 51 | 52 | #tabs .active { 53 | border-bottom-color: #f00; 54 | color: #222; 55 | } 56 | 57 | .tab-container .content { 58 | display: none; 59 | } 60 | 61 | /* 页面布局 */ 62 | .main { 63 | padding: 30px 100px; 64 | width: 960px; 65 | margin: 0 auto; 66 | } 67 | 68 | .main .logo { 69 | color: #333; 70 | text-align: left; 71 | margin-bottom: 30px; 72 | line-height: 1; 73 | height: 110px; 74 | margin-top: -50px; 75 | overflow: hidden; 76 | *zoom: 1; 77 | } 78 | 79 | .main .logo a { 80 | font-size: 160px; 81 | color: #333; 82 | } 83 | 84 | .helps { 85 | margin-top: 40px; 86 | } 87 | 88 | .helps pre { 89 | padding: 20px; 90 | margin: 10px 0; 91 | border: solid 1px #e7e1cd; 92 | background-color: #fffdef; 93 | overflow: auto; 94 | } 95 | 96 | .icon_lists { 97 | width: 100% !important; 98 | overflow: hidden; 99 | *zoom: 1; 100 | } 101 | 102 | .icon_lists li { 103 | width: 100px; 104 | margin-bottom: 10px; 105 | margin-right: 20px; 106 | text-align: center; 107 | list-style: none !important; 108 | cursor: default; 109 | } 110 | 111 | .icon_lists li .code-name { 112 | line-height: 1.2; 113 | } 114 | 115 | .icon_lists .icon { 116 | display: block; 117 | height: 100px; 118 | line-height: 100px; 119 | font-size: 42px; 120 | margin: 10px auto; 121 | color: #333; 122 | -webkit-transition: font-size 0.25s linear, width 0.25s linear; 123 | -moz-transition: font-size 0.25s linear, width 0.25s linear; 124 | transition: font-size 0.25s linear, width 0.25s linear; 125 | } 126 | 127 | .icon_lists .icon:hover { 128 | font-size: 100px; 129 | } 130 | 131 | .icon_lists .svg-icon { 132 | /* 通过设置 font-size 来改变图标大小 */ 133 | width: 1em; 134 | /* 图标和文字相邻时,垂直对齐 */ 135 | vertical-align: -0.15em; 136 | /* 通过设置 color 来改变 SVG 的颜色/fill */ 137 | fill: currentColor; 138 | /* path 和 stroke 溢出 viewBox 部分在 IE 下会显示 139 | normalize.css 中也包含这行 */ 140 | overflow: hidden; 141 | } 142 | 143 | .icon_lists li .name, 144 | .icon_lists li .code-name { 145 | color: #666; 146 | } 147 | 148 | /* markdown 样式 */ 149 | .markdown { 150 | color: #666; 151 | font-size: 14px; 152 | line-height: 1.8; 153 | } 154 | 155 | .highlight { 156 | line-height: 1.5; 157 | } 158 | 159 | .markdown img { 160 | vertical-align: middle; 161 | max-width: 100%; 162 | } 163 | 164 | .markdown h1 { 165 | color: #404040; 166 | font-weight: 500; 167 | line-height: 40px; 168 | margin-bottom: 24px; 169 | } 170 | 171 | .markdown h2, 172 | .markdown h3, 173 | .markdown h4, 174 | .markdown h5, 175 | .markdown h6 { 176 | color: #404040; 177 | margin: 1.6em 0 0.6em 0; 178 | font-weight: 500; 179 | clear: both; 180 | } 181 | 182 | .markdown h1 { 183 | font-size: 28px; 184 | } 185 | 186 | .markdown h2 { 187 | font-size: 22px; 188 | } 189 | 190 | .markdown h3 { 191 | font-size: 16px; 192 | } 193 | 194 | .markdown h4 { 195 | font-size: 14px; 196 | } 197 | 198 | .markdown h5 { 199 | font-size: 12px; 200 | } 201 | 202 | .markdown h6 { 203 | font-size: 12px; 204 | } 205 | 206 | .markdown hr { 207 | height: 1px; 208 | border: 0; 209 | background: #e9e9e9; 210 | margin: 16px 0; 211 | clear: both; 212 | } 213 | 214 | .markdown p { 215 | margin: 1em 0; 216 | } 217 | 218 | .markdown>p, 219 | .markdown>blockquote, 220 | .markdown>.highlight, 221 | .markdown>ol, 222 | .markdown>ul { 223 | width: 80%; 224 | } 225 | 226 | .markdown ul>li { 227 | list-style: circle; 228 | } 229 | 230 | .markdown>ul li, 231 | .markdown blockquote ul>li { 232 | margin-left: 20px; 233 | padding-left: 4px; 234 | } 235 | 236 | .markdown>ul li p, 237 | .markdown>ol li p { 238 | margin: 0.6em 0; 239 | } 240 | 241 | .markdown ol>li { 242 | list-style: decimal; 243 | } 244 | 245 | .markdown>ol li, 246 | .markdown blockquote ol>li { 247 | margin-left: 20px; 248 | padding-left: 4px; 249 | } 250 | 251 | .markdown code { 252 | margin: 0 3px; 253 | padding: 0 5px; 254 | background: #eee; 255 | border-radius: 3px; 256 | } 257 | 258 | .markdown strong, 259 | .markdown b { 260 | font-weight: 600; 261 | } 262 | 263 | .markdown>table { 264 | border-collapse: collapse; 265 | border-spacing: 0px; 266 | empty-cells: show; 267 | border: 1px solid #e9e9e9; 268 | width: 95%; 269 | margin-bottom: 24px; 270 | } 271 | 272 | .markdown>table th { 273 | white-space: nowrap; 274 | color: #333; 275 | font-weight: 600; 276 | } 277 | 278 | .markdown>table th, 279 | .markdown>table td { 280 | border: 1px solid #e9e9e9; 281 | padding: 8px 16px; 282 | text-align: left; 283 | } 284 | 285 | .markdown>table th { 286 | background: #F7F7F7; 287 | } 288 | 289 | .markdown blockquote { 290 | font-size: 90%; 291 | color: #999; 292 | border-left: 4px solid #e9e9e9; 293 | padding-left: 0.8em; 294 | margin: 1em 0; 295 | } 296 | 297 | .markdown blockquote p { 298 | margin: 0; 299 | } 300 | 301 | .markdown .anchor { 302 | opacity: 0; 303 | transition: opacity 0.3s ease; 304 | margin-left: 8px; 305 | } 306 | 307 | .markdown .waiting { 308 | color: #ccc; 309 | } 310 | 311 | .markdown h1:hover .anchor, 312 | .markdown h2:hover .anchor, 313 | .markdown h3:hover .anchor, 314 | .markdown h4:hover .anchor, 315 | .markdown h5:hover .anchor, 316 | .markdown h6:hover .anchor { 317 | opacity: 1; 318 | display: inline-block; 319 | } 320 | 321 | .markdown>br, 322 | .markdown>p>br { 323 | clear: both; 324 | } 325 | 326 | 327 | .hljs { 328 | display: block; 329 | background: white; 330 | padding: 0.5em; 331 | color: #333333; 332 | overflow-x: auto; 333 | } 334 | 335 | .hljs-comment, 336 | .hljs-meta { 337 | color: #969896; 338 | } 339 | 340 | .hljs-string, 341 | .hljs-variable, 342 | .hljs-template-variable, 343 | .hljs-strong, 344 | .hljs-emphasis, 345 | .hljs-quote { 346 | color: #df5000; 347 | } 348 | 349 | .hljs-keyword, 350 | .hljs-selector-tag, 351 | .hljs-type { 352 | color: #a71d5d; 353 | } 354 | 355 | .hljs-literal, 356 | .hljs-symbol, 357 | .hljs-bullet, 358 | .hljs-attribute { 359 | color: #0086b3; 360 | } 361 | 362 | .hljs-section, 363 | .hljs-name { 364 | color: #63a35c; 365 | } 366 | 367 | .hljs-tag { 368 | color: #333333; 369 | } 370 | 371 | .hljs-title, 372 | .hljs-attr, 373 | .hljs-selector-id, 374 | .hljs-selector-class, 375 | .hljs-selector-attr, 376 | .hljs-selector-pseudo { 377 | color: #795da3; 378 | } 379 | 380 | .hljs-addition { 381 | color: #55a532; 382 | background-color: #eaffea; 383 | } 384 | 385 | .hljs-deletion { 386 | color: #bd2c00; 387 | background-color: #ffecec; 388 | } 389 | 390 | .hljs-link { 391 | text-decoration: underline; 392 | } 393 | 394 | /* 代码高亮 */ 395 | /* PrismJS 1.15.0 396 | https://prismjs.com/download.html#themes=prism&languages=markup+css+clike+javascript */ 397 | /** 398 | * prism.js default theme for JavaScript, CSS and HTML 399 | * Based on dabblet (http://dabblet.com) 400 | * @author Lea Verou 401 | */ 402 | code[class*="language-"], 403 | pre[class*="language-"] { 404 | color: black; 405 | background: none; 406 | text-shadow: 0 1px white; 407 | font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace; 408 | text-align: left; 409 | white-space: pre; 410 | word-spacing: normal; 411 | word-break: normal; 412 | word-wrap: normal; 413 | line-height: 1.5; 414 | 415 | -moz-tab-size: 4; 416 | -o-tab-size: 4; 417 | tab-size: 4; 418 | 419 | -webkit-hyphens: none; 420 | -moz-hyphens: none; 421 | -ms-hyphens: none; 422 | hyphens: none; 423 | } 424 | 425 | pre[class*="language-"]::-moz-selection, 426 | pre[class*="language-"] ::-moz-selection, 427 | code[class*="language-"]::-moz-selection, 428 | code[class*="language-"] ::-moz-selection { 429 | text-shadow: none; 430 | background: #b3d4fc; 431 | } 432 | 433 | pre[class*="language-"]::selection, 434 | pre[class*="language-"] ::selection, 435 | code[class*="language-"]::selection, 436 | code[class*="language-"] ::selection { 437 | text-shadow: none; 438 | background: #b3d4fc; 439 | } 440 | 441 | @media print { 442 | 443 | code[class*="language-"], 444 | pre[class*="language-"] { 445 | text-shadow: none; 446 | } 447 | } 448 | 449 | /* Code blocks */ 450 | pre[class*="language-"] { 451 | padding: 1em; 452 | margin: .5em 0; 453 | overflow: auto; 454 | } 455 | 456 | :not(pre)>code[class*="language-"], 457 | pre[class*="language-"] { 458 | background: #f5f2f0; 459 | } 460 | 461 | /* Inline code */ 462 | :not(pre)>code[class*="language-"] { 463 | padding: .1em; 464 | border-radius: .3em; 465 | white-space: normal; 466 | } 467 | 468 | .token.comment, 469 | .token.prolog, 470 | .token.doctype, 471 | .token.cdata { 472 | color: slategray; 473 | } 474 | 475 | .token.punctuation { 476 | color: #999; 477 | } 478 | 479 | .namespace { 480 | opacity: .7; 481 | } 482 | 483 | .token.property, 484 | .token.tag, 485 | .token.boolean, 486 | .token.number, 487 | .token.constant, 488 | .token.symbol, 489 | .token.deleted { 490 | color: #905; 491 | } 492 | 493 | .token.selector, 494 | .token.attr-name, 495 | .token.string, 496 | .token.char, 497 | .token.builtin, 498 | .token.inserted { 499 | color: #690; 500 | } 501 | 502 | .token.operator, 503 | .token.entity, 504 | .token.url, 505 | .language-css .token.string, 506 | .style .token.string { 507 | color: #9a6e3a; 508 | background: hsla(0, 0%, 100%, .5); 509 | } 510 | 511 | .token.atrule, 512 | .token.attr-value, 513 | .token.keyword { 514 | color: #07a; 515 | } 516 | 517 | .token.function, 518 | .token.class-name { 519 | color: #DD4A68; 520 | } 521 | 522 | .token.regex, 523 | .token.important, 524 | .token.variable { 525 | color: #e90; 526 | } 527 | 528 | .token.important, 529 | .token.bold { 530 | font-weight: bold; 531 | } 532 | 533 | .token.italic { 534 | font-style: italic; 535 | } 536 | 537 | .token.entity { 538 | cursor: help; 539 | } 540 | -------------------------------------------------------------------------------- /Web/src/assets/fonts/icon/demo_index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | iconfont Demo 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 36 | 37 | 38 |
39 |

40 | 41 | 42 |

43 | 53 |
54 |
55 |
    56 | 57 |
  • 58 | 59 |
    太阳
    60 |
    &#xe60f;
    61 |
  • 62 | 63 |
  • 64 | 65 |
    月亮
    66 |
    &#xe6b8;
    67 |
  • 68 | 69 |
  • 70 | 71 |
    修改
    72 |
    &#xe696;
    73 |
  • 74 | 75 |
  • 76 | 77 |
    yksg
    78 |
    &#xe68b;
    79 |
  • 80 | 81 |
  • 82 | 83 |
    爱心
    84 |
    &#xe663;
    85 |
  • 86 | 87 |
  • 88 | 89 |
    添加
    90 |
    &#xe622;
    91 |
  • 92 | 93 |
  • 94 | 95 |
    留言
    96 |
    &#xe606;
    97 |
  • 98 | 99 |
  • 100 | 101 |
    向右1
    102 |
    &#xe775;
    103 |
  • 104 | 105 |
  • 106 | 107 |
    向左1
    108 |
    &#xe779;
    109 |
  • 110 | 111 |
  • 112 | 113 |
    关 闭
    114 |
    &#xe639;
    115 |
  • 116 | 117 |
  • 118 | 119 |
    失败报错-
    120 |
    &#xe6c6;
    121 |
  • 122 | 123 |
  • 124 | 125 |
    信息提示-
    126 |
    &#xe6ce;
    127 |
  • 128 | 129 |
  • 130 | 131 |
    成功已解决-
    132 |
    &#xe6d4;
    133 |
  • 134 | 135 |
136 |
137 |

Unicode 引用

138 |
139 | 140 |

Unicode 是字体在网页端最原始的应用方式,特点是:

141 |
    142 |
  • 支持按字体的方式去动态调整图标大小,颜色等等。
  • 143 |
  • 默认情况下不支持多色,直接添加多色图标会自动去色。
  • 144 |
145 |
146 |

注意:新版 iconfont 支持两种方式引用多色图标:SVG symbol 引用方式和彩色字体图标模式。(使用彩色字体图标需要在「编辑项目」中开启「彩色」选项后并重新生成。)

147 |
148 |

Unicode 使用步骤如下:

149 |

第一步:拷贝项目下面生成的 @font-face

150 |
@font-face {
152 |   font-family: 'iconfont';
153 |   src: url('iconfont.woff2?t=1673919549404') format('woff2'),
154 |        url('iconfont.woff?t=1673919549404') format('woff'),
155 |        url('iconfont.ttf?t=1673919549404') format('truetype');
156 | }
157 | 
158 |

第二步:定义使用 iconfont 的样式

159 |
.iconfont {
161 |   font-family: "iconfont" !important;
162 |   font-size: 16px;
163 |   font-style: normal;
164 |   -webkit-font-smoothing: antialiased;
165 |   -moz-osx-font-smoothing: grayscale;
166 | }
167 | 
168 |

第三步:挑选相应图标并获取字体编码,应用于页面

169 |
170 | <span class="iconfont">&#x33;</span>
172 | 
173 |
174 |

"iconfont" 是你项目下的 font-family。可以通过编辑项目查看,默认是 "iconfont"。

175 |
176 |
177 |
178 |
179 |
    180 | 181 |
  • 182 | 183 |
    184 | 太阳 185 |
    186 |
    .icon-taiyang 187 |
    188 |
  • 189 | 190 |
  • 191 | 192 |
    193 | 月亮 194 |
    195 |
    .icon-yueliang 196 |
    197 |
  • 198 | 199 |
  • 200 | 201 |
    202 | 修改 203 |
    204 |
    .icon-xiugai 205 |
    206 |
  • 207 | 208 |
  • 209 | 210 |
    211 | yksg 212 |
    213 |
    .icon-yksg 214 |
    215 |
  • 216 | 217 |
  • 218 | 219 |
    220 | 爱心 221 |
    222 |
    .icon-aixin1 223 |
    224 |
  • 225 | 226 |
  • 227 | 228 |
    229 | 添加 230 |
    231 |
    .icon-tianjia 232 |
    233 |
  • 234 | 235 |
  • 236 | 237 |
    238 | 留言 239 |
    240 |
    .icon-liuyan 241 |
    242 |
  • 243 | 244 |
  • 245 | 246 |
    247 | 向右1 248 |
    249 |
    .icon-xiangyou 250 |
    251 |
  • 252 | 253 |
  • 254 | 255 |
    256 | 向左1 257 |
    258 |
    .icon-xiangzuo 259 |
    260 |
  • 261 | 262 |
  • 263 | 264 |
    265 | 关 闭 266 |
    267 |
    .icon-guanbi 268 |
    269 |
  • 270 | 271 |
  • 272 | 273 |
    274 | 失败报错- 275 |
    276 |
    .icon-error 277 |
    278 |
  • 279 | 280 |
  • 281 | 282 |
    283 | 信息提示- 284 |
    285 |
    .icon-warning 286 |
    287 |
  • 288 | 289 |
  • 290 | 291 |
    292 | 成功已解决- 293 |
    294 |
    .icon-success 295 |
    296 |
  • 297 | 298 |
299 |
300 |

font-class 引用

301 |
302 | 303 |

font-class 是 Unicode 使用方式的一种变种,主要是解决 Unicode 书写不直观,语意不明确的问题。

304 |

与 Unicode 使用方式相比,具有如下特点:

305 |
    306 |
  • 相比于 Unicode 语意明确,书写更直观。可以很容易分辨这个 icon 是什么。
  • 307 |
  • 因为使用 class 来定义图标,所以当要替换图标时,只需要修改 class 里面的 Unicode 引用。
  • 308 |
309 |

使用步骤如下:

310 |

第一步:引入项目下面生成的 fontclass 代码:

311 |
<link rel="stylesheet" href="./iconfont.css">
312 | 
313 |

第二步:挑选相应图标并获取类名,应用于页面:

314 |
<span class="iconfont icon-xxx"></span>
315 | 
316 |
317 |

" 318 | iconfont" 是你项目下的 font-family。可以通过编辑项目查看,默认是 "iconfont"。

319 |
320 |
321 |
322 |
323 |
    324 | 325 |
  • 326 | 329 |
    太阳
    330 |
    #icon-taiyang
    331 |
  • 332 | 333 |
  • 334 | 337 |
    月亮
    338 |
    #icon-yueliang
    339 |
  • 340 | 341 |
  • 342 | 345 |
    修改
    346 |
    #icon-xiugai
    347 |
  • 348 | 349 |
  • 350 | 353 |
    yksg
    354 |
    #icon-yksg
    355 |
  • 356 | 357 |
  • 358 | 361 |
    爱心
    362 |
    #icon-aixin1
    363 |
  • 364 | 365 |
  • 366 | 369 |
    添加
    370 |
    #icon-tianjia
    371 |
  • 372 | 373 |
  • 374 | 377 |
    留言
    378 |
    #icon-liuyan
    379 |
  • 380 | 381 |
  • 382 | 385 |
    向右1
    386 |
    #icon-xiangyou
    387 |
  • 388 | 389 |
  • 390 | 393 |
    向左1
    394 |
    #icon-xiangzuo
    395 |
  • 396 | 397 |
  • 398 | 401 |
    关 闭
    402 |
    #icon-guanbi
    403 |
  • 404 | 405 |
  • 406 | 409 |
    失败报错-
    410 |
    #icon-error
    411 |
  • 412 | 413 |
  • 414 | 417 |
    信息提示-
    418 |
    #icon-warning
    419 |
  • 420 | 421 |
  • 422 | 425 |
    成功已解决-
    426 |
    #icon-success
    427 |
  • 428 | 429 |
430 |
431 |

Symbol 引用

432 |
433 | 434 |

这是一种全新的使用方式,应该说这才是未来的主流,也是平台目前推荐的用法。相关介绍可以参考这篇文章 435 | 这种用法其实是做了一个 SVG 的集合,与另外两种相比具有如下特点:

436 |
    437 |
  • 支持多色图标了,不再受单色限制。
  • 438 |
  • 通过一些技巧,支持像字体那样,通过 font-size, color 来调整样式。
  • 439 |
  • 兼容性较差,支持 IE9+,及现代浏览器。
  • 440 |
  • 浏览器渲染 SVG 的性能一般,还不如 png。
  • 441 |
442 |

使用步骤如下:

443 |

第一步:引入项目下面生成的 symbol 代码:

444 |
<script src="./iconfont.js"></script>
445 | 
446 |

第二步:加入通用 CSS 代码(引入一次就行):

447 |
<style>
448 | .icon {
449 |   width: 1em;
450 |   height: 1em;
451 |   vertical-align: -0.15em;
452 |   fill: currentColor;
453 |   overflow: hidden;
454 | }
455 | </style>
456 | 
457 |

第三步:挑选相应图标并获取类名,应用于页面:

458 |
<svg class="icon" aria-hidden="true">
459 |   <use xlink:href="#icon-xxx"></use>
460 | </svg>
461 | 
462 |
463 |
464 | 465 |
466 |
467 | 486 | 487 | 488 | -------------------------------------------------------------------------------- /Web/src/assets/fonts/icon/iconfont.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: "iconfont"; /* Project id 3395343 */ 3 | src: url('iconfont.woff2?t=1673919549404') format('woff2'), 4 | url('iconfont.woff?t=1673919549404') format('woff'), 5 | url('iconfont.ttf?t=1673919549404') format('truetype'); 6 | } 7 | 8 | .iconfont { 9 | font-family: "iconfont" !important; 10 | font-size: 16px; 11 | font-style: normal; 12 | -webkit-font-smoothing: antialiased; 13 | -moz-osx-font-smoothing: grayscale; 14 | } 15 | 16 | .icon-taiyang:before { 17 | content: "\e60f"; 18 | } 19 | 20 | .icon-yueliang:before { 21 | content: "\e6b8"; 22 | } 23 | 24 | .icon-xiugai:before { 25 | content: "\e696"; 26 | } 27 | 28 | .icon-yksg:before { 29 | content: "\e68b"; 30 | } 31 | 32 | .icon-aixin1:before { 33 | content: "\e663"; 34 | } 35 | 36 | .icon-tianjia:before { 37 | content: "\e622"; 38 | } 39 | 40 | .icon-liuyan:before { 41 | content: "\e606"; 42 | } 43 | 44 | .icon-xiangyou:before { 45 | content: "\e775"; 46 | } 47 | 48 | .icon-xiangzuo:before { 49 | content: "\e779"; 50 | } 51 | 52 | .icon-guanbi:before { 53 | content: "\e639"; 54 | } 55 | 56 | .icon-error:before { 57 | content: "\e6c6"; 58 | } 59 | 60 | .icon-warning:before { 61 | content: "\e6ce"; 62 | } 63 | 64 | .icon-success:before { 65 | content: "\e6d4"; 66 | } 67 | 68 | -------------------------------------------------------------------------------- /Web/src/assets/fonts/icon/iconfont.js: -------------------------------------------------------------------------------- 1 | window._iconfont_svg_string_3395343='',function(e){var t=(t=document.getElementsByTagName("script"))[t.length-1],c=t.getAttribute("data-injectcss"),t=t.getAttribute("data-disable-injectsvg");if(!t){var o,i,l,n,a,s=function(t,c){c.parentNode.insertBefore(t,c)};if(c&&!e.__iconfont__svg__cssinject__){e.__iconfont__svg__cssinject__=!0;try{document.write("")}catch(t){console&&console.log(t)}}o=function(){var t,c=document.createElement("div");c.innerHTML=e._iconfont_svg_string_3395343,(c=c.getElementsByTagName("svg")[0])&&(c.setAttribute("aria-hidden","true"),c.style.position="absolute",c.style.width=0,c.style.height=0,c.style.overflow="hidden",c=c,(t=document.body).firstChild?s(c,t.firstChild):t.appendChild(c))},document.addEventListener?~["complete","loaded","interactive"].indexOf(document.readyState)?setTimeout(o,0):(i=function(){document.removeEventListener("DOMContentLoaded",i,!1),o()},document.addEventListener("DOMContentLoaded",i,!1)):document.attachEvent&&(l=o,n=e.document,a=!1,m(),n.onreadystatechange=function(){"complete"==n.readyState&&(n.onreadystatechange=null,d())})}function d(){a||(a=!0,l())}function m(){try{n.documentElement.doScroll("left")}catch(t){return void setTimeout(m,50)}d()}}(window); -------------------------------------------------------------------------------- /Web/src/assets/fonts/icon/iconfont.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "3395343", 3 | "name": "yike基础版", 4 | "font_family": "iconfont", 5 | "css_prefix_text": "icon-", 6 | "description": "", 7 | "glyphs": [ 8 | { 9 | "icon_id": "1724889", 10 | "name": "太阳", 11 | "font_class": "taiyang", 12 | "unicode": "e60f", 13 | "unicode_decimal": 58895 14 | }, 15 | { 16 | "icon_id": "3402343", 17 | "name": "月亮", 18 | "font_class": "yueliang", 19 | "unicode": "e6b8", 20 | "unicode_decimal": 59064 21 | }, 22 | { 23 | "icon_id": "421237", 24 | "name": "修改", 25 | "font_class": "xiugai", 26 | "unicode": "e696", 27 | "unicode_decimal": 59030 28 | }, 29 | { 30 | "icon_id": "30295631", 31 | "name": "yksg", 32 | "font_class": "yksg", 33 | "unicode": "e68b", 34 | "unicode_decimal": 59019 35 | }, 36 | { 37 | "icon_id": "918722", 38 | "name": "爱心", 39 | "font_class": "aixin1", 40 | "unicode": "e663", 41 | "unicode_decimal": 58979 42 | }, 43 | { 44 | "icon_id": "1304889", 45 | "name": "添加", 46 | "font_class": "tianjia", 47 | "unicode": "e622", 48 | "unicode_decimal": 58914 49 | }, 50 | { 51 | "icon_id": "1418212", 52 | "name": "留言", 53 | "font_class": "liuyan", 54 | "unicode": "e606", 55 | "unicode_decimal": 58886 56 | }, 57 | { 58 | "icon_id": "577402", 59 | "name": "向右1", 60 | "font_class": "xiangyou", 61 | "unicode": "e775", 62 | "unicode_decimal": 59253 63 | }, 64 | { 65 | "icon_id": "577406", 66 | "name": "向左1", 67 | "font_class": "xiangzuo", 68 | "unicode": "e779", 69 | "unicode_decimal": 59257 70 | }, 71 | { 72 | "icon_id": "9430532", 73 | "name": "关 闭", 74 | "font_class": "guanbi", 75 | "unicode": "e639", 76 | "unicode_decimal": 58937 77 | }, 78 | { 79 | "icon_id": "250681", 80 | "name": "失败报错-", 81 | "font_class": "error", 82 | "unicode": "e6c6", 83 | "unicode_decimal": 59078 84 | }, 85 | { 86 | "icon_id": "250689", 87 | "name": "信息提示-", 88 | "font_class": "warning", 89 | "unicode": "e6ce", 90 | "unicode_decimal": 59086 91 | }, 92 | { 93 | "icon_id": "250695", 94 | "name": "成功已解决-", 95 | "font_class": "success", 96 | "unicode": "e6d4", 97 | "unicode_decimal": 59092 98 | } 99 | ] 100 | } 101 | -------------------------------------------------------------------------------- /Web/src/assets/fonts/icon/iconfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wxy05240/MessageWall/4f6fbd2c4c963fc47e46260af1ff1ddb49914050/Web/src/assets/fonts/icon/iconfont.ttf -------------------------------------------------------------------------------- /Web/src/assets/fonts/icon/iconfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wxy05240/MessageWall/4f6fbd2c4c963fc47e46260af1ff1ddb49914050/Web/src/assets/fonts/icon/iconfont.woff -------------------------------------------------------------------------------- /Web/src/assets/fonts/icon/iconfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wxy05240/MessageWall/4f6fbd2c4c963fc47e46260af1ff1ddb49914050/Web/src/assets/fonts/icon/iconfont.woff2 -------------------------------------------------------------------------------- /Web/src/assets/images/card.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 便签 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /Web/src/assets/images/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wxy05240/MessageWall/4f6fbd2c4c963fc47e46260af1ff1ddb49914050/Web/src/assets/images/favicon.ico -------------------------------------------------------------------------------- /Web/src/assets/images/favicon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 编组 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /Web/src/assets/images/loading.json: -------------------------------------------------------------------------------- 1 | {"v":"4.10.1","fr":24,"ip":0,"op":60,"w":400,"h":400,"nm":"Comp 1","ddd":0,"assets":[{"id":"comp_0","layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Capa de formas 12","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":24,"s":[81.5,370.25,0],"e":[445.5,199.25,0],"to":[60.6666679382324,-28.5,0],"ti":[-60.6666679382324,28.5,0]},{"t":48}],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[43,43,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[28,0],[34.935,-19.483],[31.619,18.821],[33,-14],[57,29],[0,0],[0,0],[0,0]],"o":[[-28,0],[-52,29],[-42,-25],[-28.892,12.257],[-57,-29],[0,0],[0,0],[0,0]],"v":[[367.75,-97],[277,-75],[155,-82],[35,-82],[-94,-82.326],[-200,-74],[-352.07,320.209],[499.162,354.093]],"c":true},"ix":2},"nm":"Trazado 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.198431351606,0.588595042509,0.733333333333,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"Relleno 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transformar"}],"nm":"Forma 1","np":3,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":144,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Capa de formas 2","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":24,"s":[-133,374,0],"e":[231,203,0],"to":[60.6666679382324,-28.5,0],"ti":[-60.6666679382324,28.5,0]},{"t":48}],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[43,43,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[28,0],[34.935,-19.483],[31.619,18.821],[33,-14],[57,29],[0,0],[0,0],[0,0]],"o":[[-28,0],[-52,29],[-42,-25],[-28.892,12.257],[-57,-29],[0,0],[0,0],[0,0]],"v":[[367.75,-97],[277,-75],[155,-82],[35,-82],[-94,-82.326],[-200,-74],[-352.07,320.209],[499.162,354.093]],"c":true},"ix":2},"nm":"Trazado 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.2,0.588235294118,0.733333333333,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"Relleno 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transformar"}],"nm":"Forma 1","np":3,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":144,"st":0,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Capa de formas 5","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":15,"s":[100],"e":[0]},{"t":16}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":0,"s":[199,-14,0],"e":[199,156,0],"to":[0,28.3333339691162,0],"ti":[0,-28.9375,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":12,"s":[199,156,0],"e":[199,164.066,0],"to":[0,4.54861259460449,0],"ti":[0,-2.45892143249512,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":13,"s":[199,164.066,0],"e":[199,166.125,0],"to":[0,13.1843204498291,0],"ti":[0,-1.72074222564697,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":14,"s":[199,166.125,0],"e":[199,168.375,0],"to":[0,2.04166674613953,0],"ti":[0,-0.04166666790843,0]},{"t":15}],"ix":2},"a":{"a":0,"k":[-1,-182.375,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"n":["0p833_0p833_0p167_0p167","0p833_0p833_0p167_0p167","0p833_0p833_0p167_0p167"],"t":0,"s":[50,50,100],"e":[50,94,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"n":["0p833_0p833_0p167_0p167","0p833_0p833_0p167_0p167","0p833_0p833_0p167_0p167"],"t":12,"s":[50,94,100],"e":[70,43.333,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"n":["0p833_0p833_0p167_0p167","0p833_0p833_0p167_0p167","0p833_0p833_0p167_0p167"],"t":13,"s":[70,43.333,100],"e":[104.258,32,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"n":["0p833_0p833_0p167_0p167","0p833_0p833_0p167_0p167","0p833_0p833_0p167_0p167"],"t":14,"s":[104.258,32,100],"e":[212,18,100]},{"t":15}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0.938,0],[0,-5.25],[-4.563,0.125],[0.108,4.624]],"o":[[-0.813,0.125],[0,4.813],[4.563,-0.125],[-0.125,-5.375]],"v":[[-1.344,-193.078],[-8.75,-180.5],[-1.063,-172.313],[6.938,-180.188]],"c":true},"ix":2},"nm":"Trazado 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.317647058824,0.325490196078,0.341176470588,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"Relleno 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transformar"}],"nm":"Forma 1","np":3,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":60,"st":0,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":"Capa de formas 3","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":46,"s":[0],"e":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":47,"s":[100],"e":[100]},{"t":48}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":47,"s":[199.98,168.25,0],"e":[199.98,158.037,0],"to":[0,-0.20375619828701,0],"ti":[0,17.58864402771,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":48,"s":[199.98,158.037,0],"e":[199.98,-10,0],"to":[-2.8421709430404e-14,-50.4047393798828,0],"ti":[0,1.17485654354095,0]},{"t":53}],"ix":2},"a":{"a":0,"k":[-32,-31,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"n":["0p833_0p833_0p167_0p167","0p833_0p833_0p167_0p167","0p833_0p833_0p167_0p167"],"t":47,"s":[-4,1,100],"e":[1.5,4,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"n":["0p833_0p833_0p167_0p167","0p833_0p833_0p167_0p167","0p833_0p833_0p167_0p167"],"t":48,"s":[1.5,4,100],"e":[2,3,100]},{"t":53}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[308,308],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Trazado elíptico 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[0.317647058824,0.325490196078,0.341176470588,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"Relleno 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-31,-31],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transformar"}],"nm":"Elipse 1","np":3,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":60,"st":0,"bm":0},{"ddd":0,"ind":9,"ty":4,"nm":"Capa de formas 4","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[199,253,0],"ix":2},"a":{"a":0,"k":[-32,-31,0],"ix":1},"s":{"a":0,"k":[55,55,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[308,308],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Trazado elíptico 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.317093434053,0.325121112898,0.341176470588,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":10,"ix":5},"lc":1,"lj":1,"ml":4,"nm":"Trazo 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[-31,-31],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transformar"}],"nm":"Elipse 1","np":3,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":12,"s":[50],"e":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":24,"s":[100],"e":[50]},{"t":48}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":12,"s":[50],"e":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":24,"s":[0],"e":[50]},{"t":48}],"ix":2},"o":{"a":0,"k":180,"ix":3},"m":1,"ix":2,"nm":"Recortar trazados 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":0,"op":60,"st":0,"bm":0},{"ddd":0,"ind":10,"ty":4,"nm":"Capa de formas 1","td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[199,253,0],"ix":2},"a":{"a":0,"k":[-32,-31,0],"ix":1},"s":{"a":0,"k":[50,50,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[308,308],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Trazado elíptico 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[0.913725490196,0.347995563582,0.03941561007,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"Relleno 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-31,-31],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transformar"}],"nm":"Elipse 1","np":3,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":60,"st":0,"bm":0},{"ddd":0,"ind":11,"ty":0,"nm":"Precomp. 1","tt":1,"refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[200,200,0],"ix":2},"a":{"a":0,"k":[200,200,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"w":400,"h":400,"ip":0,"op":144,"st":0,"bm":0}]} -------------------------------------------------------------------------------- /Web/src/assets/images/photo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 照片 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | HOME 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | LOVE 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /Web/src/assets/images/qm1.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wxy05240/MessageWall/4f6fbd2c4c963fc47e46260af1ff1ddb49914050/Web/src/assets/images/qm1.mp4 -------------------------------------------------------------------------------- /Web/src/assets/router/index.js: -------------------------------------------------------------------------------- 1 | import { createRouter, createWebHashHistory } from "vue-router"; 2 | const routes = [ 3 | { 4 | path : '/', 5 | redirect : '/wall?id=0', 6 | name : 'index', 7 | components : { 8 | default : () => import('@/views/index.vue'), 9 | pc : () => import('@/views/index.vue'), 10 | mobile : () => import('~/components/mobile/index.vue') 11 | }, 12 | children : [{ 13 | path : 'wall', 14 | components : { 15 | default: () => import('@/views/WallMessage.vue'), 16 | pc : () => import('@/views/WallMessage.vue'), 17 | mobile : () => import('~/components/mobile/WallMessage.vue') 18 | }} 19 | ] 20 | } 21 | ] 22 | const router = createRouter({ 23 | history : createWebHashHistory(), 24 | routes 25 | }) 26 | export default router -------------------------------------------------------------------------------- /Web/src/assets/store/index.js: -------------------------------------------------------------------------------- 1 | import { createStore } from "vuex"; 2 | const store = createStore( 3 | { 4 | states (){ 5 | return { 6 | count : 0, 7 | user : '' 8 | } 9 | }, 10 | mutations : { 11 | increament(state){ 12 | state.count++ 13 | }, 14 | getUser(state,n){ 15 | state.user = n 16 | } 17 | }, 18 | actions : { 19 | 20 | } 21 | } 22 | ) 23 | export default store 24 | 25 | -------------------------------------------------------------------------------- /Web/src/assets/styles/common.css: -------------------------------------------------------------------------------- 1 | body { 2 | padding: 0px; 3 | margin: 0px; 4 | line-height: 1.5; 5 | color: #202020; 6 | font-size: 14px; 7 | background-color: #FFFFFF; 8 | transition: all 0.3s; 9 | font-family: Avenir, Arial, Helvetica, sans-serif; 10 | -webkit-font-smoothing: antialiased; 11 | -moz-osx-font-smoothing: grayscale; 12 | } 13 | p { 14 | padding: 0; 15 | margin: 0; 16 | } 17 | li { 18 | list-style: none; 19 | } 20 | img { 21 | padding: 0; 22 | margin: 0; 23 | display: block; 24 | } 25 | a { 26 | text-decoration: none; 27 | } 28 | a:hover { 29 | text-decoration: none; 30 | } 31 | input, 32 | textarea { 33 | outline: none; 34 | } 35 | -------------------------------------------------------------------------------- /Web/src/assets/styles/common.less: -------------------------------------------------------------------------------- 1 | // ----------Colors---------- 2 | @primary-color : #3B73F0; //全局主色 3 | @link-color : #1890ff ; //链接色 4 | @success-color : #22BF87; //成功色 5 | @warning-color : #F67770; //警告色 6 | @error-color : #F35248; //错误色 7 | @like : #F67770;//喜欢 8 | // ----------中性色---------- 9 | @gray-1 : #202020; 10 | @gray-2 : #5B5B5B; 11 | @gray-3 : #949494; 12 | @gray-9 : #F6F6F8; 13 | @gray-10 : #FFFFFF; 14 | 15 | // ----------Font---------- 16 | @size-12 : 12px; 17 | @size-14 : 14px; 18 | @size-16 : 16px; 19 | 20 | // ----------间距---------- 21 | @padding-4 : 4px; 22 | @padding-8 : 8px; 23 | @padding-12 : 12px; 24 | @padding-20 : 20px; 25 | 26 | // ----------动画---------- 27 | @tr : all 0.3s; 28 | // ----------全局控制---------- 29 | body{ 30 | padding: 0px; 31 | margin: 0px; 32 | line-height: 1.5; 33 | color : @gray-1; 34 | font-size: @size-14; 35 | background-color: @gray-10; 36 | transition: all .3s; 37 | font-family: Avenir,Arial, Helvetica, sans-serif; 38 | -webkit-font-smoothing: antialiased; 39 | -moz-osx-font-smoothing: grayscale; 40 | } 41 | 42 | p{ 43 | padding: 0; 44 | margin: 0; 45 | } 46 | 47 | li{ 48 | list-style: none; 49 | } 50 | 51 | img{ 52 | padding: 0; 53 | margin: 0; 54 | display: block; 55 | } 56 | 57 | a{ 58 | text-decoration: none; 59 | &:hover{ 60 | text-decoration: none; 61 | } 62 | } 63 | 64 | input,textarea{ 65 | outline: none; 66 | } 67 | -------------------------------------------------------------------------------- /Web/src/assets/utils/axios.js: -------------------------------------------------------------------------------- 1 | import { baseUrl } from "./env"; 2 | import axios from "axios"; 3 | const service = axios.create({ 4 | baseURL : baseUrl, 5 | }) 6 | 7 | //请求拦截器 8 | service.interceptors.request.use( 9 | config => { 10 | return config 11 | }, 12 | error => { 13 | console.log(error) 14 | return Promise.reject() 15 | } 16 | ) 17 | 18 | //相应拦截器 19 | service.interceptors.response.use( 20 | response => { 21 | if(response.status == 200){ 22 | return response.data 23 | }else{ 24 | Promise.reject() 25 | } 26 | }, 27 | error => { 28 | console.log(error) 29 | return Promise.reject() 30 | } 31 | ) 32 | export default service -------------------------------------------------------------------------------- /Web/src/assets/utils/data.js: -------------------------------------------------------------------------------- 1 | //墙的性质 2 | export const wallType = [{ 3 | name : '留言墙', 4 | slogan : '很多事情值得记录,当然也值得回味' 5 | },{ 6 | name : '照片墙', 7 | slogan : '多事情值得记录,当然也值得回味' 8 | }] 9 | //分类标签 10 | export const label = [ 11 | ['留言','目标','理想','过去','将来','爱情','亲情','友情','秘密','信条','无题'], 12 | ['我','ta','喜欢的','有意义的','值得纪念的','母校','生活','天空','我在的城市','大海','无题'] 13 | ] 14 | //卡片背景色 15 | export const cardColor = [ 16 | 'rgba(252,175,162,0.30)', 17 | 'rgba(255,227,148,0.30)', 18 | 'rgba(146,230,245,0.30)', 19 | 'rgba(168,237,138,0.30)', 20 | 'rgba(202,167,247,0.30)', 21 | 'rgba(212,212,212,0.30)', 22 | 23 | ] 24 | export const cardColorBlock = [ 25 | 'rgba(252,175,162,0.30)', 26 | 'rgba(255,227,148,0.30)', 27 | 'rgba(146,230,245,0.30)', 28 | 'rgba(168,237,138,0.30)', 29 | 'rgba(202,167,247,0.30)', 30 | 31 | ] 32 | //评论头像背景 33 | export const portrait = [ 34 | 'linear-gradient(180deg,#FFA9D9 0%,#E83D3D 100%)', 35 | 'linear-gradient(180deg,#FFA7EB 0%,#F026A8 100%)', 36 | 'linear-gradient(180deg,#F5A8FF 0%,#BF23E5 100%)', 37 | 'linear-gradient(180deg,#DFA1FF 0%,#9A36F0 100%)', 38 | 'linear-gradient(180deg,#C9AAFF 0%,#6D3CF5 100%)', 39 | 'linear-gradient(180deg,#9EAAFF 0%,#3846F4 100%)', 40 | 'linear-gradient(180deg,#8CD8FF 0%,#2A6AF0 100%)', 41 | 'linear-gradient(180deg,#7BE7FF 2%,#1E85E2 100%)', 42 | 'linear-gradient(180deg,#92FDFF 0%,#14B2DD 100%)', 43 | 'linear-gradient(180deg,#89FED8 0%,#18C997 100%)', 44 | 'linear-gradient(180deg,#D7FFA7 0%,#5ED52A 100%)', 45 | 'linear-gradient(180deg,#FFED48 0%,#FD9E16 100%)', 46 | 'linear-gradient(180deg,#FFDC83 0%,#F88816 100%)', 47 | 'linear-gradient(180deg,#FFVA8D 1%,#EB6423 100%)', 48 | ] 49 | 50 | 51 | export const none = [ 52 | { 53 | url : './assets/images/card.svg', 54 | msg : '还没有留言,快贴上第一张吧' 55 | }, 56 | { 57 | url : './assets/images/photo.svg', 58 | msg : '还没有照片,快贴上第一张吧' 59 | } 60 | ] 61 | // //开发环境配置 62 | // export const none = [ 63 | // { 64 | // url : '/src/assets/images/card.svg', 65 | // msg : '还没有留言,快贴上第一张吧' 66 | // }, 67 | // { 68 | // url : '/src/assets/images/photo.svg', 69 | // msg : '还没有照片,快贴上第一张吧' 70 | // } 71 | // ] -------------------------------------------------------------------------------- /Web/src/assets/utils/env.js: -------------------------------------------------------------------------------- 1 | let baseUrl = '' 2 | let routerMode = 'hash' 3 | let avatarUrl = '' 4 | let baseImgPath 5 | if(process.env.NODE_ENV == 'development'){ 6 | baseUrl = 'http://localhost:3000/walls' 7 | baseImgPath = 'http://localhost:3000' 8 | avatarUrl = 'http://img.5i21.cn/LightPicture/2022/10/eeaaaa6df26aefe5.jpg' 9 | }else{ 10 | // 此处只需要修改api.5i21.cn为你的后端地址 11 | baseUrl = 'https://api.5i21.cn/walls' 12 | // 此处只需要修改api.5i21.cn为你的后端地址 13 | baseImgPath = 'https://api.5i21.cn' 14 | // 此处需要修改为自己的头像地址 15 | avatarUrl = 'http://img.5i21.cn/LightPicture/2022/10/eeaaaa6df26aefe5.jpg' 16 | } 17 | export { 18 | baseUrl, 19 | routerMode, 20 | baseImgPath, 21 | avatarUrl 22 | } -------------------------------------------------------------------------------- /Web/src/assets/utils/methods.js: -------------------------------------------------------------------------------- 1 | //时间方法 2 | export const dateTransform = (e) => { 3 | let d = new Date(e) 4 | 5 | let Y = d.getFullYear() 6 | let M = d.getMonth() + 1 7 | let D = d.getDate() 8 | if (D < 10) { 9 | D = '0' + D 10 | } 11 | if (M < 10) { 12 | M = '0' + M 13 | } 14 | let date = Y + '.' + M + '.' + D 15 | return date 16 | } 17 | //时间方法 18 | export const getObjectURL = (file) => { 19 | var url = null 20 | if (window.createObjectURL != undefined) { 21 | url = window.createObjectURL(file) 22 | } else if (window.URL != undefined) { 23 | url = window.URL.createObjectURL(file) 24 | } else if (window.webkitURL != undefined) { 25 | url = window.webkitURL.createObjectURL(file) 26 | } 27 | return url 28 | } -------------------------------------------------------------------------------- /Web/src/assets/views/WallMessage.vue: -------------------------------------------------------------------------------- 1 | 46 | 47 | 292 | -------------------------------------------------------------------------------- /Web/src/assets/views/index.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 29 | -------------------------------------------------------------------------------- /Web/src/components/KMR/index.js: -------------------------------------------------------------------------------- 1 | import Message from './message/message' 2 | export default { 3 | install(app){ 4 | app.config.globalProperties.Modal = Message 5 | } 6 | } -------------------------------------------------------------------------------- /Web/src/components/KMR/message/IMessage.vue: -------------------------------------------------------------------------------- 1 | 11 | 44 | -------------------------------------------------------------------------------- /Web/src/components/KMR/message/message.js: -------------------------------------------------------------------------------- 1 | import { createVNode,render } from "vue"; 2 | import iMessage from './iMessage.vue' 3 | const divVNode = createVNode('div',{class : 'xtx-message-container'}) 4 | render(divVNode,document.body) 5 | const div = divVNode.el 6 | const IMessage = ({message,type}) => { 7 | const comVNode = createVNode(iMessage,{message,type}) 8 | render(comVNode,div) 9 | setTimeout(()=>{ 10 | render(null,div) 11 | },6000) 12 | } 13 | export default IMessage -------------------------------------------------------------------------------- /Web/src/components/mobile/CardDetail.vue: -------------------------------------------------------------------------------- 1 | 37 | 127 | -------------------------------------------------------------------------------- /Web/src/components/mobile/IModal.vue: -------------------------------------------------------------------------------- 1 | 14 | 29 | 30 | -------------------------------------------------------------------------------- /Web/src/components/mobile/Ibutton.vue: -------------------------------------------------------------------------------- 1 | 8 | 18 | -------------------------------------------------------------------------------- /Web/src/components/mobile/NewCard.vue: -------------------------------------------------------------------------------- 1 | 51 | 180 | -------------------------------------------------------------------------------- /Web/src/components/mobile/NodeCard.vue: -------------------------------------------------------------------------------- 1 | 27 | 68 | -------------------------------------------------------------------------------- /Web/src/components/mobile/PhotoCard.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 52 | 53 | -------------------------------------------------------------------------------- /Web/src/components/mobile/TopBar.vue: -------------------------------------------------------------------------------- 1 | 18 | 19 | 34 | -------------------------------------------------------------------------------- /Web/src/components/mobile/WallMessage.vue: -------------------------------------------------------------------------------- 1 | 44 | 233 | 234 | 387 | -------------------------------------------------------------------------------- /Web/src/components/mobile/index.vue: -------------------------------------------------------------------------------- 1 | 8 | 26 | -------------------------------------------------------------------------------- /Web/src/components/pc/CardDetail.vue: -------------------------------------------------------------------------------- 1 | 34 | 123 | -------------------------------------------------------------------------------- /Web/src/components/pc/FootBar.vue: -------------------------------------------------------------------------------- 1 | 5 | -------------------------------------------------------------------------------- /Web/src/components/pc/IModal.vue: -------------------------------------------------------------------------------- 1 | 14 | 29 | 30 | -------------------------------------------------------------------------------- /Web/src/components/pc/Ibutton.vue: -------------------------------------------------------------------------------- 1 | 8 | 18 | -------------------------------------------------------------------------------- /Web/src/components/pc/NewCard.vue: -------------------------------------------------------------------------------- 1 | 51 | 180 | -------------------------------------------------------------------------------- /Web/src/components/pc/NodeCard.vue: -------------------------------------------------------------------------------- 1 | 27 | 68 | -------------------------------------------------------------------------------- /Web/src/components/pc/PhotoCard.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 52 | 53 | -------------------------------------------------------------------------------- /Web/src/components/pc/TopBar.vue: -------------------------------------------------------------------------------- 1 | 18 | 19 | 36 | -------------------------------------------------------------------------------- /Web/src/components/pc/Viewer.vue: -------------------------------------------------------------------------------- 1 | 20 | 52 | -------------------------------------------------------------------------------- /Web/src/main.js: -------------------------------------------------------------------------------- 1 | import { createApp } from 'vue' 2 | import App from './App.vue' 3 | import router from '@/router' 4 | import store from '@/store' 5 | import KMR from './components/KMR/index' 6 | const app = createApp(App) 7 | app.use(router) 8 | app.use(store) 9 | app.use(KMR) 10 | app.mount('#app') 11 | -------------------------------------------------------------------------------- /Web/vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import vue from '@vitejs/plugin-vue' 3 | import path from 'path' 4 | 5 | // https://vitejs.dev/config/ 6 | export default defineConfig({ 7 | base : './', 8 | plugins: [vue()], 9 | resolve : { 10 | alias : { 11 | '@' : path.resolve(__dirname,'./src/assets'), 12 | '~' : path.resolve(__dirname,'./src') 13 | } 14 | }, 15 | css: { 16 | // css预处理器 17 | preprocessorOptions: { 18 | less: { 19 | charset: false, 20 | additionalData: '@import "./src/assets/styles/common.less";', 21 | }, 22 | }, 23 | }, 24 | 25 | }) 26 | --------------------------------------------------------------------------------