form.html 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422
  1. {extend name='admin@main'}
  2. {block name="content"}
  3. {include file='mall@store_goods/form_style'}
  4. <style>
  5. .layui-form-radio{
  6. margin: 0 !important;
  7. padding-right:0 !important;
  8. }
  9. .layui-form-select{
  10. margin-right: 10px !important;
  11. }
  12. </style>
  13. <form onsubmit="return false;" id="GoodsForm" data-auto="true" method="post" class='layui-form layui-card' autocomplete="off">
  14. <div class="layui-card-body think-box-shadow padding-left-40">
  15. <div class="layui-tab">
  16. <ul class="layui-tab-title">
  17. <li class="layui-this">基础设置</li>
  18. <li>规格设置</li>
  19. </ul>
  20. <div class="layui-tab-content">
  21. <!--基础设置-->
  22. <div class="layui-tab-item layui-show">
  23. <!--基础设置start-->
  24. <div class="layui-form-item layui-row layui-col-space15">
  25. <label class="layui-col-xs9 relative">
  26. <span class="color-green">商品名称</span>
  27. <input name="name" required class="layui-input" placeholder="请输入商品名称" value="{$vo.name|default=''}">
  28. </label>
  29. </div>
  30. <div class="layui-form-item layui-row layui-col-space15">
  31. <label class="layui-col-xs9 relative">
  32. <span class="color-green">副标题</span>
  33. <input name="desc" required class="layui-input" placeholder="请输入商品副标题" value="{$vo.desc|default=''}">
  34. </label>
  35. </div>
  36. <!-- 商品分类-->
  37. <div class="layui-form-item layui-row layui-col-space15">
  38. <label class="layui-col-xs9 relative" style="width: 100%;">
  39. <span class="color-green">商品分类</span>
  40. </label>
  41. <div style="width: 100%">
  42. <div style="width: 15%;float: left;">
  43. <select class="layui-select" id="first_classify" name="first_classify" lay-filter="first_classify" lay-search>
  44. <option selected data-first_key="-1" selected value="0">请选择</option>
  45. {if !empty($goods_cate)}
  46. {foreach $goods_cate as $ck=>$cv}
  47. {if isset_full_check($vo,'first_classify',$cv['id'])}
  48. <option selected data-first_key="{$ck}" value="{$cv['id']}">{$cv['title']}</option>
  49. {else}
  50. <option data-first_key="{$ck}" value="{$cv['id']}">{$cv['title']}</option>
  51. {/if}
  52. {/foreach}
  53. {/if}
  54. </select>
  55. </div>
  56. </div>
  57. </div>
  58. <div class="layui-form-item">
  59. <span class="color-green label-required-prev">商品LOGO及轮播展示图片</span>
  60. <table class="layui-table">
  61. <thead>
  62. <tr>
  63. <th class="text-center">LOGO</th>
  64. <th class="text-left">展示图片</th>
  65. </tr>
  66. <tr>
  67. <td width="90px" class="text-center"><input name="cover" type="hidden" value="{$vo.cover|default=''}"></td>
  68. <td width="auto" class="text-left"><input name="image" type="hidden" value="{$vo.image|default=''}"></td>
  69. </tr>
  70. </thead>
  71. </table>
  72. <script>$('[name="cover"]').uploadOneImage(), $('[name="image"]').uploadMultipleImage()</script>
  73. </div>
  74. <div class="layui-form-item">
  75. <span class="color-green label-required-prev">商品详情图</span>
  76. <table class="layui-table">
  77. <thead>
  78. <tr>
  79. <th class="text-left">展示图片</th>
  80. </tr>
  81. <tr>
  82. <td width="auto" class="text-left"><input name="content" type="hidden" value="{$vo.content|default=''}"></td>
  83. </tr>
  84. </thead>
  85. </table>
  86. <script>$('[name="content"]').uploadMultipleImage()</script>
  87. </div>
  88. </div>
  89. <!--规格设置start-->
  90. <div class="layui-tab-item">
  91. <div class="layui-form-item">
  92. <span class="color-green label-required-prev">商品规格及商品SKU绑定<span class="color-red font-s12">(规格填写后不允许再次修改)</span></span>
  93. <div ng-repeat="x in specs track by $index" style="display:none" class="margin-bottom-10" ng-class="{true:'layui-show'}[isAddMode&&specs.length>0]">
  94. <div class="goods-spec-box padding-10 margin-0 relative" style="background:#ddd">
  95. <span class="text-center goods-spec-title">分组</span>
  96. <label class="label-required-null inline-block"><input ng-blur="x.name=trimSpace(x.name)" ng-model="x.name" required placeholder="请输入分组名称"></label>
  97. <div class="pull-right">
  98. <a class="layui-btn layui-btn-sm layui-btn-primary goods-spec-btn" ng-click="addSpecVal(x.list)">增加</a>
  99. <a class="layui-btn layui-btn-sm layui-btn-primary goods-spec-btn" ng-class="{false:'layui-bg-gray'}[$index>0]" ng-click="upSpecRow(specs,$index)">上移</a>
  100. <a class="layui-btn layui-btn-sm layui-btn-primary goods-spec-btn" ng-class="{false:'layui-bg-gray'}[$index<specs.length-1]" ng-click="dnSpecRow(specs,$index)">下移</a>
  101. <a class="layui-btn layui-btn-sm layui-btn-primary goods-spec-btn" ng-click="delSpecRow(specs,$index)" ng-if="specs.length>1">删除</a>
  102. </div>
  103. </div>
  104. <div class="goods-spec-box padding-10 margin-0 layui-bg-gray block relative" ng-if="x.list && x.list.length > 0">
  105. <label class="label-required-null inline-block margin-right-10 margin-bottom-5 relative nowrap" ng-repeat="xx in x.list">
  106. <input type="checkbox" lay-ignore ng-model="xx.check" ng-click="xx.check=checkListChecked(x.list,$event.target.checked)">
  107. <input type="text" ng-blur="xx.name=trimSpace(xx.name)" ng-model="xx.name" ng-keyup="xx.name=$event.target.value" required placeholder="请输入规格">
  108. <a ng-if="x.list.length>1" ng-click="x.list=delSpecVal(x.list,$index)" class="layui-icon layui-icon-close font-s12 goods-spec-close"></a>
  109. </label>
  110. </div>
  111. </div>
  112. <!-- <a ng-if="isAddMode&&specs.length<3" class="layui-btn layui-btn-sm layui-btn-primary" ng-click="addSpecRow(specs)">增加分组</a>
  113. -->
  114. <table class="layui-table margin-top-10">
  115. <thead>
  116. <tr>
  117. <th ng-repeat="x in specsTreeNava track by $index" class="nowrap" ng-bind="x"></th>
  118. <th width="10%" class="text-center nowrap">商品SKU <a ng-click="batchSet('sku',null)" data-tips-text="批量设置" class="layui-icon">&#xe63c;</a></th>
  119. <th width="10%" class="text-center nowrap">市场价格 <a ng-click="batchSet('original_price',2)" data-tips-text="批量设置" class="layui-icon">&#xe63c;</a></th>
  120. <th width="10%" class="text-center nowrap">销售价格 <a ng-click="batchSet('sell_price',2)" data-tips-text="批量设置" class="layui-icon">&#xe63c;</a></th>
  121. <th width="10%" class="text-center nowrap">虚拟销量 <a ng-click="batchSet('virtual',0)" data-tips-text="批量设置" class="layui-icon">&#xe63c;</a></th>
  122. <th width="10%" class="text-center nowrap">重量(KG)<a ng-click="batchSet('weight',2)" data-tips-text="批量设置" class="layui-icon">&#xe63c;</a></th>
  123. <th width="10%" class="text-center nowrap">销售状态</th>
  124. </tr>
  125. </thead>
  126. <tbody>
  127. <tr ng-repeat="rows in specsTreeData track by $index">
  128. <td class="layui-bg-gray" ng-if="td.show" rowspan="{{td.span}}" ng-repeat="td in rows" ng-bind="td.name"></td>
  129. <td class="padding-0">
  130. <label class="padding-0 margin-0">
  131. <input ng-blur="rows[0].sku=setValue(rows[0].key,'sku',$event.target.value)" class="layui-input border-0 padding-left-0 text-center" ng-model="rows[0].sku">
  132. </label>
  133. </td>
  134. <td class="padding-0">
  135. <label class="padding-0 margin-0">
  136. <input ng-blur="rows[0].original_price=setValue(rows[0].key,'original_price',$event.target.value,'(parseFloat(_)||0).toFixed(2)')" class="layui-input border-0 padding-left-0 text-center" ng-model="rows[0].original_price">
  137. </label>
  138. </td>
  139. <td class="padding-0">
  140. <label class="padding-0 margin-0">
  141. <input ng-blur="rows[0].sell_price=setValue(rows[0].key,'sell_price',$event.target.value,'(parseFloat(_)||0).toFixed(2)')" class="layui-input border-0 padding-left-0 text-center" ng-model="rows[0].sell_price">
  142. </label>
  143. </td>
  144. <td class="padding-0">
  145. <label class="padding-0 margin-0">
  146. <input ng-blur="rows[0].virtual=setValue(rows[0].key,'virtual',$event.target.value,'(parseInt(_)||0)')" class="layui-input border-0 padding-left-0 text-center" ng-model="rows[0].virtual">
  147. </label>
  148. </td>
  149. <td class="padding-0">
  150. <label class="padding-0 margin-0">
  151. <input ng-blur="rows[0].weight=setValue(rows[0].key,'weight',$event.target.value,'(parseInt(_)||0).toFixed(2)')" class="layui-input border-0 padding-left-0 text-center" ng-model="rows[0].weight">
  152. </label>
  153. </td>
  154. <td class="text-center layui-bg-gray">
  155. <label class="think-checkbox margin-0 full-width full-height block"><input lay-ignore type="checkbox" ng-model="rows[0].status"></label>
  156. </td>
  157. </tr>
  158. </tbody>
  159. </table>
  160. <p class="color-desc">请从仓储平台获取商品SKU与商品条码,请注意尽量不要重复,也不能产生订单后再修改!</p>
  161. <textarea class="layui-textarea layui-hide" name="specs">{{specs}}</textarea>
  162. <textarea class="layui-textarea layui-hide" name="lists">{{specsTreeData}}</textarea>
  163. </div>
  164. <div class="layui-form-item layui-row layui-col-space15">
  165. <label class="layui-col-xs9 relative">
  166. <span class="color-green">详情</span>
  167. <textarea name="detail">{$vo.detail|default=""}</textarea>
  168. </label>
  169. </div>
  170. <div class="layui-form-item text-center">
  171. {notempty name='vo.id'}<input type="hidden" name="id" value="{$vo.id}">{/notempty}
  172. <button class="layui-btn" type="submit">保存商品</button>
  173. <button class="layui-btn layui-btn-danger" type='button' onclick="history.go(-1)" data-close>返回</button>
  174. </div>
  175. </div>
  176. </div>
  177. </div>
  178. </div>
  179. </form>
  180. {/block}
  181. {block name='script'}
  182. <textarea class="layui-hide" id="goods-specs">{$vo.specs|raw|default=''}</textarea>
  183. <textarea class="layui-hide" id="goods-value">{$defaultValues|raw|default=''}</textarea>
  184. <script>
  185. window.form.render();
  186. layui.use('form', function () {
  187. var form = layui.form;
  188. //日期时间范围
  189. laydate.render({
  190. elem: '#sell_time'
  191. ,type: 'datetime'
  192. });
  193. //监听指定开关
  194. form.on('radio(freight_type)', function(data) {
  195. if (data.value == 1) {
  196. $(".freight_mud").show();
  197. $(".postage").hide();
  198. } else {
  199. $(".freight_mud").hide();
  200. $(".postage").show();
  201. }
  202. })
  203. //监听指定开关
  204. })
  205. require(['ckeditor', 'angular'], function () {
  206. //window.createEditor('[name="content"]', {height: 500});
  207. var app = angular.module("GoodsForm", []).run(callback);
  208. angular.bootstrap(document.getElementById(app.name), [app.name]);
  209. function getRand(length, prefix) {
  210. return (function (time, code) {
  211. code += parseInt(time.substr(0, 1)) + parseInt(time.substr(1, 1)) + time.substr(2, 8);
  212. while (code.length < length) code += Math.round(Math.random() * 10);
  213. return code;
  214. })(Date.now().toString(), prefix || '' + '')
  215. }
  216. function callback($rootScope) {
  217. $rootScope.isAddMode = parseInt('{$isAddMode|default=0}');
  218. $rootScope.maps = JSON.parse(angular.element('#goods-value').val() || '[]') || {};
  219. $rootScope.specs = JSON.parse(angular.element('#goods-specs').val() || '[{"name":"默认分组","list":[{"name":"默认规格","check":true}]}]');
  220. // 批量设置数值
  221. $rootScope.batchSet = function (type, fixed) {
  222. layer.prompt({title: '请输入数值', formType: 0}, function (value, index) {
  223. $rootScope.$apply(function () {
  224. var val = (parseFloat(value) || 0).toFixed(fixed);
  225. for (var i in $rootScope.specsTreeData) for (var j in $rootScope.specsTreeData[i]) {
  226. $rootScope.specsTreeData[i][j][type] = val;
  227. }
  228. });
  229. layer.close(index);
  230. });
  231. };
  232. // 返回商品列表
  233. $rootScope.hsitoryBack = function () {
  234. $.msg.confirm('确定要取消编辑吗?', function (index) {
  235. history.back(), $.msg.close(index);
  236. });
  237. };
  238. // 设置默认值
  239. $rootScope.setValue = function (key, type, value, call) {
  240. $rootScope.maps[key] || ($rootScope.maps[key] = {});
  241. return $rootScope.maps[key][type] = eval(call.replace('_', "'" + value + "'"));
  242. };
  243. // 读取默认值
  244. $rootScope.getValue = function (key, callback) {
  245. if (typeof callback === 'function') {
  246. return callback($rootScope.maps[key] || {});
  247. }
  248. return {};
  249. };
  250. // 去除空白字符
  251. $rootScope.trimSpace = function (value) {
  252. return (value + '').replace(/\s*/ig, '');
  253. };
  254. // 生成交叉表格数据
  255. $rootScope.specsTreeData = [];
  256. $rootScope.specsTreeNava = [];
  257. // 当前商品规格发生变化时重新计算规格列表
  258. $rootScope.$watch('specs', function () {
  259. var data = $rootScope.specs, list = [], navs = [], table = [[]];
  260. // 过滤无效记录
  261. for (var i in data) {
  262. var tmp = [];
  263. for (var j in data[i].list) if (data[i].list[j].check && data[i].list[j].name.length > 0) {
  264. data[i].list[j].span = 1, data[i].list[j].show = true, data[i].list[j].group = data[i].name;
  265. tmp.push(data[i].list[j]);
  266. }
  267. list.push(tmp), navs.push(data[i].name);
  268. }
  269. $rootScope.specsTreeNava = navs;
  270. // 表格交叉
  271. for (var i in list) {
  272. var tmp = [];
  273. for (var j in table) for (var k in list[i]) tmp.push(table[j].concat(list[i][k]));
  274. table = tmp;
  275. }
  276. // 表格合并
  277. list = angular.fromJson(angular.toJson(table));
  278. for (var i in list) {
  279. var key = [], _key = '';
  280. for (var td in list[i]) key.push(list[i][td].group + '::' + list[i][td].name);
  281. for (var td in list[i]) if (_key.length === 0) {
  282. list[i][0].key = _key = key.join(';;');
  283. list[i][0].sku = $rootScope.getValue(_key, function (data) {
  284. return data.sku || getRand(14, 'D')
  285. });
  286. list[i][0].virtual = $rootScope.getValue(_key, function (data) {
  287. return data.virtual || '0';
  288. });
  289. list[i][0].express = $rootScope.getValue(_key, function (data) {
  290. return data.express || '1';
  291. });
  292. list[i][0].original_price = $rootScope.getValue(_key, function (data) {
  293. return data.original_price || '0.00';
  294. });
  295. list[i][0].sell_price = $rootScope.getValue(_key, function (data) {
  296. return data.sell_price || '0.00';
  297. });
  298. list[i][0].status = $rootScope.getValue(_key, function (data) {
  299. return !!(typeof data.status !== 'undefined' ? data.status : true);
  300. });
  301. list[i][0].weight = $rootScope.getValue(_key, function (data) {
  302. return data.weight || '0.00';
  303. });
  304. list[i][0].goods_no = $rootScope.getValue(_key, function (data) {
  305. return data.goods_no || '';
  306. });
  307. }
  308. }
  309. $rootScope.specsTreeData = list;
  310. }, true);
  311. // 判断规则是否能取消选择
  312. $rootScope.checkListChecked = function (list, check) {
  313. for (var i in list) if (list[i].check) return check;
  314. return true;
  315. };
  316. // 增加整行规格分组
  317. $rootScope.addSpecRow = function (data) {
  318. data.push({name: '规格分组', list: [{name: '规格属性', check: true}]})
  319. };
  320. // 下移整行规格分组
  321. $rootScope.dnSpecRow = function (data, $index) {
  322. var tmp = [], cur = data[$index];
  323. if ($index > data.length - 2) return false;
  324. for (var i in data) {
  325. (parseInt(i) !== parseInt($index)) && tmp.push(data[i]);
  326. (parseInt(i) === parseInt($index) + 1) && tmp.push(cur);
  327. }
  328. return $rootScope.specs = tmp;
  329. };
  330. // 上移整行规格分组
  331. $rootScope.upSpecRow = function (data, $index) {
  332. var tmp = [], cur = data[$index];
  333. if ($index < 1) return false;
  334. for (var i in data) {
  335. (parseInt(i) === parseInt($index) - 1) && tmp.push(cur);
  336. (parseInt(i) !== parseInt($index)) && tmp.push(data[i]);
  337. }
  338. return $rootScope.specs = tmp;
  339. };
  340. // 移除整行规格分组
  341. $rootScope.delSpecRow = function (data, $index) {
  342. var tmp = [];
  343. for (var i in data) if (parseInt(i) !== parseInt($index)) tmp.push(data[i]);
  344. return $rootScope.specs = tmp;
  345. };
  346. // 增加分组的属性
  347. $rootScope.addSpecVal = function (list) {
  348. list.push({name: '规格属性', check: true});
  349. };
  350. // 移除分组的属性
  351. $rootScope.delSpecVal = function (data, $index) {
  352. var temp = [];
  353. for (var i in data) if (parseInt(i) !== parseInt($index)) temp.push(data[i]);
  354. return temp;
  355. };
  356. }
  357. })
  358. layui.use('element', function(){
  359. var $ = layui.jquery
  360. ,element = layui.element;
  361. var active = {
  362. tabAdd: function(){
  363. element.tabAdd('demo', {
  364. title: '新选项'+ (Math.random()*1000|0)
  365. ,content: '内容'+ (Math.random()*1000|0)
  366. ,id: new Date().getTime()
  367. })
  368. }
  369. ,tabDelete: function(othis){
  370. element.tabDelete('demo', '44');
  371. othis.addClass('layui-btn-disabled');
  372. }
  373. ,tabChange: function(){
  374. element.tabChange('demo', '22');
  375. }
  376. };
  377. $('.site-demo-active').on('click', function(){
  378. var othis = $(this), type = othis.data('type');
  379. active[type] ? active[type].call(this, othis) : '';
  380. });
  381. //Hash地址的定位
  382. var layid = location.hash.replace(/^#test=/, '');
  383. element.tabChange('test', layid);
  384. element.on('tab(test)', function(elem){
  385. location.hash = 'test='+ $(this).attr('lay-id');
  386. });
  387. });
  388. require(['ckeditor', 'angular'], function () {
  389. window.createEditor('[name="detail"]', {
  390. height: 500,
  391. });
  392. })
  393. </script>
  394. {/block}