0


【前端截屏上传存储于Caddy静态目录-签到系统的信息保存】

VUE截屏上传存储于Caddy-签到系统的信息保存

前端

按需引入

Vite官方脚本的步骤:

1. 首先环境初始
确保您已经安装了Node.js,pnpm。

在命令行中运行以下命令来全局安装Vite:
pnpm install -g create-vite
创建新的Vue项目:
create-vite my-vue-app --template vue
其中my-vue-app是您的项目名称。
进入项目文件夹:
cd my-vue-app
安装依赖:
pnpm install
启动开发服务器:
pnpm run dev
2. 使用Naive UI ,
是一个 Vue3 的组件库。全都可以 treeshaking。也就是按需导入.
参考https://www.naiveui.com/zh-CN/os-theme/docs/import-on-demand
我使用了这个配置,接下就可以用里面的库了. 过程中手工 pnpm install unplugin-auto-import/vite
unplugin-vue-components/vite’因为会有提示.

// vite.config.ts
import{ defineConfig } from 'vite'import vue from '@vitejs/plugin-vue'import AutoImport from 'unplugin-auto-import/vite'import Components from 'unplugin-vue-components/vite'import{ NaiveUiResolver } from 'unplugin-vue-components/resolvers'

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [
    vue(),
    AutoImport({
      imports: ['vue',
        {'naive-ui':['useDialog',
            'useMessage',
            'useNotification',
            'useLoadingBar']}]}),
    Components({
      resolvers: [NaiveUiResolver()]})]})

显示功能组件

由于本次要显示打印表格https://www.naiveui.com/zh-CN/os-theme/components/data-table
把项目里的helloworld,全文替换成,页面里的示例.
由于太长不再提供,需要注意的是message这个组件.示例中用到,也会报错.但是改起了有点费劲. 因为message是和系统window绑定的,需要一个入口.
入口就是helloworld的上层,APP.vue. 在APP.vue中用

 <n-message-provider> 包围<helloworld >,

才能使用提示窗口.我实验通过,但是弃用这个功能.
定义 vue的过程中, <scrite setup常出现在示例中,而我常消化不了这个语法,最后全换成了 没有它有时也会报错.
接下来的app.vue引入布局
<n-split size=“0.5”
是比例,不然可能会随页面内容变化,我需要中分所以是0.5,布局有各种,我只取这一种.这样能看到基本效果了.进入获取数据的下一步.

<n-gradient-text:size="26"type="error">
  {{ title }}  
  </n-gradient-text><br><h3align="right">  会议:
    <fontstyle="text-decoration: underline;margin-right:30px;">{{ meeting }} </font>时间:
    <fontstyle="text-decoration: underline;margin-right:30px;"> {{day}} </font></h3><n-message-provider><n-splitdirection="horizontal"style="height: 800px"max="300px"min="300px"size="0.5"default-size="300px"><template#1><HelloWorldref="leftgd":datas="lefts"/></template><template#2><HelloWorld:datas="rights"/></template></n-split></n-message-provider></div></template><style>h3{margin-top: 0px;margin-bottom: 4px;}.n-gradient-text{letter-spacing: 15px;}</style>

说下表格主体HelloWorld 这个表的margin ,也就是外框,和padding好像太大.所以用chrome的开发工具,拷贝css过来

<style lang="css">
 
table, th, td {
  border: 1px solid rgb(65, 44, 44);
  border-collapse: collapse; /* 移除单元格间的间隔 */
}
.n-data-table .n-data-table-td {
    padding: 4px;
  font-size : 16px;
  border: 1px solid rgb(65, 44, 44);
  border-collapse: collapse; /* 移除单元格间的间隔 */

     }
   .n-data-table .n-data-table-th {
    padding: 8px;
    font-size : 20px;
    border: 1px solid rgb(65, 44, 44);
    border-collapse: collapse; /* 移除单元格间的间隔 */
    font-family: '黑体', 'Heiti SC', sans-serif;}</style>

变成紧凑有边框的样式.

服务器数据拉取

本来上一个模板所用的v-for 语法,可以支持,数据Arrary,的splice操作,进行切片,分成两半.
但是datatable的,数据源,定义必须不能这样用.
下面是方式,遍历均分成两个新建的ref([])

constfetchUsers=async()=>{try{const response =awaitfetch('./api/getcheckin');
     
       stas.value=await response.json();
        
         stas.value.map((v:RowData,k:number)=>{
      v["key"]=k
      v['note']=''
      v['names']= v['names'].join(',')return v
    })
    stas.value.forEach((v:RowData,k:number)=>{if(k<17){
                lefts.value.push(v)}else{

        rights.value.push(v)}})//   getCurrentInstance().$refs.leftgd.dataref.value=lefts.value//   console.log( stas.value);}catch(error ){
        console.error('Fetch Error', error);}};

其中
v[“key”]=k
v[‘note’]=‘’
v[‘names’]= v[‘names’].join(‘,’)
key是必须的,按索引赋值, sta是原来就有的,names是格式需要变字符串,note是没用的备注.暂无信息.
这几个对应,HelloWorld,table的列定义

function createColumns(): DataTableColumns<RowData>{return[{
      title: '站点',
      key: 'sta'},
    {
      title: '人员',
      key: 'names'},
    {
      title: '备注',
      key: 'note'},
  
     
  ]}

调试通过以后这样
在这里插入图片描述

截屏包使用

在表头位置加入按钮保存,方法是产生主体的截屏,因为这些数据的redis只保存一天,会被覆盖,而且没有用数据库做后台,简化了配置.
注意最后一个 <div id=“maindiv”
这是用来获取内容的主体
<button @click=“takeScreenshot”>保存这是主要的功能

<template><divstyle="width=140px;"><n-inputautosizestyle="min-width: 20%"v-model:value="meeting"type="text"placeholder="会议名称"/><button@click="takeScreenshot">保存</button><ahref="./checkin/"><button>浏览</button></a><ahref="javascript:window.history.back()"><button>返回</button></a></div><divid="maindiv"ref="screenshotElement">

在scripte

import domtoimage from 'dom-to-image'

安装的时候注意使用 ts版本,因为默认安装了js的,build会报错.

pnpm i --save-dev @types/dom-to-image

这是报错指导的方法, 然后虽然baidu ai提示一段自用的编码来截屏,但是无法生效,这个库简洁明了,很是可爱.

主功函数,有两种保存方式,我注释了本地下载.link.a的那一整套.使用了上传post,API/putpng

//meeting后来加入的会议名,放在标题栏目下,可以任意定制,因为不需要服务器数据.只为模板图片保存.const meeting=ref("会议名称")consttakeScreenshot=async()=>{awaitnextTick();// 确保DOM更新const node = document.getElementById('maindiv')// 通过id获取domif(!node)return;//在ts下会提升node可能为空,所以是必须的.
      domtoimage
        .toPng(node).then((dataUrl:string)=>{//   const a = document.createElement('a') // 生成一个a元素//   const event = new MouseEvent('click') // 创建一个单击事件// a.download =getCurrentDate() // 设置图片名称没有设置则为默认//  a.href = "./checkin/" // 将生成的URL设置为a.href属性//  a.dispatchEvent(event) // 触发a的单击事件setTimeout( putpng ,10,(dataUrl))})};

上传截屏字节流需要注意的

上传数据函数putpng, 采用get参数应该是超长了,300K的base64,decode以后是200K多一点.四分一的扩展体积.参数里 key,dataurl是本次截取的数据,服务端要用.
这里本来没有跳转逻辑,window.location.href,放在这里很合适,毕竟不清楚,多久存储结束可以跳转.

const putpng = async (datastr:string)=>{
      try {
       const response = await fetch('./api/putpng', { method: 'POST', body: JSON.stringify({ dataurl: datastr }), 
       headers: {'Content-Type':'application/json'}});
     const r= await response.json()if(r["OK"]==1){
        setTimeout(function(){window.location.href="./checkin/"+getCurrentDate()+'.png'} ,100)}} catch (error ){
        console.error('Fetch Error', error);}};

加批注保存浏览返回细节调整

就是上面提到 cost meeting=ref(“名称”),批注上会议名字, 然后用style美化一下边距.虽然依然丑.
用浏览,返回caddy管理的图片列表.要比nginx好太多.而且反代,配置依然简洁,后面会介绍
在这里插入图片描述

<template><divstyle="width=140px;"><n-inputautosizestyle="min-width: 20%"v-model:value="meeting"type="text"placeholder="会议名称"/><button@click="takeScreenshot">保存</button><ahref="./checkin/"><button>浏览</button></a><ahref="javascript:window.history.back()"><button>返回</button></a></div> 
  .....
  </tmplate><style>h3{margin-top: 0px;margin-bottom: 4px;}.n-gradient-text{letter-spacing: 15px;}</style>

至此前端就完成了,主要提到了几个关键注意点,比如message, 按需引入,style样式更改,布局变化,datatable定义,后端将从flask入手.介绍算法的组成,和数据的安排.

后端

后端使用前大概已经做过了.vite.config.js

exportdefaultdefineConfig({
  plugins:[vue()],
  server:{
    proxy:{'/api/':{
        target:'http://127.0.0.1:8866/',// 目标服务器的域名
        changeOrigin:true,// 改变源到目标服务器// 其他可选配置...}}},})

这样, server的api路径,会定义到dev环境5173的api

基础数据类型

  • Redis库. 1,签到人员 key :check:{点位名} value,:集合 ,内容,人名字符串. 2, 请假人员, key:heck:{点位名}:thin value, Hash, {“人名”:“原因”} 此次只使用, Hash的keys.也就是人名列表,不使用所存内容.
  • 存储方式 保存为文件,在flask可管理,caddy被指定哦file-server, 且broser的一个目录.
  • 编程语言python,其实可以是任何语言的.

签到API数据提取

@app.route("/api/getck")defgetck():#{ m:"a,n,c" ,sta:"Z"},
    listr=[]
    ck_sta=cl.keys("check:*")for i in ck_sta:
        checks=cl.smembers(i)
        staname=i.split(b':')[1]
        listr.append({'sta':staname.decode(),'names':[m.decode()for m in checks]})print(listr)return json.dumps(listr)

以上是只有做过签到的站点,
以目前的版式,必须均分,所以没有签到的也包含才合适,另外请假的信息也需要包含进来,更正主要部分为


 day=getday()# 2024-11-22#初始化时,根据模板,把每个站点,建立一个  日期/店名的key:list#然后key被存储在了 日期+keys里,这里是为了一个站点名称名称排序,#否则,keys是错乱的,所以在这里必须借鉴这一天的排序,站点名.由此提前check信息.
allstas=[i.decode()for i in cl.lrange(day+"keys",0,-1)]
 ck_sta=cl.keys("check:*")#包含两类数据 Set是签到  check:{sta}:thin,是Hash,
 stats=[i.split('/')[1]for i in  allstats]for i in stats:iff"check:{i}".encode()in ck_sta:
            checks=cl.smembers(f"check:{i}")
            value=[m.decode()for m in checks]
             value.sort(key=lambda x:  stasdick[i].index(x))#需要根据名字模板排序,毕竟习惯老大,不能居于人下
             theone={'sta':i,'names':value}iff"check:{i}:thin".encode()in ck_sta:
                thins=[i.decode()for i in   cl.hkeys(f"check:{i}:thin")]for N in thins:if N in value:
                        value.remove(N)
                theone['names'].append('有事:('+'&'.join(thins)+")")else:
           theone={'sta':i,'names':[]}#啥也没有
        listr.append(theone)

png图片的提取储存和展示

注意,获取纯base64的值,去除22位前的说明.这是用于直接的<img
下展示的东西.然后decode.转换成bytes.用bw模式打开文件,既可以保持.
或者的第二个接口, 格式png.直接发送给请求方,就是一个图片文件.

@app.route("/api/putpng",methods=['POST'])defputpng():
   data = request.get_json()import base64
   dataraw=base64.b64decode(data['dataurl'][22:])withopen('./checkin/'+datatime+'.png','bw')as fp:
       fp.write(dataraw)
   cl.set("imgtoday",dataraw)return json.dumps({"OK":1})@app.route("/api/getpng")defgetpng():
   data=cl.get('imgtoday')print(len(data))
   response = make_response(data)
   response.headers['Content-Type']='image/png'# response.status=200return  response

关于caddy反代的配置文件

为了展示图片,原来打算用PanIndex,后来没有找到sfx的安装包.转入了caddy的怀抱,这是第三四次部署.也没太多难点了,开始还是不适用.主要在反代的路径配置上, 被反代的flask地址不能有路径, 必须到端口为止.这让后面的操作有点懵. 必须是转api的地址,但是转发后,默认,直接到根目录,要是也转发到api.需要使用rewrite指令.用法是试出来

:80 {# Set this path to your site's directory.
    root * /www/
   
    handle_path /api/* {
    rewrite * /api{path}
    reverse_proxy 1.1.1.25:7055 #此处为flask的服务和端口}# Enable the static file server.
    file_server {
         browse   #这样才能浏览目录}# Another common task is to set up a reverse proxy:# reverse_proxy localhost:8080# Or serve a PHP site through php-fpm:# php_fastcgi localhost:9000}

我记得以前从版本80会自动跳转443,目前这个默认关闭这个功能,caddy外网会自动取得ssl正式.
效果
在这里插入图片描述
打开一个
在这里插入图片描述

至此本部分的功能结束,遗留的一大隐患是,必须人来操作保存,而不能自动化存储.因为存储前需要渲染页面,设定会议标题.这些可以用slimdafadsf,那个S开头的代理访问浏览器完成.我不想复杂化,
毕竟人工也是必不会少的部分.
由于checkin在二级目标, 反代以后, vite-vue项目 pnpm build 以后的dist目录可以直接甩到根目录下.省去了以前改来改去的烦恼.
因为nginx是借住的另外一个项目里的. 也是演示性质的.
caddy目前和flask分属不同容器,但公用一个目录.我不清楚为啥,现在啥权限也不用搞,就能读写. 也许是一开始就赋予高权限.
docker版本的ubuntu的安装vscode,1.93后,据说权限必须高级才能打开,为此.去docker commit了.然后,重新高权限启动一次4G以上的大约10G的大数据.
另外

新开的这个vue项目,在pnpm build的时候开启了严格检查, 每个类型空,无用的变量名,引用,都在报警.
记得刚开始接触vue的3年前, 差不多把我折腾疯了.
然而自从开始这个签到系统.还没遇到过这种检查.在这个功能实现的时候,又遇到一次,关闭的地方在项目根目录
package.json

"scripts":{"dev":"vite",
    "build":"vite build",

build这样写
但后来

"build":"vue-tsc -b && vite build",

在半夜还是改成了这样写.也许是vite帮了很大的忙. 快而准.这次不是太痛苦.
话说ts的基础为0的我,还是被 setup
export 折腾的要疯
别提那些react ,ascy, await , 这些奇怪的语法,
感觉在rust也都会遇到.

今天就这样.

标签: 前端 python NativeUI

本文转载自: https://blog.csdn.net/wjcroom/article/details/143108162
版权归原作者 wjcroom 所有, 如有侵权,请联系我们删除。

“【前端截屏上传存储于Caddy静态目录-签到系统的信息保存】”的评论:

还没有评论