Template.php 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351
  1. <?php
  2. namespace app\api\controller\ps;
  3. use app\common\controller\Api;
  4. use app\common\library\ps\FactoryContext;
  5. use app\common\library\ps\MarketPublisher;
  6. use app\common\model\ps\MarketGoods;
  7. use app\common\model\ps\Template as TemplateModel;
  8. /**
  9. * 模板接口
  10. */
  11. class Template extends Api
  12. {
  13. protected $noNeedRight = '*';
  14. /**
  15. * @var TemplateModel
  16. */
  17. protected $model = null;
  18. public function _initialize()
  19. {
  20. parent::_initialize();
  21. if (!FactoryContext::id()) {
  22. $this->error('账号未绑定工厂');
  23. }
  24. $this->model = new TemplateModel;
  25. }
  26. /**
  27. * 本厂模板库
  28. */
  29. public function index()
  30. {
  31. $limit = $this->request->request('limit/d', 50);
  32. $printable = $this->request->request('printable/d', 0);
  33. $query = $this->model->where('status', 'normal')->order('id desc');
  34. if ($printable) {
  35. $query->printable();
  36. }
  37. $list = $query->paginate($limit);
  38. $rows = [];
  39. foreach ($list->items() as $item) {
  40. $rows[] = $this->formatRow($item);
  41. }
  42. $this->attachMarket($rows);
  43. $this->success('', ['total' => $list->total(), 'rows' => $rows]);
  44. }
  45. /**
  46. * 详情
  47. */
  48. public function info()
  49. {
  50. $id = $this->request->request('id/d');
  51. $row = $this->model->find($id);
  52. if (!$row) {
  53. $this->error(__('No Results were found'));
  54. }
  55. $this->success('', $this->formatRow($row, true));
  56. }
  57. /**
  58. * 封面用站内相对路径,工厂端 Vite 才能代理到 /uploads。
  59. * @param mixed $item
  60. * @param bool $withMarket
  61. * @return array
  62. */
  63. protected function formatRow($item, $withMarket = false)
  64. {
  65. $row = is_array($item) ? $item : $item->toArray();
  66. $cover = isset($row['cover']) ? trim((string)$row['cover']) : '';
  67. if ($cover === '' && !empty($row['id'])) {
  68. $versionId = (int)($row['current_version_id'] ?? 0);
  69. if ($versionId > 0) {
  70. $schema = \think\Db::name('ps_template_version')->where('id', $versionId)->value('schema_json');
  71. $decoded = $schema ? json_decode($schema, true) : [];
  72. if (is_array($decoded)) {
  73. $cover = (string)($decoded['background'] ?? $decoded['file_url'] ?? $decoded['image'] ?? '');
  74. }
  75. }
  76. }
  77. $row['cover'] = $cover;
  78. $schemaJson = '';
  79. if (!empty($row['current_version_id'])) {
  80. $schemaJson = (string)\think\Db::name('ps_template_version')->where('id', (int)$row['current_version_id'])->value('schema_json');
  81. }
  82. $schema = \app\common\library\ps\PrintPlanner::decodeSchema($schemaJson, $cover);
  83. $row['schema'] = $schema;
  84. $row['schema_json'] = json_encode($schema, JSON_UNESCAPED_UNICODE);
  85. $row['cover_url'] = $this->coverUrl($schema['background'] ?: $cover);
  86. $row['field_catalog'] = \app\common\library\ps\PrintPlanner::fieldCatalog();
  87. $row['can_delete'] = (int)$row['is_system'] !== 1 && (int)($row['factory_id'] ?? 0) === (int)FactoryContext::id();
  88. $row['can_publish'] = (int)$row['is_system'] !== 1
  89. && ($row['source'] ?? '') !== 'market'
  90. && strpos((string)($row['license_type'] ?? ''), 'market_') !== 0;
  91. if ($withMarket) {
  92. $rows = [$row];
  93. $this->attachMarket($rows);
  94. return $rows[0];
  95. }
  96. return $row;
  97. }
  98. /**
  99. * @param array $rows
  100. */
  101. protected function attachMarket(array &$rows)
  102. {
  103. $ids = [];
  104. foreach ($rows as $row) {
  105. if (!empty($row['id'])) {
  106. $ids[] = (int)$row['id'];
  107. }
  108. }
  109. $ids = array_values(array_unique($ids));
  110. $map = [];
  111. if ($ids) {
  112. $goods = (new MarketGoods())
  113. ->where('factory_id', FactoryContext::id())
  114. ->where('template_id', 'in', $ids)
  115. ->select();
  116. foreach ($goods as $item) {
  117. $g = is_array($item) ? $item : $item->toArray();
  118. $map[(int)$g['template_id']] = [
  119. 'id' => (int)$g['id'],
  120. 'status' => $g['status'],
  121. 'price_single' => (int)$g['price_single'],
  122. 'price_buyout' => (int)$g['price_buyout'],
  123. 'title' => $g['title'],
  124. 'intro' => $g['intro'],
  125. 'on_sale' => $g['status'] === 'on_sale',
  126. ];
  127. }
  128. }
  129. foreach ($rows as &$row) {
  130. $row['market'] = isset($map[(int)$row['id']]) ? $map[(int)$row['id']] : null;
  131. }
  132. unset($row);
  133. }
  134. /**
  135. * @param string $path
  136. * @return string
  137. */
  138. protected function coverUrl($path)
  139. {
  140. $path = trim((string)$path);
  141. if ($path === '') {
  142. return '';
  143. }
  144. if (preg_match('#^(https?:)?//#i', $path) || strpos($path, 'data:') === 0) {
  145. return $path;
  146. }
  147. return '/' . ltrim(str_replace('\\', '/', $path), '/');
  148. }
  149. /**
  150. * 保存套打坐标与文字(生成新版本)
  151. */
  152. public function saveSchema()
  153. {
  154. $id = $this->request->post('id/d');
  155. $row = $this->model->find($id);
  156. if (!$row) {
  157. $this->error(__('No Results were found'));
  158. }
  159. if ((int)$row['is_system'] === 1) {
  160. $this->error('官方模板不可修改');
  161. }
  162. $name = trim((string)$this->request->post('name', ''));
  163. $schema = $this->request->post('schema/a');
  164. if (!$schema) {
  165. $raw = $this->request->post('schema_json', '', null);
  166. $schema = json_decode((string)$raw, true);
  167. }
  168. if (!is_array($schema)) {
  169. $this->error('排版数据不正确');
  170. }
  171. $schema = \app\common\library\ps\PrintPlanner::decodeSchema(json_encode($schema, JSON_UNESCAPED_UNICODE), $row['cover']);
  172. if ($name !== '') {
  173. $schema['name'] = $name;
  174. }
  175. $next = (int)\think\Db::name('ps_template_version')->where('template_id', $row->id)->max('version') + 1;
  176. if ($next < 1) {
  177. $next = 1;
  178. }
  179. $ver = new \app\common\model\ps\TemplateVersion();
  180. $ver->allowField(true)->save([
  181. 'template_id' => $row->id,
  182. 'version' => $next,
  183. 'schema_json' => json_encode($schema, JSON_UNESCAPED_UNICODE),
  184. 'remark' => '页面调整',
  185. ]);
  186. $save = [
  187. 'current_version_id' => $ver->id,
  188. ];
  189. if ($name !== '') {
  190. $save['name'] = $name;
  191. }
  192. if (!empty($schema['background'])) {
  193. $save['cover'] = $schema['background'];
  194. }
  195. $row->allowField(true)->save($save);
  196. $this->success('已保存', ['id' => (int)$row->id, 'version_id' => (int)$ver->id]);
  197. }
  198. /**
  199. * 保存套打坐标与文字
  200. */
  201. public function save_schema()
  202. {
  203. return $this->saveSchema();
  204. }
  205. /**
  206. * 添加(保存到本厂模板库)
  207. */
  208. public function add()
  209. {
  210. $params = $this->request->post();
  211. if (!$params) {
  212. $this->error(__('Parameter %s can not be empty', ''));
  213. }
  214. $params['creator_user_id'] = $this->auth->id;
  215. $params['is_system'] = 0;
  216. $params['license_type'] = isset($params['license_type']) ? $params['license_type'] : 'self';
  217. unset($params['id'], $params['factory_id']);
  218. $this->model->allowField(true)->save($params);
  219. $this->success('', ['id' => $this->model->id]);
  220. }
  221. /**
  222. * 编辑
  223. */
  224. public function edit()
  225. {
  226. $id = $this->request->post('id/d');
  227. $row = $this->model->find($id);
  228. if (!$row) {
  229. $this->error(__('No Results were found'));
  230. }
  231. if ((int)$row['is_system'] === 1) {
  232. $this->error('官方模板不可修改,请先复制到本厂模板库');
  233. }
  234. $params = $this->request->post();
  235. unset($params['id'], $params['factory_id'], $params['is_system']);
  236. $row->allowField(true)->save($params);
  237. $this->success();
  238. }
  239. /**
  240. * 删除
  241. */
  242. public function del()
  243. {
  244. $id = $this->request->post('id/d');
  245. $row = $this->model->find($id);
  246. if (!$row) {
  247. $this->error(__('No Results were found'));
  248. }
  249. if ((int)$row['is_system'] === 1) {
  250. $this->error('官方模板不可删除');
  251. }
  252. \think\Db::name('ps_template_version')->where('template_id', $row->id)->delete();
  253. \think\Db::name('ps_ai_job')->where('template_id', $row->id)->update(['template_id' => 0]);
  254. MarketPublisher::offByTemplate($row->id, FactoryContext::id());
  255. $row->delete();
  256. $this->success('已删除');
  257. }
  258. /**
  259. * 从空白纸新建可套打模板
  260. */
  261. public function create_blank()
  262. {
  263. $name = trim((string)$this->request->post('name', ''));
  264. if ($name === '') {
  265. $name = '空白模板 ' . date('m-d H:i');
  266. }
  267. $schema = [
  268. 'name' => $name,
  269. 'mode' => 'compose',
  270. 'page' => ['w' => 210, 'h' => 297, 'background' => '#ffffff'],
  271. 'background' => '',
  272. 'file_url' => '',
  273. 'elements' => [],
  274. 'source' => 'manual',
  275. ];
  276. $row = new TemplateModel();
  277. $row->allowField(true)->save([
  278. 'creator_user_id' => $this->auth->id,
  279. 'name' => $name,
  280. 'cover' => '',
  281. 'source' => 'manual',
  282. 'license_type' => 'self',
  283. 'locked' => 0,
  284. 'is_system' => 0,
  285. 'status' => 'normal',
  286. ]);
  287. $ver = new \app\common\model\ps\TemplateVersion();
  288. $ver->allowField(true)->save([
  289. 'template_id' => $row->id,
  290. 'version' => 1,
  291. 'schema_json' => json_encode($schema, JSON_UNESCAPED_UNICODE),
  292. 'remark' => '空白新建',
  293. ]);
  294. $row->save(['current_version_id' => $ver->id]);
  295. $this->success('已创建空白模板', ['id' => (int)$row->id]);
  296. }
  297. /**
  298. * 复制为本厂新模板
  299. */
  300. public function copy()
  301. {
  302. $id = $this->request->post('id/d');
  303. $row = $this->model->find($id);
  304. if (!$row) {
  305. $this->error(__('No Results were found'));
  306. }
  307. $schemaJson = \app\common\library\ps\PrintPlanner::schemaJson($row);
  308. $schema = \app\common\library\ps\PrintPlanner::decodeSchema($schemaJson, $row['cover']);
  309. $name = trim((string)$row['name']) . ' 副本';
  310. $schema['name'] = $name;
  311. $dup = new TemplateModel();
  312. $dup->allowField(true)->save([
  313. 'creator_user_id' => $this->auth->id,
  314. 'name' => $name,
  315. 'cover' => (string)$row['cover'],
  316. 'source' => 'manual',
  317. 'license_type' => 'self',
  318. 'locked' => 0,
  319. 'source_template_id' => (int)$row->id,
  320. 'source_version_id' => (int)$row['current_version_id'],
  321. 'is_system' => 0,
  322. 'status' => 'normal',
  323. ]);
  324. $ver = new \app\common\model\ps\TemplateVersion();
  325. $ver->allowField(true)->save([
  326. 'template_id' => $dup->id,
  327. 'version' => 1,
  328. 'schema_json' => json_encode($schema, JSON_UNESCAPED_UNICODE),
  329. 'remark' => '复制模板',
  330. ]);
  331. $dup->save(['current_version_id' => $ver->id]);
  332. $this->success('已复制', ['id' => (int)$dup->id]);
  333. }
  334. }