├── .gitignore ├── LICENSE ├── README.en.md ├── README.md └── server ├── C.py ├── R.py ├── app.yml ├── dao.py ├── data └── db │ └── poster.sqlite ├── fast.py ├── poster.py ├── requirements.txt ├── resource ├── fonts │ └── 0d44d315557a4a25.woff └── img │ └── no-img.jpg ├── static ├── css │ ├── app.742ff3ff.css │ └── chunk-vendors.87d3b6c6.css ├── favicon.ico ├── fonts │ ├── ionicons.143146fa.woff2 │ ├── ionicons.99ac3308.woff │ └── ionicons.d535a25a.ttf ├── img │ ├── ionicons.a2c4a261.svg │ └── no-img.3679ff87.svg ├── index.html ├── js │ ├── about.01fcc122.js │ ├── app.32a1d95f.js │ └── chunk-vendors.7e40b481.js └── static │ └── font │ ├── iconfont.css │ ├── iconfont.ttf │ ├── iconfont.woff │ └── iconfont.woff2 └── store.py /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | downloads/ 14 | eggs/ 15 | .eggs/ 16 | lib/ 17 | lib64/ 18 | parts/ 19 | sdist/ 20 | var/ 21 | wheels/ 22 | share/python-wheels/ 23 | *.egg-info/ 24 | .installed.cfg 25 | *.egg 26 | MANIFEST 27 | 28 | # PyInstaller 29 | # Usually these files are written by a python script from a template 30 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 31 | *.manifest 32 | *.spec 33 | 34 | # Installer logs 35 | pip-log.txt 36 | pip-delete-this-directory.txt 37 | 38 | # Unit test / coverage reports 39 | htmlcov/ 40 | .tox/ 41 | .nox/ 42 | .coverage 43 | .coverage.* 44 | .cache 45 | nosetests.xml 46 | coverage.xml 47 | *.cover 48 | .hypothesis/ 49 | .pytest_cache/ 50 | 51 | # Translations 52 | *.mo 53 | *.pot 54 | 55 | # Django stuff: 56 | *.log 57 | local_settings.py 58 | db.sqlite3 59 | 60 | # Flask stuff: 61 | instance/ 62 | .webassets-cache 63 | 64 | # Scrapy stuff: 65 | .scrapy 66 | 67 | # Sphinx documentation 68 | docs/_build/ 69 | 70 | # PyBuilder 71 | target/ 72 | 73 | # Jupyter Notebook 74 | .ipynb_checkpoints 75 | 76 | # IPython 77 | profile_default/ 78 | ipython_config.py 79 | 80 | # pyenv 81 | .python-version 82 | 83 | # celery beat schedule file 84 | celerybeat-schedule 85 | 86 | # SageMath parsed files 87 | *.sage.py 88 | 89 | # Environments 90 | .env 91 | .venv 92 | env/ 93 | venv/ 94 | ENV/ 95 | env.bak/ 96 | venv.bak/ 97 | 98 | # Spyder project settings 99 | .spyderproject 100 | .spyproject 101 | 102 | # Rope project settings 103 | .ropeproject 104 | 105 | # mypy 106 | .mypy_cache/ 107 | .dmypy.json 108 | dmypy.json 109 | 110 | # Pyre type checker 111 | .pyre/ 112 | .DS_Store 113 | .idea 114 | static/storage 115 | 116 | build.sh 117 | cache.sqlite 118 | 119 | #git -c credential.helper= -c core.quotepath=false -c log.showSignature=false fetch github --recurse-submodules=no --progress --prune 120 | 121 | design 122 | *.sh 123 | 124 | server/data/store 125 | .do** 126 | server/static/static/js/ 127 | server/static/static/css/ 128 | 129 | docker -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 fastposter 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.en.md: -------------------------------------------------------------------------------- 1 |

fast-poster logo

2 | 3 |

4 | Gitcode Repo stars 5 | GitHub Repo stars 6 | csharp 7 | csharp 8 | license 9 | version 10 |

11 | 12 | ## Introduction 13 | 14 | Fastposter is a rapid poster development tool that allows you to quickly create posters. Simply upload a background image and place components (`text`, `image`, `QR code`, `avatar`) in the desired positions to generate a poster. Click the `Code` button to directly generate SDK calling code in various languages, making development fast and easy. 15 | 16 | It has served numerous e-commerce projects, with over `80,000` users across multiple projects. Tested in production environments over the years, it's proven to be stable and reliable. It is widely used in various e-commerce, distribution systems, e-commerce posters, e-commerce main images, and other poster generation and production scenarios. 17 | 18 | > If this project has been helpful to you, please give it a star. 19 | 20 | ## Documentation 21 | 22 | - Developer Documentation: [https://fastposter.net/doc/](https://fastposter.net/doc/) 23 | - Java Professional Version - Online Experience: [https://fastposter.net/demo/java/](https://fastposter.net/demo/java/) 24 | - Python Professional Version - Online Experience: [https://fastposter.net/demo/python/](https://fastposter.net/demo/python/) 25 | - Community Version - Online Experience: [https://fastposter.net/demo/open/](https://fastposter.net/demo/open/) 26 | - 🔥🔥Cloud Service - Free Trial: [https://fastposter.net/](https://fastposter.net/) 27 | 28 | ## Features 29 | 30 | - Supports fast Docker deployment. 31 | - Supports production-level e-commerce environments. 32 | - Supports popular SDKs for quick development in `Java`, `Python`, `PHP`, `Go`, `JavaScript`, `mini-program`. 33 | - No need to write complex rendering code. 34 | - Supports multiple file formats: `jpeg`, `png`, `webp`, `pdf`, `base64`. 35 | - Convenient code generation. 36 | 37 | 38 | ## Getting Started 39 | 40 | ### Step 1: Start the Service 41 | 42 | ```bash 43 | docker run -it --name fastposter -p 5000:5000 fastposter/fastposter 44 | ``` 45 | 46 | ### Step 2: Edit the Poster 47 | 48 | ![image-20230726174142177](https://fastposter.net/dassets/image-20230726174142177.png) 49 | 50 | 51 | ### Step 3: Generate Code 52 | 53 | ![image-20230726174208989](https://fastposter.net/dassets/image-20230726174208989.png) 54 | 55 | 56 | Request Example (parameters can be passed directly): 57 | 58 | ```java 59 | // 1. Create a poster client object 60 | FastposterClient client = FastposterClient.builder() 61 | .endpoint("http://127.0.0.1:5000") // Set the access endpoint 62 | .token("ApfrIzxCoK1DwNZOEJCwlrnv6QZ0PCdv") // Set the token 63 | .build(); 64 | 65 | // 2. Prepare poster parameters 66 | Map params = new HashMap<>(); 67 | params.put("name", "Test Text"); 68 | 69 | // 3. Generate and save the poster 70 | client.buildPoster("80058c79d1e2e617").params(params).build().save("demo.png"); 71 | ``` 72 | 73 | 74 | 75 | ## Use Cases 76 | 77 | - Poster generator 78 | - Automatic poster generation tool 79 | - Online poster design and generation 80 | - Online poster maker 81 | - Generate Moments (WeChat) posters 82 | - E-commerce poster editor 83 | - Certificate creation 84 | - Automatic certificate generation tool 85 | - QR code sharing poster images 86 | - Create posters using Python Pillow 87 | - E-commerce main image editor 88 | - Generate QR code sharing posters using Java 89 | - Create posters with Java Graphics2D 90 | - Generate WeChat mini-program share posters 91 | - Generate QR code posters using PHP 92 | - Custom business poster images 93 | - Generate HTML5 posters 94 | - Create posters using HTML5 Canvas 95 | - Generate posters using JSON data for batch production 96 | - Draw images using BufferedImage 97 | 98 | ## Community 99 | 100 | Author's WeChat: `fastposter` 101 | 102 | ![Author's WeChat](https://fastposter.net/dassets/qrcode.jpeg) 103 | 104 | 105 | 106 | 107 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

fast-poster logo

2 | 3 |

4 | Gitcode Repo stars 5 | GitHub Repo stars 6 | gitee Repo stars 7 | csharp 8 | csharp 9 | license 10 | version 11 |

12 | 13 | ## 介绍 14 | 15 | fastposter海报生成器是一款快速开发海报的工具。只需上传一张背景图,在对应的位置放上组件(`文字`、`图片`、`二维码`、`头像`)即可生成海报。 点击`代码`直接生成各种语言SDK的调用代码,方便快速开发。 16 | 17 | 现已服务众多电商类项⽬,多个项⽬有`80W+`⽤户,通过多年⽣产环境的考验,稳定可靠。广泛应用于各类电商、分销系统、电商海报、电商主图等海报生成和制作场景。 18 | 19 | > 如果项目有帮到您,请点亮你点亮的小星星 20 | 21 | ## 文档 22 | 23 | - 开发文档:[https://fastposter.net/doc/](https://fastposter.net/doc/) 24 | - Java专业版-在线体验:[https://fastposter.net/demo/java/](https://fastposter.net/demo/java/) 25 | - Python专业版-在线体验:[https://fastposter.net/demo/python/](https://fastposter.net/demo/python/) 26 | - 社区版-在线体验:[https://fastposter.net/demo/open/](https://fastposter.net/demo/open/) 27 | - 🔥🔥云服务-免费试用:[https://fastposter.net/](https://fastposter.net/) 28 | 29 | ## 特性 30 | 31 | - 支持docker快速部署(支持arm和x86架构) 32 | - 支持电商级生产环境 33 | - 主流的SDK支持,方便快速开发 `Java` `Python` `PHP` `Go` `JavaScript` `小程序` 34 | - 无需编写复杂的绘图渲染代码 35 | - 支持多种文件格式 `jpeg` `png` `webp` `pdf` `base64` 36 | - 便捷的代码生成 37 | 38 | 39 | ## 快速开始 40 | 41 | ### 一、启动服务 42 | 43 | ```bash 44 | docker run -it --name fastposter -p 5000:5000 fastposter/fastposter 45 | ``` 46 | 47 | ### 二、编辑海报 48 | 49 | ![image-20240320145745417.png](https://fastposter.net/dassets/image-20240320145745417.png) 50 | 51 | 52 | ### 三、生成代码 53 | 54 | Java代码 55 | 56 | ![image-20240320145856100.png](https://fastposter.net/dassets/image-20240320145856100.png) 57 | 58 | 59 | ```java 60 | // 进一步了解,请参考开发文档 https://fastposter.net/doc/sdk/ 61 | import net.fastposter.client.FastposterClient; 62 | import java.util.*; 63 | 64 | public class FastposterClientDemo { 65 | 66 | public static void main(String[] args) { 67 | 68 | // 1.创建海报客户端对象 69 | FastposterClient client = FastposterClient.builder() 70 | .endpoint("http://127.0.0.1:5000") // 设置接入端点 71 | .token("ApfrIzxCoK1DwNZOEJCwlrnv6QZ0PCdv") // 设置token 72 | .build(); 73 | 74 | // 2.准备海报参数 75 | Map params = new HashMap<>(); 76 | params.put("NO", "SN88888888"); 77 | 78 | 79 | // 3.生成海报并保存 80 | client.buildPoster("6fba72004fa20aee").params(params).build().save(); 81 | 82 | } 83 | 84 | } 85 | ``` 86 | 87 | Python 代码 88 | 89 | ![image-20240320145914360.png](https://fastposter.net/dassets/image-20240320145914360.png) 90 | 91 | ```python 92 | # 进一步了解,请参考开发文档 https://fastposter.net/doc/sdk/ 93 | from fastposter import Client 94 | 95 | client = Client('ApfrIzxCoK1DwNZOEJCwlrnv6QZ0PCdv', 'http://127.0.0.1:5000') 96 | params = { 97 | "NO": "SN88888888" 98 | } 99 | client.buildPoster('6fba72004fa20aee', params=params).save() 100 | ``` 101 | 102 | 响应示例(返回海报图片) 103 | 104 | 105 | 106 | 107 | ## 适用场景 108 | 109 | - 海报生成器 110 | - 海报自动生成工具 111 | - 海报在线设计生成器 112 | - 海报生成器在线制作 113 | - 生成朋友圈海报 114 | - 电商海报编辑器 115 | - 证书制作 116 | - 证书自动生成工具 117 | - 二维码分享海报图片 118 | - Python Pillow绘图 Pillow制作海报 119 | - 电商主图编辑器 120 | - Java生成二维码分享海报图片 121 | - Java Graphics2D绘制海报图片 122 | - 微信小程序生成海报分享朋友圈 123 | - PHP生成二维码海报图片 124 | - 自定义商业海报图片 125 | - H5生成海报图片 126 | - canvas生成海报图片 127 | - 通过JSON生成海报图片 128 | - BufferdImage绘制图片 129 | 130 | ## 社区 131 | 132 | 作者微信`fastposter` 133 | 134 | ![fastposer作者微信](https://fastposter.net/dassets/qrcode.jpeg) 135 | -------------------------------------------------------------------------------- /server/C.py: -------------------------------------------------------------------------------- 1 | import getopt 2 | import hashlib 3 | import json 4 | import os 5 | import sys 6 | import uuid 7 | 8 | import yaml 9 | 10 | STORE_DB = 'data/db' 11 | STORE_DIR = 'data/store' 12 | STATUS_NORMAL = 1 13 | STATUS_DELETE = 2 14 | TOKEN = None 15 | 16 | config = {} 17 | if os.path.exists('app.yml'): 18 | config = yaml.safe_load(open('app.yml', encoding='utf-8')) 19 | 20 | 21 | def mkdirs(path): 22 | if not os.path.exists(path): 23 | print("mkdirs: path=" + path) 24 | os.makedirs(path) 25 | return path 26 | 27 | 28 | def init_path(): 29 | mkdirs(STORE_DB) 30 | 31 | 32 | def md5(param: str, len=32) -> str: 33 | if type(param) != 'str': 34 | param = json.dumps(param) 35 | return hashlib.md5(param.encode()).hexdigest()[0:len] 36 | 37 | 38 | def code(len=16) -> str: 39 | return md5(str(uuid.uuid4()), len) 40 | 41 | 42 | def indocker(): 43 | return os.environ.get('FASTPOSTER_IN_DOCKER', None) is not None 44 | 45 | 46 | def init(): 47 | global TOKEN 48 | help_info = """fast.py -t """ 49 | argv = sys.argv[1:] 50 | token = None 51 | try: 52 | opts, args = getopt.getopt(argv, "ht:", ["token="]) 53 | except getopt.GetoptError: 54 | print(help_info) 55 | sys.exit(2) 56 | for opt, arg in opts: 57 | if opt == '-h': 58 | print(help_info) 59 | sys.exit() 60 | elif opt in ("-t", "--token"): 61 | token = arg 62 | if not token: 63 | try: 64 | token = config.get('app')['token'] 65 | except Exception: 66 | ... 67 | TOKEN = token 68 | if not token: 69 | print(help_info) 70 | print('TOKEN', TOKEN) 71 | 72 | 73 | def check_token(token): 74 | return TOKEN == token 75 | 76 | 77 | def __load(tk=init()): 78 | ... 79 | 80 | 81 | __load() 82 | -------------------------------------------------------------------------------- /server/R.py: -------------------------------------------------------------------------------- 1 | import datetime 2 | import json 3 | 4 | class DateEncoder(json.JSONEncoder): 5 | def default(self, obj): 6 | if isinstance(obj, datetime.datetime): 7 | return obj.strftime("%Y-%m-%d %H:%M:%S") 8 | else: 9 | return json.JSONEncoder.default(self, obj) 10 | 11 | 12 | class R(): 13 | def __init__(self, code=0): 14 | self.d = {'code': code, 'msg': '', 'data': {}} 15 | 16 | def json(self): 17 | return json.dumps(self.d, ensure_ascii=False, cls=DateEncoder) 18 | 19 | def set(self, key, value): 20 | self.d[key] = value 21 | return self 22 | 23 | def add(self, key, value): 24 | self.d['data'][key] = value 25 | return self 26 | 27 | def __str__(self): 28 | return self.json() 29 | 30 | 31 | def ok(msg='success'): 32 | return R().set('msg', msg) 33 | 34 | 35 | def error(msg='failure'): 36 | return R(400).set('msg', msg) 37 | 38 | 39 | def expire(msg='token expired'): 40 | return R(401).set('msg', msg) -------------------------------------------------------------------------------- /server/app.yml: -------------------------------------------------------------------------------- 1 | app: 2 | name: fastposter 3 | token: ApfrIzxCoK1DwNZOEJCwlrnv6QZ0PCdv -------------------------------------------------------------------------------- /server/dao.py: -------------------------------------------------------------------------------- 1 | import datetime 2 | import json 3 | import sqlite3 4 | 5 | import C 6 | import poster 7 | import R 8 | import store 9 | 10 | 11 | def conn(): 12 | return sqlite3.connect(C.STORE_DB + '/poster.sqlite') 13 | 14 | 15 | def table(sql): 16 | name = sql.split(' ')[2].strip() 17 | with conn() as con: 18 | c = con.cursor() 19 | r = c.execute("select count(1) from sqlite_master where tbl_name = ?", [name]) 20 | if r.fetchone()[0] == 0: 21 | c.execute(sql) 22 | print(f"{name} created successfully.") 23 | 24 | 25 | INIT_SQL = [ 26 | 'CREATE TABLE posters (id integer NOT NULL PRIMARY KEY AUTOINCREMENT, code text, name text, preview text, json text, create_time date, update_time date, status integer)', 27 | 'CREATE TABLE links (id integer NOT NULL PRIMARY KEY AUTOINCREMENT, code text, pid integer, params text, create_time date)', 28 | ] 29 | 30 | 31 | def init(): 32 | C.init_path() 33 | for sql in INIT_SQL: table(sql) 34 | 35 | 36 | init() 37 | 38 | 39 | def db_save_poster(code: str, name: str, preview: str, json: str): 40 | with conn() as con: 41 | c = con.cursor() 42 | params = [code, name, preview, json, now_str(), int(C.STATUS_NORMAL)] 43 | c.execute("insert into posters (code, name, preview, json, create_time, status) values (?, ?, ?, ?, ?, ?)", 44 | params) 45 | con.commit() 46 | return c.lastrowid 47 | 48 | 49 | def db_update_poster(id: int, code: str, name: str, preview: str, json: str): 50 | with conn() as con: 51 | c = con.cursor() 52 | params = [name, preview, json, now_str(), id] 53 | c.execute("update posters set name=?,preview=?,json=?,update_time=? where id=?", params) 54 | con.commit() 55 | 56 | 57 | def db_delete_poster(id: int): 58 | with conn() as con: 59 | c = con.cursor() 60 | params = [C.STATUS_DELETE, id] 61 | c.execute("update posters set status=? where id=?", params) 62 | con.commit() 63 | 64 | 65 | def db_save_share(code, poster_id, param): 66 | with conn() as con: 67 | c = con.cursor() 68 | params = [code, poster_id, param, now_str()] 69 | c.execute("insert into links (code, pid, params, create_time) values (?, ?, ?, ?)", params) 70 | con.commit() 71 | return c.lastrowid 72 | 73 | 74 | def query_user_posters(): 75 | with conn() as con: 76 | c = con.cursor() 77 | r = c.execute('select * from posters where status=1 order by id desc') 78 | posters = [] 79 | for row in r: 80 | posters.append({ 81 | 'id': row[0], 82 | 'code': row[1], 83 | 'name': row[2], 84 | 'preview': row[3], 85 | 'json': row[4], 86 | 'createTime': row[5], 87 | 'updateTime': row[6], 88 | # 'status': row[7], 89 | }) 90 | return posters 91 | 92 | 93 | def query_user_poster(poster_id=0, uuid=None): 94 | with conn() as con: 95 | c = con.cursor() 96 | if uuid: 97 | r = c.execute('select * from posters where code = ? limit 1', [uuid]) 98 | else: 99 | r = c.execute('select * from posters where id = ? limit 1', [poster_id]) 100 | row = r.fetchone() 101 | if row is not None: 102 | return { 103 | 'id': row[0], 104 | 'code': row[1], 105 | 'name': row[2], 106 | 'preview': row[3], 107 | 'json': row[4], 108 | 'createTime': row[5], 109 | 'updateTime': row[6], 110 | 'status': row[7], 111 | } 112 | else: 113 | return None 114 | 115 | 116 | def query_user_share(code: str): 117 | with conn() as con: 118 | c = con.cursor() 119 | r = c.execute('select * from links where code = ? limit 1', [code]) 120 | row = r.fetchone() 121 | if row is not None: 122 | return { 123 | 'id': row[0], 124 | 'code': row[1], 125 | 'pid': row[2], 126 | 'params': row[3], 127 | 'createTime': row[4], 128 | } 129 | else: 130 | return None 131 | 132 | 133 | def now_str(days=0): 134 | return (datetime.datetime.now() + datetime.timedelta(days=days)).strftime('%Y-%m-%d %H:%M:%S') 135 | 136 | 137 | def save_user_poster(data, pd): 138 | code = C.code() 139 | name = data['name'] 140 | buf, mimetype = poster.drawio(pd, 0.4) 141 | path = store.save(buf.getvalue(), f"a.{pd['type']}", 'preview') 142 | return db_save_poster(code, name, path, data['json']) 143 | 144 | 145 | def update_user_poster(data, pd, id): 146 | code = data.get('code', C.code()) 147 | name = data['name'] 148 | buf, mimetype = poster.drawio(pd, 0.4) 149 | path = store.save(buf.getvalue(), f"a.{pd['type']}", 'preview') 150 | return db_update_poster(id, code, name, path, data['json']) 151 | 152 | 153 | def save_or_update_user_poster(data): 154 | pd = json.loads(data['json']) 155 | print(pd) 156 | id = data.get('id', 0) 157 | if id == 0: 158 | return save_user_poster(data, pd) 159 | else: 160 | return update_user_poster(data, pd, id) 161 | 162 | 163 | def copy_user_poster(id): 164 | p = query_user_poster(id) 165 | if p: 166 | code = C.code() 167 | return db_save_poster(code, p['name'] + '-复制', p['preview'], p['json']) 168 | return None 169 | 170 | 171 | def get_share_link(code, param): 172 | s = query_user_share(code) 173 | if s: 174 | return True 175 | if param.get('id', None): 176 | posterId = int(param['id']) 177 | elif param.get('posterId', None): 178 | posterId = int(param['posterId']) 179 | p = query_user_poster(posterId) 180 | if p is None: 181 | print('海报不存在') 182 | return R.error('海报不存在').json() 183 | db_save_share(code, posterId, json.dumps(param)) 184 | return True 185 | 186 | 187 | def find_share_data(code): 188 | s = query_user_share(code) 189 | if s is None: 190 | return None 191 | param = json.loads(s['params']) 192 | if param.get('id', None): 193 | posterId = int(param['id']) 194 | elif param.get('posterId', None): 195 | posterId = int(param['posterId']) 196 | p = query_user_poster(posterId) 197 | 198 | return merge_params(p, param) 199 | 200 | 201 | def find_build_data(uuid, param): 202 | p = query_user_poster(uuid=uuid) 203 | if p is None: 204 | return None 205 | return merge_params(p, param) 206 | 207 | 208 | def merge_params(p, param): 209 | d = json.loads(p['json']) 210 | for item in d['items']: 211 | vd = item['vd'].strip() 212 | if vd: 213 | if not param.get(vd, None): 214 | continue 215 | v = param[vd] 216 | if v: 217 | item['v'] = v.strip() 218 | # 处理背景图片 219 | if param.get('bgUrl', None): 220 | d['bgUrl'] = param['bgUrl'] 221 | return d 222 | -------------------------------------------------------------------------------- /server/data/db/poster.sqlite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/psoho/fast-poster/9f5fd7705c4b2107d4a9ff880d042c217c6ab757/server/data/db/poster.sqlite -------------------------------------------------------------------------------- /server/fast.py: -------------------------------------------------------------------------------- 1 | import base64 2 | import os 3 | import re 4 | from os.path import join, dirname 5 | 6 | import tornado.ioloop 7 | from tornado.web import RequestHandler, StaticFileHandler, Application 8 | 9 | import C 10 | import R 11 | import dao 12 | import json 13 | import poster 14 | import store 15 | 16 | 17 | class BaseHandler(RequestHandler): 18 | 19 | def set_default_headers(self) -> None: 20 | origin_url = self.request.headers.get('Origin') 21 | if not origin_url: origin_url = '*' 22 | self.set_header('Access-Control-Allow-Methods', 'POST, PUT, DELETE, GET, OPTIONS') 23 | self.set_header('fastposter', 'fastposter/v2.19.1') 24 | self.set_header('Access-Control-Allow-Credentials', 'true') 25 | self.set_header('Access-Control-Allow-Origin', origin_url) 26 | self.set_header('Access-Control-Allow-Headers', 'x-requested-with,token,Content-type,Client-Type,Client-Version') 27 | 28 | def options(self): 29 | self.set_status(200) 30 | self.finish() 31 | 32 | def json(self, r: R): 33 | self.set_header('Content-Type', 'application/json;charset=UTF-8') 34 | self.write(r.json()) 35 | 36 | 37 | class BaseAuthHandler(BaseHandler): 38 | 39 | def prepare(self): 40 | self.check_token() 41 | 42 | def token(self): 43 | t = self.request.headers['token'] if 'token' in self.request.headers else None 44 | if not t: 45 | t = self.get_argument('token', None) 46 | if not t: 47 | t = self.get_body_argument('token', None) 48 | return t 49 | 50 | def check_token(self): 51 | t = self.token() 52 | if not t: 53 | self.json(R.expire('not token')) 54 | return self.finish() 55 | if not C.check_token(t): 56 | self.json(R.expire()) 57 | return self.finish() 58 | 59 | 60 | class ApiLoginHandler(BaseHandler): 61 | 62 | def post(self): 63 | token = self.get_body_argument('token') 64 | if C.check_token(token): 65 | self.json(R.ok('login success.').add('token', token)) 66 | else: 67 | self.json(R.error('token not match!')) 68 | 69 | 70 | class ApiUserInfoHandler(BaseAuthHandler): 71 | 72 | def get(self): 73 | self.json(R.ok().add('user', {"id":2,"username":"user1","type":1,"status":1})) 74 | 75 | 76 | class ApiPostersHandler(BaseAuthHandler): 77 | 78 | def get(self, id): 79 | poster = dao.query_user_poster(id) 80 | self.write(R.ok().add('poster', poster).json()) 81 | 82 | 83 | class ApiUserPostersHandler(BaseAuthHandler): 84 | 85 | def get(self): 86 | posters = dao.query_user_posters() 87 | self.write(R.ok().add('posters', posters).json()) 88 | 89 | def delete(self, id): 90 | dao.db_delete_poster(int(id)) 91 | self.write(R.ok().json()) 92 | 93 | def post(self): 94 | data = json.loads(self.request.body) 95 | id = dao.save_or_update_user_poster(data) 96 | self.write(R.ok().add("id", id).json()) 97 | 98 | 99 | class ApiUserPostersCopyHandler(BaseAuthHandler): 100 | 101 | def post(self, id): 102 | id = dao.copy_user_poster(id) 103 | self.json(R.ok().add("id", id)) 104 | 105 | 106 | class ApiPreviewHandler(BaseAuthHandler): 107 | 108 | def post(self): 109 | data = json.loads(self.request.body) 110 | buf, mimetype = poster.drawio(data) 111 | self.set_header('Content-Type', mimetype) 112 | self.write(buf.getvalue()) 113 | 114 | 115 | class ApiUploadHandler(BaseAuthHandler): 116 | 117 | def post(self): 118 | for field_name, fs in self.request.files.items(): 119 | for f in fs: 120 | filename, body, content_type = f["filename"], f['body'], f["content_type"] 121 | path = store.save(body, filename) 122 | break 123 | self.json(R.ok().add("url", path)) 124 | 125 | 126 | class ApiLinkHandler(BaseAuthHandler): 127 | 128 | def post(self): 129 | param = json.loads(self.request.body) 130 | code = C.md5(param, 16) 131 | if dao.get_share_link(code, param): 132 | url = f"{uri}/v/{code}".replace('//v', '/v') 133 | self.json(R.ok().add('url', url)) 134 | else: 135 | self.json(R.error(f'the poster [{param["posterId"]}] not exits.')) 136 | 137 | 138 | class ApiBuildPosterHandler(BaseAuthHandler): 139 | 140 | def post(self): 141 | args = json.loads(self.request.body) 142 | print(args) 143 | traceId = C.code(32) 144 | payload = args['payload'] # type: str 145 | if not payload.startswith("{"): 146 | # 需要base64解码 147 | payload = base64.b64decode(payload) 148 | data = dao.find_build_data(args['uuid'], json.loads(payload)) 149 | if data is None: 150 | print('no poster here!') 151 | self.write(R.error('no poster here!')) 152 | return 153 | buf, mimetype = poster.drawio(data) 154 | self.set_header('fastposter-traceid', traceId) 155 | if args.get('b64', False): 156 | b64 = base64.b64encode(buf.read()).decode() 157 | self.write(b64) 158 | else: 159 | self.set_header('Content-Type', mimetype) 160 | self.write(buf.getvalue()) 161 | 162 | 163 | class ApiViewHandler(BaseHandler): 164 | 165 | def get(self, code: str): 166 | c = code.split('.') 167 | data = dao.find_share_data(c[0]) 168 | if data is None: 169 | print('no poster here!') 170 | self.write(R.error('no poster here!')) 171 | return 172 | if len(c) == 2 and (c[1] == 'png'): 173 | data['type'] = c[1] 174 | buf, mimetype = poster.drawio(data) 175 | if len(c) == 2 and c[1].startswith('b64'): 176 | b64 = base64.b64encode(buf.read()).decode() 177 | self.write(b64) 178 | else: 179 | self.set_header('Content-Type', mimetype) 180 | self.write(buf.getvalue()) 181 | 182 | 183 | class MyStaticFileHandler(StaticFileHandler, BaseHandler): 184 | pass 185 | 186 | 187 | def make_app(p): 188 | # path = "static" if C.indocker() else "../design/dist" 189 | path = "static" 190 | settings = { 191 | 'debug': not C.indocker() or os.environ.get('POSTER_DEBUG', 'false') == 'true' 192 | } 193 | print('p', p) 194 | return Application([ 195 | (f"{p}api/user/info", ApiUserInfoHandler), 196 | (f"{p}api/login", ApiLoginHandler), 197 | (f"{p}api/user/posters", ApiUserPostersHandler), 198 | (f"{p}api/user/posters/copy/(.+)", ApiUserPostersCopyHandler), 199 | (f"{p}api/user/posters/(.+)", ApiUserPostersHandler), 200 | (f"{p}api/user/poster/(.+)", ApiPostersHandler), 201 | (f"{p}api/preview", ApiPreviewHandler), 202 | (f"{p}api/upload", ApiUploadHandler), 203 | (f"{p}api/link", ApiLinkHandler), 204 | (f"{p}v1/build/poster", ApiBuildPosterHandler), 205 | (f"{p}v/(.+)", ApiViewHandler), 206 | (f'{p}(store/.*)$', StaticFileHandler, {"path": join(dirname(__file__), "data")}), 207 | (f'{p}resource/(.*)$', MyStaticFileHandler, {"path": join(dirname(__file__), "resource")}), 208 | (f'{p}(.*)$', StaticFileHandler, {"path": join(dirname(__file__), path), "default_filename": "index.html"}) 209 | 210 | ], **settings) 211 | 212 | 213 | if __name__ == "__main__": 214 | banner = ''' 215 | __ _ _ 216 | / _| | | | | 217 | | |_ __ _ ___ | |_ _ __ ___ ___ | |_ ___ _ __ 218 | | _| / _` |/ __|| __|| '_ \ / _ \ / __|| __| / _ \| '__| 219 | | | | (_| |\__ \| |_ | |_) || (_) |\__ \| |_ | __/| | 220 | |_| \__,_||___/ \__|| .__/ \___/ |___/ \__| \___||_| 221 | | | 222 | |_| 223 | fastposter(v2.19.1) 224 | https://fastposter.net/doc/ 225 | ''' 226 | PORT = 5000 227 | print(banner) 228 | uri = os.environ.get('POSTER_URI_PREFIX', f'http://0.0.0.0:{PORT}/') 229 | print(f'Listening at {uri}\n') 230 | g = re.search(r'http[s]?://.*?(/.*)', uri) 231 | web_context_path = '/' if not g else g.group(1) 232 | app = make_app(web_context_path) 233 | app.listen(port=PORT, address='0.0.0.0') 234 | tornado.ioloop.IOLoop.current().start() 235 | -------------------------------------------------------------------------------- /server/poster.py: -------------------------------------------------------------------------------- 1 | import os 2 | import traceback 3 | from io import BytesIO 4 | 5 | import qrcode 6 | import requests 7 | import requests_cache 8 | import urllib3 9 | from PIL import Image, ImageDraw, ImageFont 10 | 11 | import C 12 | 13 | headers = { 14 | 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.132 Safari/537.36' 15 | } 16 | 17 | NO_IMG = Image.open(os.path.join(os.path.dirname(__file__), 'resource/img/no-img.jpg')).convert('RGBA') 18 | requests_cache.install_cache(C.STORE_DB + '/cache') 19 | 20 | 21 | def fetchImg(url=''): 22 | try: 23 | if url.startswith('store/upload/'): 24 | if os.path.exists(f'data/{url}'): 25 | return Image.open(f'data/{url}').convert('RGBA') 26 | else: 27 | return NO_IMG 28 | r = requests.get(url, timeout=0.2) 29 | return Image.open(BytesIO(r.content)).convert('RGBA') 30 | except urllib3.exceptions.ReadTimeoutError: 31 | print(f'ERROR: fetch image timeout: url={url}') 32 | traceback.print_exc() 33 | return None 34 | except Exception: 35 | traceback.print_exc() 36 | return NO_IMG 37 | 38 | 39 | def drawImg(draw, d, bg): 40 | url, w, h, x, y = d['v'], d['w'], d['h'], d['x'], d['y'] 41 | try: 42 | img = fetchImg(url) 43 | if img == None: 44 | return 45 | img = img.resize((w, h), Image.ANTIALIAS) 46 | bg.paste(img, (x, y), img) 47 | except Exception as e: 48 | print('绘制图片异常: %s' % e) 49 | pass 50 | 51 | 52 | def drawBg(item): 53 | url, w, h, c = str(item['bgUrl']), item['w'], item['h'], item['bgc'] 54 | c = '#fafbfc00' if c == '' else c 55 | if not url.strip(): 56 | img = Image.new('RGBA', (w, h), c) 57 | else: 58 | img = fetchImg(url) 59 | img = img.resize((w, h), Image.ANTIALIAS) 60 | draw = ImageDraw.Draw(img) 61 | return img, draw 62 | 63 | 64 | def getFont(item): 65 | fn, size = item['fn'], item['s'] 66 | if fn == "": 67 | fn = '0d44d315557a4a25.woff' 68 | font = 'resource/fonts/' + fn 69 | if not os.path.exists(font): 70 | font = 'resource/fonts/0d44d315557a4a25.woff' 71 | return ImageFont.truetype(font, size) 72 | 73 | 74 | def wrap_text(text, font, width): 75 | sb = [] 76 | temp = '' 77 | for s in text: 78 | if s == '\n': # 优化本文中含有换行符 79 | sb.append(temp) 80 | temp = '' 81 | continue 82 | t = temp + s 83 | if font.getsize(t)[0] > width: 84 | sb.append(temp) 85 | temp = s 86 | else: 87 | temp += s 88 | if temp != '': 89 | sb.append(temp) 90 | return sb 91 | 92 | 93 | def drawText(draw, item, bg): 94 | font = getFont(item) 95 | v, w, h, x, y, c = item['v'], item['w'], item['h'], item['x'], item['y'], item.get('c', '#010203') 96 | img = Image.new("RGBA", (w, h), '#fff0') 97 | draw = ImageDraw.Draw(img) # type:ImageDraw.ImageDraw 98 | t = wrap_text(v, font, w) 99 | draw.text((0, 0), '\n'.join(t), fill=c, font=font) 100 | if img is not None: 101 | bg.paste(img, (x, y), img) 102 | 103 | 104 | def drawQrCode(draw, item, bg): 105 | url, w, h, x, y, c = item['v'], item['w'], item['h'], item['x'], item['y'], item.get('c', '#010203').strip() 106 | c = '#010203' if len(c) == 0 else c 107 | p = item.get('p', 0) 108 | qr = qrcode.QRCode( 109 | version=2, 110 | error_correction=qrcode.constants.ERROR_CORRECT_M, 111 | box_size=10, 112 | border=p, 113 | ) 114 | qr.add_data(url) 115 | qr.make(fit=True) 116 | img = qr.make_image(fill_color=c, back_color="#ffffff") 117 | img = img.resize((w, h), Image.ANTIALIAS) 118 | bg.paste(img, (x, y), None) 119 | 120 | 121 | def drawAvatar(draw, item, bg): 122 | url, w, h, x, y, c = item['v'], item['w'], item['h'], item['x'], item['y'], item.get('c', '#ffffff').strip() 123 | c = '#ffffff' if len(c) == 0 else c 124 | im = fetchImg(url) 125 | if im == None: 126 | return 127 | bigsize = (im.size[0] * 3, im.size[1] * 3) 128 | mask = Image.new('L', bigsize, 0) 129 | draw = ImageDraw.Draw(mask) 130 | draw.ellipse((0, 0) + bigsize, fill=255) 131 | mask = mask.resize(im.size, Image.ANTIALIAS) 132 | im.putalpha(mask) 133 | im = im.resize((w, h), Image.ANTIALIAS) 134 | mask = Image.new('RGBA', bigsize) 135 | draw = ImageDraw.Draw(mask) 136 | draw.ellipse((0, 0) + bigsize, outline=c, width=4 * 3) 137 | mask = mask.resize(im.size, Image.ANTIALIAS) 138 | im.paste(mask, (0, 0), mask) 139 | bg.paste(im, (x, y), im) 140 | pass 141 | 142 | 143 | def draw(data): 144 | img, draw = drawBg(data) 145 | 146 | for item in data['items']: 147 | type = item['t'] 148 | if 'text' == type: 149 | drawText(draw, item, bg=img) 150 | if 'image' == type: 151 | drawImg(draw, item, bg=img) 152 | if 'avatar' == type: 153 | drawAvatar(draw, item, bg=img) 154 | if 'qrcode' == type: 155 | url = item.get('v', '') 156 | if url.startswith('img:'): 157 | url = url[4:] 158 | item['v'] = url 159 | drawImg(draw, item, bg=img) 160 | else: 161 | drawQrCode(draw, item, bg=img) 162 | 163 | if data['type'] == "jpeg": 164 | img = img.convert("RGB") 165 | return img 166 | 167 | 168 | def drawio(data, scale=1): 169 | type = data['type'] 170 | if type == "jpg": 171 | type = "jpeg" 172 | data['type'] = type 173 | mimetype = "image/" + data['type'] 174 | img = draw(data) 175 | quality = data['quality'] 176 | if scale < 1: 177 | w = img.size[0] 178 | h = img.size[1] 179 | img = img.resize((int(w * scale), int(h * scale)), Image.ANTIALIAS) 180 | buf = BytesIO() 181 | img.save(buf, type, quality=quality, progressive=True) 182 | buf.seek(0) 183 | return buf, mimetype 184 | -------------------------------------------------------------------------------- /server/requirements.txt: -------------------------------------------------------------------------------- 1 | requests==2.31.0 2 | Pillow==9.5.0 3 | qrcode==7.4.2 4 | requests_cache==1.1.0 5 | tornado==6.2 6 | pyyaml==6.0.1 -------------------------------------------------------------------------------- /server/resource/fonts/0d44d315557a4a25.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/psoho/fast-poster/9f5fd7705c4b2107d4a9ff880d042c217c6ab757/server/resource/fonts/0d44d315557a4a25.woff -------------------------------------------------------------------------------- /server/resource/img/no-img.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/psoho/fast-poster/9f5fd7705c4b2107d4a9ff880d042c217c6ab757/server/resource/img/no-img.jpg -------------------------------------------------------------------------------- /server/static/css/app.742ff3ff.css: -------------------------------------------------------------------------------- 1 | #app{font-family:Avenir,Helvetica,Arial,sans-serif;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;color:#2c3e50;width:100%;height:100%;position:absolute}div.ivu-modal-content{border-radius:0}div.ivu-modal-footer{display:none}div.ivu-modal{top:132px}button.ivu-btn{border-radius:0}.ivu-modal-wrap .code *{-webkit-user-select:text;-moz-user-select:text;-ms-user-select:text;user-select:text}.poster-item-qrcode[data-v-0a24c513]{width:100%!important;height:100%!important}.item-image[data-v-e03238ea]{width:100%;height:100%}.poster-item .vdr.active:before{content:"";width:100%;height:100%;top:0;left:0;outline:1px solid #6ccfff}.vdr{text-align:left}.vdr.active{cursor:move}.poster-item-vue-drag :hover{outline:1px solid #6ccfff}.poster-item-vue-drag .vdr-stick-bl,.poster-item-vue-drag .vdr-stick-br,.poster-item-vue-drag .vdr-stick-tl,.poster-item-vue-drag .vdr-stick-tr{border-radius:50%}.poster-item-vue-drag .vdr-stick{width:12px!important;height:12px!important;border:1px solid rgba(0,0,0,.2)}.poster-item-vue-drag .vdr-stick:hover{outline:none}.poster-item-vue-drag .vdr-stick-ml,.poster-item-vue-drag .vdr-stick-mr{width:7px!important;height:14px!important;border-radius:6px}.poster-item-vue-drag .vdr-stick-bm,.poster-item-vue-drag .vdr-stick-tm{width:14px!important;height:7px!important;border-radius:6px}.poster-item-vue-drag .vdr-stick-tl{top:-6px!important;left:-6px!important}.poster-item-vue-drag .vdr-stick-tr{top:-6px!important;right:-6px!important}.poster-item-vue-drag .vdr-stick-bl{bottom:-6px!important;left:-6px!important}.poster-item-vue-drag .vdr-stick-br{bottom:-6px!important;right:-6px!important}.poster-item-vue-drag .vdr-stick-ml,.poster-item-vue-drag .vdr-stick-mr{margin-top:-7px!important}.poster-item-vue-drag .vdr-stick-bm,.poster-item-vue-drag .vdr-stick-tm{margin-left:-6px!important}.contextmenu[data-v-014fdc05]{position:absolute;z-index:1000}.contextmenu ul[data-v-014fdc05]{border:1px solid #e4e7ed;border-radius:4px;background-color:#fff;-webkit-box-shadow:0 2px 12px 0 rgba(0,0,0,.1);box-shadow:0 2px 12px 0 rgba(0,0,0,.1);-webkit-box-sizing:border-box;box-sizing:border-box;margin:5px 0;padding:6px 0;text-align:left}.contextmenu ul li[data-v-014fdc05]{font-size:14px;padding:0 20px;position:relative;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;color:#606266;height:34px;line-height:34px;-webkit-box-sizing:border-box;box-sizing:border-box;cursor:pointer}.contextmenu ul li[data-v-014fdc05]:hover{background-color:#f5f7fa}p[data-v-2a577a8e]{margin:0;padding:0}.content-warpper[data-v-2a577a8e]{text-align:center;width:100%;height:calc(100vh - 58px);background-color:#f1f3f7}.content-warpper .canvas-wrapper[data-v-2a577a8e]{position:absolute;left:80px;right:260px;top:0;bottom:0;background:#f1f3f7;overflow:auto;-webkit-transition:left .3s ease-in-out;transition:left .3s ease-in-out}.content-warpper .canvas-wrapper.sidebar-extend[data-v-2a577a8e]{left:408px}.content-warpper .canvas-content-wrapper[data-v-2a577a8e]{background-color:#fff;position:relative;display:flow-root;-webkit-box-shadow:rgba(0,0,0,.2) 1px 1px 15px;box-shadow:1px 1px 15px rgba(0,0,0,.2);margin:80px auto}.content-warpper .canvas-content-wrapper .canvas-content[data-v-2a577a8e]{padding:0;margin:0;height:100%}.content-warpper .canvas-content-wrapper .canvas-content.bl[data-v-2a577a8e],.content-warpper .canvas-content-wrapper .canvas-content.br[data-v-2a577a8e]{border-right:1px dashed var(--primary)}.content-warpper .canvas-content-wrapper .canvas-content.bt[data-v-2a577a8e]{border-top:1px dashed var(--primary)}.content-warpper .canvas-content-wrapper .canvas-content.bb[data-v-2a577a8e]{border-bottom:1px dashed var(--primary)}.content-warpper .canvas-tool-bar[data-v-2a577a8e]{width:120px;margin-left:-100px;height:36px;background:#fff;border-radius:4px;position:fixed;right:300px;bottom:25px;color:#333;line-height:36px;font-size:12px;z-index:99;-webkit-box-shadow:0 2px 8px 0 rgba(0,0,0,.06);box-shadow:0 2px 8px 0 rgba(0,0,0,.06)}.content-warpper .canvas-tool-bar .scale-area[data-v-2a577a8e]{margin:0 auto;width:88px;font-size:14px;font-weight:700}.content-warpper .canvas-tool-bar .scale-area .icon-minus[data-v-2a577a8e]{float:left;font-size:20px;cursor:pointer}.content-warpper .canvas-tool-bar .scale-area .scale-num[data-v-2a577a8e]{display:inline-block;font-weight:200}.content-warpper .canvas-tool-bar .scale-area .icon-plus[data-v-2a577a8e]{float:right;font-size:20px;cursor:pointer}.content-warpper .canvas-tool-bar .iconfont[data-v-2a577a8e]{float:left;font-size:14px;cursor:pointer}.content-warpper .canvas-tool-bar .iconfont[data-v-2a577a8e]:hover{color:#555}.my-poster-list[data-v-577ecc48]{padding-top:30px;overflow-y:auto}.my-poster-list .picture-container[data-v-577ecc48]{padding:0 16px 20px;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-direction:row;flex-direction:row;-ms-flex-wrap:wrap;flex-wrap:wrap}.my-poster-list .my-poster-item[data-v-577ecc48]{width:130px;height:230px;border:1px solid #e0e5ea;border-radius:4px;overflow:hidden;position:relative;margin:4px}.my-poster-list .my-poster-item .item-title[data-v-577ecc48]{position:absolute;display:none;width:100%;height:100%}.my-poster-list .my-poster-item .item-title .title[data-v-577ecc48]{width:100%;cursor:auto;color:#fff;background:#2c3e50;opacity:.8;font-size:11px;display:inline-block;border-radius:2px;padding:4px}.my-poster-list .my-poster-item .item-title .btn-delete[data-v-577ecc48]{position:absolute;display:block;bottom:0;right:2px;cursor:pointer}.my-poster-list .my-poster-item .item-title .btn-delete[data-v-577ecc48]:hover{color:#ff787b;font-size:20px;font-weight:bolder;-webkit-transition:font-size .3s ease-in-out;transition:font-size .3s ease-in-out}.my-poster-list .my-poster-item .item-title .btn-copy[data-v-577ecc48]{position:absolute;display:block;bottom:0;left:2px;cursor:pointer}.my-poster-list .my-poster-item .item-title .btn-copy[data-v-577ecc48]:hover{color:var(--primary);font-size:20px;font-weight:bolder;-webkit-transition:font-size .3s ease-in-out;transition:font-size .3s ease-in-out}.my-poster-list .my-poster-item:hover .item-title[data-v-577ecc48]{display:block}.my-poster-list .my-poster-item[data-v-577ecc48]:before{content:" ";background:rgba(0,0,0,.15);position:absolute;left:0;top:0;right:0;bottom:0;opacity:0;-webkit-transition:opacity .2s ease;transition:opacity .2s ease}.my-poster-list .my-poster-item[data-v-577ecc48]:hover:before{opacity:1}.my-poster-list .poster-preview-img[data-v-577ecc48]{width:130px;height:230px;min-height:100px}.setting-layer[data-v-26ff44a0]{padding:6px;color:var(--primary);color:var(--text);background-color:#f1f3f7;border-radius:2px;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;margin:6px 4px 0;font-size:12px}.setting-layer .mr8[data-v-26ff44a0]{margin-right:10px}.setting-layer .warn[data-v-26ff44a0]{color:var(--red)}.setting-layer .icon[data-v-26ff44a0]{font-size:16px}.setting-layer.active[data-v-26ff44a0]{color:var(--primary)}.setting-layer[data-v-26ff44a0]:focus{outline:1px dashed var(--text);-webkit-transition:opacity 1s ease-in-out;transition:opacity 1s ease-in-out;-webkit-animation:glow-data-v-26ff44a0 .8s ease-out infinite alternate;animation:glow-data-v-26ff44a0 .8s ease-out infinite alternate}@-webkit-keyframes glow-data-v-26ff44a0{0%{outline:1px dashed #ccc;-webkit-box-shadow:none;box-shadow:none}to{outline:1px dashed var(--primary);-webkit-box-shadow:rgba(0,0,0,.3) 1px 1px 6px;box-shadow:1px 1px 6px rgba(0,0,0,.3)}}@keyframes glow-data-v-26ff44a0{0%{outline:1px dashed #ccc;-webkit-box-shadow:none;box-shadow:none}to{outline:1px dashed var(--primary);-webkit-box-shadow:rgba(0,0,0,.3) 1px 1px 6px;box-shadow:1px 1px 6px rgba(0,0,0,.3)}}.tool-layout[data-v-9d9eaeae]{position:absolute;height:100%}.tool-layout .preview-picture[data-v-9d9eaeae]{display:none}.nav-layout[data-v-9d9eaeae]{position:absolute;left:0;top:0;width:80px;background-color:#fff;border-right:1px solid #f1f3f7;height:100%;padding-top:10px;z-index:12}.nav-layout .nav-item[data-v-9d9eaeae]{position:relative;display:inline-block;text-align:center;width:100%;height:66px;cursor:pointer;margin-top:1px;border-left:4px solid #fff;border-right:4px solid #fff}.nav-layout .nav-item .nav-item-text[data-v-9d9eaeae]{color:var(--text);font-size:12px;margin-top:4px}.nav-layout .nav-item.active[data-v-9d9eaeae]{color:var(--primary);border-left-color:var(--primary)}.nav-layout .nav-item.active .iconfont[data-v-9d9eaeae],.nav-layout .nav-item.active .nav-item-text[data-v-9d9eaeae]{color:var(--primary)}.nav-layout .nav-item[data-v-9d9eaeae]:hover{border-left-color:var(--primary)}.nav-layout .nav-item .iconfont[data-v-9d9eaeae]{display:inline-block;margin-top:4px;font-size:24px;color:var(--text)}.tool-extend-wrapper[data-v-9d9eaeae]{position:absolute;top:0;height:100%;width:328px;background:#fff;margin-left:80px;left:-328px;z-index:11;-webkit-transition:left .3s ease-in-out;transition:left .3s ease-in-out}.tool-extend-wrapper[data-v-9d9eaeae]:hover{outline:none}.tool-extend-wrapper.active[data-v-9d9eaeae]{left:0}.tool-extend-wrapper .panel-layers[data-v-9d9eaeae]{width:100%;height:100%;text-align:center;overflow:hidden}.tool-extend-wrapper .panel-layers .panel-layers-title[data-v-9d9eaeae]{padding:10px;background-color:#fff}.tool-extend-wrapper .panel-layers .panel-layers-items[data-v-9d9eaeae]{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:reverse;-ms-flex-direction:column-reverse;flex-direction:column-reverse;text-align:left;background-color:#fff;padding:12px;overflow:auto}.setting-item-base{text-align:center;vertical-align:center}.setting-item-base .input{width:56px}.setting-item-base .ivu-input-number-handler-wrap{width:18px!important}.setting-item-base .ivu-row{margin-top:6px}.setting-item-base .lh32{line-height:32px}.setting-item-base .lh36{line-height:36px}.setting-item-base .mt10{margin-top:10px}.property-layout{text-align:center;vertical-align:center}.property-layout .input{width:56px}.property-layout .ivu-input-number-handler-wrap{width:18px!important}.property-layout .ivu-row{margin-top:6px}.property-layout .lh32{line-height:32px}.property-layout .lh36{line-height:36px}.property-layout .mt10{margin-top:10px}.property-layout .mt20{margin-top:20px}p[data-v-16c46d15]{margin:0;padding:0}.property-layout[data-v-16c46d15]{position:absolute;right:0;top:0;bottom:0;background:#fff;width:260px;-webkit-box-shadow:0 0 10px #cecece;box-shadow:0 0 10px #cecece;z-index:99}.property-layout .title[data-v-16c46d15]{width:100%;height:59px;border-bottom:1px solid #e4e9ee}.property-layout .title .item[data-v-16c46d15]{width:130px;height:60px;text-align:center;float:left;cursor:pointer}.property-layout .title .item p[data-v-16c46d15]{padding:0;margin:0;height:58px;line-height:58px;font-size:16px;color:var(--text);display:inline-block}.property-layout .title .item.active p[data-v-16c46d15],.property-layout .title .item:hover p[data-v-16c46d15]{border-bottom:2px solid var(--primary)}.property-layout .canvas-setting[data-v-16c46d15]{width:100%;padding-top:20px;height:calc(100% - 80px)}.property-layout .canvas-setting .panel-item[data-v-16c46d15]{display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-pack:justify;-webkit-box-pack:justify;justify-content:space-between;-webkit-box-align:center;-ms-flex-align:center;align-items:center;margin-left:19px;margin-bottom:10px}.property-layout .canvas-setting .panel-item .item-title[data-v-16c46d15]{display:inline;font-size:14px;color:#666;float:left}.property-layout .canvas-setting .panel-item .input-area[data-v-16c46d15]{right:20px;position:relative}.property-layout .canvas-setting .panel-item .input-area input[data-v-16c46d15]{background:#f4f4f4;width:60px;height:36px;border-radius:4px;text-align:center;font-size:14px;color:#999;outline:none;border:0 solid #fff}.property-layout .canvas-setting .panel-item .input-area input[data-v-16c46d15]:focus{width:58px;height:34px;border:1px solid var(--primary)}.property-layout .canvas-setting .panel-item.panel-item-bg-color .input-area input[data-v-16c46d15],.property-layout .canvas-setting .panel-item.panel-item-bg-color .input-area input[data-v-16c46d15]:focus{width:100px}.debug-layout[data-v-a4c62e20]{width:1px;background-color:#2c3e50;color:#f1f1f1;position:absolute;top:0;z-index:100;overflow:hidden;cursor:default;-webkit-user-select:text;-moz-user-select:text;-ms-user-select:text;user-select:text;-webkit-transition:left .4s ease-in-out;transition:left .4s ease-in-out;width:420px;height:100vh;overflow:auto;left:-419px}.debug-layout pre[data-v-a4c62e20]{-webkit-user-select:auto;-moz-user-select:auto;-ms-user-select:auto;user-select:auto}.debug-layout.active[data-v-a4c62e20]{left:0}.iv-modal .ivu-modal-mask{background-color:#5edfff;background-color:#dcdfe6}.vertical-center-modal{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center}.vertical-center-modal .ivu-modal{top:0}.code[data-v-2f10b55e],.code[data-v-3f6e72c3],.code[data-v-6fb1b24c],.code[data-v-604543c2],.code[data-v-d1df5c38],.code[data-v-d2523e40]{text-align:left;overflow:auto;-webkit-user-select:text;-moz-user-select:text;-ms-user-select:text;user-select:text;cursor:text;max-height:500px}.top-bar-layout[data-v-287a91b7]{height:58px;background:#fff;border-bottom:0 solid #ff7671;z-index:100;position:absolute;min-width:inherit;width:100%;-webkit-box-shadow:0 1px 4px hsla(0,0%,88.2%,.5);box-shadow:0 1px 4px hsla(0,0%,88.2%,.5)}.top-bar-layout .left-bar[data-v-287a91b7]{height:58px;line-height:58px;float:left;padding-left:12px}.top-bar-layout .left-bar .main-title[data-v-287a91b7]{font-size:20px;font-weight:bolder;display:inline-block;margin-right:10px}.top-bar-layout .left-bar .btn-icon[data-v-287a91b7]{padding:8px 10px;font-size:20px;border-radius:4px;cursor:pointer;margin-right:4px}.top-bar-layout .left-bar .btn-icon[data-v-287a91b7]:hover{background-color:rgba(44,62,80,.12549019607843137)}.top-bar-layout .left-bar .unused[data-v-287a91b7]{cursor:unset}.top-bar-layout .left-bar .text-saved[data-v-287a91b7]{color:rgba(0,0,0,.4666666666666667);font-size:14px}.top-bar-layout .right-bar[data-v-287a91b7]{height:58px;line-height:58px;float:right;padding-right:30px;display:-webkit-box;display:-ms-flexbox;display:flex;width:168px;-webkit-box-pack:space-evenly;-ms-flex-pack:space-evenly;justify-content:space-evenly}.top-bar-layout .right-bar .iconfont[data-v-287a91b7]{font-size:30px;color:#2c3e50;display:block}.top-bar-layout .right-pro[data-v-287a91b7]{display:-webkit-box;display:-ms-flexbox;display:flex;float:right;line-height:58px;height:58px;width:360px;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between}.top-bar-layout .right-xxx[data-v-287a91b7]{display:-webkit-box;display:-ms-flexbox;display:flex;width:160px;-webkit-box-pack:space-evenly;-ms-flex-pack:space-evenly;justify-content:space-evenly}.top-bar-layout .right-xxx a[data-v-287a91b7]{color:#00b07e}.feedback[data-v-287a91b7]{width:100%}.kf-qrcode[data-v-287a91b7]{width:200px;margin:60px auto;display:block}.pro-logo[data-v-287a91b7]{display:block;text-decoration:none;font-size:16px;font-weight:700}body,html{padding:0;margin:0}*{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}:root{--blue:#2c8ef8;--indigo:#727cf5;--purple:#6b5eae;--pink:#ff787b;--red:#fa5c7c;--orange:#fd7e14;--yellow:#ffbc00;--green:#0acf97;--teal:#02a8b5;--cyan:#39afd1;--white:#fff;--gray:#98a6ad;--gray-dark:#343a40;--primary:#2c8ef8;--secondary:#6c757d;--success:#0acf97;--info:#39afd1;--warning:#ffbc00;--danger:#fa5c7c;--light:#e3eaef;--dark:#313a46;--text:#333;--breakpoint-xs:0;--breakpoint-sm:576px;--breakpoint-md:768px;--breakpoint-lg:992px;--breakpoint-xl:1200px;--font-family-sans-serif:"Nunito",sans-serif;--font-family-monospace:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace}.poster-layout{width:100%;height:100%;overflow:hidden;position:relative}.layout-wrapper{background-color:#f1f3f7;position:absolute;top:58px;left:0;width:100%;height:calc(100% - 58px);overflow:hidden}.home[data-v-21eff840]{width:100%;height:100%}.container{width:100vw;height:100vh;background-color:#f1f3f7}.container .top{height:80px;-webkit-box-shadow:0 1px 4px hsla(0,0%,88.2%,.5);box-shadow:0 1px 4px hsla(0,0%,88.2%,.5);line-height:80px;padding-left:40px}.container .nav-bar,.container .top{background-color:#2c3e50;z-index:10000;color:#fff;font-weight:700;font-size:20px}.container .nav-bar{height:calc(100vh - 80px);width:200px;position:absolute;left:0;top:80px}.container .nav-bar .nav-item{padding-left:20px;margin-top:10px}.container .nav-bar .nav-item:hover{background-color:#fff;color:#2c3e50}.container .content-container{height:calc(100% - 80px);position:relative;overflow:hidden;padding-left:200px}.container .content-container iframe{width:100%;height:100%;border:none} -------------------------------------------------------------------------------- /server/static/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/psoho/fast-poster/9f5fd7705c4b2107d4a9ff880d042c217c6ab757/server/static/favicon.ico -------------------------------------------------------------------------------- /server/static/fonts/ionicons.143146fa.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/psoho/fast-poster/9f5fd7705c4b2107d4a9ff880d042c217c6ab757/server/static/fonts/ionicons.143146fa.woff2 -------------------------------------------------------------------------------- /server/static/fonts/ionicons.99ac3308.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/psoho/fast-poster/9f5fd7705c4b2107d4a9ff880d042c217c6ab757/server/static/fonts/ionicons.99ac3308.woff -------------------------------------------------------------------------------- /server/static/fonts/ionicons.d535a25a.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/psoho/fast-poster/9f5fd7705c4b2107d4a9ff880d042c217c6ab757/server/static/fonts/ionicons.d535a25a.ttf -------------------------------------------------------------------------------- /server/static/img/no-img.3679ff87.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /server/static/index.html: -------------------------------------------------------------------------------- 1 | fastposter海报生成器
-------------------------------------------------------------------------------- /server/static/js/about.01fcc122.js: -------------------------------------------------------------------------------- 1 | (window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["about"],{8166:function(t,e,n){"use strict";n.r(e);var a=function(){var t=this,e=t.$createElement;t._self._c;return t._m(0)},s=[function(){var t=this,e=t.$createElement,n=t._self._c||e;return n("div",{staticClass:"about"},[n("h1",[t._v("This is an about page")])])}],u=n("2877"),c={},i=Object(u["a"])(c,a,s,!1,null,null,null);e["default"]=i.exports}}]); -------------------------------------------------------------------------------- /server/static/js/app.32a1d95f.js: -------------------------------------------------------------------------------- 1 | (function(t){function e(e){for(var r,i,s=e[0],c=e[1],u=e[2],l=0,f=[];l>>: OK")},cancel:function(){},handleSubmit:function(t){var e=this,n=this;this.$refs[t].validate((function(t){t?n.$http.post("api/login",n.formLogin,{headers:{"content-type":"application/x-www-form-urlencoded"}}).then((function(t){var r=t.data;0===r.code?(e.$Message.info(r.msg),n.login(r),console.info("关闭登录窗口"),c["a"].replace({name:"home"}),location.reload()):alert(r.msg)})):e.$Message.error("Fail!")}))}})},f=p,m=(n("f59e"),n("8f93"),n("2877")),d=Object(m["a"])(f,r,o,!1,null,null,null);e["default"]=d.exports},"25d7":function(t,e,n){"use strict";n("c927")},"261c":function(t,e,n){},"32cc":function(t,e,n){"use strict";n("8137")},"33c1":function(t,e,n){"use strict";n("ed5c")},3566:function(t,e,n){"use strict";n("b790")},3791:function(t,e,n){"use strict";n("899c")},"37a5":function(t,e,n){"use strict";n("e8b9")},"37f3":function(t,e,n){},"41cb":function(t,e,n){"use strict";n("7f7f");var r=n("2b0e"),o=n("8c4f"),a=function(){var t=this,e=t.$createElement,n=t._self._c||e;return n("div",{staticClass:"home"},[n("poster-layout")],1)},i=[],s=function(){var t=this,e=t.$createElement,n=t._self._c||e;return n("div",{staticClass:"poster-layout"},[n("top-bar-layout"),n("div",{staticClass:"layout-wrapper"},[n("tool-layout"),n("content-wrapper"),n("setting-layout")],1),n("debug-layout")],1)},c=[],u=function(){var t=this,e=t.$createElement,n=t._self._c||e;return n("div",{staticClass:"content-warpper",on:{click:t.contentWrapperClick}},[n("div",{staticClass:"canvas-wrapper",class:{"sidebar-extend":t.sidebar.showExtendBar},attrs:{tabindex:"1"},on:{keydown:function(e){return t.keyupHandler(e)},click:t.deactiveAllItem}},[n("div",{staticClass:"canvas-content-wrapper canvas-editor-wrapper",style:{width:t.w,height:t.h,"background-color":t.BGC,"background-image":t.bgi,"background-repeat":"none","background-size":t.bgs}},[n("div",{staticClass:"canvas-content",on:{contextmenu:function(e){return e.preventDefault(),t.handleContextMenu.apply(null,arguments)},click:function(e){return t.switchPanel("canvas")}}},[t._l(t.items,(function(t,e){return n("poster-item",{key:t.uuid,attrs:{item:t}})})),n("content-menu")],2)]),n("div",{staticClass:"canvas-tool-bar"},[n("div",{staticClass:"item scale-area"},[n("i",{staticClass:"icon iconfont icon-minus",attrs:{title:"缩小"},on:{click:t.shrink}}),n("p",{staticClass:"scale-num"},[t._v(t._s(t._f("formatPrcent")(t.scale)))]),n("i",{staticClass:"icon iconfont icon-plus",attrs:{title:"放大"},on:{click:t.magnify}})]),t._e()])])])},l=[],p=(n("8e6e"),n("ac6a"),n("456d"),n("6762"),n("2fdb"),n("f559"),n("bd86")),f=(n("c5f6"),function(){var t=this,e=t.$createElement,n=t._self._c||e;return n("div",{staticClass:"poster-item",attrs:{tabindex:t.item.z,id:t.idKey},on:{click:function(t){t.stopPropagation()},keydown:function(e){return t.keyupHandler(e)},contextmenu:function(e){return e.preventDefault(),t.handleContextMenu(t.item.uuid)}}},[n("vue-drag-resize",{staticClass:"poster-item-vue-drag",style:{"z-index":t.item.z},attrs:{parentLimitation:!0,parentW:t.W,parentH:t.H,w:t.w,h:t.h,x:t.x,y:t.y,minw:t.minw,minh:t.minh,isActive:t.active,aspectRatio:t.aspectRatio},on:{click:function(t){t.stopPropagation()},clicked:function(e){return t.activeItemHandler(t.item.uuid)},resizing:t.resizing,dragging:t.dragging,resizestop:t.resizestop,dragstop:t.dragstop,activated:t.activated,deactivated:t.deactivated}},["text"===t.item.t?n("p",{staticStyle:{height:"100%",width:"100%",border:"none",resize:"none",padding:"0",margin:"0",overflow:"hidden","line-height":"130%"},style:{"background-color":t.item.bgc,color:t.item.c,"font-size":t.fontSize},domProps:{textContent:t._s(t.item.v)}}):t._e(),"image"===t.item.t?n("item-image",{attrs:{item:t.item}}):t._e(),"qrcode"===t.item.t?n("item-qrcode",{attrs:{item:t.item}}):t._e(),"avatar"===t.item.t?n("item-avatar",{attrs:{item:t.item}}):t._e()],1)],1)}),m=[],d=(n("d263"),n("3b58")),A=n.n(d),h=n("2f62"),v=function(){var t=this,e=t.$createElement,n=t._self._c||e;return n("img",{staticStyle:{"border-radius":"50%"},style:{width:t.w,height:t.h,border:t.borderStyle},attrs:{src:t.imgUrl,onerror:t.defaultImg}})},b=[];function g(t,e){var n=Object.keys(t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(t);e&&(r=r.filter((function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable}))),n.push.apply(n,r)}return n}function w(t){for(var e=1;e确定要切换海报[".concat(t.name," ]吗?

"),onOk:function(){e.cp=t,e.changePoster(t)}})}},deletePoster:function(t){var e=this;this.$Modal.confirm({title:"温馨提示",content:"

确定要删除海报[".concat(t.name," ]吗?

"),onOk:function(){e.$http.delete("api/user/posters/"+t.id,{},{headers:{"content-type":"application/x-www-form-urlencoded"}}).then((function(t){var n=t.data;e.reloadMyPoster(),e.$Message.info(n.msg)}))}})},copyPoster:function(t){var e=this;console.info("复制海报: "+t.name),this.$http.post("api/user/posters/copy/"+t.id,{},{headers:{"content-type":"application/x-www-form-urlencoded"}}).then((function(t){var n=t.data;e.reloadMyPoster(),e.$Message.info(n.msg)}))}})},vt=ht,bt=(n("1272"),Object(j["a"])(vt,ft,mt,!1,null,"577ecc48",null)),gt=bt.exports,wt=function(){var t=this,e=t.$createElement,n=t._self._c||e;return n("div",{staticClass:"setting-layer",class:{active:t.item.uuid==t.ciuuid},style:{order:t.item.z},attrs:{tabindex:"1",id:t.idKey,title:"按上下方向键移动元素层次"},on:{click:t.clickHandler,keydown:t.keypressHandler}},[n("span",{staticClass:"mr8 icon iconfont",class:["icon-"+t.item.t]}),n("span",{class:{warn:!t.item.vd}},[t._v(t._s(t._f("fvd")(t.item.vd)))])])},yt=[];function Ot(t,e){var n=Object.keys(t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(t);e&&(r=r.filter((function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable}))),n.push.apply(n,r)}return n}function jt(t){for(var e=1;e=2&&t<=4?"点击添加到设计器":e},isExtendItem:function(t){return 0==this.activeIndex||1==this.activeIndex},choiceItem:function(t,e){this.activeIndex=e,t.t&&this.addItem({t:t.t,name:t.name}),this.isExtendItem(e)&&(this.showExtendBarMyPosters="我的海报"===t.name&&!this.showExtendBarMyPosters,this.showExtendBarLevels="图层"===t.name&&!this.showExtendBarLevels,this.sidebar.showExtendBar=this.showExtendBarMyPosters||this.showExtendBarLevels),"我的海报"===t.name&&this.showExtendBarMyPosters&&this.reloadMyPoster(),t.name}})},kt=Et,St=(n("729a"),Object(j["a"])(kt,ut,lt,!1,null,"9d9eaeae",null)),Mt=St.exports,Qt=function(){var t=this,e=t.$createElement,n=t._self._c||e;return n("div",{staticClass:"property-layout"},[n("div",{staticClass:"title"},[n("div",{staticClass:"item",class:{active:"item"==t.currentPanel},on:{click:function(e){return t.switchPanel("item")}}},[n("p",[t._v("属性设置")])]),n("div",{staticClass:"item",class:{active:"canvas"==t.currentPanel},on:{click:function(e){return t.switchPanel("canvas")}}},[n("p",[t._v("海报设置")])])]),n("div",{directives:[{name:"show",rawName:"v-show",value:"canvas"==t.currentPanel,expression:"currentPanel == 'canvas' "}],staticClass:"canvas-setting"},[n("div",{staticClass:"panel"},[n("Row",{staticClass:"mt10"},[n("Col",{staticClass:"lh32",attrs:{span:"6"}},[t._v("\n UUID\n ")]),n("Col",{attrs:{span:"16"}},[n("Input",{attrs:{readonly:""},model:{value:t.$store.state.p.uuid,callback:function(e){t.$set(t.$store.state.p,"uuid",e)},expression:"$store.state.p.uuid"}})],1)],1),n("Row",{staticClass:"mt10"},[n("Col",{staticClass:"lh32",attrs:{span:"6"}},[t._v("\n 名称\n ")]),n("Col",{attrs:{span:"16"}},[n("Input",{model:{value:t.$store.state.p.name,callback:function(e){t.$set(t.$store.state.p,"name",e)},expression:"$store.state.p.name"}})],1)],1),n("Row",[n("Col",{staticClass:"lh32",attrs:{span:"6"}},[t._v("\n 格式\n ")]),n("Col",{staticClass:"lh32",attrs:{span:"16"}},[n("RadioGroup",{model:{value:t.$store.state.p.type,callback:function(e){t.$set(t.$store.state.p,"type",e)},expression:"$store.state.p.type"}},[n("Radio",{attrs:{label:"png"}},[n("span",[t._v("png")])]),n("Radio",{attrs:{label:"jpeg"}},[n("span",[t._v("jpeg")])])],1)],1)],1),n("Row",{directives:[{name:"show",rawName:"v-show",value:"jpeg"===t.$store.state.p.type,expression:"$store.state.p.type === 'jpeg'"}]},[n("Col",{staticClass:"lh32",attrs:{span:"6"}},[t._v("\n 质量\n ")]),n("Col",{attrs:{span:"16"}},[n("Slider",{attrs:{max:100,min:30},model:{value:t.$store.state.p.quality,callback:function(e){t.$set(t.$store.state.p,"quality",e)},expression:"$store.state.p.quality"}})],1)],1),n("Divider",{attrs:{orientation:"left"}},[n("Tooltip",{attrs:{content:"修改海报尺寸"}},[t._v("\n 海报尺寸\n ")])],1),n("Row",{staticClass:"mt20"},[n("Col",{attrs:{span:"6"}},[t._v(" ")]),n("Col",{attrs:{span:"6"}},[t._v(" ")]),n("Col",{staticClass:"lh32",attrs:{span:"6"}},[t._v("宽度")]),n("Col",{staticClass:"lh32",attrs:{span:"6"}},[t._v("高度")])],1),n("Row",[n("Col",{attrs:{span:"12"}},[n("Dropdown",{on:{"on-click":t.itemChange}},[n("Button",{attrs:{type:"primary"}},[t._v("\n 常用尺寸\n "),n("Icon",{attrs:{type:"ios-arrow-down"}})],1),n("DropdownMenu",{attrs:{slot:"list"},slot:"list"},[n("DropdownItem",{attrs:{name:"640,1008"}},[t._v("640 x 1008")]),n("DropdownItem",{attrs:{name:"720,1280"}},[t._v("720 x 1280")]),n("DropdownItem",{attrs:{name:"750,1181"}},[t._v("750 x 1181")]),n("DropdownItem",{attrs:{name:"750,1333"}},[t._v("750 x 1333")]),n("DropdownItem",{attrs:{name:"800,2000"}},[t._v("800 x 2000")]),n("DropdownItem",{attrs:{name:"1242,2208"}},[t._v("1242 x 2208")])],1)],1)],1),n("Col",{attrs:{span:"6"}},[n("InputNumber",{staticClass:"input ",attrs:{max:1e3,min:50},model:{value:t.$store.state.p.w,callback:function(e){t.$set(t.$store.state.p,"w",e)},expression:"$store.state.p.w"}})],1),n("Col",{attrs:{span:"6"}},[n("InputNumber",{staticClass:"input ",attrs:{max:2e3,min:50},model:{value:t.$store.state.p.h,callback:function(e){t.$set(t.$store.state.p,"h",e)},expression:"$store.state.p.h"}})],1)],1),n("Divider",{attrs:{orientation:"left"}},[n("Tooltip",{attrs:{content:"修改背景颜色和图片"}},[t._v("\n 背景\n ")])],1),n("Row",{staticClass:"mt10"},[n("Col",{staticClass:"lh32",attrs:{span:"6"}},[t._v("\n 背景色\n ")]),n("Col",{attrs:{span:"6"}},[n("ColorPicker",{attrs:{recommend:""},model:{value:t.$store.state.p.bgc,callback:function(e){t.$set(t.$store.state.p,"bgc",e)},expression:"$store.state.p.bgc"}})],1)],1),n("Row",{staticClass:"mt10"},[n("Col",{staticClass:"lh32",attrs:{span:"6"}},[t._v("\n 背景图\n ")]),n("Col",{attrs:{span:"8"}},[n("Upload",{attrs:{action:t.UPLOAD_URL,"on-success":t.successHandler,headers:{token:t.token},format:["jpg","jpeg","png"],"show-upload-list":!1}},[n("Button",{attrs:{type:"primary",icon:"ios-cloud-upload-outline"}},[t._v("上传")])],1)],1),n("Col",{attrs:{span:"4"}},[n("Button",{attrs:{type:"primary"},on:{click:t.deleteBgImage}},[t._v("删除背景图")])],1)],1),n("Row",{directives:[{name:"show",rawName:"v-show",value:t.$store.state.p.bgUrl,expression:"$store.state.p.bgUrl"}]},[n("Col",{attrs:{span:"6"}},[t._v("\n 背景图地址\n ")]),n("Col",{attrs:{span:"17"}},[n("Input",{attrs:{type:"textarea",rows:4},model:{value:t.$store.state.p.bgUrl,callback:function(e){t.$set(t.$store.state.p,"bgUrl",e)},expression:"$store.state.p.bgUrl"}})],1)],1)],1)]),n("setting-item-layout",{directives:[{name:"show",rawName:"v-show",value:"item"==t.currentPanel,expression:"currentPanel == 'item' "}],staticClass:"item-setting"})],1)},Rt=[],Yt=(n("28a5"),function(){var t=this,e=t.$createElement,n=t._self._c||e;return null!=t.currentItem?n("div",{staticClass:"item-setting-panel"},[n("setting-item-base",{attrs:{item:t.currentItem}})],1):t._e()}),Ht=[],Wt=function(){var t=this,e=t.$createElement,n=t._self._c||e;return n("div",{staticClass:"setting-item-base"},[n("Divider",{attrs:{orientation:"left"}},[n("Tooltip",{attrs:{"max-width":"200",content:"此处可进行位置和大小的调整"}},[t._v("\n 位置大小\n ")])],1),n("Row",[n("Col",{attrs:{span:"6"}},[t._v("x")]),n("Col",{attrs:{span:"6"}},[t._v("y")]),n("Col",{attrs:{span:"6"}},[t._v("宽度")]),n("Col",{attrs:{span:"6"}},[t._v("高度")])],1),n("Row",[n("Col",{attrs:{span:"6"}},[n("InputNumber",{staticClass:"input ",attrs:{max:t.w-t.item.w,min:0},model:{value:t.item.x,callback:function(e){t.$set(t.item,"x",e)},expression:"item.x"}})],1),n("Col",{attrs:{span:"6"}},[n("InputNumber",{staticClass:"input ",attrs:{max:t.h-t.item.h,min:0},model:{value:t.item.y,callback:function(e){t.$set(t.item,"y",e)},expression:"item.y"}})],1),n("Col",{attrs:{span:"6"}},[n("InputNumber",{staticClass:"input ",attrs:{max:t.w,min:0},model:{value:t.item.w,callback:function(e){t.$set(t.item,"w",e)},expression:"item.w"}})],1),n("Col",{attrs:{span:"6"}},[n("InputNumber",{staticClass:"input ",attrs:{max:t.h,min:0},model:{value:t.item.h,callback:function(e){t.$set(t.item,"h",e)},expression:"item.h"}})],1)],1),n("Divider",{attrs:{orientation:"left"}},[n("Tooltip",{attrs:{"max-width":"200",content:"点击修改颜色"}},[t._v("颜色")])],1),n("Row",[n("Col",{staticClass:"lh32",attrs:{span:"6"}},[t._v("\n 颜色\n ")]),n("Col",{attrs:{span:"6"}},[n("color-picker",{attrs:{recommend:""},on:{"on-change":t.changeColor},model:{value:t.item.c,callback:function(e){t.$set(t.item,"c",e)},expression:"item.c"}})],1)],1),n("div",{directives:[{name:"show",rawName:"v-show",value:"image"===t.item.t||"avatar"===t.item.t,expression:"item.t === 'image' || item.t === 'avatar' "}]},[n("Divider",{attrs:{orientation:"left"}},[n("Tooltip",{attrs:{"max-width":"200",content:"图片"}},[t._v("图片")])],1),n("Row",{staticClass:"mt10"},[n("Col",{staticClass:"lh32",attrs:{span:"4"}},[t._v("\n 图片\n ")]),n("Col",{attrs:{span:"6"}},[n("Upload",{attrs:{action:t.UPLOAD_URL,"on-success":t.successHandler,headers:{token:t.token},format:["jpg","jpeg","png"],"show-upload-list":!1}},[n("Button",{attrs:{type:"primary"}},[t._v("上传")])],1)],1),n("Col",{attrs:{span:"8"}},[n("Button",{on:{click:t.changeImgSize}},[t._v("原始尺寸")])],1),n("Col",{attrs:{span:"4"}},[n("Button",{on:{click:t.deleteImg}},[t._v("删除")])],1)],1)],1),n("div",{directives:[{name:"show",rawName:"v-show",value:"text"===t.item.t,expression:"item.t === 'text' "}]},[n("Divider",{attrs:{orientation:"left"}},[n("Tooltip",{attrs:{"max-width":"200",content:"拖动修改字体大小"}},[t._v("字体")])],1),n("Row",[n("Col",{staticClass:"lh36",attrs:{span:"6"}},[t._v("\n 字体大小\n ")]),n("Col",{attrs:{span:"10"}},[n("Slider",{attrs:{min:10},model:{value:t.item.s,callback:function(e){t.$set(t.item,"s",e)},expression:"item.s"}})],1),n("Col",{attrs:{span:"1"}},[t._v("\n  \n ")]),n("Col",{attrs:{span:"6"}},[n("InputNumber",{staticClass:"input ",attrs:{max:100,min:0},model:{value:t.item.s,callback:function(e){t.$set(t.item,"s",e)},expression:"item.s"}})],1)],1)],1),n("div",[n("Divider",{attrs:{orientation:"left"}},[n("Tooltip",{attrs:{"max-width":"200",content:"静态参数: 效果预览使用,不可变 动态参数: 调用接口使用,可变"}},[t._v("\n 参数\n ")])],1),n("Row",[n("Col",{attrs:{span:"6"}},[t._v("\n 名称\n ")]),n("Col",{attrs:{span:"17"}},[n("Input",{model:{value:t.item.vd,callback:function(e){t.$set(t.item,"vd",e)},expression:"item.vd"}})],1)],1),n("Row",[n("Col",{attrs:{span:"6"}},[t._v("\n 备注\n ")]),n("Col",{attrs:{span:"17"}},[n("Input",{model:{value:t.item.name,callback:function(e){t.$set(t.item,"name",e)},expression:"item.name"}})],1)],1),n("Row",[n("Col",{attrs:{span:"6"}},[t._v("\n 默认\n ")]),n("Col",{attrs:{span:"17"}},[n("Input",{attrs:{type:"textarea",rows:4},on:{"on-change":t.changeV},model:{value:t.item.v,callback:function(e){t.$set(t.item,"v",e)},expression:"item.v"}})],1)],1)],1)],1)},Kt=[];function Gt(t,e){var n=Object.keys(t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(t);e&&(r=r.filter((function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable}))),n.push.apply(n,r)}return n}function Jt(t){for(var e=1;e=1},set:function(t){this.item.st=t?Number((this.item.s/10).toFixed(0)):0}}}),methods:{isQrcode:function(){return"qrcode"===this.item.t},changeColor:function(t){this.isQrcode()&&S(this.item.uuid,"buildQrcode")},changeBgColor:function(t){this.isQrcode()&&S(this.item.uuid,"buildQrcode")},deleteImg:function(t){this.item.v=""},changeV:function(){this.isQrcode()&&S(this.item.uuid,"buildQrcode")},changeImgSize:function(){var t=this.item,e=new Image;e.src=t.v.startsWith("http")?t.v:API_URL+t.v,e.onload=function(){t.w=e.width,setTimeout((function(){t.h=e.height}),10)}},successHandler:function(t,e){var n=this;if(0!==t.code);else{var r=t.data.url,o=new Image;o.src=r.startsWith("http")?r:API_URL+r;var a=400,i=setInterval((function(){a--<=0&&window.clearInterval(i),o.width>0&&(n.item.v=r,window.clearInterval(i))}),50)}}}},Lt=Ut,Ft=(n("db58"),Object(j["a"])(Lt,Wt,Kt,!1,null,null,null)),Nt=Ft.exports;function Vt(t,e){var n=Object.keys(t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(t);e&&(r=r.filter((function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable}))),n.push.apply(n,r)}return n}function Tt(t){for(var e=1;e0&&(n.changeBgImage(r),n.changeWH({w:o.width,h:o.height}),window.clearInterval(i))}),50)}}})},ee=te,ne=(n("ffea"),n("a8c3"),Object(j["a"])(ee,Qt,Rt,!1,null,"16c46d15",null)),re=ne.exports,oe=function(){var t=this,e=t.$createElement,n=t._self._c||e;return n("div",{staticClass:"debug-layout",class:{active:t.show},on:{dblclick:function(e){t.show=!t.show}}},[n("pre",[t._v(t._s(t.json))])])},ae=[];function ie(t,e){var n=Object.keys(t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(t);e&&(r=r.filter((function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable}))),n.push.apply(n,r)}return n}function se(t){for(var e=1;e'),t="["+t.substring(1,t.length-1)+"]";var e='buildPoster("').concat(this.posterUuid,'", $params)->save("demo.png");');return e}}},Se=ke,Me=(n("3791"),Object(j["a"])(Se,xe,Be,!1,null,"6fb1b24c",null)),Qe=Me.exports,Re=function(){var t=this,e=t.$createElement,n=t._self._c||e;return n("div",{staticStyle:{"text-align":"left"}},[n("pre",{staticClass:"code language-shell line-numbers",domProps:{innerHTML:t._s(t.html)}},[t._v(" "),n("span"),t._v("\n ")]),n("Button",{attrs:{id:"btnCopyCurl",type:"primary"}},[t._v("复制")])],1)},Ye=[];n("8009");function He(t,e){var n=Object.keys(t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(t);e&&(r=r.filter((function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable}))),n.push.apply(n,r)}return n}function We(t){for(var e=1;e{\n // 将res 信息直接复制到 img 标签的 src 属性上即可\n // document.getElementById('myImg').src = res\n})\n");return e}}},nn=en,rn=(n("25d7"),Object(j["a"])(nn,Ze,_e,!1,null,"d2523e40",null)),on=rn.exports,an=function(){var t=this,e=t.$createElement,n=t._self._c||e;return n("div",{staticStyle:{"text-align":"left"}},[n("pre",{staticClass:"code language-shell line-numbers",domProps:{innerHTML:t._s(t.html)}},[t._v(" "),n("span"),t._v("\n ")]),n("Button",{attrs:{id:"btnCopyGo",type:"primary"}},[t._v("复制")]),n("a",{attrs:{href:t.link}},[t._v(t._s(t.link))])],1)},sn=[];n("1989");function cn(t,e){var n=Object.keys(t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(t);e&&(r=r.filter((function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable}))),n.push.apply(n,r)}return n}function un(t){for(var e=1;e请在新建海报前,保存当前修改。

",onOk:function(){t.newPoster()}})},feedback:function(){this.m.showFeedbackModal=!0},preview:function(){var t=this.$refs.showImg,e=this,n=this.json,r=new XMLHttpRequest;r.withCredentials=!0,r.open("POST",window.PREVIEW_URL,!0),r.setRequestHeader("Content-Type","application/json"),r.setRequestHeader("token",localStorage.getItem("fptoken")),r.responseType="blob",r.onload=function(){if(200===this.status){var n=this.response;t.onload=function(t){var n=e.$el.querySelector(".images").$viewer;n.show()},t.src=window.URL.createObjectURL(n)}401===this.status&&alert("请登录后再操作")},r.send(n)}})},vn=hn,bn=(n("5222"),Object(j["a"])(vn,fe,me,!1,null,"287a91b7",null)),gn=bn.exports,wn={name:"PosterLayout",components:{TopBarLayout:gn,ContentWrapper:ct,ToolLayout:Mt,SettingLayout:re,DebugLayout:pe},mounted:function(){window.app=this},methods:{}},yn=wn,On=(n("607f"),Object(j["a"])(yn,s,c,!1,null,null,null)),jn=On.exports,Cn={name:"home",components:{PosterLayout:jn},mounted:function(){},computed:{},data:function(){return{}}},Pn=Cn,In=(n("37a5"),Object(j["a"])(Pn,a,i,!1,null,"21eff840",null)),xn=In.exports,Bn=function(){var t=this,e=t.$createElement,n=t._self._c||e;return n("div",{staticClass:"container"},[n("div",{staticClass:"top"},[t._v("\n 演示以Vue组件方式嵌入系统中\n ")]),n("div",{staticClass:"nav-bar"},t._l(10,(function(e){return n("div",{staticClass:"nav-item"},[t._v("\n 菜单: "+t._s(e)+"\n ")])})),0),n("div",{staticClass:"content-container"},[n("poster-layout")],1)])},Dn=[],En={name:"B",components:{PosterLayout:jn},mounted:function(){},methods:{}},kn=En,Sn=(n("6a03"),Object(j["a"])(kn,Bn,Dn,!1,null,null,null)),Mn=Sn.exports,Qn=function(){var t=this,e=t.$createElement,n=t._self._c||e;return n("div",{staticClass:"container"},[n("div",{staticClass:"top"},[t._v("\n 演示以Iframe方式嵌入系统中(推荐使用)\n ")]),n("div",{staticClass:"nav-bar"},t._l(10,(function(e){return n("div",{staticClass:"nav-item"},[t._v("\n 菜单: "+t._s(e)+"\n ")])})),0),t._m(0)])},Rn=[function(){var t=this,e=t.$createElement,n=t._self._c||e;return n("div",{staticClass:"content-container"},[n("iframe",{attrs:{src:"/"}})])}],Yn={name:"B2",components:{},mounted:function(){},methods:{}},Hn=Yn,Wn=(n("f2ee"),Object(j["a"])(Hn,Qn,Rn,!1,null,null,null)),Kn=Wn.exports;r["default"].use(o["a"]);var Gn=new o["a"]({routes:[{path:"/",name:"home",component:xn},{path:"/login",name:"login",component:function(){return n.e("about").then(n.bind(null,"1345"))}},{path:"/b",name:"b",component:Mn},{path:"/b2",name:"b2",component:Kn},{path:"/about",name:"about",component:function(){return n.e("about").then(n.bind(null,"8166"))}}]});Gn.beforeEach((function(t,e,n){0===t.matched.length?e.name?n({name:e.name}):n("/"):n()}));e["a"]=Gn},"46de":function(t,e,n){"use strict";n("e15c")},"49ac":function(t,e,n){"use strict";n("37f3")},5222:function(t,e,n){"use strict";n("cdcd")},5405:function(t,e,n){},"55c4":function(t,e,n){"use strict";n("d54c")},"56d7":function(t,e,n){"use strict";n.r(e);n("cadf"),n("551c"),n("f751"),n("097d");var r=n("2b0e"),o=function(){var t=this,e=t.$createElement,n=t._self._c||e;return n("div",{attrs:{id:"app"}},[n("router-view")],1)},a=[],i=(n("7c55"),n("2877")),s={},c=Object(i["a"])(s,o,a,!1,null,null,null),u=c.exports,l=n("41cb"),p=(n("8e6e"),n("ac6a"),n("456d"),n("bd86")),f=n("2f62");n("f559"),n("7f7f"),n("c5f6"),n("55dd"),n("3b2b"),n("28a5"),n("6b54"),n("a481");function m(t,e){var n,r,o="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".split(""),a=[];if(e=e||o.length,t)for(n=0;n=10)console.error("对不起, 暂时只支持添加10个元素。请联系客服开通权限。");else{var n={uuid:d(),x:400,y:200,w:150,h:150,z:1,s:15,c:"#000000",bgc:"",v:"https://poster.prodapi.cn/static/images/xiaoniu.png",vd:"",fn:"",st:0,active:!1};n=B(B({},e),n),n.x=~~(t.p.w/2-n.w/2),n.y=~~(t.p.h/2-n.h/2),"text"===n.t&&(n.w=324,n.h=58,n.s=24,n.x=120,n.y=200,n.v="多行文本测试1多行文本测试2多行文本测试3多行文本测试4"),"image"===n.t&&(n.w=200,n.h=200),"qrcode"===n.t&&(n.p=0,n.c="#000000",n.bgc="#ffffff",n.v="https://fastposter.net/#from=qrcode"),"avatar"===n.t&&(n.w=80,n.h=80,n.c="#888888");var r=Math.max.apply(Math,t.p.items.map((function(t){return t.z})));r>=1&&(n.z=r+1),t.p.items.push(n),G.commit("activeItemAndShowProperty",n.uuid)}},copyItem:function(t,e){var n=t.p.items.filter((function(t){return t.uuid===e}))[0];t.copyItem=B({},n)},pasteItem:function(t,e){if(t.copyItem){t.copyItem.uuid=d();var n=t.copyItem;n.x=n.x+24,n.y=n.y+24;var r=Math.max.apply(Math,t.p.items.map((function(t){return t.z})));r>=1&&(n.z=r+1),t.p.items.push(n),G.commit("activeItemAndShowProperty",n.uuid)}},deactiveAllItem:function(t,e){t.p.items.forEach((function(t){return t.active=!1}))},activeItemDontShow:function(t,e){G.commit("activeItem",e),t.p.editor.cp="item"},activeItemAndShowProperty:function(t,e){G.commit("activeItem",e),t.p.editor.cp="item"},activeItem:function(t,e){t.p.editor.ciuuid!==e&&(t.p.items.forEach((function(t){t.active=t.uuid===e})),t.p.editor.ciuuid=e)},removeItem:function(t,e){var n=[];t.p.items.forEach((function(t){t.uuid!==e&&n.push(t)})),n.length>=1&&(n[0].active=!0,t.p.editor.ciuuid=n[0].uuid),t.p.items=n},switchPanel:function(t,e){t.p.editor.cp=e},adjustScale:function(t,e){var n=t.p.editor.scale;n+=e,n=Number(n.toFixed(2)),nD?console.warn("缩放比达到极限"):(t.p.editor.scale=n,console.info("调整缩放比例: scale="+n))},autoScale:function(t,e){t.p.scale=.6},itemUp:function(t,e){var n=t.p.items.filter((function(t){return t.uuid===e}))[0],r=n.z,o=Math.max.apply(Math,t.p.items.map((function(t){return t.z})));if(o!==r){var a=r+1,i=t.p.items.filter((function(t){return t.z===a&&t.uuid!==e}));if(i&&0!==i.length){var s=i[0];n.z=a,s.z=r}else console.warn("元素上移(没有匹配的元素): z="+r+", uuid="+e)}else console.warn("元素上移(元素已经到了最上面): z="+r+", uuid="+e)},itemDown:function(t,e){var n=t.p.items.filter((function(t){return t.uuid===e}))[0],r=n.z;if(!(r<=1)){var o=r-1,a=t.p.items.filter((function(t){return t.z===o&&t.uuid!==e}));if(a&&0!==a.length){var i=a[0];n.z=o,i.z=r}}},changeWH:function(t,e){t.p.w=e.w,t.p.h=e.h},changeBgImage:function(t,e){t.p.bgUrl=e},login:function(t,e){localStorage.setItem("fptoken",e.token)},logout:function(t,e){t.user=null,localStorage.removeItem("fptoken")},changePoster:function(t,e){var n=e.id,r=e.name,o=JSON.parse(e.json);o.items.forEach((function(t){t.uuid=t.uuid?t.uuid:d()})),o.editor=o.editor?o.editor:t.p.editor,o.editor.scaleNew=k,o.editor.sidebar=o.editor.sidebar?o.editor.sidebar:t.p.editor.sidebar,o.editor.saveStatus=o.editor.saveStatus?o.editor.saveStatus:"draft",o.id=n,o.name=r,o.uuid=e.code,t.p=o,window.setTimeout((function(){G.commit("adjustScale",.01)}),100),window.setTimeout((function(){G.commit("adjustScale",-.01)}),200)},newPoster:function(t,e){var n={name:"未命名",id:0,w:720,h:1280,bgc:"#ffffff",type:"jpeg",quality:M,bgUrl:"",items:[],editor:{scaleNew:k,scale:k,cp:"canvas",ciuuid:"",debug:S,saveStatus:"draft",sidebar:{showExtendBar:t.p.editor.sidebar.showExtendBar}}};t.p=n},reloadMyPoster:function(t,e){I.get("api/user/posters",{},{headers:{"content-type":"application/x-www-form-urlencoded"}}).then((function(e){var n=e.data;n.posters.forEach((function(t){return t.preview=(t.preview.startsWith("http")?t.preview:window.API_URL+t.preview)+"?t="+(new Date).getTime()})),t.posters=n.posters}))},savePoster:function(t,e){var n={};n.id=t.p.id,n.json=G.getters.json,n.name=t.p.name,n.quality=t.p.quality,t.p.editor.saveStatus="saving",I.post("api/user/posters",n).then((function(n){var r=n.data;0!==r.code&&alert(r.msg),r.id&&(t.p.id=r.id),t.p.editor.saveStatus="saved",G.commit("reloadMyPoster",t,e)}))}},actions:{}},R=Q,Y={state:{menuTop:0,menuLeft:0,menuShow:!1},mutations:{showContextMenu:function(t,e){var n=e.top,r=e.left;t.menuShow=!0,t.menuTop=n,t.menuLeft=r},hideContextMenu:function(t){t.menuShow=!1}}};function H(t,e){var n=Object.keys(t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(t);e&&(r=r.filter((function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable}))),n.push.apply(n,r)}return n}function W(t){for(var e=1;e