ProjectCreate.vue 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562
  1. <template>
  2. <div class="create-container" v-loading="loading">
  3. <div class="title h1">创建项目</div>
  4. <div class="create-body">
  5. <el-form :model="project" :rules="rules" ref="project" label-width="12%" class="demo-project">
  6. <el-form-item label="项目名称" prop="name">
  7. <el-input size="small" v-model="project.name" placeholder="请输入项目名称"></el-input>
  8. </el-form-item>
  9. <el-form-item label="联系人" prop="contactName">
  10. <el-input size="small" v-model="project.contactName" placeholder="请输入联系人姓名"></el-input>
  11. </el-form-item>
  12. <el-form-item label="手机号" prop="contactPhone">
  13. <el-input size="small" v-model="project.contactPhone" placeholder="请输入联系人电话"></el-input>
  14. </el-form-item>
  15. <el-form-item label="预算" prop="budget">
  16. <el-input size="small" type="number" v-model="project.budget" placeholder="请输入项目预算">
  17. <template slot="append">¥</template>
  18. </el-input>
  19. </el-form-item>
  20. <el-form-item label="需求描述" prop="desc">
  21. <el-input type="textarea" style="width: 400px" v-model="project.desc"
  22. placeholder="请输入对项目的描述"></el-input>
  23. </el-form-item>
  24. <!--<el-form-item label="价格" prop="price">-->
  25. <!--<el-input type="number" v-model="project.price">-->
  26. <!--<template slot="append">¥</template>-->
  27. <!--</el-input>-->
  28. <!--</el-form-item>-->
  29. <el-form-item label="平台" prop="platform">
  30. <el-checkbox-group v-model="project.platform">
  31. <span v-for="(item,index) in platforms" :key="index">
  32. <el-checkbox :label="item">{{ item }}&nbsp;&nbsp;&nbsp;&nbsp;</el-checkbox>
  33. </span>
  34. </el-checkbox-group>
  35. </el-form-item>
  36. <el-form-item label="服务类型" prop="type">
  37. <el-checkbox-group v-model="project.type">
  38. <span v-for="(item,index) in serviceType" :key="index">
  39. <el-checkbox :label="item" name="type">{{item}}&nbsp;&nbsp;&nbsp;&nbsp;</el-checkbox>
  40. </span>
  41. </el-checkbox-group>
  42. </el-form-item>
  43. <el-form-item label="项目可见性" prop="resource">
  44. <el-tabs
  45. :tab-position="tabPosition"
  46. v-model="project.resource"
  47. style="max-height: 200px;"
  48. >
  49. <el-tab-pane :label="resourceType[0]" name="0">
  50. <el-radio-group v-model="project.institution" prop="institution">
  51. <el-radio :label="item" name="type" v-for="item,index in institutionArray" :key="index">{{item.name}}
  52. </el-radio>
  53. </el-radio-group>
  54. </el-tab-pane>
  55. <el-tab-pane :label="resourceType[1]" name="1">
  56. <provincecity
  57. ref="addFormProvince"
  58. @selectChange="locationChange"
  59. :provinceCode="project.location.provinceCode"
  60. :cityCode="project.location.cityCode"
  61. ></provincecity>
  62. </el-tab-pane>
  63. <el-tab-pane :label="resourceType[2]" name="2"></el-tab-pane>
  64. </el-tabs>
  65. </el-form-item>
  66. <el-form-item label="需求文档" prop="doc">
  67. <el-upload
  68. style="width: 400px"
  69. drag
  70. class="upload-demo"
  71. action=""
  72. :on-remove="handleRemove"
  73. :before-remove="beforeRemove"
  74. :limit="1"
  75. :on-exceed="handleExceed"
  76. :before-upload="beforeFileUpload"
  77. :http-request="uploadRequireDoc"
  78. :file-list="project.doc"
  79. >
  80. <i class="el-icon-upload"></i>
  81. <div class="el-upload__text">
  82. 将文件拖到此处,或
  83. <em>点击上传</em>
  84. </div>
  85. </el-upload>
  86. </el-form-item>
  87. <el-form-item label="安装包" prop="file">
  88. <el-upload
  89. drag
  90. style="width: 400px"
  91. class="upload-demo"
  92. action=""
  93. :on-remove="handleRemove"
  94. :limit="1"
  95. :on-exceed="handleExceed"
  96. :before-upload="beforeApkUpload"
  97. :http-request="uploadApkFile"
  98. :file-list="project.file"
  99. >
  100. <i class="el-icon-upload"></i>
  101. <div class="el-upload__text">
  102. 将文件拖到此处,或
  103. <em>点击上传</em>
  104. </div>
  105. </el-upload>
  106. </el-form-item>
  107. <el-form-item label="项目截止时间" prop="datetime">
  108. <div class="block">
  109. <el-date-picker
  110. size="small"
  111. v-model="project.datetime"
  112. type="datetime"
  113. placeholder="选择截止时间"
  114. align="right"
  115. :picker-options="pickerOptions"
  116. ></el-date-picker>
  117. </div>
  118. </el-form-item>
  119. <el-form-item>
  120. <div class="btn btn-medium btn-info" v-on:click="submitForm('project')">立即申请</div>
  121. <div class="btn btn-medium" @click="resetForm('project')">重置</div>
  122. </el-form-item>
  123. </el-form>
  124. </div>
  125. </div>
  126. </template>
  127. <script>
  128. import Http from '@/js/http.js'
  129. import Apis from '@/js/api.js'
  130. import provincecity from '@/components/commons/ProvinceCity'
  131. import provinceCityJSON from '@/constants/provinceCity.json'
  132. import ResourceType from '@/constants/enum/resource-type'
  133. import {notify} from '@/constants/index'
  134. import {
  135. checkFileType,
  136. getAllInstitutions,
  137. getAllPlatformTypes,
  138. getAllServiceTypes,
  139. getProvinceNameByProvinceCode,
  140. storageGet
  141. } from '@/js/index'
  142. export default {
  143. name: 'ProjectCreate',
  144. components: {
  145. provincecity
  146. },
  147. data () {
  148. var validatePass = (rule, value, callback) => {
  149. var reg = /^(0|86|17951)?(13[0-9]|15[012356789]|17[678]|18[0-9]|14[57])[0-9]{8}$/
  150. if (this.contactPhone) {
  151. if (!reg.test(this.contactPhone)) {
  152. callback(new Error('请检查手机号码'))
  153. } else {
  154. callback()
  155. }
  156. }
  157. }
  158. return {
  159. user: {},
  160. loading: false,
  161. tabPosition: 'top',
  162. institutionArray: [],
  163. platforms: [],
  164. serviceType: [],
  165. resourceType: ResourceType,
  166. project: {
  167. userId: 0,
  168. name: '',
  169. contactName: '',
  170. contactPhone: '',
  171. type: [],
  172. platform: [],
  173. desc: '',
  174. doc: [],
  175. file: [],
  176. requireDocUrl: '',
  177. fileUrl: '',
  178. resource: '0',
  179. location: {provinceCode: '3200', cityCode: '3201'},
  180. institution: {},
  181. datetime: '',
  182. price: '',
  183. usage: '',
  184. budget: ''
  185. },
  186. pickerOptions: {
  187. disabledDate(time) {
  188. return time.getTime() <= Date.now();
  189. },
  190. shortcuts: [
  191. {
  192. text: '今天',
  193. onClick (picker) {
  194. picker.$emit('pick', new Date())
  195. }
  196. },
  197. {
  198. text: '明天',
  199. onClick (picker) {
  200. const date = new Date()
  201. date.setTime(date.getTime() + 3600 * 1000 * 24)
  202. picker.$emit('pick', date)
  203. }
  204. },
  205. {
  206. text: '一周后',
  207. onClick (picker) {
  208. const date = new Date()
  209. date.setTime(date.getTime() + 3600 * 1000 * 24 * 7)
  210. picker.$emit('pick', date)
  211. }
  212. }
  213. ]
  214. },
  215. rules: {
  216. name: [
  217. {required: true, message: '请输入项目名称', trigger: 'blur'},
  218. {min: 5, max: 50, message: '项目名称长度在 5 到 50 个字符', trigger: 'blur'}
  219. ],
  220. contactName: [
  221. {required: true, message: '请输入联系人姓名', trigger: 'blur'}
  222. // { min: 3, max: 5, message: "长度在 3 到 5 个字符", trigger: "blur" }
  223. ],
  224. contactPhone: [
  225. {required: true, message: '请输入手机号', trigger: 'blur'},
  226. {min: 11, max: 11, message: '请输入正确的手机号', trigger: 'blur'}
  227. ],
  228. type: [
  229. {
  230. type: 'array',
  231. required: true,
  232. message: '请至少选择一种服务类型',
  233. trigger: 'change'
  234. }
  235. ],
  236. platform: [
  237. {
  238. type: 'array',
  239. required: true,
  240. message: '请至少选择一个平台',
  241. trigger: 'change'
  242. }
  243. ],
  244. desc: [{required: false, message: '请填写描述', trigger: 'blur'}],
  245. //price: [{required: true, message: '请填写价格', trigger: 'blur'}],
  246. budget: [
  247. {required: true, message: '预算不可为空', trigger: 'blur'},
  248. {
  249. validator: (rule, value, callback) => {
  250. if(value < 0){
  251. callback(new Error('请输入不小于0的数'))
  252. } else {
  253. callback()
  254. }
  255. }, trigger: 'blur'
  256. },
  257. ],
  258. resource: [
  259. {required: true},
  260. {
  261. validator: (rule, value, callback) => {
  262. if (value == 0 && this.project.institution.id == null) {
  263. callback(new Error('定向发布至少要选择一个区域管理员'))
  264. } else {
  265. callback()
  266. }
  267. }, trigger: 'change'
  268. },
  269. ],
  270. datetime:[{required: true, message: '截止时间不可为空', trigger: 'blur'}],
  271. }
  272. }
  273. },
  274. mounted () {
  275. this.$nextTick(() => {
  276. this.init()
  277. })
  278. },
  279. watch: {
  280. serviceType (val) {
  281. this.serviceType = val
  282. },
  283. institutionArray (val) {
  284. this.institutionArray = val
  285. },
  286. // 'project.institution' () {
  287. // if (this.project.institution) {
  288. // this.$refs.addFormProvince.resetProviceCity()
  289. // this.project.location = {provinceCode: '', cityCode: ''}
  290. // }
  291. // },
  292. // 'project.location' () {
  293. // if (this.project.location.provinceCode || this.project.location.cityCode) {
  294. // this.project.institution = ''
  295. // }
  296. // },
  297. // 'project.resource' () {
  298. // if (this.project.resource == '2') {
  299. // this.$refs.addFormProvince.resetProviceCity()
  300. // this.project.institution = ''
  301. // this.project.location = {provinceCode: '', cityCode: ''}
  302. // }
  303. // },
  304. deep: true
  305. },
  306. methods: {
  307. updateLocation (location) {
  308. var provinceName = ''
  309. var cityName = ''
  310. for (var item of provinceCityJSON.provinces) {
  311. if (item.code === location.provinceCode) {
  312. provinceName = item.name
  313. for (var city of item.cities) {
  314. if (city.code === location.cityCode) {
  315. cityName = city.name
  316. break
  317. }
  318. }
  319. }
  320. }
  321. return provinceName + ' / ' + cityName
  322. },
  323. locationChange (provinceId, cityId) {
  324. if (provinceId || cityId) {
  325. this.project.location = {provinceCode: provinceId, cityCode: cityId}
  326. }
  327. },
  328. init () {
  329. this.setServiceType()
  330. this.setPlatforms()
  331. this.setInstitution()
  332. this.setUserInfo()
  333. // this.project.platform.map(item => {
  334. // this.platformType.push(PlatformType[item])
  335. // })
  336. },
  337. submitForm () {
  338. this.$refs['project'].validate(valid => {
  339. if (valid) {
  340. //console.log(this.project)
  341. this.showLoading()
  342. const newLocation = getProvinceNameByProvinceCode(this.project.location.provinceCode, this.project.location.cityCode)
  343. const newProject = {
  344. userId: this.user.userVO.id,
  345. name: this.project.name,
  346. type: this.project.type,
  347. platform: this.project.platform,
  348. desc: this.project.desc,
  349. resource: this.project.resource,
  350. location: newLocation,
  351. institution: this.project.institution.id,
  352. contactName: this.project.contactName,
  353. contactPhone: this.project.contactPhone,
  354. doc: this.project.requireDocUrl,
  355. file: this.project.fileUrl,
  356. budget: this.project.budget,
  357. datetime: this.project.datetime,
  358. usage: this.project.usage,
  359. price: this.project.price
  360. }
  361. Http.post(Apis.PROJECT.CREATE_PROJECT, newProject).then((res) => {
  362. //notify('success', '创建成功')
  363. this.hideLoading()
  364. this.createProjectSuccess(res.projectDetails.id)
  365. // if (window.history.length <= 1) {
  366. // this.$router.push({path: '/'})
  367. // return false
  368. // } else {
  369. // this.$router.go(-1)
  370. // }
  371. }).catch(error => {
  372. //console.log(error)
  373. notify('error', error.data)
  374. })
  375. } else {
  376. console.log(valid)
  377. notify('error','表单填写错误!')
  378. return false
  379. }
  380. })
  381. },
  382. resetForm (formName) {
  383. this.$refs[formName].resetFields()
  384. this.project.name = ''
  385. this.project.type = []
  386. this.project.platform = []
  387. this.project.desc = ''
  388. this.project.file = ''
  389. this.project.doc = ''
  390. this.project.contactName = ''
  391. this.project.contactPhone = ''
  392. this.project.resource = '非定向'
  393. this.project.institution = ''
  394. this.project.datetime = ''
  395. this.project.price = ''
  396. this.project.usage = ''
  397. this.project.budget = ''
  398. },
  399. beforeApkUpload (file) {
  400. const fileType = ['exe', 'apk', 'dmg']
  401. return checkFileType(file, fileType, this.beforeApkUploadError)
  402. },
  403. beforeApkUploadError () {
  404. this.$message.error('上传文件只能是exe,dmg,apk格式!')
  405. },
  406. beforeFileUpload (file) {
  407. const fileTypeList = ['pdf', 'xls', 'xlsx', 'doc', 'docx', 'txt']
  408. return checkFileType(file, fileTypeList, this.beforeFileUploadError)
  409. },
  410. beforeFileUploadError () {
  411. this.$message.error('上传文件只能是 PDF 、 DOC 、DOCX 、XLS、TXT、XLSX 格式!')
  412. },
  413. loadData () {
  414. Http.get(Apis.PAGE.PROJECT_DETAIL_PAGE).then((res) => {
  415. this.project = res.project
  416. })
  417. },
  418. handleRemove (file, fileList) {
  419. //console.log(file, fileList)
  420. },
  421. handleExceed (files, fileList) {
  422. this.$message.warning(
  423. `当前限制选择 1 个文件,本次选择了 ${
  424. files.length
  425. } 个文件,共选择了 ${files.length + fileList.length} 个文件`
  426. )
  427. },
  428. beforeRemove (file, fileList) {
  429. //return this.$confirm(`确定移除 ${file.name}?`)
  430. },
  431. uploadRequireDoc (param) {
  432. this.showLoading()
  433. const formData = new FormData()
  434. let config = {
  435. //添加请求头
  436. headers: {'Content-Type': 'multipart/form-data'},
  437. }
  438. formData.append('file', param.file)
  439. Http.upload(Apis.FILE.REQUIREMENT_FILE.replace('{userId}', this.user.userVO.id), formData, config).then((res) => {
  440. //console.log('上传成功')
  441. this.hideLoading()
  442. notify('success', '需求文档上传成功')
  443. this.project.requireDocUrl = res.data
  444. //console.log(this.project.doc)
  445. //console.log(res.data)
  446. }).catch((error) => {
  447. this.hideLoading()
  448. notify('error', '需求文档上传失败:' + error.data)
  449. })
  450. },
  451. uploadApkFile (param) {
  452. this.showLoading()
  453. const formData = new FormData()
  454. let config = {
  455. //添加请求头
  456. headers: {'Content-Type': 'multipart/form-data'},
  457. }
  458. formData.append('file', param.file)
  459. Http.upload(Apis.FILE.APK.replace('{userId}', this.user.userVO.id), formData, config).then((res) => {
  460. this.hideLoading()
  461. notify('success', '文件上传成功')
  462. this.project.fileUrl = res.data
  463. console.log(res)
  464. }).catch((error) => {
  465. this.hideLoading()
  466. notify('error', '文件上传失败:' + error.data)
  467. })
  468. },
  469. setServiceType () {
  470. getAllServiceTypes().then((res) => {
  471. this.serviceType = res
  472. }).catch((error) => {
  473. notify('error', '获取项目服务类型列表失败')
  474. })
  475. },
  476. setPlatforms () {
  477. this.platforms = getAllPlatformTypes()
  478. },
  479. setInstitution () {
  480. getAllInstitutions().then((res) => {
  481. this.institutionArray = res
  482. })
  483. },
  484. setUserInfo () {
  485. this.user = storageGet('user')
  486. },
  487. createProjectSuccess (projectId) {
  488. this.$alert('项目创建成功', '创建成功', {
  489. confirmButtonText: '确定',
  490. callback: action => {
  491. this.$router.push({
  492. name: 'Project',
  493. params: {projectId: projectId}
  494. })
  495. }
  496. })
  497. },
  498. showLoading () {
  499. this.loading = true
  500. },
  501. hideLoading () {
  502. this.loading = false
  503. }
  504. }
  505. }
  506. </script>
  507. <style lang="less" scoped>
  508. .el-col {
  509. padding: 0 !important;
  510. }
  511. .el-row {
  512. margin-bottom: 10px;
  513. }
  514. .el-radio {
  515. margin: 10px 20px 10px 0;
  516. }
  517. .el-form-item /deep/ .el-tabs__content {
  518. max-height: 120px !important;
  519. overflow: auto;
  520. }
  521. .el-input {
  522. width: 400px;
  523. }
  524. </style>
  525. <!--<el-form-item label="联系方式" prop="contact">-->
  526. <!--<div>-->
  527. <!--<el-row :gutter="2">-->
  528. <!--<el-col :span="2">-->
  529. <!--<span>联系人</span>-->
  530. <!--</el-col>-->
  531. <!--<el-col :span="10">-->
  532. <!--<el-input v-model="project.contactName" placeholder="请输入联系人姓名"></el-input>-->
  533. <!--</el-col>-->
  534. <!--</el-row>-->
  535. <!--<el-row :gutter="2">-->
  536. <!--<el-col :span="2">-->
  537. <!--<span>联系人电话</span>-->
  538. <!--</el-col>-->
  539. <!--<el-col :span="10">-->
  540. <!--<el-input v-model="project.contactPhone" placeholder="请输入联系人电话"></el-input>-->
  541. <!--</el-col>-->
  542. <!--</el-row>-->
  543. <!--</div>-->
  544. <!--</el-form-item>-->
  545. <!--<el-form-item label="用途" prop="usage">-->
  546. <!--<el-input v-model="project.usage"></el-input>-->
  547. <!--</el-form-item>-->