add.html 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430
  1. {extend name="common/common2" /}
  2. {block name="main"}
  3. <style>
  4. .main-content{
  5. background-color: #f0f0f0;
  6. }
  7. .page-content{
  8. padding: 0;
  9. background-color: #f0f0f0;
  10. }
  11. .page-content2{
  12. padding: 8px 20px 24px;
  13. position: relative;
  14. }
  15. .box-left{
  16. width: 200px;
  17. position: fixed;
  18. z-index: 10;
  19. top: 100px;
  20. left: 210px;
  21. bottom: 40px;
  22. border: 1px solid #000;
  23. }
  24. .question-box{
  25. width: 800px;
  26. margin:0 auto;
  27. background-color: #ffffff;
  28. margin-top: 10px;
  29. padding: 55px 35px;
  30. box-shadow: #bbbbbb;
  31. min-height: 800px;
  32. overflow: hidden;
  33. }
  34. .question-box-title,.question-box-desc,.question-box-btn{
  35. padding: 10px 0;
  36. overflow: hidden;
  37. }
  38. .question-box-desc{
  39. text-indent:30px;
  40. }
  41. .question-box-info{
  42. padding: 15px 0;
  43. overflow: hidden;
  44. cursor: pointer;
  45. }
  46. .border-line{
  47. border-top: 1px solid #cccccc;
  48. border-bottom: 1px solid #cccccc;
  49. }
  50. .question-form{
  51. height: 34px;
  52. line-height: 34px;
  53. margin: 5px 0;
  54. overflow: hidden;
  55. }
  56. .question-form-option{
  57. height: auto;
  58. margin: 5px 0;
  59. overflow: hidden;
  60. }
  61. .question-form-title{
  62. display: inline-block;
  63. width: 30px;
  64. height: 100%;
  65. }
  66. .question-form-input{
  67. display: inline-block;
  68. width: 690px;
  69. height: 100%;
  70. }
  71. .question-options{
  72. width: 640px;
  73. height: 32px;
  74. color: #606266!important;
  75. font-size: 13px!important;
  76. padding: 5px 15px!important;
  77. border-width: 1px;
  78. border-style: solid;
  79. border-color: rgb(229, 230, 231);
  80. }
  81. .xz:focus,.form-select:focus,.question-options:focus{
  82. border-color: #148d8f !important;
  83. outline:0;
  84. }
  85. ul, ol {
  86. margin: 0;
  87. }
  88. .form-select{
  89. height: 32px;
  90. color: #606266!important;
  91. font-size: 13px!important;
  92. padding: 5px 15px!important;
  93. box-shadow:none;
  94. border-width: 1px;
  95. border-style: solid;
  96. border-color: rgb(229, 230, 231);
  97. }
  98. .xz{
  99. width: 60px;
  100. line-height: 1.2px;
  101. padding: 5px 4px;
  102. border-width: 1px;
  103. border-style: solid;
  104. border-color: rgb(229, 230, 231);
  105. }
  106. .lb{
  107. width: 100px !important;
  108. }
  109. </style>
  110. <div class="row">
  111. <div class="col-sm-12">
  112. <div class="ibox float-e-margins">
  113. <div class="ibox-content">
  114. <div class="page-content2" id="vueapp">
  115. <div class="question-box">
  116. <div class="question-box-title">
  117. <h3 v-if="editother !== 1" class="text-center" @click="editOthers(1)">{{title}}</h3>
  118. <input v-if="editother === 1" type="text" v-model="title" class="form-control" placeholder="请输入标题">
  119. </div>
  120. <div class="question-box-desc">
  121. <div v-if="editother !== 2" @click="editOthers(2)">{{description}}</div>
  122. <textarea v-if="editother === 2" v-model="description" class="form-control" rows="3" placeholder="请输入描述"></textarea>
  123. </div>
  124. <draggable :list="question" :move="getdata2" @update="datadragEnd2" :options="{animation: 100,handle:'.dargDiv2'}">
  125. <transition-group name="list-complete" >
  126. <div v-for="(item,index) in question" :key="index" class="question-box-list">
  127. <div v-if="edit !== item.id" class="question-box-info dargDiv2">
  128. <div @click="editQuestion(item)">
  129. <div>{{index + 1}}、{{item.title}} <span v-if="item.required" class="text-danger">*</span></div>
  130. <div>{{item.remark}}</div>
  131. <div v-if="item.type === 'radio'||item.type === 'checkbox'" style="padding: 20px;">
  132. <div v-for="(oitem,oindex) in item.options" :key="oindex">
  133. <label><input :type="item.type" disabled>{{oitem.text}}</label>
  134. </div>
  135. </div>
  136. <div v-if="item.type === 'text'" style="padding: 10px 20px;">
  137. <input type="text" style="width: 100%" readonly>
  138. </div>
  139. <div v-if="item.type === 'textarea'" style="padding: 10px 20px;">
  140. <textarea rows="3" style="width: 100%" readonly></textarea>
  141. </div>
  142. <div v-if="item.type === 'star'" style="padding: 10px 20px;">
  143. <span>{{item.star_min_text}}</span>&nbsp;&nbsp;
  144. <label v-for="n in item.star_val_max" :key="n"><input type="radio" disabled>{{n}}&nbsp;&nbsp;</label>
  145. <span>{{item.star_max_text}}</span>&nbsp;&nbsp;
  146. </div>
  147. </div>
  148. </div>
  149. <div v-if="edit === item.id" class="question-box-info border-line">
  150. <div class="question-form">
  151. <div class="question-form-title">题目</div>
  152. <div class="question-form-input">
  153. <input type="text" v-model="item.title" class="form-control">
  154. </div>
  155. </div>
  156. <div class="question-form">
  157. <div class="question-form-title">备注</div>
  158. <div class="question-form-input">
  159. <input type="text" v-model="item.remark" class="form-control">
  160. </div>
  161. </div>
  162. <div class="question-form">
  163. <div class="question-form-title">&nbsp;</div>
  164. <div class="question-form-input">
  165. <select class="form-select" v-model="item.type" @change="changeType">
  166. <option v-for="(type,index2) in types" :key="index2" :value="type.val">{{type.name}}</option>
  167. </select>
  168. &nbsp;&nbsp;&nbsp;
  169. <label><input type="checkbox" v-model="item.required" checked>必填</label>
  170. &nbsp;&nbsp;&nbsp;
  171. <label v-if="item.type === 'text'||item.type === 'textarea'">字数限制 <input v-model="item.limit" type="number" class="xz"> 字</label>
  172. </div>
  173. </div>
  174. <div class="question-form-option" v-if="item.type === 'radio'||item.type === 'checkbox'">
  175. <ul class="list-group" id="question-options">
  176. <draggable :list="item.options" :move="getdata" @update="datadragEnd" :options="{animation: 100,handle:'.dargDiv'}">
  177. <transition-group name="list-complete" >
  178. <li v-for="(item3,index3) in item.options" :key="index3" class="list-group-item">
  179. <span class="glyphicon glyphicon-menu-hamburger dargDiv"></span>
  180. &nbsp;
  181. <input type="text" v-model="item3.text" class="question-options ">
  182. &nbsp;
  183. <span @click="delOption(item,item3.id)">×</span>
  184. </li>
  185. </transition-group>
  186. </draggable>
  187. </ul>
  188. <a href="javascript:;" @click="addOption(item)">添加选项</a>
  189. </div>
  190. <div class="question-form-option" v-if="item.type === 'star'">
  191. 量表程度 <input class="xz lb" v-model="item.star_min_text" type="text"> - <input v-model="item.star_max_text" type="text" class="xz lb" > &nbsp;&nbsp; 量表范围 {{item.star_val_min}} - {{item.star_val_max}}
  192. </div>
  193. <div class="question-form" style="text-align: center;margin-top: 20px;">
  194. <button class="btn btn-primary btn-sm" type="button" @click="confirm(item)">确定</button>
  195. <button class="btn btn-danger btn-sm" type="button" @click="delQuestion(index)">删除</button>
  196. </div>
  197. </div>
  198. </div>
  199. </transition-group>
  200. </draggable>
  201. <div class="question-box-btn" v-if="!edit">
  202. <button type="button" class="btn btn-primary btn-block" @click="addQuestion">新增题目</button>
  203. </div>
  204. <div class="question-box-btn" v-if="question.length > 0 && title && !edit">
  205. <button type="button" class="btn btn-success btn-block" onclick="savequestionnaire(this)">保存问卷</button>
  206. </div>
  207. </div>
  208. </div>
  209. </div>
  210. </div>
  211. </div>
  212. </div>
  213. {/block}
  214. {block name="script"}
  215. <script type="text/javascript" src="/static/vuejs/require.js"></script>
  216. <script>
  217. $(document).ready(function(){
  218. formSetValue("enable", {$info.enable|default=1});
  219. });
  220. var question = [];
  221. var qstr = '';
  222. var tstr = '';
  223. var dstr = '';
  224. var types = [
  225. {"name":"单选题",val:"radio"},
  226. {"name":"多选题",val:"checkbox"},
  227. {"name":"单行文本题",val:"text"},
  228. {"name":"多行文本题",val:"textarea"},
  229. {"name":"量表题",val:"star"},
  230. ];
  231. require.config({
  232. urlargs: "ver=1.0_0",
  233. paths:{
  234. "vue":'/static/vuejs/vue.min2',
  235. "sortablejs":'/static/vuejs/sortable',
  236. "vuedraggable":'/static/vuejs/vuedraggable'
  237. },
  238. shim:{
  239. 'vue':{
  240. exports:'vue'
  241. }
  242. }
  243. });
  244. require(['vue','vuedraggable'],function(Vue,draggable){
  245. Vue.component('draggable', draggable);
  246. var vm = new Vue({
  247. el: '#vueapp',
  248. data: {
  249. question: question,
  250. title: '满意度调查',
  251. description: '满意度调查描述',
  252. editother: 0,
  253. types: types,
  254. edit: 0,
  255. maxid: 1,
  256. info: {
  257. id: 1,
  258. title: "",
  259. remark: "",
  260. type: "radio", // radio=单选 checkbox=多选 text=单行文本题 textarea=多行文本题 star=量表题
  261. required: true, // true=不填
  262. options: [{
  263. id: 2,
  264. text: "选项"
  265. }],
  266. star_min_text: "非常不满意",
  267. star_max_text: "非常满意",
  268. star_val_min: 1,
  269. star_val_max: 5,
  270. limit: 200 // 单行文本题/多行文本题字数限制
  271. }
  272. },
  273. computed: {
  274. resoptions: function () {
  275. return JSON.parse(JSON.stringify(this.question));
  276. }
  277. },
  278. watch: {
  279. resoptions: function (newval, oldval) {
  280. console.log(newval, oldval);
  281. this.formatData();
  282. },
  283. },
  284. created: function () {
  285. this.formatData();
  286. },
  287. methods: {
  288. addQuestion() {
  289. const item = JSON.parse(JSON.stringify(this.info));
  290. item.id = this.maxid;
  291. item.options[0].id = this.maxid;
  292. this.maxid += 2;
  293. this.edit = item.id;
  294. this.editother = 0;
  295. this.question.push(JSON.parse(JSON.stringify(item)));
  296. },
  297. editQuestion(obj) {
  298. this.edit = obj.id;
  299. this.editother = 0;
  300. },
  301. delQuestion(index) {
  302. let oldoptions = JSON.parse(JSON.stringify(this.question));
  303. let newoptions = [];
  304. for(let o in oldoptions){
  305. if(o != index){
  306. newoptions.push(oldoptions[o]);
  307. }
  308. }
  309. this.question = JSON.parse(JSON.stringify(newoptions));
  310. this.edit = 0;
  311. },
  312. addOption(obj){
  313. this.question.forEach((item) => {
  314. const info = item;
  315. if(obj.id === item.id){
  316. const oitem = {
  317. id: this.maxid,
  318. text: "选项"
  319. };
  320. this.maxid += 1;
  321. info.options.push(oitem);
  322. }
  323. })
  324. },
  325. delOption(obj,id){
  326. this.question.forEach((item) => {
  327. const info = item;
  328. if(obj.id === item.id){
  329. const opts = item.options.filter((item2) => {
  330. return item2.id !== id;
  331. });
  332. info.options = opts;
  333. }
  334. })
  335. },
  336. editOthers(val){
  337. this.editother = val;
  338. this.edit = 0;
  339. },
  340. changeType(val){
  341. console.log(this.question);
  342. },
  343. confirm(obj){
  344. // 检查内容是否填写完整
  345. if(obj.title === ''){
  346. layer.msg('题目不能为空');
  347. return false;
  348. }
  349. if(obj.type === 'radio'||obj.type === 'checkbox'){
  350. if(obj.options.lenght === 0){
  351. layer.msg('未设置选项');
  352. return false;
  353. }
  354. for (let o in obj.options){
  355. if(obj.options[o].text === ''){
  356. layer.msg('选项内容不能为空');
  357. return false;
  358. }
  359. }
  360. }
  361. if(obj.type === 'star'){
  362. if(obj.star_min_text === '' || obj.star_max_text === ''){
  363. layer.msg('量表程度不能为空');
  364. return false;
  365. }
  366. }
  367. this.edit = 0;
  368. },
  369. formatData(){
  370. qstr = JSON.stringify(this.question);
  371. tstr = this.title;
  372. dstr = this.description;
  373. },
  374. getdata: function(evt){
  375. console.log(evt);
  376. },
  377. datadragEnd:function(evt){
  378. console.log('拖动前的索引:'+evt.oldIndex);
  379. console.log('拖动后的索引:'+evt.newIndex);
  380. console.log(evt);
  381. },
  382. getdata2: function(evt){
  383. console.log(evt);
  384. },
  385. datadragEnd2:function(evt){
  386. console.log('拖动前的索引:'+evt.oldIndex);
  387. console.log('拖动后的索引:'+evt.newIndex);
  388. console.log(evt);
  389. }
  390. }
  391. })
  392. });
  393. function savequestionnaire(_self) {
  394. var flag = $(_self).attr('data-flag');
  395. if(flag == 1){
  396. return false;
  397. }
  398. $(_self).attr('data-flag',1).html('保 存...');
  399. var url = "add";
  400. $.post(url,{title:tstr,description:dstr,question:qstr},function (res) {
  401. if(res.code === 1){
  402. parent.layer.closeAll();
  403. }else{
  404. layer.msg(res.info);
  405. }
  406. $(_self).attr('data-flag',0).html('保 存')
  407. });
  408. }
  409. </script>
  410. {/block}