AdConfigDialog.vue 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290
  1. <template>
  2. <confirm-dialog
  3. ref="configDialog"
  4. :title="title"
  5. @confirm="onSave"
  6. >
  7. <div class="c-grid-form auto u-align-self--center">
  8. <span class="c-grid-form__label">自助投放</span>
  9. <div class="l-flex--row c-grid-form__option">
  10. <el-switch
  11. v-model="attributes.enable"
  12. active-color="#13ce66"
  13. inactive-color="#ff4949"
  14. />
  15. </div>
  16. <span class="c-grid-form__label">单次时长(s)</span>
  17. <el-input-number
  18. v-model="attributes.minDuration"
  19. class="has-info"
  20. data-info="范围:5~600"
  21. controls-position="right"
  22. :min="5"
  23. :max="600"
  24. :step="5"
  25. step-strictly
  26. />
  27. <span class="c-grid-form__label">起投次数</span>
  28. <el-input-number
  29. v-model="attributes.minCount"
  30. controls-position="right"
  31. :min="1"
  32. :max="1000"
  33. step-strictly
  34. />
  35. <span class="c-grid-form__label">单价(分)</span>
  36. <el-input-number
  37. v-model="attributes.price"
  38. class="has-info"
  39. :data-info="price"
  40. controls-position="right"
  41. :min="1"
  42. :max="1000000000"
  43. step-strictly
  44. />
  45. <span class="c-grid-form__label">类型</span>
  46. <el-select
  47. v-model="attributes.tag"
  48. class="u-width--sm"
  49. >
  50. <el-option
  51. v-for="option in tagOptions"
  52. :key="option.value"
  53. :label="option.label"
  54. :value="option.value"
  55. />
  56. </el-select>
  57. <span class="c-grid-form__label">简介</span>
  58. <el-input
  59. v-model.trim="attributes.introduce"
  60. class="u-width--lg"
  61. type="textarea"
  62. :rows="3"
  63. />
  64. <span class="c-grid-form__label">简介图片</span>
  65. <div class="l-flex--row">
  66. <div
  67. v-for="(file, index) in files"
  68. :key="index"
  69. class="l-flex--row c-sibling-item u-relative"
  70. >
  71. <img
  72. class="c-media"
  73. :src="file.url"
  74. >
  75. <i
  76. class="l-flex__none c-media__del el-icon-delete has-active"
  77. @click="onDelFile(file, index)"
  78. />
  79. </div>
  80. <div
  81. v-show="files.length < 3"
  82. class="c-sibling-item c-media add u-pointer"
  83. @click="onSelect"
  84. >
  85. <i class="el-icon-plus" />
  86. </div>
  87. <!-- <el-upload
  88. ref="upload"
  89. class="c-config-dialog__upload"
  90. action="none"
  91. :auto-upload="false"
  92. :show-file-list="false"
  93. :on-change="onChange"
  94. >
  95. <button class="c-sibling-item o-button">
  96. 上传 <i class="el-icon-upload el-icon--right" />
  97. </button>
  98. </el-upload> -->
  99. </div>
  100. <span class="c-grid-form__label">日均观看人次</span>
  101. <el-input
  102. v-model.trim="attributes.dailyFlow"
  103. class="u-width"
  104. />
  105. <span class="c-grid-form__label">男女比(%)</span>
  106. <el-input
  107. v-model.trim="attributes.gendeRatio"
  108. class="u-width"
  109. />
  110. <span class="c-grid-form__label">老少青比(%)</span>
  111. <el-input
  112. v-model.trim="attributes.ageRatio"
  113. class="u-width"
  114. />
  115. </div>
  116. <single-asset-dialog
  117. ref="assetDialog"
  118. :choosen="onChoosenAsset"
  119. @directory-changed="onAssetDirectoryChanged"
  120. @view="onViewAsset"
  121. />
  122. <preview-dialog ref="previewDialog" />
  123. </confirm-dialog>
  124. </template>
  125. <script>
  126. import { AssetType } from '@/constant'
  127. import {
  128. getAssetsByQuery,
  129. getAssetUrl
  130. } from '@/api/asset'
  131. import {
  132. getAdAttributes,
  133. updateAdAttributes,
  134. bindFileToAttributes
  135. } from '../api'
  136. export default {
  137. name: 'AdConfigDialog',
  138. data () {
  139. return {
  140. isAdd: false,
  141. attributes: {},
  142. files: [],
  143. schema: {
  144. list: getAssetsByQuery,
  145. cols: [
  146. { prop: 'file', label: '', type: 'asset' }
  147. ]
  148. },
  149. tagOptions: [
  150. { label: '不限', value: '' },
  151. { label: '商圈百货', value: '1' },
  152. { label: '星级酒店', value: '2' },
  153. { label: '地产物业', value: '3' },
  154. { label: '企业机构', value: '4' },
  155. { label: '机场车站', value: '5' },
  156. { label: '旅游景区', value: '6' },
  157. { label: '住宅社区', value: '7' },
  158. { label: '医疗机构', value: '8' },
  159. { label: '教育机构', value: '9' }
  160. ],
  161. directoryOption: null
  162. }
  163. },
  164. computed: {
  165. title () {
  166. return `${this.isAdd ? '新增' : '更新'}广告属性`
  167. },
  168. price () {
  169. const price = this.attributes.price || 0
  170. return `5秒 x ${this.attributes.minCount}次 = ${(price / 100).toFixed(2)}元`
  171. }
  172. },
  173. methods: {
  174. onChange ({ raw }) {
  175. this.$refs.upload.clearFiles()
  176. const isImg = raw.type === 'image/jpeg' || raw.type === 'image/png' || raw.type === 'image/jpg'
  177. if (!isImg) {
  178. this.$message({
  179. type: 'warning',
  180. message: '上传格式不正确(只能是.png,.jpg,.jpeg'
  181. })
  182. return
  183. }
  184. bindFileToAttributes(this.$deviceId, raw)
  185. },
  186. randomDailyFlow () {
  187. return Math.random() * 2000 | 0
  188. },
  189. randomGende () {
  190. const random = Math.random() * 100 | 0
  191. return `${random}:${100 - random}`
  192. },
  193. randomAge () {
  194. const random1 = Math.random() * 100 | 0
  195. const random2 = Math.random() * (100 - random1) | 0
  196. return `${100 - random1 - random2}:${random1}:${random2}`
  197. },
  198. show ({ id }) {
  199. const loading = this.$showLoading()
  200. this.$deviceId = id
  201. getAdAttributes(id).then(({ data }) => {
  202. this.isAdd = !data
  203. this.files = data?.pictureUrl ? this.getFiles(data.pictureUrl) : []
  204. this.attributes = {
  205. enable: false,
  206. minDuration: 5, // 最小投放广告时长(单位秒)
  207. minCount: 10, // 最小投放次数
  208. price: 1000, // 单位分
  209. ...data,
  210. dailyFlow: this.randomDailyFlow(),
  211. gendeRatio: this.randomGende(),
  212. ageRatio: this.randomAge()
  213. }
  214. this.$refs.configDialog.show()
  215. }).finally(() => {
  216. this.$closeLoading(loading)
  217. })
  218. },
  219. getFiles (pictureUrl) {
  220. const result = []
  221. pictureUrl.split(',').forEach(keyName => {
  222. result.push({
  223. url: getAssetUrl(keyName),
  224. keyName
  225. })
  226. })
  227. return result
  228. },
  229. onSave (done) {
  230. updateAdAttributes(this.$deviceId, {
  231. ...this.attributes,
  232. pictureUrl: this.files.map(({ keyName }) => keyName).join(',')
  233. }).then(done)
  234. },
  235. onSelect () {
  236. this.$refs.assetDialog.show(
  237. AssetType.IMAGE,
  238. this.directoryOption
  239. )
  240. },
  241. onAssetDirectoryChanged (directory) {
  242. this.directoryOption = directory
  243. },
  244. onViewAsset ({ file }) {
  245. this.$refs.previewDialog.show(file)
  246. },
  247. onChoosenAsset ({ keyName }) {
  248. this.files.push({
  249. url: getAssetUrl(keyName),
  250. keyName
  251. })
  252. return Promise.resolve()
  253. },
  254. onDelFile (file, index) {
  255. this.files.splice(index, 1)
  256. }
  257. }
  258. }
  259. </script>
  260. <style lang="scss" scoped>
  261. .c-media {
  262. width: 64px;
  263. height: 64px;
  264. border-radius: $radius;
  265. &.add {
  266. display: inline-flex;
  267. justify-content: center;
  268. align-items: center;
  269. border: 1px dashed #ccc;
  270. &:hover{
  271. border: 1px dashed $primary;
  272. }
  273. }
  274. &__del {
  275. display: inline-flex;
  276. justify-content: center;
  277. align-items: center;
  278. position: absolute;
  279. top: $padding--2xs;
  280. right: $padding--2xs;
  281. color: $gray;
  282. }
  283. }
  284. </style>